agentplugged 1.0.6 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { n as SESSION_INSTANCE_ENV, r as SESSION_KEY_ENV, t as ENGINE_CHILD_ENV } from "./launcher-env.js";
2
2
  import { $ as engineEntry, A as resolveEngineCommand, B as planOf, C as codexHookHashes, D as questionToolHookIn, E as elicitationHookIn, F as STATE_CACHE_PATH, G as DEFAULT_THRESHOLDS, H as compare, I as evalStatus, J as casesDigest, K as EVALS_DIR, L as loadSkill, M as validateInstallChannel, N as writeInstallChannel, O as parseRootPin, P as detectGitWorkflow, Q as engineDir, R as suggestStarter, S as recordToolRead, T as planCodexTrust, U as keep, V as selection, W as CASES_FILE, X as ENGINE_PACKAGE, Y as readCases, Z as agentpluggedHome, _ as codexCallOf, a as NodeProofRunner, b as callOf, c as createCommandRegistry, f as envValue, g as CODEX_FLAVOR, h as cursorSessionOf, i as NodeMutationLab, j as readInstallChannel, k as rootPinText, l as ResponseMemory, m as cursorCallOf, n as productRootOf, nt as isReleaseVersion, o as NodeEvalAgent, p as CURSOR_FLAVOR, q as REFERENCE_FILE, r as NodeUsageTraces, s as NodeToolProbe, tt as isInstalledEngine, u as shapeResponse, v as codexSessionOf, w as codexTrustSupported, x as guardToolCall, y as recordCodexRead, z as evaluate } from "./product-root.js";
3
- import { Aa as DeferredIdInputSchema, Ao as resolveGitWorkflow, Bo as ErrorCode, Bt as journalRemoteRef, D as DeviationIdInputSchema, Do as GitBranchSchema, Eo as GIT_MERGE_MODES, Fo as ULID_PATTERN, Ft as JOURNAL_DIR, Io as eventInvalid, It as JOURNAL_REF, Ja as DEFAULT_VALIDATION_MODE, Ka as DEFAULT_INSTALL_MODE, Mo as EVENT_REASON, O as DeviationReasonSchema, P as TracedRequirementInputSchema, Pt as EVENT_TYPES, Qa as INSTALL_MODES, Ro as parseEventEnvelope, Sa as contentSections, Sr as QUESTION_TOOL_NAME, Vt as journalSeenRef, Xa as DEVELOPER_SPECIALTIES, Ya as DEFAULT_VALIDATION_POINTS, Za as DOMAIN_IDS, d as utf8, fo as TOOL_IDS, g as JOURNAL_PROJECTED_REF, ho as VALIDATION_POINTS, i as randomBytes, ko as recommendedGitWorkflow, l as toBase64url, mo as VALIDATION_MODES, no as PHASE_IDS, o as sha256Hex, qa as DEFAULT_PERMISSION_MODE, ro as PROFILE_PRESET_IDS, s as fromBase64url, to as PERMISSION_MODES, u as toHex, un as MAX_ELICITED_NOTE_LENGTH, wo as GIT_CI_MODES, zt as journalEventPath } from "./webauthn.js";
4
- import { $o as displayName, An as maybeAutoUpdate, Ar as AgentSession, Bo as publishedShape, Br as nextDeviceHead, Bu as waiverRefusal, Cn as withAnswers, Cs as formDigest, Ds as CI_CONFIG_PATHS, En as engineTargetOf, Eu as byOpening, Fd as creatorText, G as researchLines, Go as SKILL_OVERRIDES_DIR, Ha as renderCodexHooks, Ho as toolCallOf, Hr as prepareEngineEvents, Ir as checkHumanEvents, Iu as reviewActions, Ja as withEngineCommand, K as costsLines, Kr as forgetProductKey, Ku as METHOD_CONFIG_PATH, Lu as statusAt, Md as eventHash, Ml as ARCHITECTURE_SECURITY_REVIEW_PATH, Ms as isWorkflowFile, On as installAndPin, Os as GITHUB_WORKFLOWS_DIR, Pd as ANTIGRAVITY_UNCHECKED_REASON, Pr as createUlidFactory, Pu as parseWaiverAnswer, Qn as checkCreate, Ro as inputShapeOf, Rr as deviceHeads, Ru as waiverDeadlineProblem, Sn as runFix, Sr as COMMIT_STORIES_DIR, Ta as checkEngine, Td as normalizeChatText, Uo as toolNotation, Vo as TOOL_GROUPS, Vr as prepareAppend, Vu as AgentPluggedError, Wo as withToolNotation, Wr as announcedKey, Xn as AGENT_ACTIONS, Xr as sensitiveProductKey, _c as forgeOfHost$1, _r as CHAINED_HOOK_NAME, _s as keychainFull, ad as isAntigravityClient, au as STORY_BUILDERS, bc as remoteLocation, bn as displayCommand, br as COMMIT_HOOK_NAME, bs as DECISION_FORM_FIELDS, cd as isHookedClient, cr as recordGitWorkflow, dn as JournalBackup, es as toolName, fd as sameProject, fu as DEFAULT_PRESET, gc as forgeCli, io as methodNotInstalled, jd as canonicalBytes, jt as parseConflictMarkers, ku as ACTION_DECISIONS, ls as readDefinitions, mi as stackPromptDigest, mu as isPresetId, no as detectTools, od as isCodexClient, oo as readProfile, pu as inactiveAgents, qo as isPersonalLayerFile, ru as isRetiredDeveloper, sd as isCursorClient, so as resolveProfile, sr as validateCreateField, st as reviewNotInteractive, to as toolsFromDetection, ts as TOOL_CATALOG, ui as stackField, un as JOURNAL_REMOTE_NAME, vr as COMMIT_CHECK_PATH, vs as loadMachineKey, wd as messageDigest, xc as repositoryWebUrl, xr as COMMIT_SKIPS_PATH, yn as answerProblem, yr as COMMIT_HOOK_LINE, zr as journalProduct } from "./agent-commands.js";
5
- import { t as parsePresenceAttestation } from "./webauthn-verify2.js";
3
+ import { At as JOURNAL_REF, Bo as recommendedGitWorkflow, Fo as GIT_CI_MODES, Ft as journalSeenRef, Ko as ULID_PATTERN, Lo as GIT_MERGE_MODES, Mr as QUESTION_TOOL_NAME, Nt as journalEventPath, Ot as EVENT_TYPES, Pt as journalRemoteRef, Ro as GitBranchSchema, So as TOOL_IDS, To as VALIDATION_POINTS, Uo as EVENT_REASON, Vo as resolveGitWorkflow, Yo as parseEventEnvelope, Zo as ErrorCode, a as fromBase64url, ao as DEVELOPER_SPECIALTIES, c as toHex, do as PHASE_IDS, fo as PROFILE_PRESET_IDS, g as JOURNAL_PROJECTED_REF, i as sha256Hex, in as MAX_ELICITED_NOTE_LENGTH, io as DEFAULT_VALIDATION_POINTS, ja as contentSections, kt as JOURNAL_DIR, l as utf8, n as randomBytes, no as DEFAULT_PERMISSION_MODE, on as DeviationIdInputSchema, oo as DOMAIN_IDS, pn as TracedRequirementInputSchema, qo as eventInvalid, ro as DEFAULT_VALIDATION_MODE, s as toBase64url, sn as DeviationReasonSchema, so as INSTALL_MODES, to as DEFAULT_INSTALL_MODE, uo as PERMISSION_MODES, wo as VALIDATION_MODES, za as DeferredIdInputSchema } from "./hash.js";
4
+ import { $n as checkCreate, As as CI_CONFIG_PATHS, Br as journalProduct, Bu as waiverDeadlineProblem, Cc as remoteLocation, Cn as runFix, Cr as COMMIT_STORIES_DIR, Cs as DECISION_FORM_FIELDS, Dd as normalizeChatText, Dn as engineTargetOf, Ed as messageDigest, Es as formDigest, Fl as ARCHITECTURE_SECURITY_REVIEW_PATH, Fr as createUlidFactory, Fs as isWorkflowFile, Ga as renderCodexHooks, Go as toolCallOf, Gr as adoptRotatedKey, Hr as prepareAppend, Hu as waiverRefusal, Id as ANTIGRAVITY_UNCHECKED_REASON, Iu as parseWaiverAnswer, Jo as SKILL_OVERRIDES_DIR, Ju as METHOD_CONFIG_PATH, K as researchLines, Ko as toolNotation, Kr as announcedKey, Ld as creatorText, Lr as checkHumanEvents, Md as canonicalBytes, Mt as parseConflictMarkers, Nd as eventHash, Oa as checkEngine, Ou as byOpening, Qa as withEngineCommand, Qr as sensitiveProductKey, Ru as reviewActions, Sr as COMMIT_SKIPS_PATH, Uo as publishedShape, Ur as prepareEngineEvents, Uu as AgentPluggedError, Vo as inputShapeOf, Vr as nextDeviceHead, Wo as TOOL_GROUPS, Xo as isPersonalLayerFile, Zn as AGENT_ACTIONS, _i as stackPromptDigest, _u as isPresetId, ao as detectTools, bc as forgeOfHost$1, bn as answerProblem, br as COMMIT_HOOK_LINE, bs as keychainFull, cd as isCodexClient, cr as validateCreateField, ct as reviewNotInteractive, cu as STORY_BUILDERS, dn as JOURNAL_REMOTE_NAME, fn as JournalBackup, fs as readDefinitions, gu as inactiveAgents, hu as DEFAULT_PRESET, io as toolsFromDetection, is as TOOL_CATALOG, jn as maybeAutoUpdate, jr as AgentSession, js as GITHUB_WORKFLOWS_DIR, ju as ACTION_DECISIONS, kn as installAndPin, ld as isCursorClient, lo as readProfile, lr as recordGitWorkflow, md as sameProject, ns as displayName, ou as isRetiredDeveloper, pi as stackField, q as costsLines, qo as withToolNotation, qr as forgetProductKey, rs as toolName, sd as isAntigravityClient, so as methodNotInstalled, ud as isHookedClient, uo as resolveProfile, vr as CHAINED_HOOK_NAME, wc as repositoryWebUrl, wn as withAnswers, xn as displayCommand, xr as COMMIT_HOOK_NAME, xs as loadMachineKey, yc as forgeCli, yr as COMMIT_CHECK_PATH, zr as deviceHeads, zu as statusAt } from "./agent-commands.js";
5
+ import { t as parsePresenceAttestation } from "./webauthn-verify.js";
6
6
  import { createRequire } from "node:module";
7
7
  import { constants, existsSync, realpathSync, statSync } from "node:fs";
8
8
  import { access, chmod, copyFile, link, lstat, mkdir, open, readFile, readdir, realpath, rename, rm, rmdir, stat, statfs, unlink, utimes, writeFile } from "node:fs/promises";
