Skip to content

MarIA: permissions, agents, worktrees, questions, @-agent chains and Ruflo memory - #2

Merged
dr-phil-2004 merged 18 commits into
mainfrom
claude/zen-hawking-ioda4g
Oct 2, 2026
Merged

dr-phil-2004 merged 18 commits into
mainfrom
claude/zen-hawking-ioda4g

Conversation

@dr-phil-2004

@dr-phil-2004 dr-phil-2004 commented Oct 2, 2026 •

Copy link
Copy Markdown
Owner

Follow-up to #1, which was merged right after the schema commit. This brings the rest of the MarIA work to main so Vercel can deploy it to production. Every change is under apps/maria/; Ruflo's core is untouched.

What's included

  • Permission prompts: actions that aren't pre-allowed show an Allow/Deny window in MarIA. This goes through a small MCP server (worker/permission-mcp.ts) passed to --permission-prompt-tool. If that server fails to start, the feed reports it.
  • Agent questions: AskUserQuestion opens a pop-up with options and free text. The answer goes back to the agent.
  • Agents panel: Claude Code sub-agents (running, done, failed), plus a snapshot of the Ruflo registry.
  • Worktree missions: optional per-mission git branch. Up to MARIA_MAX_PARALLEL run at once per folder. Merge or discard from the UI.
  • @-agent chains: @architect @coder … restricts the mission to those sub-agents, delegated in order and synchronously. A PreToolUse hook blocks any other sub-agent and any background launch. The form autocompletes @ from the folder's .claude/agents.
  • Ruflo memory view: the worker reads .swarm/memory.db read-only (node:sqlite) and mirrors changes to Supabase every 30 s. A new "Mémoire" tab shows entries, with a namespace filter and search.
  • Headless guidance and feed cleanup:
    • the agent is told how to run without a terminal: no cd, && or git -C;
    • sub-agents are run synchronously, one after another;
    • the feed has one session line and shows the cost only on the final result.
  • Node 22 requirement: the worker refuses older versions, because supabase-js needs native WebSocket. The memory view needs 22.13+.

Database

Run migrations 0002 to 0007 in supabase/migrations/ in order, if they aren't applied yet. All 7 migrations were applied on Postgres 16 with a Supabase-like shim, and RLS was checked: members can read, outsiders see nothing, and the browser cannot write the worker's tables.

Deployment (Vercel)

  • Root directory: apps/maria.
  • Environment variables: NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY. Never set SUPABASE_SERVICE_ROLE_KEY on Vercel.
  • The worker keeps running on the local machine.

Testing

  • npm run typecheck and npm run build pass.
  • Real Claude Code CLI:
    • the permission tool allows and denies;
    • AskUserQuestion answers come back to the agent;
    • the stream format of sub-agents was checked;
    • the chain guard denies a sub-agent that wasn't mentioned, and a background launch.
  • Real git: worktree creation, commit, merge, conflict abort, discard.
  • Fake claude runner: parallel worktree missions and an in-place regression run.
  • Real Ruflo memory.db: diff sync of additions, changes and removals.

🤖 Generated with RuFlo

https://claude.ai/code/session_01EYLzTmzezSkXAERkr41FBp


Generated by Claude Code


Devin Review

claude and others added 18 commits October 1, 2026 15:36
Fail fast in the worker with an actionable message instead of the
supabase-js realtime WebSocket error, add .nvmrc and bump engines.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01EYLzTmzezSkXAERkr41FBp
…enials

- Append a system prompt telling the agent it runs unattended: no cd or
  chained commands (so pre-approved tool patterns match), no retrying
  denied variants, end with a question for follow-ups.
- Show the result event's permission_denials in the activity feed so the
  user knows which tools to add to MARIA_ALLOWED_TOOLS.
- Broaden the example allowlist to common npm/node/git read commands.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01EYLzTmzezSkXAERkr41FBp
Those variants miss simple allowlist patterns like Bash(git status) and
get denied; ask for the plain form run from the working directory.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01EYLzTmzezSkXAERkr41FBp
Instead of auto-denying tools that are not pre-approved, the agent's
permission prompts are now routed to the user:

- worker/permission-mcp.ts: a minimal stdio MCP server that Claude Code
  calls through --permission-prompt-tool. It records each request in
  maria.permission_requests and waits for the user's decision (fails
  closed: deny on timeout or technical error).
- Migration 0002: permission_requests table, decide_permission() RPC
  (members only, first decision wins), realtime publication.
- Front: PermissionPrompt modal with tool, command summary and full
  parameters; tab title shows pending count.
- Pending requests expire when a mission ends or the worker restarts.
- Configurable via MARIA_INTERACTIVE_PERMISSIONS (default on) and
  MARIA_PERMISSION_TIMEOUT_MS (default 10 min).

Verified with the real claude CLI (allow runs the command, deny returns
the refusal to the agent) and the SQL against Postgres 16.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01EYLzTmzezSkXAERkr41FBp
…denying

- Read mcp_servers from the init event; if the 'maria' permission server
  is not connected, post an error in the activity feed explaining that
  non-allowlisted actions will be denied without a prompt.
- Log permission-server errors (startup and Supabase failures) to
  $TMPDIR/maria-permissions.log, since Claude Code hides MCP stderr.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01EYLzTmzezSkXAERkr41FBp
- src/lib/agents.ts rebuilds the mission's agents from the event stream:
  each Agent/Task tool call opens a sub-agent, messages carrying its
  parent_tool_use_id count as its actions, and the matching tool_result
  closes it (done / error; interrupted if the mission ends first). Also
  tallies calls to Ruflo MCP tools (swarm_init, agent_spawn...).
- AgentsPanel shows main agent, sub-agents (type, description, status,
  action count, last action, nesting) and the Ruflo section.
- After a mission that used Ruflo, the worker snapshots the registry via
  `ruflo agent list --format json` into missions.ruflo_agents (migration
  0003). `--all` is avoided: the CLI turns it into a status === 'all'
  filter that never matches. Command configurable via MARIA_RUFLO_CMD.

Verified against a real stream-json capture of a sub-agent run and the
real ruflo CLI (spawned agents are listed).

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01EYLzTmzezSkXAERkr41FBp
…ished

- Background sub-agents return 'Async agent launched' immediately; the
  panel no longer marks them done on that result. The final status now
  comes from the system task_notification event (completed / failed /
  stopped), and task_progress keeps the action count up to date.
- Feed: one line per finished sub-agent, and intermediate result events
  (one per turn with async agents) are labelled 'Tour terminé' so only the
  last one reads as the end of the mission.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01EYLzTmzezSkXAERkr41FBp
- New per-mission option "Branche isolée": the worker creates a worktree
  on branch maria/<id>-<slug> from the workspace HEAD, links shared
  untracked state (.claude-flow, .swarm, node_modules) and copies local
  config (.mcp.json, .claude, CLAUDE.md) when they are not versioned.
- Worktree missions run in parallel (MARIA_MAX_PARALLEL per workspace,
  default 3); in-place missions and merges stay exclusive on the main
  folder. claim_next_mission now takes in-place and worktree eligible
  workspaces separately (migration 0004).
- At the end of a mission, the agent's changes are committed on the
  branch (linked/copied entries excluded). "Continuer" reuses the parent's
  worktree so the Claude session can resume in the same directory.
- Branch panel in the mission view: merge into the workspace's current
  branch (refused if it has uncommitted changes; aborted cleanly on
  conflict) or discard (worktree and branch removed), via the
  request_worktree_action RPC; the worker executes and reports errors.