@@ -154,7 +154,7 @@ const UNSAFE_FOR_CMD = /["%!\r\n^&|<>]/;
154
154
  * How to run npm: the `npm-cli.js` that npm itself names or that sits next to this Node.js (no
155
155
  * shell), else the `npm` command of the PATH (through `cmd` on Windows, arguments quoted).
156
156
  */
157
- function npmProgram(env) {
157
+ function npmProgram$1(env) {
158
158
  const named = env.npm_execpath;
159
159
  if (named !== void 0 && basename(named) === "npm-cli.js" && existsSync(named)) return {
160
160
  program: process.execPath,
@@ -391,7 +391,7 @@ var NodeEngineUpdates = class {
391
391
  env: this.#options.env,
392
392
  timeoutMs: this.#options.installTimeoutMs ?? INSTALL_TIMEOUT_MS
393
393
  };
394
- const how = npmProgram(this.#options.env);
394
+ const how = npmProgram$1(this.#options.env);
395
395
  if (!how.shell) return await runProgram$1(how.program, [...how.prefix, ...args], options);
396
396
  const windows = process.platform === "win32";
397
397
  if (windows && args.some((arg) => UNSAFE_FOR_CMD.test(arg))) return "no_npm";
@@ -580,9 +580,11 @@ function gitEnv() {
580
580
  /**
581
581
  * Runs one `git` command to completion. Rejects only when `git` cannot be started. `env` adds
582
582
  * variables (for example `LC_ALL=C`, so that messages can be recognised). After `timeoutMs`, the
583
- * process is killed and the run ends with `status: null` and `timedOut: true`.
583
+ * process is killed and the run ends with `status: null` and `timedOut: true`. With `maxBytes`,
584
+ * the process is killed once its output goes past that many bytes, and the run ends with
585
+ * `capped: true` and the output cut at the limit.
584
586
  */
585
- function runGit(cwd, args, input, env = {}, timeoutMs) {
587
+ function runGit(cwd, args, input, env = {}, timeoutMs, maxBytes) {
586
588
  return new Promise((resolve, reject) => {
587
589
  const child = spawn("git", args, {
588
590
  cwd,
@@ -599,7 +601,20 @@ function runGit(cwd, args, input, env = {}, timeoutMs) {
599
601
  }, timeoutMs);
600
602
  const out = [];
601
603
  const err = [];
602
- child.stdout.on("data", (chunk) => out.push(chunk));
604
+ let size = 0;
605
+ let capped = false;
606
+ child.stdout.on("data", (chunk) => {
607
+ if (capped) return;
608
+ if (maxBytes !== void 0 && size + chunk.length > maxBytes) {
609
+ out.push(chunk.subarray(0, maxBytes - size));
610
+ size = maxBytes;
611
+ capped = true;
612
+ child.kill();
613
+ return;
614
+ }
615
+ size += chunk.length;
616
+ out.push(chunk);
617
+ });
603
618
  child.stderr.on("data", (chunk) => err.push(chunk));
604
619
  child.on("error", (error) => {
605
620
  clearTimeout(timer);
@@ -609,10 +624,11 @@ function runGit(cwd, args, input, env = {}, timeoutMs) {
609
624
  clearTimeout(timer);
610
625
  const stderr = Buffer.concat(err).toString("utf8").trim();
611
626
  resolve({
612
- status: timedOut ? null : status,
627
+ status: timedOut ? null : capped ? 0 : status,
613
628
  stdout: Buffer.concat(out),
614
629
  stderr: timedOut ? `${stderr}\nfatal: git ${args[0] ?? ""} took more than ${Math.round((timeoutMs ?? 0) / 1e3)} s`.trim() : stderr,
615
- timedOut
630
+ timedOut,
631
+ ...capped ? { capped: true } : {}
616
632
  });
617
633
  });
618
634
  child.stdin.on("error", () => {});
@@ -4296,9 +4312,20 @@ var GitStateStore = class {
4296
4312
  async #append(drafts, precondition) {
4297
4313
  const repo = await this.#repository();
4298
4314
  const key = await this.#machineKey();
4299
- const productKey = await sensitiveProductKey(this.#options.keys, drafts);
4315
+ let productKey = await sensitiveProductKey(this.#options.keys, drafts);
4300
4316
  try {
4301
- return await this.#appendWith(repo, key, drafts, precondition, productKey);
4317
+ try {
4318
+ return await this.#appendWith(repo, key, drafts, precondition, productKey);
4319
+ } catch (error) {
4320
+ const product = drafts.find((draft) => draft.payload !== void 0)?.product;
4321
+ if (productKey === void 0 || product === void 0 || !(error instanceof AgentPluggedError) || error.code !== ErrorCode.PRODUCT_KEY_MISMATCH) throw error;
4322
+ const adopted = await adoptRotatedKey(this.#options.keys, product, await this.list());
4323
+ await forgetProductKey(adopted);
4324
+ if (adopted === void 0 || adopted.keyId === productKey.keyId) throw error;
4325
+ await forgetProductKey(productKey);
4326
+ productKey = await sensitiveProductKey(this.#options.keys, drafts);
4327
+ return await this.#appendWith(repo, key, drafts, precondition, productKey);
4328
+ }
4302
4329
  } finally {
4303
4330
  await forgetProductKey(productKey);
4304
4331
  }
@@ -6890,6 +6917,8 @@ var PowerShellCredentials = class PowerShellCredentials {
6890
6917
  const KEYCHAIN_SERVICE = "agentplugged";
6891
6918
  /** Prefix of the product keys' accounts: `product:<product_id>`. */
6892
6919
  const PRODUCT_ACCOUNT = "product:";
6920
+ /** Prefix of the accounts of connection secrets: `connection:<name>`. */
6921
+ const CONNECTION_ACCOUNT = "connection:";
6893
6922
  function productAccount(productId) {
6894
6923
  return `${PRODUCT_ACCOUNT}${productId}`;
6895
6924
  }
@@ -7098,6 +7127,18 @@ var NodeKeyStore = class {
7098
7127
  writeProductBackup(productId, keyId, secret) {
7099
7128
  return this.#write(`${productAccount(productId)}:previous:${keyId}`, secret);
7100
7129
  }
7130
+ readProductBackup(productId, keyId) {
7131
+ return this.#read(`${productAccount(productId)}:previous:${keyId}`);
7132
+ }
7133
+ readConnectionSecret(name) {
7134
+ return this.#read(`${CONNECTION_ACCOUNT}${name}`);
7135
+ }
7136
+ writeConnectionSecret(name, secret) {
7137
+ return this.#write(`${CONNECTION_ACCOUNT}${name}`, secret);
7138
+ }
7139
+ deleteConnectionSecret(name) {
7140
+ return explained(async () => (await this.#backend()).remove(this.service, `${CONNECTION_ACCOUNT}${name}`));
7141
+ }
7101
7142
  /** Deletes the machine key's entry; true when there was one. */
7102
7143
  deleteMachineSecret() {
7103
7144
  return explained(async () => (await this.#backend()).remove(this.service, this.account));
@@ -7111,7 +7152,7 @@ var NodeKeyStore = class {
7111
7152
  if (this.service === "agentplugged") throw new Error(`deleteAll refuses the real keychain service ${KEYCHAIN_SERVICE}`);
7112
7153
  let deleted = false;
7113
7154
  const backend = await explained(() => this.#backend());
7114
- const products = await backend.accounts(this.service).then((found) => found.filter((name) => name.startsWith(PRODUCT_ACCOUNT))).catch(() => []);
7155
+ const products = await backend.accounts(this.service).then((found) => found.filter((name) => name.startsWith("product:") || name.startsWith("connection:"))).catch(() => []);
7115
7156
  for (const account of [
7116
7157
  this.account,
7117
7158
  this.humanAccount,
@@ -7510,7 +7551,7 @@ async function syncFolder(folder) {
7510
7551
  //#region ../../packages/i18n/dist/catalogs/en.js
7511
7552
  /** English catalog: the reference set of keys, and the fallback language. */
7512
7553
  const en = {
7513
- "cli.usage": "Usage: agentplugged <command> [options]\n\nFrom the chat: ask your agent, typed or dictated, for what only you decide (“pass the CI of story 4-3, the runner is down”):\n it opens a request, you approve it in the chat, and the engine carries it out. The commands below also exist, for whoever prefers the command line; only the strict level requires them.\n\nCommands:\n init Install the method in the current folder\n profile Choose what the method does for this product (or in the chat)\n doctor [--json] [--error <message>] [--exit-code <n>] [--report] Look at your machine (Node, Git, the forge, your AI tools, the keychain…), say what is missing and repair it with your agreement; exit code 1 when a blocking point remains\n sync Generate the files of the AI tools (Claude Code, Codex, Antigravity CLI, Cursor) from the method\n agent Manage your agents and skills (or in the chat):\n agent create <id> create an agent (or a skill with --skill)\n agent edit <id> show the files to edit (creates the customisation file for a shipped agent or skill)\n agent edit <skill> --personal\n your own layer of a shipped skill, ignored by Git\n agent edit <id> --tier <tier> --tool <tool>\n choose the agent's model tier and preferred AI tool\n agent enable <id> activate an agent or a skill\n agent disable <id> deactivate an agent or a skill\n journal sync Bring the remote's journal into this one, then send it the events it lacks (never with force)\n journal status Show the state of the product computed from the journal: events applied, ignored, warnings\n (.agentplugged/.cache/state.json; its computed_at is the date of the last event applied, in projection order)\n docs check Check the documents of .agentplugged/docs, epics and stories: their headers, the stories (contract, coverage of the PRD, dependencies, approved intents), and that no requirement identifier was renumbered, reused or removed since the base (exit code 1 when problems are found, 2 when the check could not run)\n mcp Run the MCP server the agents report through, over stdio: a stable launcher that moves to a newer engine between two calls, without reconnecting (sync declares it in each AI tool)\n update [--check on|off] [--auto on|off] Install the latest engine in its own folder and bring the product to it (what a yes to Noah does; in an interactive terminal only); --check on|off: ask the npm registry whether a version is out, at most twice a day (on by default); --auto on|off: install it without a question (off by default)\n hook antigravity|codex pre-tool|post-tool The hooks of Antigravity CLI's plugin and of Codex's project, run by the tool: the permission rules before a tool, the reads of outside content after it (sync writes them)\n publication <G-id> [--file <path>] [--raw] Show the full text of a deliverable of launch, marketing or sales, the version you were shown (one file with --file; --raw: the file whole, header included)\n publication export <G-id> [--force] [--unverified] Write a deliverable you validated, ready to publish, in .agentplugged/exports/<G-id>/ (nothing is published, sent or paid)\n review [<G-id>] Answer an open checkpoint, signed by your key, or reopen one applied automatically (in an interactive terminal only)\n key presence [--reset] Protect your validations with Windows Hello (--reset: create the credential again when it no longer works)\n key endorse [<human:…>] List the creator keys waiting for an endorsement, or endorse one you trust\n key export [--out <file>] Export the product key, encrypted with a passphrase, for another machine\n key import [--in <file>] Import the product key exported on another machine (typed, not shown, without --in)\n key seal Encrypt the files of the Salle and of the memory still in clear\n trust dismiss Dismiss the event that blocks the orders when the journal holds another root of trust than the one pinned on this machine (nothing to do otherwise)\n (review, key and trust: in an interactive terminal only)\n history Show your validations, most recent first (--story <e-s>, --since <ISO date>, --decision <decision>;\n --all: also the answers the journal ignored, with their reason)\n history --export <file.json|file.csv> [--force] Write them to a file (JSON or CSV, by its extension)\n rules [show] Show the permission rules: what agents do on their own (allow), after asking you (ask) or never (deny), read from the main branch\n rules set <action> <allow|ask|deny> Change one rule; rules reset: back to the defaults (in an interactive terminal only)\n next Show the next step in three lines: the current step, the agent to call and where, and what waits for your validation,\n then a fourth line with the command to run when the step has one\n migrate [--check] Bring .agentplugged/ to the format of this engine and pin it, recorded in the journal (in an interactive terminal only; --check: show what it would do, without writing)\n deferred [list] [<e-s>] [--all] [--json] Show the open deferred work (the items that lock this story; --all: the closed ones too)\n deferred show <D-id> [--json] Show one deferred item\n deferred resolve|drop <D-id> <reason> Mark a deferred item done, or drop it (or in the chat; at the terminal: interactive only)\n story start <e-s> Start a story: its branch feat/<e-s>-<slug>, its working copy next to the repository and the commit hook (for you or an agent)\n story pr <e-s> Deliver a story: push its branch (never the main one) and open or update its pull request with the fixed template, through gh or glab already logged in\n story ci <e-s> [--forge github|gitlab] Read the CI of a story's open pull request (gh or glab); a failed CI sends the story back to development\n story ci <e-s> --waive \"<reason>\" Accept a story whose CI cannot be read, for its branch's current commit (or in the chat; at the terminal: interactive only)\n ci setup [--forge github|gitlab] Write the product's base CI (lint, tests, build, dependency audit), never over an existing CI\n tests setup [--runner <name>] [--e2e <name>|none] Plan the product's test framework from its files and propose, in .agentplugged/proofs.yaml, the command that runs the tests of a criterion (never over a declaration that exists)\n trace [<EF-n>] [--json] Show the traceability: every requirement with its status (to do, in development, in review, delivered, deviation), or one requirement with its stories, tests, pull requests and deviations\n trace resolve <V-id> <reason> Lift a deviation (or in the chat; at the terminal: interactive only)\n usage [--by story|step|skill|agent|session] [--story <e-s>] [--since <day>] [--until <day>] [--session <tool>:<id>] [--json] Show what your AI tools consumed: tokens and the origin of each figure (named by the tool, deduced from the journal, or unknown), the share nothing could attribute, the tools that cannot be measured; no amount of money, only a story's estimate\n eval check [<skill>] Check a skill's behaviour cases (valid, called by the words of its description, pass kept): free, no agent\n eval init <skill> Propose cases to start from, written once, never over a file that exists\n eval run <skill> [--mode quality|baseline|variant|trigger] [--runs <n>] [--record] [--plan] Run the cases with a real agent in a clean folder (it uses tokens: the plan comes first; never part of the tests), note them, count the tokens and compare with the pass kept: a case that no longer passes, or a cost over the threshold, makes it exit with 1\n pair [--no-open] [--nouveau] [--changer-de-compte] Link your web app to this product: shows a link to click, nothing else to do (the bridge does it, once installed)\n bridge start|status Run the bridge on this machine, or tell its state. The bridge is distributed apart, under the licence of Innovel Studio SASU: this command only launches it once installed\n\nOptions:\n --profile <profile> new-product, maintenance, launch-only or prototype, without questions\n --validation <level> init, profile: how you answer checkpoints, chat (in your AI tool's chat, the default), auto or strict\n --installs <mode> init, profile: how the dependencies are installed, visible (no validation, shown in the activity and written to the journal, the default) or validate (one validation each)\n --points <list> init, profile: the points of validation that wait for you (framing, architecture, breakdown, merge, release, publication, separated by commas; none: no point), the agents decide the others\n --workflow recommended init, profile: keep the recommended Git workflow for everything (a branch per story, the CI on the forge when there is one, merge by pull request, a review before the merge)\n --branches <model> init, profile: the base branches, main (alone), main+dev (stories land on dev, a release moves it into main) or <production>+<integration>\n --story-branches <yes|no> init, profile: a branch per story, or work on the branch the stories land on\n --ci <mode> init, profile: the CI, none, local (your machine) or remote (the forge)\n --merge <mode> init, profile: how a story is merged, pr (a pull request) or direct (by the engine, never pushed)\n --review <yes|no> init, profile: a review before the merge\n --skill agent create: create a skill instead of an agent\n --name, --title, --description, --domain, --phase, --icon, --role <text>\n agent create: answers given without questions (a skill takes only --description)\n --tier <tier> agent edit: model tier, reasoning, code, fast or multimodal; `--tier default` goes back to the agent's own tier\n --tool <tool> agent edit: preferred AI tool, claude-code, codex, antigravity or cursor; `--tool none` removes the preferred tool\n --remote <name> journal sync: the Git remote to use (by default the one the current branch tracks, else origin)\n --recreate-remote journal sync: push the local journal as a new remote branch, after the remote one was deleted on purpose\n --base <ref> docs check: the Git version to compare with (HEAD by default)\n --story <e-s> history, usage: only this story (for example 2-6)\n --since <date> history, usage: from this date on: 2026-10-03 (local midnight), or a date and time with its offset, 2026-10-03T12:00:00Z or 2026-10-03T14:00:00+02:00\n --by <axis> usage: story, step (the default), skill, agent or session\n --until <day> usage: up to this day (YYYY-MM-DD, UTC), with --since\n --session <tool>:<id> usage: also name what made this session dearer (skills loaded twice, files read again, tools failing; Claude Code only)\n --decision <decision> history: approved, approved_with_reservations, rejected, changes_requested, option_chosen, waived or reopened\n --all history: also the answers the journal ignored, with their reason (in the export too)\n --export <file> history: write to a .json file (exact) or a .csv file (for spreadsheets), relative to the current folder\n --force history --export, publication export: replace an existing file\n --file <path> publication: show only this file of the deliverable\n --unverified publication export: also export an approval given in the chat without proof (a tool without the hook)\n --raw publication: the file whole, with the YAML header of the knowledge base\n --error <message> doctor: the message of the command that failed (`--error=<message>` when it starts with a dash; `-`: read from the standard input, piped); the engine says what it sees on your machine, apart from what it only supposes\n --exit-code <n> doctor: the exit code of the command that failed (137, 127…)\n --report doctor: the report to attach to a request for help (system, versions, result of every check), with no user name, personal path, token or product content; it repairs nothing\n --json next, deferred, trace, usage, doctor: the answer in JSON, for scripts (an error too, on standard output, except doctor)\n --yes, -y init: asks nothing, takes the recommended answers (and writes the AI tools' files); with a script, the exit code says whether a blocking point remains\n --tools <list> init: the AI tools to wire in, among claude-code, codex, antigravity and cursor, separated by commas (by default those found, else all)\n --permissions <mode> init, profile: protected (default: your AI tool keeps asking before sensitive gestures) or free (its mode without questions stays possible)\n --channel <store> init: the store the method was found in (claude-plugin), written by the welcome skill of the Claude Code plugin so that `doctor` says how the method was installed\n --no-sync init: does not write the AI tools' files\n --out <file> key export: write the exported key to this new file, outside the repository\n --in <file> key import: read the exported key from this file\n --check migrate: show what it would do, without writing anything\n --forge <forge> ci setup, story ci: github or gitlab (by default, ci.forge of method.yaml, else the forge of the origin remote)\n --runner <name> tests setup: the unit and API runner (vitest, jest, mocha, node-test, pytest, go-test, cargo-test, rspec, phpunit, dotnet-test, maven, gradle)\n --e2e <name> tests setup: the end-to-end runner (playwright, cypress) or none\n --waive <reason> story ci: accept the story without its CI, for its branch's current commit\n --upgrade-engine init: pin the running engine version in `.agentplugged/method.yaml` and refresh the method (not recorded in the journal: for an engine bump alone, prefer `migrate`)\n --engine-any run even when `.agentplugged/method.yaml` pins another engine version (with a warning)\n --version, -v print the version of agentplugged\n --help, -h print this help",
7554
+ "cli.usage": "Usage: agentplugged <command> [options]\n\nFrom the chat: ask your agent, typed or dictated, for what only you decide (“pass the CI of story 4-3, the runner is down”):\n it opens a request, you approve it in the chat, and the engine carries it out. The commands below also exist, for whoever prefers the command line; only the strict level requires them.\n\nCommands:\n init Install the method in the current folder\n profile Choose what the method does for this product (or in the chat)\n doctor [--json] [--error <message>] [--exit-code <n>] [--report] Look at your machine (Node, Git, the forge, your AI tools, the keychain…), say what is missing and repair it with your agreement; exit code 1 when a blocking point remains\n sync Generate the files of the AI tools (Claude Code, Codex, Antigravity CLI, Cursor) from the method\n agent Manage your agents and skills (or in the chat):\n agent create <id> create an agent (or a skill with --skill)\n agent edit <id> show the files to edit (creates the customisation file for a shipped agent or skill)\n agent edit <skill> --personal\n your own layer of a shipped skill, ignored by Git\n agent edit <id> --tier <tier> --tool <tool>\n choose the agent's model tier and preferred AI tool\n agent enable <id> activate an agent or a skill\n agent disable <id> deactivate an agent or a skill\n journal sync Bring the remote's journal into this one, then send it the events it lacks (never with force)\n journal status Show the state of the product computed from the journal: events applied, ignored, warnings\n (.agentplugged/.cache/state.json; its computed_at is the date of the last event applied, in projection order)\n docs check Check the documents of .agentplugged/docs, epics and stories: their headers, the stories (contract, coverage of the PRD, dependencies, approved intents), and that no requirement identifier was renumbered, reused or removed since the base (exit code 1 when problems are found, 2 when the check could not run)\n mcp Run the MCP server the agents report through, over stdio: a stable launcher that moves to a newer engine between two calls, without reconnecting (sync declares it in each AI tool)\n update [--check on|off] [--auto on|off] Install the latest engine in its own folder and bring the product to it (what a yes to Noah does; in an interactive terminal only); --check on|off: ask the npm registry whether a version is out, at most twice a day (on by default); --auto on|off: install it without a question (off by default)\n hook antigravity|codex pre-tool|post-tool The hooks of Antigravity CLI's plugin and of Codex's project, run by the tool: the permission rules before a tool, the reads of outside content after it (sync writes them)\n publication <G-id> [--file <path>] [--raw] Show the full text of a deliverable of launch, marketing or sales, the version you were shown (one file with --file; --raw: the file whole, header included)\n publication export <G-id> [--force] [--unverified] Write a deliverable you validated, ready to publish, in .agentplugged/exports/<G-id>/ (nothing is published, sent or paid)\n review [<G-id>] Answer an open checkpoint, signed by your key, or reopen one applied automatically (in an interactive terminal only)\n key presence [--reset] Protect your validations with Windows Hello (--reset: create the credential again when it no longer works)\n key endorse [<human:…>] List the creator keys waiting for an endorsement, or endorse one you trust\n key export [--out <file>] Export the product key, encrypted with a passphrase, for another machine\n key import [--in <file>] Import the product key exported on another machine (typed, not shown, without --in)\n key seal Encrypt the files of the Salle and of the memory still in clear\n trust dismiss Dismiss the event that blocks the orders when the journal holds another root of trust than the one pinned on this machine (nothing to do otherwise)\n (review, key and trust: in an interactive terminal only)\n history Show your validations, most recent first (--story <e-s>, --since <ISO date>, --decision <decision>;\n --all: also the answers the journal ignored, with their reason)\n history --export <file.json|file.csv> [--force] Write them to a file (JSON or CSV, by its extension)\n rules [show] Show the permission rules: what agents do on their own (allow), after asking you (ask) or never (deny), read from the main branch\n rules set <action> <allow|ask|deny> Change one rule; rules reset: back to the defaults (in an interactive terminal only)\n next Show the next step in three lines: the current step, the agent to call and where, and what waits for your validation,\n then a fourth line with the command to run when the step has one\n migrate [--check] Bring .agentplugged/ to the format of this engine and pin it, recorded in the journal (in an interactive terminal only; --check: show what it would do, without writing)\n deferred [list] [<e-s>] [--all] [--json] Show the open deferred work (the items that lock this story; --all: the closed ones too)\n deferred show <D-id> [--json] Show one deferred item\n deferred resolve|drop <D-id> <reason> Mark a deferred item done, or drop it (or in the chat; at the terminal: interactive only)\n story start <e-s> Start a story: its branch feat/<e-s>-<slug>, its working copy next to the repository and the commit hook (for you or an agent)\n story pr <e-s> Deliver a story: push its branch (never the main one) and open or update its pull request with the fixed template, through gh or glab already logged in\n story ci <e-s> [--forge github|gitlab] Read the CI of a story's open pull request (gh or glab); a failed CI sends the story back to development\n story ci <e-s> --waive \"<reason>\" Accept a story whose CI cannot be read, for its branch's current commit (or in the chat; at the terminal: interactive only)\n ci setup [--forge github|gitlab] Write the product's base CI (lint, tests, build, dependency audit), never over an existing CI\n tests setup [--runner <name>] [--e2e <name>|none] Plan the product's test framework from its files and propose, in .agentplugged/proofs.yaml, the command that runs the tests of a criterion (never over a declaration that exists)\n trace [<EF-n>] [--json] Show the traceability: every requirement with its status (to do, in development, in review, delivered, deviation), or one requirement with its stories, tests, pull requests and deviations\n trace resolve <V-id> <reason> Lift a deviation (or in the chat; at the terminal: interactive only)\n usage [--by story|step|skill|agent|session] [--story <e-s>] [--since <day>] [--until <day>] [--session <tool>:<id>] [--json] Show what your AI tools consumed: tokens and the origin of each figure (named by the tool, deduced from the journal, or unknown), the share nothing could attribute, the tools that cannot be measured; no amount of money, only a story's estimate\n eval check [<skill>] Check a skill's behaviour cases (valid, called by the words of its description, pass kept): free, no agent\n eval init <skill> Propose cases to start from, written once, never over a file that exists\n eval run <skill> [--mode quality|baseline|variant|trigger] [--runs <n>] [--record] [--plan] Run the cases with a real agent in a clean folder (it uses tokens: the plan comes first; never part of the tests), note them, count the tokens and compare with the pass kept: a case that no longer passes, or a cost over the threshold, makes it exit with 1\n pair [--no-open] [--nouveau] [--changer-de-compte] Link your web app to this product: shows a link to click, nothing else to do (the bridge does it, once installed)\n device list|revoke <device> List the devices linked to this product, or remove one: it receives nothing more and can be linked again (the bridge does it, once installed)\n bridge install|uninstall|start|status Install the bridge (and update it) as a service of your account, remove it, run it on this machine, or tell its state. The bridge is distributed apart, under the licence of Innovel Studio SASU: this command only installs and launches it\n\nOptions:\n --profile <profile> new-product, maintenance, launch-only or prototype, without questions\n --validation <level> init, profile: how you answer checkpoints, chat (in your AI tool's chat, the default), auto or strict\n --installs <mode> init, profile: how the dependencies are installed, visible (no validation, shown in the activity and written to the journal, the default) or validate (one validation each)\n --points <list> init, profile: the points of validation that wait for you (framing, architecture, breakdown, merge, release, publication, separated by commas; none: no point), the agents decide the others\n --workflow recommended init, profile: keep the recommended Git workflow for everything (a branch per story, the CI on the forge when there is one, merge by pull request, a review before the merge)\n --branches <model> init, profile: the base branches, main (alone), main+dev (stories land on dev, a release moves it into main) or <production>+<integration>\n --story-branches <yes|no> init, profile: a branch per story, or work on the branch the stories land on\n --ci <mode> init, profile: the CI, none, local (your machine) or remote (the forge)\n --merge <mode> init, profile: how a story is merged, pr (a pull request) or direct (by the engine, never pushed)\n --review <yes|no> init, profile: a review before the merge\n --skill agent create: create a skill instead of an agent\n --name, --title, --description, --domain, --phase, --icon, --role <text>\n agent create: answers given without questions (a skill takes only --description)\n --tier <tier> agent edit: model tier, reasoning, code, fast or multimodal; `--tier default` goes back to the agent's own tier\n --tool <tool> agent edit: preferred AI tool, claude-code, codex, antigravity or cursor; `--tool none` removes the preferred tool\n --remote <name> journal sync: the Git remote to use (by default the one the current branch tracks, else origin)\n --recreate-remote journal sync: push the local journal as a new remote branch, after the remote one was deleted on purpose\n --base <ref> docs check: the Git version to compare with (HEAD by default)\n --story <e-s> history, usage: only this story (for example 2-6)\n --since <date> history, usage: from this date on: 2026-10-03 (local midnight), or a date and time with its offset, 2026-10-03T12:00:00Z or 2026-10-03T14:00:00+02:00\n --by <axis> usage: story, step (the default), skill, agent or session\n --until <day> usage: up to this day (YYYY-MM-DD, UTC), with --since\n --session <tool>:<id> usage: also name what made this session dearer (skills loaded twice, files read again, tools failing; Claude Code only)\n --decision <decision> history: approved, approved_with_reservations, rejected, changes_requested, option_chosen, waived or reopened\n --all history: also the answers the journal ignored, with their reason (in the export too)\n --export <file> history: write to a .json file (exact) or a .csv file (for spreadsheets), relative to the current folder\n --force history --export, publication export: replace an existing file\n --file <path> publication: show only this file of the deliverable\n --unverified publication export: also export an approval given in the chat without proof (a tool without the hook)\n --raw publication: the file whole, with the YAML header of the knowledge base\n --error <message> doctor: the message of the command that failed (`--error=<message>` when it starts with a dash; `-`: read from the standard input, piped); the engine says what it sees on your machine, apart from what it only supposes\n --exit-code <n> doctor: the exit code of the command that failed (137, 127…)\n --report doctor: the report to attach to a request for help (system, versions, result of every check), with no user name, personal path, token or product content; it repairs nothing\n --json next, deferred, trace, usage, doctor: the answer in JSON, for scripts (an error too, on standard output, except doctor)\n --yes, -y init: asks nothing, takes the recommended answers (and writes the AI tools' files); with a script, the exit code says whether a blocking point remains\n --tools <list> init: the AI tools to wire in, among claude-code, codex, antigravity and cursor, separated by commas (by default those found, else all)\n --permissions <mode> init, profile: protected (default: your AI tool keeps asking before sensitive gestures) or free (its mode without questions stays possible)\n --channel <store> init: the store the method was found in (claude-plugin), written by the welcome skill of the Claude Code plugin so that `doctor` says how the method was installed\n --no-sync init: does not write the AI tools' files\n --clean-gemini sync: remove only the files AgentPlugged wrote for the retired Gemini CLI, and list the others (with --yes: remove those too)\n --out <file> key export: write the exported key to this new file, outside the repository\n --in <file> key import: read the exported key from this file\n --check migrate: show what it would do, without writing anything\n --forge <forge> ci setup, story ci: github or gitlab (by default, ci.forge of method.yaml, else the forge of the origin remote)\n --runner <name> tests setup: the unit and API runner (vitest, jest, mocha, node-test, pytest, go-test, cargo-test, rspec, phpunit, dotnet-test, maven, gradle)\n --e2e <name> tests setup: the end-to-end runner (playwright, cypress) or none\n --waive <reason> story ci: accept the story without its CI, for its branch's current commit\n --upgrade-engine init: pin the running engine version in `.agentplugged/method.yaml` and refresh the method (not recorded in the journal: for an engine bump alone, prefer `migrate`)\n --engine-any run even when `.agentplugged/method.yaml` pins another engine version (with a warning)\n --version, -v print the version of agentplugged\n --help, -h print this help",
7514
7555
  "cli.error": "Error {code}: {message}",
7515
7556
  "init.summary.title": "Method installed in {root}",
7516
7557
  "init.action.created": "created",
@@ -7549,6 +7590,10 @@ const en = {
7549
7590
  "sync.warning.overwritten": "{path}: manual modification overwritten.",
7550
7591
  "sync.warning.conflict": "{path}: no agentplugged mark (a header, or the generated description of a plugin), so it is yours and was left as is. Rename or remove it to let sync generate it.",
7551
7592
  "sync.warning.kept": "{path}: no longer generated, but its header was removed, so it is yours and was kept.",
7593
+ "sync.warning.gemini_legacy": "Gemini CLI is no longer supported by Google; AgentPlugged now uses Antigravity CLI. Your old Gemini CLI files ({path}) are still read and are left as they are: nothing is written or removed there. To remove only the files AgentPlugged wrote, run `npx agentplugged sync --clean-gemini`.",
7594
+ "sync.warning.gemini_unproven": "{path}: AgentPlugged cannot prove it wrote this as it is (changed since, or no trace of it), so it was kept.",
7595
+ "sync.gemini.confirm": "The files above were kept. To remove them too, check them, then run `npx agentplugged sync --clean-gemini --yes`.",
7596
+ "sync.gemini.nothing": "Nothing to clean: no file written by AgentPlugged for Gemini CLI was found.",
7552
7597
  "tools.title": "AI tools",
7553
7598
  "tools.line": "{name} {version} — {sources}",
7554
7599
  "tools.line.unknown_version": "{name} (version not recognized) — {sources}",
@@ -7977,7 +8022,7 @@ const en = {
7977
8022
  "history.author.root": "{device} (root key)",
7978
8023
  "history.author.endorsed": "{device} (endorsed on {date})",
7979
8024
  "history.author.endorsed_undated": "{device} (endorsed)",
7980
- "history.source.terminal": "terminal",
8025
+ "history.source.terminal": "at the terminal",
7981
8026
  "history.option": "option {option}",
7982
8027
  "history.waiver_until": "until {date}",
7983
8028
  "history.assurance": "assurance {assurance}",
@@ -8044,6 +8089,10 @@ const en = {
8044
8089
  "key.export.hint": "On the other machine, run `npx agentplugged key import` (or `--in <file>`) and type the same passphrase. Keep the passphrase safe: without it the export is useless, and a lost product key makes the encrypted content unreadable for ever.",
8045
8090
  "key.import.done": "Product key {key_id} imported into this machine's keychain.",
8046
8091
  "key.import.already": "This machine already holds the product key {key_id}.",
8092
+ "key.export.many": "This export holds {count} keys: the current one and the ones kept from before each renewal, so the whole history is readable wherever you import it.",
8093
+ "key.export.missing": "Warning: this machine does not hold {count} older key(s) of this product ({key_ids}). What they wrote cannot be read from this export; export from a machine that holds them.",
8094
+ "key.import.many": "Keys kept on this machine: {key_ids}.",
8095
+ "key.import.older": "Older keys of the product imported: the history written under them is readable. The current key {key_id} is still missing here: import an export made after the last renewal, or let the renewal reach this machine.",
8047
8096
  "init.product_key.created": "Product key created ({key_id}): costs, security notes, the Salle and the memory are encrypted with it. It stays in this machine's keychain, never in the repository.",
8048
8097
  "init.product_key.ready": "Product key: {key_id}.",
8049
8098
  "init.product_key.published": "Its identifier is announced in this product's journal.",
@@ -9069,9 +9118,29 @@ const en = {
9069
9118
  "error.relay.relay_connection_replaced": "A newer connection of this device replaced this one.",
9070
9119
  "error.relay.relay_prekey_invalid": "The relay refused this receiving key. Nothing was kept.",
9071
9120
  "error.relay.relay_unavailable": "The relay could not do this right now. Nothing was done: try again.",
9121
+ "error.relay.vault_refused": "The relay did not keep the last state of your project. Your machine seals it again.",
9122
+ "error.relay.push_refused": "The relay did not take this notification request. Nothing was sent.",
9072
9123
  "error.relay.rendezvous_unknown": "This pairing link no longer exists. Run the command again to get a new one.",
9073
9124
  "error.relay.rendezvous_refused": "The relay could not open this rendezvous. Try again in a moment.",
9074
9125
  "error.relay.rendezvous_attach_refused": "The relay could not attach this machine to your account. Try again with a new link.",
9126
+ "error.relay.challenge_expired": "This step took too long. Start again.",
9127
+ "error.relay.challenge_reused": "This step was already used. Start again.",
9128
+ "error.relay.origin_mismatch": "This page is not allowed to use your passkey with AgentPlugged. Open the official address.",
9129
+ "error.relay.credential_already_registered": "This passkey already belongs to an account. Sign in with it instead.",
9130
+ "error.relay.email_code_invalid": "That code is not right. Check the e-mail and try again.",
9131
+ "error.relay.email_code_expired": "That code is no longer valid. Ask for a new code.",
9132
+ "error.relay.email_already_registered": "An account already exists with this address. Sign in with your passkey.",
9133
+ "error.relay.account_request_invalid": "The request is not valid. Check what you typed.",
9134
+ "error.relay.account_sign_in_failed": "This passkey was not recognized. Try again, or use another device.",
9135
+ "error.relay.account_session_required": "You are signed out. Sign in again.",
9136
+ "error.relay.account_deleted": "This account was deleted: this device is no longer linked to it.",
9137
+ "error.relay.export_not_ready": "Your export is still being prepared. Try again in a moment.",
9138
+ "error.relay.export_gone": "This export was already downloaded, or its link has expired. Ask for a new one.",
9139
+ "error.relay.passkey_limit": "You already have the most passkeys an account may hold. Remove one before adding another.",
9140
+ "error.relay.passkey_last": "This is your last passkey: without one, nobody could sign in to this account. Add another first.",
9141
+ "error.relay.share_limit": "You already have the most share links active. Withdraw one before making another.",
9142
+ "error.relay.share_too_large": "This page is too large to be shared.",
9143
+ "error.relay.share_unavailable": "This link does not work: it has expired or was withdrawn.",
9075
9144
  "error.relay.upgrade_required": "This device speaks a version of the protocol that the relay no longer accepts: update it.",
9076
9145
  "points.title": "The points of validation: the ones you keep for yourself. Every other point is decided by the agent responsible for it, with its reason in the journal, and you can reopen it whenever you want.",
9077
9146
  "points.point.framing": "Framing documents (brief, PRD, UX specification) and the end of their phases",
@@ -9084,7 +9153,10 @@ const en = {
9084
9153
  "points.summary": "Points that wait for you: {list}. The agents decide the others.",
9085
9154
  "points.summary.none": "No point waits for you: the agents decide every point.",
9086
9155
  "history.source.agent": "decided by the agent responsible",
9156
+ "history.source.web": "from the web cockpit",
9157
+ "history.source.mobile": "from the phone",
9087
9158
  "assurance.agent": "an agent's decision (not your answer), with its reason; you can reopen it",
9159
+ "assurance.device": "signed by a device you linked (the web cockpit or your phone)",
9088
9160
  "review.agent_decided": "Decided by the agent {agent} on {at}: {decision}. Reason: {reason}",
9089
9161
  "next.step.point_decision": "A point you do not keep waits for the agent responsible to decide it",
9090
9162
  "next.independent": "The work goes on without you: this step does not depend on any of the points that wait for you.",
@@ -9137,7 +9209,10 @@ const en = {
9137
9209
  "update.done_pinned": "Engine {version} is installed (the product already pinned it). Your open sessions move to it at their next call.",
9138
9210
  "update.failed": "The update did not happen ({reason}). {message} The running engine was not touched.",
9139
9211
  "error.engine_version_too_old.agent": "{path} pins engine {pinned} and this session still runs {engine_version}: nothing was written. Call `state.next` (or `state.get`): it carries `engine_update`, and the creator's one « oui » to guard.creator_action `engine_update` {install: true} installs {pinned} and moves this session to it at your next call. Say it to the creator in one sentence; never tell them to reconnect or to type a command.",
9140
- "bridge.launcher.not_installed": "The bridge is not installed on this machine. It is distributed apart, under the licence of Innovel Studio SASU: get it at https://agentplugged.ai. The rest of AgentPlugged (`state.next`, `review`, the MCP server) works without it.",
9212
+ "bridge.launcher.not_installed": "The bridge is not installed on this machine. It is distributed apart, under the licence of Innovel Studio SASU: install it with `agentplugged bridge install` (details at https://agentplugged.ai). The rest of AgentPlugged (`state.next`, `review`, the MCP server) works without it.",
9213
+ "bridge.launcher.installing": "Getting the bridge (the newest version)…",
9214
+ "bridge.launcher.install_failed": "The bridge could not be downloaded ({reason}). Nothing was installed. Try again, or get it at https://agentplugged.ai.",
9215
+ "bridge.launcher.update_failed": "The newest bridge could not be downloaded ({reason}): the installed one is kept.",
9141
9216
  "workflow.title": "Git workflow (branches, CI, merges, review)",
9142
9217
  "workflow.recommended": "(recommended)",
9143
9218
  "workflow.intro": "I propose what suits a solo creator: {line}. Answer yes to keep it all, or no to choose each point.",
@@ -9305,6 +9380,7 @@ const en = {
9305
9380
  "init.sync.done": "Files of your AI tools written ({count} created or updated).",
9306
9381
  "init.sync.skipped": "No sync for now: run `npx agentplugged sync` whenever you want.",
9307
9382
  "init.done.noah": "Ready. Open {tool} in this folder and write: noah ?",
9383
+ "init.link.hint": "To link it to your web app: `npx agentplugged pair`",
9308
9384
  "init.done.noah.several": "Ready. Open one of your tools ({tools}) in this folder and write: noah ?",
9309
9385
  "init.done.sync_first": "Next: run `npx agentplugged sync`, then open {tool} in this folder and write: noah ?",
9310
9386
  "init.done.sync_first.several": "Next: run `npx agentplugged sync`, then open one of your tools ({tools}) in this folder and write: noah ?",
@@ -9389,7 +9465,6 @@ const FALLBACK_REASONS = { fr: {
9389
9465
  "codex.untrusted": "les hooks de Codex enregistrent une lecture faite par une commande réseau (`curl`, `wget`, `gh`, `git pull`…) ou par un outil d'un autre serveur MCP. La recherche web propre à Codex est un outil hébergé que les hooks ne voient pas : après une recherche web, l'agent appelle `guard.external_read` pour que le journal en garde la trace (source, heure, agent) ; rien n'est bloqué. Les actions faites par les outils de fichiers (lire, modifier, écrire) ne passent pas par un hook de lecture : seules les règles de permission les encadrent (`read_secrets` est toujours refusé). Seul Claude Code contrôle aussi une écriture avant qu'elle ait lieu (un secret, un fichier hors de la story, une décision d'architecture) : pas cet outil.",
9390
9466
  "codex.isolation": "les fichiers d'agents de cet outil ne savent pas lancer un développeur dans une copie de travail à lui : chaque développeur travaille seulement dans le `workdir` que renvoie `story.start`, la copie de travail propre à la story, une par story. Le bac à sable de Codex garde aussi les écritures dans le dossier du projet, et la copie de travail d'une story est à côté (`<projet>.worktrees/<id>`) : un développeur n'y écrit que si `sandbox_workspace_write.writable_roots` de Codex la liste par son chemin absolu (observé sur Codex 0.160.1, le 2026-10-06 : un chemin relatif est lu depuis le dossier du projet et son `..` est ignoré ; `~/` fonctionne), ce que `sync` n'écrit pas parce que le moteur ne sait pas où se trouve le projet sur cette machine. Sous Windows, Codex ne laisse écrire dans le projet qu'une fois son bac à sable Windows installé (le mode élevé, une approbation d'administrateur, proposée par l'extension d'éditeur) : sinon la session retombe en silence en lecture seule, et le mode non élevé refuse un projet dont `.git` et `.codex` sont protégés.",
9391
9467
  "codex.decisions": "Codex n'envoie à son client les formulaires qu'un serveur MCP demande (« elicitation ») que si sa politique d'approbation les laisse passer : un `never` seul les refuse en silence, d'où la forme granulaire que `sync` écrit et qui refuse tout le reste (observé sur Codex 0.160.1, le 2026-10-06, par son serveur d'application : la demande arrive au client, dont le moteur enregistre la réponse). `codex exec` les refuse, et aucun n'a été vu affiché à l'écran de l'extension d'éditeur : les décisions te sont posées en texte dans le chat (« a, b ou c ? »), et l'agent enregistre ta réponse avec `chat.answer`, en la citant. Le moteur essaie quand même le formulaire d'abord (`chat.ask`) et passe au chat quand l'outil ne peut pas l'afficher.",
9392
- "gemini-cli.permissions": "agentplugged ne génère aucun fichier de permissions pour Gemini CLI : aucun chemin n'est bloqué.",
9393
9468
  "cursor.permissions.hooks-kept": "sync n'a pas pu écrire `.cursor/hooks.json` (le fichier est à toi) : aucun hook n'applique les chemins et les commandes protégés dans l'éditeur Cursor. `.cursorignore` garde les secrets hors de portée de l'agent, et `.cursor/cli.json` bloque les chemins interdits dans la CLI de Cursor seulement (l'éditeur ne le lit pas).",
9394
9469
  "cursor.rules": "les hooks de Cursor refusent ce que le produit refuse (push sur la branche principale, force push, suppression en masse, écriture des fichiers protégés du produit, lancement d'un autre agent Cursor) et demandent pour une commande qu'une règle demande (`ask`), dans l'éditeur et dans la ligne de commande quand elle envoie le hook. Ils ne demandent pas avant l'écriture d'un fichier ni avant un accès au web (`preToolUse` ignore `ask`) : une règle qui demande d'abord pour une modification de fichier (`edit_code: ask`) ou pour le web (`internet: ask`) n'est pas demandée par Cursor, donc avant une telle action l'agent te demande dans le chat ; `internet: deny` et `edit_code: deny` sont refusés. Les outils de Cursor qui lisent un fichier ne passent pas par un hook : `.cursorignore` garde les secrets (`.env` et ses semblables) hors de portée de l'agent, et une commande qui en lit un est refusée. Le texte saisi dans une console déjà ouverte n'est pas vu non plus. Les hooks ne tournent que dans un dossier auquel tu fais confiance.",
9395
9470
  "cursor.rules.hooks-kept": CURSOR_HOOKS_KEPT_FR,
@@ -9400,18 +9475,15 @@ const FALLBACK_REASONS = { fr: {
9400
9475
  "cursor.usage": "Cursor ne garde aucun nombre de jetons nulle part sur la machine : ses transcriptions (`~/.cursor/projects/<projet>/agent-transcripts/`) contiennent les messages et les appels d'outils, sans jetons, sans modèle et sans date par ligne. Le moteur ne mesure donc rien d'une session Cursor (`measure.usage` répond `available: false`) et ne l'estime jamais ; la page d'usage de Cursor (le tableau de bord de ton compte) est la seule source. Le hook `stop` de l'éditeur porte peut-être des jetons (vu dans le code de Cursor lui-même, non vérifié rempli) : il n'est pas utilisé.",
9401
9476
  "*.usage": "le moteur ne lit aucune trace de cet outil : il ne mesure rien de ses sessions (`measure.usage` répond `available: false`) et ne l'estime jamais.",
9402
9477
  "codex.mcp.config-kept": "sync n'a pas pu écrire `.codex/config.toml` (le fichier est à toi) : le serveur MCP `agentplugged` n'est pas déclaré pour Codex. Ajoute toi-même `[mcp_servers.agentplugged]` avec `command = \"npx\"` et `args = [\"-y\", \"agentplugged@<engine_version>\", \"mcp\"]`.",
9403
- "gemini-cli.mcp": "sync ne déclare le serveur MCP `agentplugged` dans `.gemini/settings.json` que si ce fichier existe déjà (sync ne crée jamais les réglages de Gemini CLI) : sinon, les anciennes installations de Gemini CLI ne voient pas le serveur.",
9404
9478
  "*.mcp.conflict": "`{path}` déclare déjà un serveur MCP `agentplugged` qui n'est pas celui qu'écrit sync : il est laissé tel quel. Vérifie qu'il lance `npx -y agentplugged@<engine_version> mcp`.",
9405
9479
  ...Object.fromEntries([
9406
9480
  "claude-code",
9407
9481
  "codex",
9408
9482
  "antigravity",
9409
- "gemini-cli",
9410
9483
  "cursor"
9411
9484
  ].map((client) => [`${client}.model`, MODEL_INHERIT_FR])),
9412
9485
  "codex.rules": "les hooks de Codex répondent `allow` ou `deny`, jamais `ask` : une règle de permission qui demande d'abord (`ask`, que toi seul poses) est écrite en règle `prompt` dans `.codex/rules/agentplugged.rules` seulement tant que Codex demande des approbations (niveau `strict`, modifications qui demandent d'abord) : sans approbation (par défaut, écrite en forme granulaire qui laisse quand même passer les formulaires), Codex ne peut pas demander, rien n'est écrit, et le hook laisse l'appel passer. Avant une telle action, l'agent te demande dans le chat. Ce que le produit refuse (push sur la branche principale, force push, suppression en masse, lecture de secrets, écriture de ses fichiers protégés) est refusé par le hook et, pour les commandes, par les règles propres à Codex. `internet: ask` désactive la recherche web et garde le bac à sable hors ligne ; `edit_code: ask` ou `deny` donne un bac à sable en lecture seule avec approbation sur demande. Les hooks ne tournent qu'une fois que tu les as approuvés (`/hooks` dans Codex, une seule fois).",
9413
9486
  "codex.rules.config-kept": "sync n'a pas pu écrire `.codex/config.toml` (le fichier est à toi) : aucun hook n'applique les règles de permission pour Codex ; seules les règles de commandes de `.codex/rules/agentplugged.rules` le font.",
9414
- "gemini-cli.rules": "agentplugged ne génère aucun fichier de permissions pour Gemini CLI : les règles de permission de la constitution ne sont pas appliquées techniquement. Rien n'empêche un agent de modifier `.agentplugged/method.yaml` ou de lancer `npx agentplugged sync`, `rules set` ou `migrate` dans cet outil : les changements de règles passent par toi.",
9415
9487
  "*.chat_proof": "agentplugged n'écrit pour cet outil aucun hook qui retienne tes messages : une réponse que tu donnes dans le chat est enregistrée « non vérifiée » (`chat_unverified`) et affichée ainsi partout, quel que soit le point (le journal garde la trace de chaque réponse). Pour que chaque réponse soit vérifiée, travaille dans Claude Code ; pour que les points à risque élevé passent par ta clé, choisis le niveau `strict`.",
9416
9488
  "*.isolation": "les fichiers d'agents de cet outil ne savent pas lancer un développeur dans une copie de travail à lui : chaque développeur travaille seulement dans le `workdir` que renvoie `story.start`, la copie de travail propre à la story, une par story.",
9417
9489
  ...Object.fromEntries([
@@ -9430,7 +9502,7 @@ const FALLBACK_REASONS = { fr: {
9430
9502
  //#endregion
9431
9503
  //#region ../../packages/i18n/dist/catalogs/fr.js
9432
9504
  const fr = {
9433
- "cli.usage": "Utilisation : agentplugged <commande> [options]\n\nDepuis le chat : demande à ton agent, à l'écrit ou en dictée, ce qui t'est réservé (« passe la CI de la story 4-3, le runner est en panne ») :\n il ouvre une demande, tu la valides dans le chat, et le moteur l'exécute. Les commandes ci-dessous existent aussi, pour qui préfère la ligne de commande ; seul le niveau strict les exige.\n\nCommandes :\n init Installe la méthode dans le dossier courant\n profile Choisit ce que fait la méthode pour ce produit (ou dans le chat)\n doctor [--json] [--error <message>] [--exit-code <n>] [--report] Regarde ta machine (Node, Git, la forge, tes outils IA, le trousseau…), dit ce qui manque et le répare avec ton accord ; code de sortie 1 si un point bloquant demeure\n sync Génère les fichiers des outils IA (Claude Code, Codex, Antigravity CLI, Cursor) à partir de la méthode\n agent Gère tes agents et compétences (ou dans le chat) :\n agent create <id> crée un agent (ou une compétence avec --skill)\n agent edit <id> indique les fichiers à modifier (crée le fichier de personnalisation d'un agent ou d'une compétence livrés)\n agent edit <skill> --personal\n ta couche à toi d'une compétence livrée, ignorée par Git\n agent edit <id> --tier <niveau> --tool <outil>\n choisit le niveau de modèle et l'outil IA préféré de l'agent\n agent enable <id> active un agent ou une compétence\n agent disable <id> désactive un agent ou une compétence\n journal sync Récupère le journal du dépôt distant, puis lui envoie les événements qui lui manquent (sans jamais forcer)\n journal status Affiche l'état du produit calculé à partir du journal : événements appliqués, ignorés, avertissements\n (.agentplugged/.cache/state.json ; son computed_at est la date du dernier événement appliqué, dans l'ordre de projection)\n docs check Vérifie les documents de .agentplugged/docs, epics et stories : leurs en-têtes, les stories (contrat, couverture du PRD, dépendances, intentions validées), et qu'aucun identifiant d'exigence n'a été renuméroté, réutilisé ou supprimé depuis la base (code de sortie 1 si des problèmes sont trouvés, 2 si la vérification n'a pas pu se faire)\n mcp Lance le serveur MCP par lequel les agents rendent compte, en stdio : un lanceur stable qui passe à un moteur plus récent entre deux appels, sans reconnexion (sync le déclare dans chaque outil IA)\n update [--check on|off] [--auto on|off] Installe le dernier moteur dans son propre dossier et met le produit dessus (ce que fait un oui à Noah ; dans un terminal interactif seulement) ; --check on|off : interroger le registre npm pour savoir si une version est sortie, au plus deux fois par jour (activé par défaut) ; --auto on|off : l'installer sans question (désactivé par défaut)\n hook antigravity|codex pre-tool|post-tool Les hooks du plugin d'Antigravity CLI et du projet de Codex, lancés par l'outil : les règles de permission avant un outil, les lectures de contenu extérieur après (sync les écrit)\n publication <G-id> [--file <chemin>] [--raw] Affiche le texte complet d'un livrable de lancement, de marketing ou de vente, la version qu'on t'a montrée (un seul fichier avec --file ; --raw : le fichier entier, en-tête compris)\n publication export <G-id> [--force] [--unverified] Écrit un livrable que tu as validé, prêt à publier, dans .agentplugged/exports/<G-id>/ (rien n'est publié, envoyé ni payé)\n review [<G-id>] Réponds à un point de contrôle ouvert, signé par ta clé, ou rouvre un point appliqué automatiquement (dans un terminal interactif seulement)\n key presence [--reset] Protège tes validations avec Windows Hello (--reset : recrée l'identifiant quand il ne marche plus)\n key endorse [<human:…>] Liste les clés de créateur en attente d'approbation, ou approuve une clé dont tu es sûr\n key export [--out <fichier>] Exporte la clé du produit, chiffrée par une phrase de passe, pour une autre machine\n key import [--in <fichier>] Importe la clé du produit exportée sur une autre machine (tapée, non affichée, sans --in)\n key seal Chiffre les fichiers de la Salle et de la mémoire encore en clair\n trust dismiss Écarte l'événement qui bloque les ordres quand le journal contient une autre racine de confiance que celle épinglée sur cette machine (rien à faire sinon)\n (review, key et trust : dans un terminal interactif seulement)\n history Affiche tes validations, de la plus récente à la plus ancienne (--story <e-s>, --since <date ISO>, --decision <décision> ;\n --all : aussi les réponses ignorées par le journal, avec leur raison)\n history --export <fichier.json|fichier.csv> [--force] Les écrit dans un fichier (JSON ou CSV, selon son extension)\n rules [show] Affiche les règles de permission : ce que les agents font seuls (allow), après t'avoir demandé (ask) ou jamais (deny), lues sur la branche principale\n rules set <action> <allow|ask|deny> Change une règle ; rules reset : revient aux défauts (dans un terminal interactif seulement)\n next Affiche la prochaine étape en trois lignes : l'étape en cours, l'agent à appeler et où, et ce qui attend ta validation,\n puis une quatrième ligne avec la commande à lancer quand l'étape en a une\n migrate [--check] Passe .agentplugged/ au format de ce moteur et l'épingle, avec une trace dans le journal (dans un terminal interactif seulement ; --check : montre ce qu'il ferait, sans rien écrire)\n deferred [list] [<e-s>] [--all] [--json] Affiche le travail reporté ouvert (les points qui verrouillent cette story ; --all : aussi les points fermés)\n deferred show <D-id> [--json] Affiche un point reporté\n deferred resolve|drop <D-id> <raison> Marque un point reporté traité, ou l'abandonne (ou dans le chat ; au terminal : interactif seulement)\n story start <e-s> Démarre une story : sa branche feat/<e-s>-<slug>, sa copie de travail à côté du dépôt et le hook de commit (pour toi ou un agent)\n story pr <e-s> Livre une story : pousse sa branche (jamais la principale) et ouvre ou met à jour sa pull request au modèle fixe, par gh ou glab déjà connecté\n story ci <e-s> [--forge github|gitlab] Lit la CI de la pull request ouverte d'une story (gh ou glab) ; en échec, la story repasse en développement\n story ci <e-s> --waive \"<raison>\" Accepte une story dont la CI ne peut pas être lue, pour le commit actuel de sa branche (ou dans le chat ; au terminal : interactif seulement)\n ci setup [--forge github|gitlab] Écrit la CI de base du produit (lint, tests, build, audit des dépendances), jamais par-dessus une CI existante\n tests setup [--runner <nom>] [--e2e <nom>|none] Prépare le cadre de test du produit d'après ses fichiers et propose, dans .agentplugged/proofs.yaml, la commande qui lance les tests d'un critère (jamais par-dessus une déclaration existante)\n trace [<EF-n>] [--json] Affiche la traçabilité : chaque exigence et son statut (à faire, en développement, en revue, livrée, en écart), ou une exigence avec ses stories, tests, pull requests et écarts\n trace resolve <V-id> <raison> Lève un écart (ou dans le chat ; au terminal : interactif seulement)\n usage [--by story|step|skill|agent|session] [--story <e-s>] [--since <jour>] [--until <jour>] [--session <outil>:<id>] [--json] Montre ce que tes outils d'IA ont consommé : des jetons et l'origine de chaque chiffre (nommé par l'outil, déduit du journal, ou inconnu), la part que rien n'a permis d'attribuer, les outils qu'on ne peut pas mesurer ; aucun montant, seulement l'estimation d'une story\n eval check [<compétence>] Vérifie les cas de comportement d'une compétence (valides, appelée d'après les mots de sa description, passage gardé) : gratuit, sans agent\n eval init <compétence> Propose des cas pour démarrer, écrits une fois, jamais par-dessus un fichier existant\n eval run <compétence> [--mode quality|baseline|variant|trigger] [--runs <n>] [--record] [--plan] Lance les cas avec un vrai agent dans un dossier propre (cela consomme des jetons : le plan vient d'abord ; jamais dans les tests), les note, compte les jetons et compare au passage gardé : un cas qui ne passe plus, ou un coût au-dessus du seuil, donne le code de sortie 1\n pair [--no-open] [--nouveau] [--changer-de-compte] Relie ton application web à ce produit : affiche un lien à cliquer, rien d'autre à faire (c'est le pont qui s'en charge, une fois installé)\n bridge start|status Lance le pont sur cette machine, ou dit son état. Le pont se distribue à part, sous la licence d'Innovel Studio SASU : cette commande ne fait que le lancer une fois installé\n\nOptions :\n --profile <profil> new-product, maintenance, launch-only ou prototype, sans questions\n --validation <niveau> init, profile : comment tu réponds aux points de contrôle, chat (dans le chat de ton outil IA, par défaut), auto ou strict\n --installs <mode> init, profile : comment s'installent les dépendances, visible (sans validation, affichées dans l'activité et inscrites au journal, par défaut) ou validate (une validation chacune)\n --points <liste> init, profile : les points de validation qui t'attendent (framing, architecture, breakdown, merge, release, publication, séparés par des virgules ; none : aucun), les agents décident les autres\n --workflow recommended init, profile : garde le workflow Git recommandé pour tout (une branche par story, la CI sur la forge quand il y en a une, fusion par pull request, une revue avant la fusion)\n --branches <modèle> init, profile : les branches de base, main (seule), main+dev (les stories arrivent sur dev, une mise en production la fait passer dans main) ou <production>+<intégration>\n --story-branches <yes|no> init, profile : une branche par story, ou on travaille sur la branche où arrivent les stories\n --ci <mode> init, profile : la CI, none, local (ta machine) ou remote (la forge)\n --merge <mode> init, profile : comment une story est fusionnée, pr (une pull request) ou direct (par le moteur, jamais poussé)\n --review <yes|no> init, profile : une revue avant la fusion\n --skill agent create : crée une compétence plutôt qu'un agent\n --name, --title, --description, --domain, --phase, --icon, --role <texte>\n agent create : réponses données sans questions (une compétence ne prend que --description)\n --tier <niveau> agent edit : niveau de modèle, reasoning, code, fast ou multimodal ; `--tier default` revient au niveau propre de l'agent\n --tool <outil> agent edit : outil IA préféré, claude-code, codex, antigravity ou cursor ; `--tool none` retire l'outil préféré\n --remote <nom> journal sync : le dépôt distant Git à utiliser (par défaut celui que suit la branche courante, sinon origin)\n --recreate-remote journal sync : envoie le journal local comme nouvelle branche distante, après la suppression voulue de l'ancienne\n --base <réf> docs check : la version Git avec laquelle comparer (HEAD par défaut)\n --story <e-s> history, usage : seulement cette story (par exemple 2-6)\n --since <date> history, usage : à partir de cette date : 2026-10-03 (minuit, heure locale), ou une date et une heure avec leur décalage, 2026-10-03T12:00:00Z ou 2026-10-03T14:00:00+02:00\n --by <axe> usage : story, step (par défaut), skill, agent ou session\n --until <jour> usage : jusqu'à ce jour (AAAA-MM-JJ, UTC), avec --since\n --session <outil>:<id> usage : dit aussi ce qui a rendu cette session plus chère (compétences chargées deux fois, fichiers relus, outils en échec ; Claude Code seulement)\n --decision <décision> history : approved, approved_with_reservations, rejected, changes_requested, option_chosen, waived ou reopened\n --all history : aussi les réponses ignorées par le journal, avec leur raison (dans l'export aussi)\n --export <fichier> history : écrit dans un fichier .json (exact) ou .csv (pour les tableurs), relatif au dossier courant\n --force history --export, publication export : remplace un fichier existant\n --file <chemin> publication : n'affiche que ce fichier du livrable\n --unverified publication export : exporte aussi une approbation donnée dans le chat sans preuve (outil sans hook)\n --raw publication : le fichier entier, avec l'en-tête YAML de la base de connaissance\n --error <message> doctor : le message de la commande qui a échoué (`--error=<message>` s'il commence par un tiret ; `-` : lu sur l'entrée standard, redirigée) ; le moteur dit ce qu'il constate sur ta machine, à part de ce qu'il suppose\n --exit-code <n> doctor : le code de sortie de la commande qui a échoué (137, 127…)\n --report doctor : le rapport à joindre à une demande d'aide (système, versions, résultat de chaque vérification), sans nom d'utilisateur, chemin personnel, jeton ni contenu de ton produit ; il ne répare rien\n --json next, deferred, trace, usage, doctor : la réponse en JSON, pour les scripts (une erreur aussi, sur la sortie standard, sauf doctor)\n --yes, -y init : ne demande rien, prend les réponses recommandées (et écrit les fichiers des outils IA) ; dans un script, le code de sortie dit si un point bloquant demeure\n --tools <liste> init : les outils IA à brancher, parmi claude-code, codex, antigravity et cursor, séparés par des virgules (par défaut ceux qui sont trouvés, sinon tous)\n --permissions <mode> init, profile : protected (par défaut : ton outil IA continue de demander avant les gestes sensibles) ou free (son mode sans questions reste possible)\n --channel <boutique> init : la boutique où la méthode a été trouvée (claude-plugin), écrite par la compétence d'accueil du plugin Claude Code pour que `doctor` dise comment la méthode a été installée\n --no-sync init : n'écrit pas les fichiers des outils IA\n --out <fichier> key export : écrit la clé exportée dans ce nouveau fichier, hors du dépôt\n --in <fichier> key import : lit la clé exportée dans ce fichier\n --check migrate : montre ce qu'il ferait, sans rien écrire\n --forge <forge> ci setup, story ci : github ou gitlab (par défaut, ci.forge de method.yaml, sinon la forge du dépôt distant origin)\n --runner <nom> tests setup : le lanceur de tests unitaires et d'API (vitest, jest, mocha, node-test, pytest, go-test, cargo-test, rspec, phpunit, dotnet-test, maven, gradle)\n --e2e <nom> tests setup : le lanceur de bout en bout (playwright, cypress) ou none\n --waive <raison> story ci : accepte la story sans sa CI, pour le commit actuel de sa branche\n --upgrade-engine init : épingle la version du moteur en cours dans `.agentplugged/method.yaml` et rafraîchit la méthode (sans trace dans le journal : pour changer seulement de moteur, préfère `migrate`)\n --engine-any s'exécute même si `.agentplugged/method.yaml` épingle une autre version du moteur (avec un avertissement)\n --version, -v affiche la version d'agentplugged\n --help, -h affiche cette aide",
9505
+ "cli.usage": "Utilisation : agentplugged <commande> [options]\n\nDepuis le chat : demande à ton agent, à l'écrit ou en dictée, ce qui t'est réservé (« passe la CI de la story 4-3, le runner est en panne ») :\n il ouvre une demande, tu la valides dans le chat, et le moteur l'exécute. Les commandes ci-dessous existent aussi, pour qui préfère la ligne de commande ; seul le niveau strict les exige.\n\nCommandes :\n init Installe la méthode dans le dossier courant\n profile Choisit ce que fait la méthode pour ce produit (ou dans le chat)\n doctor [--json] [--error <message>] [--exit-code <n>] [--report] Regarde ta machine (Node, Git, la forge, tes outils IA, le trousseau…), dit ce qui manque et le répare avec ton accord ; code de sortie 1 si un point bloquant demeure\n sync Génère les fichiers des outils IA (Claude Code, Codex, Antigravity CLI, Cursor) à partir de la méthode\n agent Gère tes agents et compétences (ou dans le chat) :\n agent create <id> crée un agent (ou une compétence avec --skill)\n agent edit <id> indique les fichiers à modifier (crée le fichier de personnalisation d'un agent ou d'une compétence livrés)\n agent edit <skill> --personal\n ta couche à toi d'une compétence livrée, ignorée par Git\n agent edit <id> --tier <niveau> --tool <outil>\n choisit le niveau de modèle et l'outil IA préféré de l'agent\n agent enable <id> active un agent ou une compétence\n agent disable <id> désactive un agent ou une compétence\n journal sync Récupère le journal du dépôt distant, puis lui envoie les événements qui lui manquent (sans jamais forcer)\n journal status Affiche l'état du produit calculé à partir du journal : événements appliqués, ignorés, avertissements\n (.agentplugged/.cache/state.json ; son computed_at est la date du dernier événement appliqué, dans l'ordre de projection)\n docs check Vérifie les documents de .agentplugged/docs, epics et stories : leurs en-têtes, les stories (contrat, couverture du PRD, dépendances, intentions validées), et qu'aucun identifiant d'exigence n'a été renuméroté, réutilisé ou supprimé depuis la base (code de sortie 1 si des problèmes sont trouvés, 2 si la vérification n'a pas pu se faire)\n mcp Lance le serveur MCP par lequel les agents rendent compte, en stdio : un lanceur stable qui passe à un moteur plus récent entre deux appels, sans reconnexion (sync le déclare dans chaque outil IA)\n update [--check on|off] [--auto on|off] Installe le dernier moteur dans son propre dossier et met le produit dessus (ce que fait un oui à Noah ; dans un terminal interactif seulement) ; --check on|off : interroger le registre npm pour savoir si une version est sortie, au plus deux fois par jour (activé par défaut) ; --auto on|off : l'installer sans question (désactivé par défaut)\n hook antigravity|codex pre-tool|post-tool Les hooks du plugin d'Antigravity CLI et du projet de Codex, lancés par l'outil : les règles de permission avant un outil, les lectures de contenu extérieur après (sync les écrit)\n publication <G-id> [--file <chemin>] [--raw] Affiche le texte complet d'un livrable de lancement, de marketing ou de vente, la version qu'on t'a montrée (un seul fichier avec --file ; --raw : le fichier entier, en-tête compris)\n publication export <G-id> [--force] [--unverified] Écrit un livrable que tu as validé, prêt à publier, dans .agentplugged/exports/<G-id>/ (rien n'est publié, envoyé ni payé)\n review [<G-id>] Réponds à un point de contrôle ouvert, signé par ta clé, ou rouvre un point appliqué automatiquement (dans un terminal interactif seulement)\n key presence [--reset] Protège tes validations avec Windows Hello (--reset : recrée l'identifiant quand il ne marche plus)\n key endorse [<human:…>] Liste les clés de créateur en attente d'approbation, ou approuve une clé dont tu es sûr\n key export [--out <fichier>] Exporte la clé du produit, chiffrée par une phrase de passe, pour une autre machine\n key import [--in <fichier>] Importe la clé du produit exportée sur une autre machine (tapée, non affichée, sans --in)\n key seal Chiffre les fichiers de la Salle et de la mémoire encore en clair\n trust dismiss Écarte l'événement qui bloque les ordres quand le journal contient une autre racine de confiance que celle épinglée sur cette machine (rien à faire sinon)\n (review, key et trust : dans un terminal interactif seulement)\n history Affiche tes validations, de la plus récente à la plus ancienne (--story <e-s>, --since <date ISO>, --decision <décision> ;\n --all : aussi les réponses ignorées par le journal, avec leur raison)\n history --export <fichier.json|fichier.csv> [--force] Les écrit dans un fichier (JSON ou CSV, selon son extension)\n rules [show] Affiche les règles de permission : ce que les agents font seuls (allow), après t'avoir demandé (ask) ou jamais (deny), lues sur la branche principale\n rules set <action> <allow|ask|deny> Change une règle ; rules reset : revient aux défauts (dans un terminal interactif seulement)\n next Affiche la prochaine étape en trois lignes : l'étape en cours, l'agent à appeler et où, et ce qui attend ta validation,\n puis une quatrième ligne avec la commande à lancer quand l'étape en a une\n migrate [--check] Passe .agentplugged/ au format de ce moteur et l'épingle, avec une trace dans le journal (dans un terminal interactif seulement ; --check : montre ce qu'il ferait, sans rien écrire)\n deferred [list] [<e-s>] [--all] [--json] Affiche le travail reporté ouvert (les points qui verrouillent cette story ; --all : aussi les points fermés)\n deferred show <D-id> [--json] Affiche un point reporté\n deferred resolve|drop <D-id> <raison> Marque un point reporté traité, ou l'abandonne (ou dans le chat ; au terminal : interactif seulement)\n story start <e-s> Démarre une story : sa branche feat/<e-s>-<slug>, sa copie de travail à côté du dépôt et le hook de commit (pour toi ou un agent)\n story pr <e-s> Livre une story : pousse sa branche (jamais la principale) et ouvre ou met à jour sa pull request au modèle fixe, par gh ou glab déjà connecté\n story ci <e-s> [--forge github|gitlab] Lit la CI de la pull request ouverte d'une story (gh ou glab) ; en échec, la story repasse en développement\n story ci <e-s> --waive \"<raison>\" Accepte une story dont la CI ne peut pas être lue, pour le commit actuel de sa branche (ou dans le chat ; au terminal : interactif seulement)\n ci setup [--forge github|gitlab] Écrit la CI de base du produit (lint, tests, build, audit des dépendances), jamais par-dessus une CI existante\n tests setup [--runner <nom>] [--e2e <nom>|none] Prépare le cadre de test du produit d'après ses fichiers et propose, dans .agentplugged/proofs.yaml, la commande qui lance les tests d'un critère (jamais par-dessus une déclaration existante)\n trace [<EF-n>] [--json] Affiche la traçabilité : chaque exigence et son statut (à faire, en développement, en revue, livrée, en écart), ou une exigence avec ses stories, tests, pull requests et écarts\n trace resolve <V-id> <raison> Lève un écart (ou dans le chat ; au terminal : interactif seulement)\n usage [--by story|step|skill|agent|session] [--story <e-s>] [--since <jour>] [--until <jour>] [--session <outil>:<id>] [--json] Montre ce que tes outils d'IA ont consommé : des jetons et l'origine de chaque chiffre (nommé par l'outil, déduit du journal, ou inconnu), la part que rien n'a permis d'attribuer, les outils qu'on ne peut pas mesurer ; aucun montant, seulement l'estimation d'une story\n eval check [<compétence>] Vérifie les cas de comportement d'une compétence (valides, appelée d'après les mots de sa description, passage gardé) : gratuit, sans agent\n eval init <compétence> Propose des cas pour démarrer, écrits une fois, jamais par-dessus un fichier existant\n eval run <compétence> [--mode quality|baseline|variant|trigger] [--runs <n>] [--record] [--plan] Lance les cas avec un vrai agent dans un dossier propre (cela consomme des jetons : le plan vient d'abord ; jamais dans les tests), les note, compte les jetons et compare au passage gardé : un cas qui ne passe plus, ou un coût au-dessus du seuil, donne le code de sortie 1\n pair [--no-open] [--nouveau] [--changer-de-compte] Relie ton application web à ce produit : affiche un lien à cliquer, rien d'autre à faire (c'est le pont qui s'en charge, une fois installé)\n device list|revoke <appareil> Liste les appareils reliés à ce produit, ou en retire un : il ne reçoit plus rien et peut être relié de nouveau (c'est le pont qui s'en charge, une fois installé)\n bridge install|uninstall|start|status Installe le pont (et le met à jour) comme service de ton compte, le retire, le lance sur cette machine, ou dit son état. Le pont se distribue à part, sous la licence d'Innovel Studio SASU : cette commande ne fait que l'installer et le lancer\n\nOptions :\n --profile <profil> new-product, maintenance, launch-only ou prototype, sans questions\n --validation <niveau> init, profile : comment tu réponds aux points de contrôle, chat (dans le chat de ton outil IA, par défaut), auto ou strict\n --installs <mode> init, profile : comment s'installent les dépendances, visible (sans validation, affichées dans l'activité et inscrites au journal, par défaut) ou validate (une validation chacune)\n --points <liste> init, profile : les points de validation qui t'attendent (framing, architecture, breakdown, merge, release, publication, séparés par des virgules ; none : aucun), les agents décident les autres\n --workflow recommended init, profile : garde le workflow Git recommandé pour tout (une branche par story, la CI sur la forge quand il y en a une, fusion par pull request, une revue avant la fusion)\n --branches <modèle> init, profile : les branches de base, main (seule), main+dev (les stories arrivent sur dev, une mise en production la fait passer dans main) ou <production>+<intégration>\n --story-branches <yes|no> init, profile : une branche par story, ou on travaille sur la branche où arrivent les stories\n --ci <mode> init, profile : la CI, none, local (ta machine) ou remote (la forge)\n --merge <mode> init, profile : comment une story est fusionnée, pr (une pull request) ou direct (par le moteur, jamais poussé)\n --review <yes|no> init, profile : une revue avant la fusion\n --skill agent create : crée une compétence plutôt qu'un agent\n --name, --title, --description, --domain, --phase, --icon, --role <texte>\n agent create : réponses données sans questions (une compétence ne prend que --description)\n --tier <niveau> agent edit : niveau de modèle, reasoning, code, fast ou multimodal ; `--tier default` revient au niveau propre de l'agent\n --tool <outil> agent edit : outil IA préféré, claude-code, codex, antigravity ou cursor ; `--tool none` retire l'outil préféré\n --remote <nom> journal sync : le dépôt distant Git à utiliser (par défaut celui que suit la branche courante, sinon origin)\n --recreate-remote journal sync : envoie le journal local comme nouvelle branche distante, après la suppression voulue de l'ancienne\n --base <réf> docs check : la version Git avec laquelle comparer (HEAD par défaut)\n --story <e-s> history, usage : seulement cette story (par exemple 2-6)\n --since <date> history, usage : à partir de cette date : 2026-10-03 (minuit, heure locale), ou une date et une heure avec leur décalage, 2026-10-03T12:00:00Z ou 2026-10-03T14:00:00+02:00\n --by <axe> usage : story, step (par défaut), skill, agent ou session\n --until <jour> usage : jusqu'à ce jour (AAAA-MM-JJ, UTC), avec --since\n --session <outil>:<id> usage : dit aussi ce qui a rendu cette session plus chère (compétences chargées deux fois, fichiers relus, outils en échec ; Claude Code seulement)\n --decision <décision> history : approved, approved_with_reservations, rejected, changes_requested, option_chosen, waived ou reopened\n --all history : aussi les réponses ignorées par le journal, avec leur raison (dans l'export aussi)\n --export <fichier> history : écrit dans un fichier .json (exact) ou .csv (pour les tableurs), relatif au dossier courant\n --force history --export, publication export : remplace un fichier existant\n --file <chemin> publication : n'affiche que ce fichier du livrable\n --unverified publication export : exporte aussi une approbation donnée dans le chat sans preuve (outil sans hook)\n --raw publication : le fichier entier, avec l'en-tête YAML de la base de connaissance\n --error <message> doctor : le message de la commande qui a échoué (`--error=<message>` s'il commence par un tiret ; `-` : lu sur l'entrée standard, redirigée) ; le moteur dit ce qu'il constate sur ta machine, à part de ce qu'il suppose\n --exit-code <n> doctor : le code de sortie de la commande qui a échoué (137, 127…)\n --report doctor : le rapport à joindre à une demande d'aide (système, versions, résultat de chaque vérification), sans nom d'utilisateur, chemin personnel, jeton ni contenu de ton produit ; il ne répare rien\n --json next, deferred, trace, usage, doctor : la réponse en JSON, pour les scripts (une erreur aussi, sur la sortie standard, sauf doctor)\n --yes, -y init : ne demande rien, prend les réponses recommandées (et écrit les fichiers des outils IA) ; dans un script, le code de sortie dit si un point bloquant demeure\n --tools <liste> init : les outils IA à brancher, parmi claude-code, codex, antigravity et cursor, séparés par des virgules (par défaut ceux qui sont trouvés, sinon tous)\n --permissions <mode> init, profile : protected (par défaut : ton outil IA continue de demander avant les gestes sensibles) ou free (son mode sans questions reste possible)\n --channel <boutique> init : la boutique où la méthode a été trouvée (claude-plugin), écrite par la compétence d'accueil du plugin Claude Code pour que `doctor` dise comment la méthode a été installée\n --no-sync init : n'écrit pas les fichiers des outils IA\n --clean-gemini sync : retire seulement les fichiers qu'AgentPlugged a écrits pour Gemini CLI (arrêté) et liste les autres (avec --yes : les retire aussi)\n --out <fichier> key export : écrit la clé exportée dans ce nouveau fichier, hors du dépôt\n --in <fichier> key import : lit la clé exportée dans ce fichier\n --check migrate : montre ce qu'il ferait, sans rien écrire\n --forge <forge> ci setup, story ci : github ou gitlab (par défaut, ci.forge de method.yaml, sinon la forge du dépôt distant origin)\n --runner <nom> tests setup : le lanceur de tests unitaires et d'API (vitest, jest, mocha, node-test, pytest, go-test, cargo-test, rspec, phpunit, dotnet-test, maven, gradle)\n --e2e <nom> tests setup : le lanceur de bout en bout (playwright, cypress) ou none\n --waive <raison> story ci : accepte la story sans sa CI, pour le commit actuel de sa branche\n --upgrade-engine init : épingle la version du moteur en cours dans `.agentplugged/method.yaml` et rafraîchit la méthode (sans trace dans le journal : pour changer seulement de moteur, préfère `migrate`)\n --engine-any s'exécute même si `.agentplugged/method.yaml` épingle une autre version du moteur (avec un avertissement)\n --version, -v affiche la version d'agentplugged\n --help, -h affiche cette aide",
9434
9506
  "cli.error": "Erreur {code} : {message}",
9435
9507
  "init.summary.title": "Méthode installée dans {root}",
9436
9508
  "init.action.created": "créé",
@@ -9469,6 +9541,10 @@ const fr = {
9469
9541
  "sync.warning.overwritten": "{path} : modification manuelle écrasée.",
9470
9542
  "sync.warning.conflict": "{path} : sans marque agentplugged (un en-tête, ou la description générée d'un plugin), il t'appartient et a été laissé tel quel. Renomme-le ou supprime-le pour que sync le génère.",
9471
9543
  "sync.warning.kept": "{path} : n'est plus généré, mais son en-tête a été retiré : il t'appartient et a été conservé.",
9544
+ "sync.warning.gemini_legacy": "Gemini CLI n'est plus pris en charge par Google ; AgentPlugged utilise maintenant Antigravity CLI. Tes anciens fichiers de Gemini CLI ({path}) sont encore lus et laissés tels quels : rien n'y est écrit ni supprimé. Pour retirer seulement les fichiers qu'AgentPlugged a écrits, lance `npx agentplugged sync --clean-gemini`.",
9545
+ "sync.warning.gemini_unproven": "{path} : AgentPlugged ne peut pas prouver qu'il l'a écrit tel quel (modifié depuis, ou sans trace), il a donc été conservé.",
9546
+ "sync.gemini.confirm": "Les fichiers ci-dessus ont été conservés. Pour les retirer aussi, vérifie-les, puis lance `npx agentplugged sync --clean-gemini --yes`.",
9547
+ "sync.gemini.nothing": "Rien à nettoyer : aucun fichier écrit par AgentPlugged pour Gemini CLI n'a été trouvé.",
9472
9548
  "tools.title": "Outils IA",
9473
9549
  "tools.line": "{name} {version} — {sources}",
9474
9550
  "tools.line.unknown_version": "{name} (version non reconnue) — {sources}",
@@ -9897,7 +9973,7 @@ const fr = {
9897
9973
  "history.author.root": "{device} (clé racine)",
9898
9974
  "history.author.endorsed": "{device} (approuvée le {date})",
9899
9975
  "history.author.endorsed_undated": "{device} (approuvée)",
9900
- "history.source.terminal": "terminal",
9976
+ "history.source.terminal": "au terminal",
9901
9977
  "history.option": "option {option}",
9902
9978
  "history.waiver_until": "jusqu'au {date}",
9903
9979
  "history.assurance": "assurance {assurance}",
@@ -9964,6 +10040,10 @@ const fr = {
9964
10040
  "key.export.hint": "Sur l'autre machine, lance `npx agentplugged key import` (ou `--in <fichier>`) et tape la même phrase de passe. Garde bien la phrase de passe : sans elle l'export ne sert à rien, et une clé du produit perdue rend le contenu chiffré illisible pour toujours.",
9965
10041
  "key.import.done": "Clé du produit {key_id} importée dans le trousseau de cette machine.",
9966
10042
  "key.import.already": "Cette machine a déjà la clé du produit {key_id}.",
10043
+ "key.export.many": "Cet export contient {count} clés : la clé actuelle et celles gardées d'avant chaque renouvellement, pour que tout l'historique reste lisible là où tu l'importes.",
10044
+ "key.export.missing": "Attention : cette machine n'a pas {count} ancienne(s) clé(s) de ce produit ({key_ids}). Ce qu'elles ont écrit ne se lira pas depuis cet export ; exporte depuis une machine qui les a.",
10045
+ "key.import.many": "Clés gardées sur cette machine : {key_ids}.",
10046
+ "key.import.older": "Anciennes clés du produit importées : l'historique écrit avec elles est lisible. La clé actuelle {key_id} manque encore ici : importe un export fait après le dernier renouvellement, ou laisse le renouvellement parvenir à cette machine.",
9967
10047
  "init.product_key.created": "Clé du produit créée ({key_id}) : les coûts, les notes de sécurité, la Salle et la mémoire sont chiffrés avec elle. Elle reste dans le trousseau de cette machine, jamais dans le dépôt.",
9968
10048
  "init.product_key.ready": "Clé du produit : {key_id}.",
9969
10049
  "init.product_key.published": "Son identifiant est annoncé dans le journal de ce produit.",
@@ -10989,9 +11069,29 @@ const fr = {
10989
11069
  "error.relay.relay_connection_replaced": "Une connexion plus récente de cet appareil a pris la place de celle-ci.",
10990
11070
  "error.relay.relay_prekey_invalid": "Le relais a refusé cette clé de réception. Rien n'a été gardé.",
10991
11071
  "error.relay.relay_unavailable": "Le relais n'a pas pu le faire maintenant. Rien n'a été fait : réessaie.",
11072
+ "error.relay.vault_refused": "Le relais n'a pas gardé le dernier état de ton projet. Ta machine le scelle de nouveau.",
11073
+ "error.relay.push_refused": "Le relais n'a pas pris cette demande de notification. Rien n'a été envoyé.",
10992
11074
  "error.relay.rendezvous_unknown": "Ce lien d'appairage n'existe plus. Relance la commande pour en obtenir un nouveau.",
10993
11075
  "error.relay.rendezvous_refused": "Le relais n'a pas pu ouvrir ce point de rencontre. Réessaie dans un moment.",
10994
11076
  "error.relay.rendezvous_attach_refused": "Le relais n'a pas pu rattacher cette machine à ton compte. Réessaie avec un nouveau lien.",
11077
+ "error.relay.challenge_expired": "Cette étape a pris trop de temps. Recommence.",
11078
+ "error.relay.challenge_reused": "Cette étape a déjà servi. Recommence.",
11079
+ "error.relay.origin_mismatch": "Cette page n'a pas le droit d'utiliser ta clé d'accès avec AgentPlugged. Ouvre l'adresse officielle.",
11080
+ "error.relay.credential_already_registered": "Cette clé d'accès appartient déjà à un compte. Connecte-toi avec elle.",
11081
+ "error.relay.email_code_invalid": "Ce code n'est pas le bon. Vérifie le courriel et réessaie.",
11082
+ "error.relay.email_code_expired": "Ce code n'est plus valable. Demande un nouveau code.",
11083
+ "error.relay.email_already_registered": "Un compte existe déjà avec cette adresse. Connecte-toi avec ta clé d'accès.",
11084
+ "error.relay.account_request_invalid": "La demande n'est pas valide. Vérifie ce que tu as saisi.",
11085
+ "error.relay.account_sign_in_failed": "Cette clé d'accès n'a pas été reconnue. Réessaie, ou utilise un autre appareil.",
11086
+ "error.relay.account_session_required": "Tu es déconnecté. Connecte-toi de nouveau.",
11087
+ "error.relay.account_deleted": "Ce compte a été supprimé : cet appareil n'y est plus relié.",
11088
+ "error.relay.export_not_ready": "Ton export est encore en préparation. Réessaie dans un instant.",
11089
+ "error.relay.export_gone": "Cet export a déjà été téléchargé, ou son lien a expiré. Demande-en un nouveau.",
11090
+ "error.relay.passkey_limit": "Tu as déjà le maximum de clés d'accès pour un compte. Retires-en une avant d'en ajouter une autre.",
11091
+ "error.relay.passkey_last": "C'est ta dernière clé d'accès : sans elle, personne ne pourrait plus se connecter à ce compte. Ajoute-en une autre d'abord.",
11092
+ "error.relay.share_limit": "Tu as déjà le maximum de liens de partage actifs. Retire-en un avant d'en créer un autre.",
11093
+ "error.relay.share_too_large": "Cette page est trop volumineuse pour être partagée.",
11094
+ "error.relay.share_unavailable": "Ce lien ne fonctionne pas : il a expiré ou a été retiré.",
10995
11095
  "error.relay.upgrade_required": "Cet appareil parle une version du protocole que le relais n'accepte plus : mets-le à jour.",
10996
11096
  "points.title": "Les points de validation : ceux que tu gardes pour toi. Tout le reste est décidé par l'agent responsable, avec sa raison au journal, et tu peux le rouvrir quand tu veux.",
10997
11097
  "points.point.framing": "Documents de cadrage (brief, PRD, spécification UX) et la fin de leurs phases",
@@ -11004,7 +11104,10 @@ const fr = {
11004
11104
  "points.summary": "Points qui t'attendent : {list}. Les agents décident les autres.",
11005
11105
  "points.summary.none": "Aucun point ne t'attend : les agents décident tous les points.",
11006
11106
  "history.source.agent": "décidé par l'agent responsable",
11107
+ "history.source.web": "depuis le cockpit web",
11108
+ "history.source.mobile": "depuis le téléphone",
11007
11109
  "assurance.agent": "décision d'un agent (pas ta réponse), avec sa raison ; tu peux la rouvrir",
11110
+ "assurance.device": "signé par un appareil que tu as relié (le cockpit web ou ton téléphone)",
11008
11111
  "review.agent_decided": "Décidé par l'agent {agent} le {at} : {decision}. Raison : {reason}",
11009
11112
  "next.step.point_decision": "Un point que tu ne gardes pas attend la décision de l'agent responsable",
11010
11113
  "next.independent": "Le travail continue sans toi : cette étape ne dépend d'aucun des points qui t'attendent.",
@@ -11057,7 +11160,10 @@ const fr = {
11057
11160
  "update.done_pinned": "Le moteur {version} est installé (le produit l'épinglait déjà). Tes sessions ouvertes passent dessus à leur prochain appel.",
11058
11161
  "update.failed": "La mise à jour n'a pas eu lieu ({reason}). {message} Le moteur qui tourne n'a pas été touché.",
11059
11162
  "error.engine_version_too_old.agent": "{path} épingle le moteur {pinned} et cette session tourne encore sur {engine_version} : rien n'a été écrit. Appelle `state.next` (ou `state.get`) : il porte `engine_update`, et le « oui » du créateur à guard.creator_action `engine_update` {install: true} installe {pinned} et fait passer cette session dessus à ton prochain appel. Dis-le au créateur en une phrase ; ne lui dis jamais de reconnecter ni de taper une commande.",
11060
- "bridge.launcher.not_installed": "Le pont n'est pas installé sur cette machine. Il se distribue à part, sous la licence d'Innovel Studio SASU : récupère-le sur https://agentplugged.ai. Le reste d'AgentPlugged (`state.next`, `review`, le serveur MCP) fonctionne sans lui.",
11163
+ "bridge.launcher.not_installed": "Le pont n'est pas installé sur cette machine. Il se distribue à part, sous la licence d'Innovel Studio SASU : installe-le avec `agentplugged bridge install` (détails sur https://agentplugged.ai). Le reste d'AgentPlugged (`state.next`, `review`, le serveur MCP) fonctionne sans lui.",
11164
+ "bridge.launcher.installing": "Récupération du pont (la version la plus récente)…",
11165
+ "bridge.launcher.install_failed": "Le pont n'a pas pu être téléchargé ({reason}). Rien n'a été installé. Réessaie, ou récupère-le sur https://agentplugged.ai.",
11166
+ "bridge.launcher.update_failed": "Le pont le plus récent n'a pas pu être téléchargé ({reason}) : celui qui est installé est gardé.",
11061
11167
  "workflow.title": "Workflow Git (branches, CI, fusions, revue)",
11062
11168
  "workflow.recommended": "(recommandé)",
11063
11169
  "workflow.intro": "Je te propose ce qui convient à un créateur solo : {line}. Réponds oui pour tout garder, non pour choisir point par point.",
@@ -11225,6 +11331,7 @@ const fr = {
11225
11331
  "init.sync.done": "Fichiers de tes outils IA écrits ({count} créés ou mis à jour).",
11226
11332
  "init.sync.skipped": "Pas de sync pour l'instant : lance `npx agentplugged sync` quand tu veux.",
11227
11333
  "init.done.noah": "C'est prêt. Ouvre {tool} dans ce dossier et écris : noah ?",
11334
+ "init.link.hint": "Pour le relier à ton application web : `npx agentplugged pair`",
11228
11335
  "init.done.noah.several": "C'est prêt. Ouvre l'un de tes outils ({tools}) dans ce dossier et écris : noah ?",
11229
11336
  "init.done.sync_first": "Ensuite : lance `npx agentplugged sync`, puis ouvre {tool} dans ce dossier et écris : noah ?",
11230
11337
  "init.done.sync_first.several": "Ensuite : lance `npx agentplugged sync`, puis ouvre l'un de tes outils ({tools}) dans ce dossier et écris : noah ?",
@@ -11919,16 +12026,16 @@ function questionToolOf(options) {
11919
12026
  * in the reference, section « Tool: <name> », and in the skills.
11920
12027
  */
11921
12028
  const TOOL_DESCRIPTIONS = {
11922
- state: "Read-only. Actions: get (ONE option only), next, trace, merge_order, environment. See reference/tool-state.md",
11923
- checkpoint: "Validation points. Actions: open (before asking the creator), decide (only a point the creator did not keep), measures, gap. Never answer for the creator. See reference/tool-checkpoint.md",
11924
- chat: "Ask the creator. Actions: ask, answer (only the creator's own words in quote, or via question_tool), stack_open, stack_ask, stack_answer, table. Never answer, reword or waive for the creator. See reference/tool-chat.md",
11925
- story: "Actions: start (only in its workdir), status, progress, result (end with it), pr (never merge), ci, deviation, lift_deviation, leave_fast_track, merge_conflict, criterion, loop. Never skip hooks or push the main branch. See reference/tool-story.md",
11926
- review: "Actions: start, submit, triage, get, publish, audit, critique, tests, qa, ready, export. Never review a story you built. See reference/tool-review.md",
11927
- agent: "Activity, handovers. Actions: status, delegate (Noah only), workshop. agent = your own id. See reference/tool-agent.md",
11928
- guard: "Creator-only actions, sensitive data. Actions: request, check (refused means never), external_read, creator_action (only with their yes), read_sensitive, write_sensitive (never read salle/ or memory/ files directly). what = action. See reference/tool-guard.md",
11929
- plan: "Actions: sprint (the creator approves), defer, complete_deferred, course (change of mind). Never start a story an open deferred item locks. See reference/tool-plan.md",
11930
- memory: "Lessons. Actions: read (before your first answer), retrospective, record, promote_propose, promote. Never record or promote a lesson before the creator approved it. See reference/tool-memory.md",
11931
- measure: "Actions: cost (never invent an amount), usage, requirements, proof (real results only), run (a command the creator accepted). See reference/tool-measure.md"
12029
+ state: "Read-only. Actions: get (ONE option only), next, trace, merge_order, environment. Ref: tool-state",
12030
+ checkpoint: "Validation points. Actions: open (before asking the creator; files in documents, as paths from the product root), decide (only a point the creator did not keep), measures, gap. Never answer for the creator. Ref: tool-checkpoint",
12031
+ chat: "Ask the creator. Actions: ask, answer (only the creator's own words in quote, or via question_tool), stack_open, stack_ask, stack_answer, table. Never answer, reword or waive for the creator. Ref: tool-chat",
12032
+ story: "Actions: start (only in its workdir), status, progress, result (end with it), pr (never merge), ci, deviation, lift_deviation, leave_fast_track, merge_conflict, criterion, loop. Never skip hooks or push the main branch. Ref: tool-story",
12033
+ review: "Actions: start, submit, triage, get, publish, audit, critique, tests, qa, ready, export. Never review a story you built. Ref: tool-review",
12034
+ agent: "Actions: status, delegate (Noah only), workshop. agent = your own id. Ref: tool-agent",
12035
+ guard: "Creator-only actions, sensitive data. Actions: request, check (refused means never), external_read, creator_action (only with their yes), read_sensitive, write_sensitive (never read salle/ or memory/ files directly). what = action. Ref: tool-guard",
12036
+ plan: "Actions: sprint (the creator approves), defer, complete_deferred, course (change of mind). Never start a story an open deferred item locks. Ref: tool-plan",
12037
+ memory: "Lessons. Actions: read (before your first answer), retrospective, record, promote_propose, promote. Never record or promote a lesson before the creator approved it. Ref: tool-memory",
12038
+ measure: "Actions: cost (never invent an amount), usage, requirements, proof (real results only), run (a command the creator accepted). Ref: tool-measure"
11932
12039
  };
11933
12040
  /** One field of a published schema: a type, and the values of a short enumeration. */
11934
12041
  function slim(field) {
@@ -13031,6 +13138,105 @@ async function findBridge(env, platform = process.platform) {
13031
13138
  return;
13032
13139
  }
13033
13140
  }
13141
+ /**
13142
+ * npm's own JavaScript program on Windows, where `npm` is a batch file that only runs through a
13143
+ * shell: the one next to Node, else the one that started this process. `undefined` when neither is
13144
+ * found.
13145
+ */
13146
+ function npmProgram(env) {
13147
+ return [join(dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js"), env.npm_execpath ?? ""].find((path) => path.endsWith("npm-cli.js") && existsSync(path));
13148
+ }
13149
+ /** Runs npm; no argument ever passes through a shell. */
13150
+ function realNpm(args, platform, env) {
13151
+ return new Promise((resolve) => {
13152
+ let output = "";
13153
+ const program = platform === "win32" ? npmProgram(env) : void 0;
13154
+ if (platform === "win32" && program === void 0) {
13155
+ resolve({
13156
+ code: -1,
13157
+ output: "npm was not found next to Node"
13158
+ });
13159
+ return;
13160
+ }
13161
+ const options = {
13162
+ env: {
13163
+ ...process.env,
13164
+ ...env
13165
+ },
13166
+ stdio: [
13167
+ "ignore",
13168
+ "pipe",
13169
+ "pipe"
13170
+ ],
13171
+ windowsHide: true
13172
+ };
13173
+ const child = program === void 0 ? spawn("npm", [...args], options) : spawn(process.execPath, [program, ...args], options);
13174
+ child.stdout.on("data", (chunk) => {
13175
+ output += chunk.toString("utf8");
13176
+ });
13177
+ child.stderr.on("data", (chunk) => {
13178
+ output += chunk.toString("utf8");
13179
+ });
13180
+ child.on("error", (error) => resolve({
13181
+ code: -1,
13182
+ output: error.message
13183
+ }));
13184
+ child.on("close", (code) => resolve({
13185
+ code: code ?? -1,
13186
+ output
13187
+ }));
13188
+ });
13189
+ }
13190
+ /**
13191
+ * `agentplugged bridge install`: gets the bridge, or its newest version, before the bridge itself
13192
+ * makes itself a service. The bridge is its own npm package, put in a folder of its own; the
13193
+ * pointer file then tells this launcher where it is. A bridge kept elsewhere
13194
+ * (`AGENTPLUGGED_BRIDGE_ENTRY`) is never touched. When the newest version cannot be fetched and a
13195
+ * bridge is already there, that one is used and the failure is said. Returns false when there is
13196
+ * no bridge at all at the end.
13197
+ */
13198
+ async function installBridgePackage(environment, t) {
13199
+ const { env } = environment;
13200
+ const platform = environment.platform ?? process.platform;
13201
+ if (env.AGENTPLUGGED_BRIDGE_ENTRY?.trim()) return await findBridge(env, platform) !== void 0;
13202
+ const dir = bridgeInstallDir(env, platform);
13203
+ const known = await findBridge(env, platform);
13204
+ const source = env.AGENTPLUGGED_BRIDGE_PACKAGE?.trim() || `agentplugged-bridge@latest`;
13205
+ if (dir === void 0 || !/^[^\s"'&|<>^%;$`-][^\s"'&|<>^%;$`]*$/.test(source)) {
13206
+ environment.stderr(`${t("bridge.launcher.install_failed", { reason: "folder" })}\n`);
13207
+ return known !== void 0;
13208
+ }
13209
+ const folder = join(dir, "package");
13210
+ environment.stdout(`${t("bridge.launcher.installing")}\n`);
13211
+ try {
13212
+ await mkdir(folder, { recursive: true });
13213
+ const manifest = join(folder, "package.json");
13214
+ if (!await isFile(manifest)) await writeFile(manifest, "{ \"private\": true }\n");
13215
+ const args = [
13216
+ "install",
13217
+ "--prefix",
13218
+ folder,
13219
+ "--omit=dev",
13220
+ "--no-audit",
13221
+ "--no-fund",
13222
+ "--loglevel=error",
13223
+ source
13224
+ ];
13225
+ const done = await (environment.runNpm ?? ((a) => realNpm(a, platform, env)))(args);
13226
+ if (done.code !== 0) throw new Error(done.output.trim().split("\n")[0] ?? "npm");
13227
+ const dependencies = JSON.parse(await readFile(manifest, "utf8")).dependencies;
13228
+ const name = Object.keys(dependencies ?? {})[0];
13229
+ if (name === void 0) throw new Error("no package");
13230
+ const entry = join(folder, "node_modules", name, "dist", "bin.js");
13231
+ if (!await isFile(entry)) throw new Error("no program");
13232
+ await writeFile(join(dir, BRIDGE_POINTER_FILE), `${JSON.stringify({ entry })}\n`);
13233
+ return true;
13234
+ } catch (error) {
13235
+ const reason = error instanceof Error ? error.message.slice(0, 200) : "unknown";
13236
+ environment.stderr(`${t(known === void 0 ? "bridge.launcher.install_failed" : "bridge.launcher.update_failed", { reason })}\n`);
13237
+ return known !== void 0;
13238
+ }
13239
+ }
13034
13240
  /** Runs the bridge's program with `args`; resolves with its exit code (1 when a signal ended it). */
13035
13241
  function runProgram(entry, args, environment, failed) {
13036
13242
  return new Promise((resolve) => {
@@ -13079,12 +13285,15 @@ function runProgram(entry, args, environment, failed) {
13079
13285
  * nothing is left half done: the pairing is entirely the bridge's.
13080
13286
  */
13081
13287
  async function runBridgeLauncher(environment, t) {
13288
+ if (environment.argv[0] === "bridge" && environment.argv[1] === "install") {
13289
+ if (!await installBridgePackage(environment, t)) return 1;
13290
+ }
13082
13291
  const entry = await findBridge(environment.env, environment.platform);
13083
13292
  if (entry === void 0) {
13084
13293
  environment.stderr(`${t("bridge.launcher.not_installed")}\n`);
13085
13294
  return 1;
13086
13295
  }
13087
- return runProgram(entry, environment.argv[0] === "pair" ? environment.argv : environment.argv.slice(1), environment, t("bridge.launcher.not_installed"));
13296
+ return runProgram(entry, environment.argv[0] === "pair" || environment.argv[0] === "device" ? environment.argv : environment.argv.slice(1), environment, t("bridge.launcher.not_installed"));
13088
13297
  }
13089
13298
  //#endregion
13090
13299
  //#region src/story-text.ts
@@ -14373,7 +14582,8 @@ const NO_KEYCHAIN = {
14373
14582
  writePresenceCredential: noKeychain,
14374
14583
  readProductSecret: noKeychain,
14375
14584
  writeProductSecret: noKeychain,
14376
- writeProductBackup: noKeychain
14585
+ writeProductBackup: noKeychain,
14586
+ readProductBackup: noKeychain
14377
14587
  };
14378
14588
  //#endregion
14379
14589
  //#region src/init-flow.ts
@@ -14528,11 +14738,18 @@ function formatProductKey(t, result, file) {
14528
14738
  const lines = [t("key.export.done", { key_id: result.key_id })];
14529
14739
  if (file === void 0) lines.push("", result.exported, "");
14530
14740
  else lines.push(t("key.export.file", { path: file }));
14741
+ if (result.key_ids !== void 0) lines.push(t("key.export.many", { count: String(result.key_ids.length) }));
14742
+ if (result.missing !== void 0) lines.push(t("key.export.missing", {
14743
+ count: String(result.missing.length),
14744
+ key_ids: result.missing.join(", ")
14745
+ }));
14531
14746
  lines.push(t("key.export.hint"), "");
14532
14747
  return lines.join("\n");
14533
14748
  }
14749
+ if (result.status === "older") return `${t("key.import.older", { key_id: result.key_id })}\n`;
14534
14750
  const lines = [t(result.status === "already" ? "key.import.already" : "key.import.done", { key_id: result.key_id })];
14535
14751
  if (result.replaced !== void 0) lines.push(t("key.import.replaced", { held_key_id: result.replaced }));
14752
+ if (result.key_ids !== void 0) lines.push(t("key.import.many", { key_ids: result.key_ids.join(", ") }));
14536
14753
  return `${lines.join("\n")}\n`;
14537
14754
  }
14538
14755
  function formatSeal(t, result) {
@@ -14576,6 +14793,48 @@ function formatInitProductKey(t, productKey) {
14576
14793
  }
14577
14794
  }
14578
14795
  //#endregion
14796
+ //#region src/link-hint.ts
14797
+ /**
14798
+ * The one line that ends `init` when this product is not linked to the web app yet: the command
14799
+ * that does it, nothing asked, nothing done. The method works alone either way. Whether the product
14800
+ * is already served is read from the bridge's own registry on this machine (a file the bridge
14801
+ * writes; this program never writes it), the way `bridge` finds its program: the command line only
14802
+ * launches the bridge and holds none of its logic.
14803
+ */
14804
+ /** Where the bridge keeps its files on each system (the same folders the bridge uses). */
14805
+ function bridgeDataDir(env, platform) {
14806
+ const given = env.AGENTPLUGGED_BRIDGE_HOME?.trim();
14807
+ if (given) return resolve(given);
14808
+ const home = env.USERPROFILE?.trim() || env.HOME?.trim() || homedir();
14809
+ const usable = (value) => {
14810
+ const trimmed = value?.trim();
14811
+ return trimmed && isAbsolute(trimmed) ? trimmed : void 0;
14812
+ };
14813
+ if (platform === "win32") return join(usable(env.LOCALAPPDATA) ?? join(home, "AppData", "Local"), "AgentPlugged", "bridge");
14814
+ if (platform === "darwin") return join(home, "Library", "Application Support", "AgentPlugged", "bridge");
14815
+ return join(usable(env.XDG_STATE_HOME) ?? join(home, ".local", "state"), "agentplugged", "bridge");
14816
+ }
14817
+ async function readJson(path) {
14818
+ try {
14819
+ return JSON.parse(await readFile(path, "utf8"));
14820
+ } catch {
14821
+ return;
14822
+ }
14823
+ }
14824
+ /** True when this machine is linked to an account and serves the product in `root`. */
14825
+ async function isLinkedToWebApp(root, env, platform) {
14826
+ const dir = bridgeDataDir(env, platform);
14827
+ if (await readJson(join(dir, "binding.json")) === void 0) return false;
14828
+ const registry = await readJson(join(dir, "products.json"));
14829
+ const same = (a, b) => platform === "win32" ? resolve(a).toLowerCase() === resolve(b).toLowerCase() : resolve(a) === resolve(b);
14830
+ return (registry?.products ?? []).some((entry) => typeof entry.path === "string" && same(entry.path, root));
14831
+ }
14832
+ /** The line, or nothing when the product is linked already. */
14833
+ async function linkHint(t, root, env, platform) {
14834
+ if (await isLinkedToWebApp(root, env, platform)) return void 0;
14835
+ return `\n${t("init.link.hint")}\n`;
14836
+ }
14837
+ //#endregion
14579
14838
  //#region src/migrate-text.ts
14580
14839
  /** One change of a step the creator should know, on one line. */
14581
14840
  function noteLine(t, note) {
@@ -16718,7 +16977,9 @@ const SYNC_WARNING_KEYS = {
16718
16977
  kept: "sync.warning.kept",
16719
16978
  description_too_long: "sync.warning.description_too_long",
16720
16979
  unknown_setting: "sync.warning.unknown_setting",
16721
- local_engine: "sync.warning.local_engine"
16980
+ local_engine: "sync.warning.local_engine",
16981
+ gemini_legacy: "sync.warning.gemini_legacy",
16982
+ gemini_unproven: "sync.warning.gemini_unproven"
16722
16983
  };
16723
16984
  /** Stands for the shipped method in commands that never read it. */
16724
16985
  const METHOD_UNAVAILABLE = {
@@ -16743,6 +17004,23 @@ function shippedMethodOrUnavailable() {
16743
17004
  return METHOD_UNAVAILABLE;
16744
17005
  }
16745
17006
  }
17007
+ /**
17008
+ * The environment the bridge is launched with: it also learns where this engine's program is, so
17009
+ * that it can run the same engine to make a product the creator asks for from a device. A value the
17010
+ * creator gave is kept; nothing is added when the program cannot be found (a test, a bundle).
17011
+ */
17012
+ function withEngineEntry(env) {
17013
+ if (env.AGENTPLUGGED_ENGINE_ENTRY?.trim()) return env;
17014
+ try {
17015
+ const entry = fileURLToPath(new URL("./bin.js", import.meta.url));
17016
+ return existsSync(entry) ? {
17017
+ ...env,
17018
+ AGENTPLUGGED_ENGINE_ENTRY: entry
17019
+ } : env;
17020
+ } catch {
17021
+ return env;
17022
+ }
17023
+ }
16746
17024
  /** Options that only change how the engine version is checked: left out of the quoted command. */
16747
17025
  const ENGINE_FLAGS = /* @__PURE__ */ new Set(["--engine-any", "--upgrade-engine"]);
16748
17026
  /**
@@ -16781,7 +17059,7 @@ const SYNC_GROUPS = [
16781
17059
  ];
16782
17060
  function groupTitle(t, group) {
16783
17061
  if (group === "shared") return t("sync.group.shared");
16784
- if (group === "antigravity") return "Antigravity CLI + Gemini CLI";
17062
+ if (group === "antigravity") return "Antigravity CLI";
16785
17063
  return TOOL_CATALOG.find((spec) => spec.id === group)?.name ?? group;
16786
17064
  }
16787
17065
  /**
@@ -16834,6 +17112,10 @@ function formatSync(t, root, result, locale = "en") {
16834
17112
  const fallbacks = result.fallbacks.map((fallback) => ` ${formatFallback(t, locale, fallback)}`);
16835
17113
  text += `\n${t("sync.fallbacks.title")}\n${fallbacks.join("\n")}\n`;
16836
17114
  }
17115
+ if (result.geminiCleanup !== void 0) {
17116
+ if (result.geminiCleanup.listed > 0) text += `\n${t("sync.gemini.confirm")}\n`;
17117
+ else if (result.entries.length === 0) text += `\n${t("sync.gemini.nothing")}\n`;
17118
+ }
16837
17119
  text += formatSyncRules(t, result.rules);
16838
17120
  if (result.codexTrustReminder) text += `\n${t("sync.codex_trust")}\n`;
16839
17121
  if (result.cursorHooksReminder) text += `\n${t("sync.cursor_hooks")}\n`;
@@ -17247,10 +17529,10 @@ async function main(rawEnvironment) {
17247
17529
  let environment = rawEnvironment;
17248
17530
  const locale = localeOf(environment.env, environment.systemLocale);
17249
17531
  const t = createTranslator(locale);
17250
- if (environment.argv[0] === "bridge" || environment.argv[0] === "pair") return await runBridgeLauncher({
17532
+ if (environment.argv[0] === "bridge" || environment.argv[0] === "pair" || environment.argv[0] === "device") return await runBridgeLauncher({
17251
17533
  argv: environment.argv,
17252
17534
  cwd: environment.cwd,
17253
- env: environment.env,
17535
+ env: withEngineEntry(environment.env),
17254
17536
  ...environment.platform === void 0 ? {} : { platform: environment.platform },
17255
17537
  stdout: environment.stdout,
17256
17538
  stderr: environment.stderr
@@ -17325,6 +17607,7 @@ async function main(rawEnvironment) {
17325
17607
  let rawOption = false;
17326
17608
  let unverifiedOption = false;
17327
17609
  let yesOption = false;
17610
+ let cleanGeminiOption = false;
17328
17611
  let toolsOption;
17329
17612
  let permissionsOption;
17330
17613
  let noSyncOption = false;
@@ -17395,6 +17678,7 @@ async function main(rawEnvironment) {
17395
17678
  type: "boolean",
17396
17679
  short: "y"
17397
17680
  },
17681
+ "clean-gemini": { type: "boolean" },
17398
17682
  tools: { type: "string" },
17399
17683
  permissions: { type: "string" },
17400
17684
  "no-sync": { type: "boolean" },
@@ -17455,6 +17739,7 @@ async function main(rawEnvironment) {
17455
17739
  rawOption = parsed.values.raw === true;
17456
17740
  unverifiedOption = parsed.values.unverified === true;
17457
17741
  yesOption = parsed.values.yes === true;
17742
+ cleanGeminiOption = parsed.values["clean-gemini"] === true;
17458
17743
  toolsOption = parsed.values.tools;
17459
17744
  permissionsOption = parsed.values.permissions;
17460
17745
  noSyncOption = parsed.values["no-sync"] === true;
@@ -17586,7 +17871,7 @@ async function main(rawEnvironment) {
17586
17871
  return failCode;
17587
17872
  }
17588
17873
  const initOnly = [
17589
- ...yesOption ? ["--yes"] : [],
17874
+ ...yesOption && !(command === "sync" && cleanGeminiOption) ? ["--yes"] : [],
17590
17875
  ...toolsOption === void 0 ? [] : ["--tools"],
17591
17876
  ...noSyncOption ? ["--no-sync"] : []
17592
17877
  ];
@@ -17594,6 +17879,10 @@ async function main(rawEnvironment) {
17594
17879
  reportError(invalidArguments(`${command}: ${initOnly.join(" ")}`));
17595
17880
  return failCode;
17596
17881
  }
17882
+ if (cleanGeminiOption && command !== "sync" && registry.names().includes(command)) {
17883
+ reportError(invalidArguments(`${command}: --clean-gemini`));
17884
+ return failCode;
17885
+ }
17597
17886
  if (channelOption !== void 0 && command !== "init" && registry.names().includes(command)) {
17598
17887
  reportError(invalidArguments(`${command}: --channel`));
17599
17888
  return failCode;
@@ -17827,6 +18116,11 @@ async function main(rawEnvironment) {
17827
18116
  return failCode;
17828
18117
  }
17829
18118
  input = prepared;
18119
+ } else if (command === "sync") {
18120
+ if (cleanGeminiOption) input = {
18121
+ clean_gemini: true,
18122
+ ...yesOption ? { yes: true } : {}
18123
+ };
17830
18124
  } else if (command === "journal") {
17831
18125
  const [action, ...extra] = rest;
17832
18126
  if (action !== "sync" && action !== "status" || extra.length > 0) {
@@ -18107,6 +18401,8 @@ async function main(rawEnvironment) {
18107
18401
  } else environment.stdout(`\n${t("init.sync.skipped")}\n`);
18108
18402
  environment.stdout(`\n${formatNextStep(t, result.value.targetedTools, synced)}`);
18109
18403
  }
18404
+ const hint = await linkHint(t, files.root, environment.env, environment.platform ?? process.platform);
18405
+ if (hint !== void 0) environment.stdout(hint);
18110
18406
  if (scripted && machineReport?.blocking === true) {
18111
18407
  environment.stderr(`${t("doctor.blocking", { list: machineReport.items.filter((item) => item.status === "fail").map((item) => locale === "fr" ? item.text.fr : item.text.en).join(" ; ") })}\n`);
18112
18408
  exitCode = 1;