Verified on real git (create, commit, merge, dirty refusal, conflict
abort, discard), the SQL on Postgres 16, and two parallel missions
through the runner with a fake claude.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01EYLzTmzezSkXAERkr41FBp
With no terminal the interactive question is lost ('The user did not
answer'). Disallow the tool so the agent asks in plain text at the end
of its answer; the user replies with 'Continuer'.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01EYLzTmzezSkXAERkr41FBp
AskUserQuestion already reaches MarIA's permission prompt tool; it used to
be approved without answers, so the agent got "did not answer".

- The permission MCP server now returns the user's answers as
  updatedInput.answers ({ question: answer }), the format Claude Code
  expects; skipping or timing out tells the agent to proceed with
  reasonable choices and say so.
- Migration 0005: permission_requests.response + answer_question() RPC
  (members only, AskUserQuestion requests only, first answer wins).
- Front: the pop-up shows each question with its options (single or
  multiple choice), an "Autre" free-text answer, "Répondre" and
  "Ne pas répondre".
- AskUserQuestion is only disabled when interactive permissions are off;
  the agent is told to use it when it needs a decision.

Verified with the real claude CLI (answered, skipped, and a regular
permission request) and the SQL on Postgres 16.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01EYLzTmzezSkXAERkr41FBp
- Show 'Session Claude Code ouverte' only once (Claude Code re-emits init
  on every resume when async sub-agents report back).
- Only announce task_notification for sub-agents; background commands
  (npm test, build) emit it too and showed up as 'Sous-agent sous-agent'.
- Cost is cumulative: display it only on the final result line.
- Headless note: sub-agents cannot message each other, so the agent is
  told to run them synchronously, relay each result itself, and not poll
  with ScheduleWakeup/ListAgents.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01EYLzTmzezSkXAERkr41FBp
- "@architect @coder Ajoute…" limits the mission to those sub-agents: the
  main agent is told to delegate each step in order, synchronously, relaying
  each result to the next.
- A PreToolUse hook (worker/agent-guard.ts, passed via --settings) denies any
  other sub-agent type and background launches.
- The worker publishes the agents available in each folder (.claude/agents,
  user agents, built-ins) to maria.workspaces.agents (migration 0006); the
  mission form autocompletes @ mentions and previews the chain.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01EYLzTmzezSkXAERkr41FBp
- Agents whose name contains spaces ("Benchmark Suite", "Performance
  Monitor"…) are now listed and mentioned as @Benchmark-Suite; the chain
  note and the guard keep the exact subagent_type.
- The suggestion menu shows every match (scrollable, keyboard-followed)
  instead of the first 8, and also matches on the description.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01EYLzTmzezSkXAERkr41FBp
- The worker reads memory_entries from each folder's .swarm/memory.db
  (read-only, node:sqlite) every 30 s and mirrors added, changed and
  removed entries into maria.memory_entries (migration 0007).
- New "Mémoire" tab: per-folder entries with namespace filters, search on
  key/content/tags and expandable content.
- MARIA_MEMORY_DB sets the database path (relative to each folder), or
  disables the sync with 0.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01EYLzTmzezSkXAERkr41FBp
@coderabbitai

coderabbitai Bot commented Oct 2, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: aae35b92-3153-4648-9a02-b6eed14c5186

  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 9 potential issues.

1 flag not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

Comment on lines +127 to +142
const parent = mission.parent_id ? await store.getMission(mission.parent_id) : null;
if (parent?.worktree_state === 'active' && parent.worktree_path && parent.branch && existsSync(parent.worktree_path)) {
const worktree: WorktreeInfo = {
path: parent.worktree_path,
cwd: await worktreeCwd(workspaceDir, parent.worktree_path),
branch: parent.branch,
baseCommit: parent.base_commit ?? '',
};
await store.update(mission.id, {
branch: worktree.branch,
worktree_path: worktree.path,
base_commit: parent.base_commit,
worktree_state: 'active',
});
sink.info(`Suite dans la branche ${worktree.branch}`);
return { cwd: worktree.cwd, worktree };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Deux suites simultanées modifient la même branche isolée

Si deux suites sont lancées pour une même mission, elles réutilisent simultanément son worktree. Leurs modifications et commits se mélangent, contrairement à l'isolation promise.

Learn more

Une suite de mission peut reprendre le dossier et la branche de son parent. Le compteur de startMission limite seulement le nombre de missions par workspace, pas l'occupation de chaque worktree. Deux suites créées depuis un même parent passent donc toutes deux ici et exécutent Claude en parallèle sur les mêmes fichiers. Le contrôle worktreeBusy ne sert que lors d'une fusion ou d'un abandon, après l'exécution.

Example: Deux suites A et B sont lancées depuis la branche de la mission P. A et B lisent le même état, modifient le même fichier et exécutent chacune un commit ; la branche contient un mélange imprévisible de leurs travaux.

Recommended fix: Réserver atomiquement le chemin de worktree avant de lancer une suite, et ne démarrer qu'une seule mission qui écrit dans ce chemin ; coordonner aussi cette réservation avec la fusion et l'abandon.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +309 to +313
const sha = await commitWorktree(cwd, `MarIA: ${title}\n\nMission ${mission.id}`, [...cfg.worktreeLinks, ...cfg.worktreeCopies]);
sink.info(sha ? `Modifications commitées sur ${worktree.branch} (${sha.slice(0, 7)}).` : `Aucune modification à commiter sur ${worktree.branch}.`);
} catch (err) {
sink.info(`Commit sur ${worktree.branch} impossible : ${(err as Error).message}`, 'error');
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 La fusion efface les modifications quand le commit a échoué

Si le commit automatique échoue, la mission reste fusionnable. La fusion puis la suppression forcée du worktree effacent ses modifications non commitées.

Learn more

Le worker tente de commiter les modifications d'une mission isolée, mais en cas d'échec il ne fait que publier un message. Il enregistre ensuite le statut terminal dans runMission, ce qui rend la fusion disponible dans BranchPanel. mergeWorktree fusionne les commits, puis removeWorktree supprime de force le dossier contenant les changements non commités.

Example: Le commit échoue parce qu'un fichier ajouté est illisible. L'utilisateur clique « Fusionner » : git fusionne la branche sans ce fichier et supprime le dossier où il se trouvait.

Recommended fix: Conserver l'erreur de commit dans l'état du worktree et bloquer toute fusion ou suppression forcée tant que le travail non commité n'a pas été sauvegardé ou que l'utilisateur n'a pas explicitement choisi de le perdre.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

if (worktree && !exit.error) {
const title = mission.prompt.split('\n')[0].slice(0, 72);
try {
const sha = await commitWorktree(cwd, `MarIA: ${title}\n\nMission ${mission.id}`, [...cfg.worktreeLinks, ...cfg.worktreeCopies]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Les fichiers suivis exclus du commit disparaissent à la fusion

Une mission peut modifier .claude ou CLAUDE.md lorsqu'ils sont suivis par git. Leur exclusion systématique du commit laisse ces changements dans le worktree, que la fusion supprime ensuite.

Learn more

Par défaut, loadConfig inclut .claude et CLAUDE.md dans les copies. Quand ces chemins sont déjà suivis, createWorktree ne les copie pas, puisqu'ils existent dans le checkout git. Pourtant commitWorktree les exclut de git add -A, même si l'agent a modifié leurs versions suivies. Une fusion ultérieure supprime de force le worktree et ces modifications.

Example: Le dépôt suit CLAUDE.md. L'agent l'édite puis termine ; le commit n'inclut pas cette édition, et « Fusionner » la perd.

Recommended fix: N'exclure du commit que les liens et copies réellement ajoutés hors suivi lors de la création du worktree ; conserver l'index des chemins suivis par git dans la sélection à commiter.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

for (const mission of await store.pendingWorktreeActions(names.filter((n) => !mainBusy.has(n)))) {
if (mainBusy.has(mission.workspace)) continue;
mainBusy.add(mission.workspace);
track(runWorktreeAction(mission, cfg.workspaces[mission.workspace], store), () => mainBusy.delete(mission.workspace));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Une erreur de fusion peut arrêter le worker

Si la lecture ou la mise à jour Supabase échoue pendant une action de branche, la promesse rejetée n'est pas interceptée. Le worker peut alors s'arrêter avec ses autres missions en cours.

Learn more

Le poller lance chaque action de branche dans runWorktreeAction via track, sans .catch. Le contrôle worktreeBusy est hors du try, et updateWorktree peut également échouer dans le bloc de rattrapage. track utilise .finally, qui conserve le rejet ; aucune autre fonction ne consomme cette promesse. Une panne Supabase transitoire crée donc un rejet non géré sous Node et peut tuer le worker.

Example: Supabase devient indisponible au moment de vérifier une demande « Fusionner ». worktreeBusy rejette ; le processus worker quitte alors que d'autres missions tournent.

Recommended fix: Intercepter explicitement toute erreur de runWorktreeAction avant track, la journaliser, et garantir que la promesse suivie se résout même quand l'enregistrement de l'erreur échoue.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +107 to +110
const entries = readMemory(path.resolve(dir, this.relPath), workspace) ?? [];
const changed = entries.filter((e) => known.get(e.id) !== Date.parse(e.updated_at ?? ''));
const current = new Set(entries.map((e) => e.id));
const removed = [...known.keys()].filter((id) => !current.has(id));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Une absence temporaire de la base efface la mémoire affichée

Si le fichier SQLite manque momentanément, la synchronisation traite cette absence comme une mémoire vide. Elle supprime alors toutes les entrées affichées dans Supabase.

Learn more

readMemory renvoie null lorsque le fichier n'existe pas, pour distinguer ce cas d'une table réellement vide. Le ?? [] efface cette distinction : les identifiants de toutes les entrées connues sont alors placés dans removed et supprimés de Supabase. Le fichier source n'est pas modifié, mais l'interface affiche une mémoire vidée jusqu'à une synchronisation réussie après son retour.

Example: .swarm/memory.db est renommé quelques secondes pour être remplacé ; un battement du worker arrive pendant l'intervalle et supprime les 100 entrées affichées.

Recommended fix: Ignorer la synchronisation lorsque readMemory renvoie null ; ne supprimer les entrées que lorsque la lecture d'une base présente confirme leur absence.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Mission « {mission.prompt.length > 80 ? `${mission.prompt.slice(0, 80)}…` : mission.prompt} » · {mission.workspace}
</p>
)}
<QuestionForm questions={questions} busy={busy} onAnswer={answer} onSkip={() => decide(false)} />

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Une nouvelle question conserve les réponses de la précédente

Lorsque deux demandes arrivent successivement, le formulaire reste monté et conserve ses choix par index. La seconde question apparaît préremplie et peut envoyer une ancienne réponse.

Suggested change
<QuestionForm questions={questions} busy={busy} onAnswer={answer} onSkip={() => decide(false)} />
<QuestionForm key={current.id} questions={questions} busy={busy} onAnswer={answer} onSkip={() => decide(false)} />

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

export async function commitWorktree(cwd: string, message: string, excluded: string[]): Promise<string | null> {
const relToTop = await git(cwd, ['rev-parse', '--show-prefix']);
const excludes = excluded.map((name) => `:(top,exclude)${path.posix.join(relToTop, name)}`);
await git(cwd, ['add', '-A', '--', ':/', ...excludes]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Le commit d'une mission englobe tout le dépôt

Quand le workspace est un sous-dossier, le commit ajoute aussi les modifications faites ailleurs dans le worktree. La fusion importe ainsi des changements étrangers à la mission.

Learn more

createWorktree prévoit explicitement qu'un workspace puisse être un sous-dossier du dépôt. Pourtant git add -A -- :/ cible la racine entière. Si l'agent ou un autre outil modifie un fichier frère dans ce worktree, celui-ci est inclus dans le commit automatique et dans la fusion, bien qu'il ne soit pas dans le dossier de travail configuré.

Example: Le workspace est repo/service-a, et un outil modifie repo/service-b/config.json depuis son checkout. Le commit automatique de la mission inclut aussi cette configuration.

Recommended fix: Limiter l'ajout aux chemins propres au workspace, ou rendre explicite et contrôler le choix d'un commit à l'échelle du dépôt ; vérifier les chemins déjà indexés avant de commiter.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +82 to +90
for (const name of opts.copies) {
const src = path.join(workspaceDir, name);
const dst = path.join(cwd, name);
if (existsSync(src) && !existsSync(dst)) cpSync(src, dst, { recursive: true });
}
for (const name of opts.links) {
const src = path.join(workspaceDir, name);
const dst = path.join(cwd, name);
if (existsSync(src) && !existsSync(dst)) symlinkSync(src, dst);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟥 Les chemins de copie des worktrees peuvent sortir du dossier autorisé

Un élément configuré avec .. peut pointer hors du workspace lors de la création d'un worktree. Le worker copie ou relie alors des fichiers extérieurs dans le dossier de l'agent.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread apps/maria/.env.example
MARIA_ALLOWED_TOOLS=Read,Glob,Grep,Edit,Write,Bash(npm run *),Bash(npx ruflo *),Bash(git status),Bash(git diff *)
# Tout ce qui n'est pas listé est refusé (personne ne peut approuver en headless) ; les refus
# s'affichent en fin de mission dans MarIA. Élargis selon ce que tes missions doivent faire.
MARIA_ALLOWED_TOOLS=Read,Glob,Grep,Edit,Write,Bash(npm install *),Bash(npm run *),Bash(npm test *),Bash(npm --prefix *),Bash(npx *),Bash(node *),Bash(ls *),Bash(git status *),Bash(git diff *),Bash(git log *)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟨 Les commandes préautorisées évitent la validation interactive

L'exemple préautorise Bash(npx *) et Bash(node *). Ces commandes peuvent exécuter du code arbitraire sans afficher la fenêtre de permission annoncée.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

@dr-phil-2004
dr-phil-2004 merged commit 64be8c1 into main Oct 2, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants