agentplugged 1.0.6 → 1.3.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
- 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";
2
+ import { $ as engineDir, 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 agentpluggedHome, R as suggestStarter, S as recordToolRead, T as planCodexTrust, U as keep, V as selection, W as CASES_FILE, X as productRootOf, Y as readCases, Z as ENGINE_PACKAGE, _ as codexCallOf, a as NodeProofRunner, b as callOf, c as createCommandRegistry, et as engineEntry, 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$1, nt as isInstalledEngine, o as NodeEvalAgent, p as CURSOR_FLAVOR, q as REFERENCE_FILE, r as NodeUsageTraces, rt as isReleaseVersion, s as NodeToolProbe, u as shapeResponse, v as codexSessionOf, w as codexTrustSupported, x as guardToolCall, y as recordCodexRead, z as evaluate } from "./product-root.js";
3
+ import { $o as EVENT_REASON, At as EVENT_TYPES, Br as QUESTION_TOOL_NAME, Fo as VALIDATION_POINTS, Ft as journalEventPath, Go as GIT_CI_MODES, It as journalRemoteRef, Jo as GitBranchSchema, Lt as journalSeenRef, Mo as TOOL_IDS, Mt as JOURNAL_REF, Po as VALIDATION_MODES, So as PROFILE_PRESET_IDS, Xo as recommendedGitWorkflow, Zo as resolveGitWorkflow, _n as TracedRequirementInputSchema, _o as INSTALL_MODES, a as fromBase64url, as as parseEventEnvelope, bo as PERMISSION_MODES, c as toHex, cn as MAX_ELICITED_NOTE_LENGTH, dn as DeviationReasonSchema, fo as DEFAULT_PERMISSION_MODE, g as JOURNAL_PROJECTED_REF, go as DOMAIN_IDS, ho as DEVELOPER_SPECIALTIES, i as sha256Hex, jt as JOURNAL_DIR, l as utf8, ls as ErrorCode, mo as DEFAULT_VALIDATION_POINTS, n as randomBytes, ns as ULID_PATTERN, po as DEFAULT_VALIDATION_MODE, qa as DeferredIdInputSchema, qo as GIT_MERGE_MODES, rs as eventInvalid, s as toBase64url, un as DeviationIdInputSchema, uo as DEFAULT_INSTALL_MODE, xo as PHASE_IDS, za as contentSections } from "./hash.js";
4
+ import { $a as renderCodexHooks, $o as toolCallOf, An as engineTargetOf, Bd as canonicalBytes, Cn as answerProblem, Cr as COMMIT_HOOK_LINE, Cu as DEFAULT_PRESET, Dc as forgeCli, Dn as withAnswers, En as runFix, Er as COMMIT_STORIES_DIR, Fd as normalizeChatText, Fr as AgentSession, Ft as parseConflictMarkers, Gd as creatorText, Gr as nextDeviceHead, Iu as byOpening, J as researchLines, Ju as waiverDeadlineProblem, Kr as prepareAppend, Ku as reviewActions, Ma as checkEngine, Mc as repositoryWebUrl, Mn as installAndPin, Oc as forgeOfHost$1, Os as keychainFull, Pd as messageDigest, Pn as maybeAutoUpdate, Ps as formDigest, Qo as TOOL_GROUPS, Rs as CI_CONFIG_PATHS, Sd as sameProject, Sr as COMMIT_CHECK_PATH, Tr as COMMIT_SKIPS_PATH, Tu as isPresetId, Ul as ARCHITECTURE_SECURITY_REVIEW_PATH, Ur as deviceHeads, Us as isWorkflowFile, Vd as eventHash, Vr as checkHumanEvents, Wd as ANTIGRAVITY_UNCHECKED_REASON, Wr as journalProduct, Wu as parseWaiverAnswer, Xr as announcedKey, Xu as waiverRefusal, Y as costsLines, Yo as inputShapeOf, Yr as adoptRotatedKey, Zo as publishedShape, Zr as forgetProductKey, Zu as AgentPluggedError, _d as isCursorClient, _i as stackField, _o as readProfile, bs as readDefinitions, dr as validateCreateField, ds as toolName, dt as reviewNotInteractive, er as AGENT_ACTIONS, es as toolNotation, fo as toolsFromDetection, fr as recordGitWorkflow, fs as TOOL_CATALOG, gd as isCodexClient, gu as STORY_BUILDERS, hd as isAntigravityClient, hn as JournalBackup, ho as methodNotInstalled, is as isPersonalLayerFile, jc as remoteLocation, js as DECISION_FORM_FIELDS, ks as loadMachineKey, mn as JOURNAL_REMOTE_NAME, mu as isRetiredDeveloper, nd as METHOD_CONFIG_PATH, ni as sensitiveProductKey, nr as checkCreate, ns as SKILL_OVERRIDES_DIR, oo as withEngineCommand, po as detectTools, qr as prepareEngineEvents, qu as statusAt, ts as withToolNotation, us as displayName, vd as isHookedClient, vo as resolveProfile, wn as displayCommand, wr as COMMIT_HOOK_NAME, wu as inactiveAgents, xi as stackPromptDigest, xr as CHAINED_HOOK_NAME, zr as createUlidFactory, zs as GITHUB_WORKFLOWS_DIR, zu as ACTION_DECISIONS } 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.",
@@ -8260,6 +8309,7 @@ const en = {
8260
8309
  "next.step.knowledge_base": "Generate the knowledge base",
8261
8310
  "next.step.knowledge_base_review": "Knowledge base waiting for your review",
8262
8311
  "next.step.knowledge_base_decision": "Answer Zoé about the knowledge base",
8312
+ "next.step.paused": "The team is paused: resume it when you are ready",
8263
8313
  "reason.docSource": "a list of { path, blob }: the path of a document read, and the blob id of the version read (40 or 64 lowercase hexadecimal characters)",
8264
8314
  "docs.check.warning.kb_stale": "the knowledge base page {path} was built from another version of {source} (blob {recorded}) than the one validated in {checkpoint} (blob {blob}): Zoé updates it.",
8265
8315
  "docs.check.warning.kb_source_unrecorded": "the knowledge base page {path} relies on {source}, validated in {checkpoint} (blob {blob}), without recording the version read (`sources` in its header): Zoé updates it.",
@@ -8330,6 +8380,7 @@ const en = {
8330
8380
  "error.story_not_startable.not_builder": "{agent} does not build story {story}: its builder is {owner} (its owner, or an agent of the sprint's capacity).",
8331
8381
  "error.story_not_startable.started_by_other": "Story {story} was started by {agent}: a story never has two developers, only {agent} takes it up again.",
8332
8382
  "error.story_not_startable.parallel_limit": "Story {story} waits: {limit} stories are already being built at once ({building}), the ceiling of the profile (max_parallel_stories). Start it once one of them is done. Nothing was created.",
8383
+ "error.story_not_startable.team_paused": "The team is paused: story {story} does not start until the creator resumes it. Nothing was created.",
8333
8384
  "error.story_not_startable.unsupported_repository": "This repository cannot hold a story's working copy ({why}: a bare repository, or one at the root of a disk). Nothing was created.",
8334
8385
  "error.story_not_startable.not_recorded": "Branch {branch} and the working copy {path} were created, but nothing was recorded ({cause}): run the same command again.",
8335
8386
  "error.journal_busy_replanned": "The journal kept changing while {command} was checked ({attempts} attempts): nothing was written. Call it again in a moment.",
@@ -8544,6 +8595,8 @@ const en = {
8544
8595
  "error.delegation_invalid.skill_autonomous": "The skill {to} has no sub-agent of its own: hand it over in the conversation. Nothing was written.",
8545
8596
  "error.delegation_invalid.story_required": "{to} is a developer: it works on a story, one instance per story. Give the story. Nothing was written.",
8546
8597
  "error.delegation_invalid.story_taken": "Story {story} is already built by {agent}: a story never has two developers. Nothing was written.",
8598
+ "error.team_already_paused": "The team is already paused since {since}: there is nothing more to hold. Nothing was written.",
8599
+ "error.delegation_invalid.team_paused": "The team is paused: nothing is handed over to {to} until the creator resumes it. Nothing was written.",
8547
8600
  "error.delegation_invalid.parallel_limit": "The ceiling of {limit} stories in parallel is reached ({building}): story {story} waits until one of them is done. Nothing was written.",
8548
8601
  "checkpoint.type.creator_action": "creator's action",
8549
8602
  "creator_action.kind.ci_waive": "accept a story without its CI",
@@ -9069,9 +9122,29 @@ const en = {
9069
9122
  "error.relay.relay_connection_replaced": "A newer connection of this device replaced this one.",
9070
9123
  "error.relay.relay_prekey_invalid": "The relay refused this receiving key. Nothing was kept.",
9071
9124
  "error.relay.relay_unavailable": "The relay could not do this right now. Nothing was done: try again.",
9125
+ "error.relay.vault_refused": "The relay did not keep the last state of your project. Your machine seals it again.",
9126
+ "error.relay.push_refused": "The relay did not take this notification request. Nothing was sent.",
9072
9127
  "error.relay.rendezvous_unknown": "This pairing link no longer exists. Run the command again to get a new one.",
9073
9128
  "error.relay.rendezvous_refused": "The relay could not open this rendezvous. Try again in a moment.",
9074
9129
  "error.relay.rendezvous_attach_refused": "The relay could not attach this machine to your account. Try again with a new link.",
9130
+ "error.relay.challenge_expired": "This step took too long. Start again.",
9131
+ "error.relay.challenge_reused": "This step was already used. Start again.",
9132
+ "error.relay.origin_mismatch": "This page is not allowed to use your passkey with AgentPlugged. Open the official address.",
9133
+ "error.relay.credential_already_registered": "This passkey already belongs to an account. Sign in with it instead.",
9134
+ "error.relay.email_code_invalid": "That code is not right. Check the e-mail and try again.",
9135
+ "error.relay.email_code_expired": "That code is no longer valid. Ask for a new code.",
9136
+ "error.relay.email_already_registered": "An account already exists with this address. Sign in with your passkey.",
9137
+ "error.relay.account_request_invalid": "The request is not valid. Check what you typed.",
9138
+ "error.relay.account_sign_in_failed": "This passkey was not recognized. Try again, or use another device.",
9139
+ "error.relay.account_session_required": "You are signed out. Sign in again.",
9140
+ "error.relay.account_deleted": "This account was deleted: this device is no longer linked to it.",
9141
+ "error.relay.export_not_ready": "Your export is still being prepared. Try again in a moment.",
9142
+ "error.relay.export_gone": "This export was already downloaded, or its link has expired. Ask for a new one.",
9143
+ "error.relay.passkey_limit": "You already have the most passkeys an account may hold. Remove one before adding another.",
9144
+ "error.relay.passkey_last": "This is your last passkey: without one, nobody could sign in to this account. Add another first.",
9145
+ "error.relay.share_limit": "You already have the most share links active. Withdraw one before making another.",
9146
+ "error.relay.share_too_large": "This page is too large to be shared.",
9147
+ "error.relay.share_unavailable": "This link does not work: it has expired or was withdrawn.",
9075
9148
  "error.relay.upgrade_required": "This device speaks a version of the protocol that the relay no longer accepts: update it.",
9076
9149
  "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
9150
  "points.point.framing": "Framing documents (brief, PRD, UX specification) and the end of their phases",
@@ -9084,10 +9157,15 @@ const en = {
9084
9157
  "points.summary": "Points that wait for you: {list}. The agents decide the others.",
9085
9158
  "points.summary.none": "No point waits for you: the agents decide every point.",
9086
9159
  "history.source.agent": "decided by the agent responsible",
9160
+ "history.source.web": "from the web view",
9161
+ "history.source.mobile": "from the phone",
9087
9162
  "assurance.agent": "an agent's decision (not your answer), with its reason; you can reopen it",
9163
+ "assurance.device": "signed by a device you linked (the web view or your phone)",
9088
9164
  "review.agent_decided": "Decided by the agent {agent} on {at}: {decision}. Reason: {reason}",
9089
9165
  "next.step.point_decision": "A point you do not keep waits for the agent responsible to decide it",
9090
9166
  "next.independent": "The work goes on without you: this step does not depend on any of the points that wait for you.",
9167
+ "next.paused": "The team is paused since {since}. Each agent finishes the step it is on and starts nothing new; resume it from the web view, the phone, or by asking Noah.",
9168
+ "next.paused.stopped": "The team was stopped in an emergency since {since}: the programs the bridge started were cut, and nothing starts until you resume it.",
9091
9169
  "next.stop": "Nothing independent is left: the points that wait for you block what follows, the agents stop here.",
9092
9170
  "next.morning": "Since your last validation: {done} story(ies) done, {decided} point(s) decided by the agents, {waiting} point(s) waiting for you.",
9093
9171
  "docs.check.skipped": "Skipped step (warning): {path}:{line}: {code}: {message}",
@@ -9137,7 +9215,10 @@ const en = {
9137
9215
  "update.done_pinned": "Engine {version} is installed (the product already pinned it). Your open sessions move to it at their next call.",
9138
9216
  "update.failed": "The update did not happen ({reason}). {message} The running engine was not touched.",
9139
9217
  "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.",
9218
+ "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.",
9219
+ "bridge.launcher.installing": "Getting the bridge (the newest version)…",
9220
+ "bridge.launcher.install_failed": "The bridge could not be downloaded ({reason}). Nothing was installed. Try again, or get it at https://agentplugged.ai.",
9221
+ "bridge.launcher.update_failed": "The newest bridge could not be downloaded ({reason}): the installed one is kept.",
9141
9222
  "workflow.title": "Git workflow (branches, CI, merges, review)",
9142
9223
  "workflow.recommended": "(recommended)",
9143
9224
  "workflow.intro": "I propose what suits a solo creator: {line}. Answer yes to keep it all, or no to choose each point.",
@@ -9305,6 +9386,7 @@ const en = {
9305
9386
  "init.sync.done": "Files of your AI tools written ({count} created or updated).",
9306
9387
  "init.sync.skipped": "No sync for now: run `npx agentplugged sync` whenever you want.",
9307
9388
  "init.done.noah": "Ready. Open {tool} in this folder and write: noah ?",
9389
+ "init.link.hint": "To link it to your web app: `npx agentplugged pair`",
9308
9390
  "init.done.noah.several": "Ready. Open one of your tools ({tools}) in this folder and write: noah ?",
9309
9391
  "init.done.sync_first": "Next: run `npx agentplugged sync`, then open {tool} in this folder and write: noah ?",
9310
9392
  "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 +9471,6 @@ const FALLBACK_REASONS = { fr: {
9389
9471
  "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
9472
  "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
9473
  "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
9474
  "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
9475
  "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
9476
  "cursor.rules.hooks-kept": CURSOR_HOOKS_KEPT_FR,
@@ -9398,20 +9479,18 @@ const FALLBACK_REASONS = { fr: {
9398
9479
  "cursor.installs.hooks-kept": CURSOR_HOOKS_KEPT_FR,
9399
9480
  "cursor.decisions": "Cursor range les formulaires qu'un serveur MCP demande (« elicitation ») parmi ce qu'il sait faire, mais des rapports de son propre forum (Windows 11, Cursor 3.10.20, le 2026-07-07, encore vus sur 3.17.8) montrent le formulaire non affiché et l'appel d'outil qui reste en attente, et aucun n'a été vu affiché dans une session de ce produit (Cursor 3.23.12, le 2026-10-07) : 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`) ; dans Cursor il attend 90 secondes un premier signe de vie, et sans rien il pose la question dans le chat pour le reste de la session. Un formulaire déjà répondu une fois est attendu aussi longtemps que dans n'importe quel autre outil.",
9400
9481
  "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é.",
9482
+ "*.budget": "cet outil n'a pas de hook qui voit chaque appel d'outil avant qu'il parte : le moteur ne peut pas arrêter le travail au plafond d'une story au plus proche, ni tenir la pause de l'équipe pendant qu'un agent écrit. Le coût est lu après coup (là où le moteur sait lire les traces de l'outil) et le point de contrôle de budget s'ouvre alors.",
9401
9483
  "*.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
9484
  "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
9485
  "*.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
9486
  ...Object.fromEntries([
9406
9487
  "claude-code",
9407
9488
  "codex",
9408
9489
  "antigravity",
9409
- "gemini-cli",
9410
9490
  "cursor"
9411
9491
  ].map((client) => [`${client}.model`, MODEL_INHERIT_FR])),
9412
9492
  "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
9493
  "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
9494
  "*.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
9495
  "*.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
9496
  ...Object.fromEntries([
@@ -9430,7 +9509,7 @@ const FALLBACK_REASONS = { fr: {
9430
9509
  //#endregion
9431
9510
  //#region ../../packages/i18n/dist/catalogs/fr.js
9432
9511
  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",
9512
+ "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
9513
  "cli.error": "Erreur {code} : {message}",
9435
9514
  "init.summary.title": "Méthode installée dans {root}",
9436
9515
  "init.action.created": "créé",
@@ -9469,6 +9548,10 @@ const fr = {
9469
9548
  "sync.warning.overwritten": "{path} : modification manuelle écrasée.",
9470
9549
  "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
9550
  "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é.",
9551
+ "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`.",
9552
+ "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é.",
9553
+ "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`.",
9554
+ "sync.gemini.nothing": "Rien à nettoyer : aucun fichier écrit par AgentPlugged pour Gemini CLI n'a été trouvé.",
9472
9555
  "tools.title": "Outils IA",
9473
9556
  "tools.line": "{name} {version} — {sources}",
9474
9557
  "tools.line.unknown_version": "{name} (version non reconnue) — {sources}",
@@ -9897,7 +9980,7 @@ const fr = {
9897
9980
  "history.author.root": "{device} (clé racine)",
9898
9981
  "history.author.endorsed": "{device} (approuvée le {date})",
9899
9982
  "history.author.endorsed_undated": "{device} (approuvée)",
9900
- "history.source.terminal": "terminal",
9983
+ "history.source.terminal": "au terminal",
9901
9984
  "history.option": "option {option}",
9902
9985
  "history.waiver_until": "jusqu'au {date}",
9903
9986
  "history.assurance": "assurance {assurance}",
@@ -9964,6 +10047,10 @@ const fr = {
9964
10047
  "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
10048
  "key.import.done": "Clé du produit {key_id} importée dans le trousseau de cette machine.",
9966
10049
  "key.import.already": "Cette machine a déjà la clé du produit {key_id}.",
10050
+ "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.",
10051
+ "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.",
10052
+ "key.import.many": "Clés gardées sur cette machine : {key_ids}.",
10053
+ "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
10054
  "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
10055
  "init.product_key.ready": "Clé du produit : {key_id}.",
9969
10056
  "init.product_key.published": "Son identifiant est annoncé dans le journal de ce produit.",
@@ -10180,6 +10267,7 @@ const fr = {
10180
10267
  "next.step.knowledge_base": "Générer la base de connaissance",
10181
10268
  "next.step.knowledge_base_review": "Base de connaissance en attente de ta relecture",
10182
10269
  "next.step.knowledge_base_decision": "Réponds à Zoé sur la base de connaissance",
10270
+ "next.step.paused": "L'équipe est en pause : reprends-la quand tu es prêt",
10183
10271
  "reason.docSource": "une liste de { path, blob } : le chemin d'un document lu, et l'id du blob de la version lue (40 ou 64 caractères hexadécimaux minuscules)",
10184
10272
  "docs.check.warning.kb_stale": "la page {path} de la base de connaissance s'appuie sur une autre version de {source} (blob {recorded}) que celle que tu as validée dans {checkpoint} (blob {blob}) : Zoé la met à jour.",
10185
10273
  "docs.check.warning.kb_source_unrecorded": "la page {path} de la base de connaissance s'appuie sur {source}, que tu as validé dans {checkpoint} (blob {blob}), sans noter la version lue (`sources` dans son en-tête) : Zoé la met à jour.",
@@ -10250,6 +10338,7 @@ const fr = {
10250
10338
  "error.story_not_startable.not_builder": "{agent} ne développe pas la story {story} : c'est à {owner} (son responsable, ou un agent de la capacité du sprint).",
10251
10339
  "error.story_not_startable.started_by_other": "La story {story} a été démarrée par {agent} : une story n'a jamais deux développeurs, seul {agent} la reprend.",
10252
10340
  "error.story_not_startable.parallel_limit": "La story {story} attend : {limit} stories sont déjà développées en même temps ({building}), le plafond du profil (max_parallel_stories). Démarre-la quand l'une d'elles sera terminée. Rien n'a été créé.",
10341
+ "error.story_not_startable.team_paused": "L'équipe est en pause : la story {story} ne démarre pas tant que le créateur ne l'a pas reprise. Rien n'a été créé.",
10253
10342
  "error.story_not_startable.unsupported_repository": "Ce dépôt ne peut pas accueillir la copie de travail d'une story ({why} : un dépôt nu, ou à la racine d'un disque). Rien n'a été créé.",
10254
10343
  "error.story_not_startable.not_recorded": "La branche {branch} et la copie de travail {path} sont créées, mais rien n'est inscrit ({cause}) : relance la même commande.",
10255
10344
  "error.journal_busy_replanned": "Le journal a changé pendant la vérification de {command} ({attempts} essais) : rien n'a été écrit. Réessaie dans un instant.",
@@ -10464,6 +10553,8 @@ const fr = {
10464
10553
  "error.delegation_invalid.skill_autonomous": "La compétence {to} n'a pas de sous-agent : passe-la dans la conversation. Rien n'a été écrit.",
10465
10554
  "error.delegation_invalid.story_required": "{to} est un développeur : il travaille sur une story, une instance par story. Donne la story. Rien n'a été écrit.",
10466
10555
  "error.delegation_invalid.story_taken": "La story {story} est déjà développée par {agent} : une story n'a jamais deux développeurs. Rien n'a été écrit.",
10556
+ "error.team_already_paused": "L'équipe est déjà en pause depuis {since} : il n'y a rien de plus à tenir. Rien n'a été écrit.",
10557
+ "error.delegation_invalid.team_paused": "L'équipe est en pause : rien n'est confié à {to} tant que le créateur ne l'a pas reprise. Rien n'a été écrit.",
10467
10558
  "error.delegation_invalid.parallel_limit": "Le plafond de {limit} stories en parallèle est atteint ({building}) : la story {story} attend qu'une d'elles soit terminée. Rien n'a été écrit.",
10468
10559
  "checkpoint.type.creator_action": "action réservée",
10469
10560
  "creator_action.kind.ci_waive": "accepter une story sans sa CI",
@@ -10989,9 +11080,29 @@ const fr = {
10989
11080
  "error.relay.relay_connection_replaced": "Une connexion plus récente de cet appareil a pris la place de celle-ci.",
10990
11081
  "error.relay.relay_prekey_invalid": "Le relais a refusé cette clé de réception. Rien n'a été gardé.",
10991
11082
  "error.relay.relay_unavailable": "Le relais n'a pas pu le faire maintenant. Rien n'a été fait : réessaie.",
11083
+ "error.relay.vault_refused": "Le relais n'a pas gardé le dernier état de ton projet. Ta machine le scelle de nouveau.",
11084
+ "error.relay.push_refused": "Le relais n'a pas pris cette demande de notification. Rien n'a été envoyé.",
10992
11085
  "error.relay.rendezvous_unknown": "Ce lien d'appairage n'existe plus. Relance la commande pour en obtenir un nouveau.",
10993
11086
  "error.relay.rendezvous_refused": "Le relais n'a pas pu ouvrir ce point de rencontre. Réessaie dans un moment.",
10994
11087
  "error.relay.rendezvous_attach_refused": "Le relais n'a pas pu rattacher cette machine à ton compte. Réessaie avec un nouveau lien.",
11088
+ "error.relay.challenge_expired": "Cette étape a pris trop de temps. Recommence.",
11089
+ "error.relay.challenge_reused": "Cette étape a déjà servi. Recommence.",
11090
+ "error.relay.origin_mismatch": "Cette page n'a pas le droit d'utiliser ta clé d'accès avec AgentPlugged. Ouvre l'adresse officielle.",
11091
+ "error.relay.credential_already_registered": "Cette clé d'accès appartient déjà à un compte. Connecte-toi avec elle.",
11092
+ "error.relay.email_code_invalid": "Ce code n'est pas le bon. Vérifie le courriel et réessaie.",
11093
+ "error.relay.email_code_expired": "Ce code n'est plus valable. Demande un nouveau code.",
11094
+ "error.relay.email_already_registered": "Un compte existe déjà avec cette adresse. Connecte-toi avec ta clé d'accès.",
11095
+ "error.relay.account_request_invalid": "La demande n'est pas valide. Vérifie ce que tu as saisi.",
11096
+ "error.relay.account_sign_in_failed": "Cette clé d'accès n'a pas été reconnue. Réessaie, ou utilise un autre appareil.",
11097
+ "error.relay.account_session_required": "Tu es déconnecté. Connecte-toi de nouveau.",
11098
+ "error.relay.account_deleted": "Ce compte a été supprimé : cet appareil n'y est plus relié.",
11099
+ "error.relay.export_not_ready": "Ton export est encore en préparation. Réessaie dans un instant.",
11100
+ "error.relay.export_gone": "Cet export a déjà été téléchargé, ou son lien a expiré. Demande-en un nouveau.",
11101
+ "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.",
11102
+ "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.",
11103
+ "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.",
11104
+ "error.relay.share_too_large": "Cette page est trop volumineuse pour être partagée.",
11105
+ "error.relay.share_unavailable": "Ce lien ne fonctionne pas : il a expiré ou a été retiré.",
10995
11106
  "error.relay.upgrade_required": "Cet appareil parle une version du protocole que le relais n'accepte plus : mets-le à jour.",
10996
11107
  "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
11108
  "points.point.framing": "Documents de cadrage (brief, PRD, spécification UX) et la fin de leurs phases",
@@ -11004,10 +11115,15 @@ const fr = {
11004
11115
  "points.summary": "Points qui t'attendent : {list}. Les agents décident les autres.",
11005
11116
  "points.summary.none": "Aucun point ne t'attend : les agents décident tous les points.",
11006
11117
  "history.source.agent": "décidé par l'agent responsable",
11118
+ "history.source.web": "depuis la vue web",
11119
+ "history.source.mobile": "depuis le téléphone",
11007
11120
  "assurance.agent": "décision d'un agent (pas ta réponse), avec sa raison ; tu peux la rouvrir",
11121
+ "assurance.device": "signé par un appareil que tu as relié (la vue web ou ton téléphone)",
11008
11122
  "review.agent_decided": "Décidé par l'agent {agent} le {at} : {decision}. Raison : {reason}",
11009
11123
  "next.step.point_decision": "Un point que tu ne gardes pas attend la décision de l'agent responsable",
11010
11124
  "next.independent": "Le travail continue sans toi : cette étape ne dépend d'aucun des points qui t'attendent.",
11125
+ "next.paused": "L'équipe est en pause depuis {since}. Chaque agent finit l'étape en cours et ne démarre rien de nouveau ; reprends-la depuis la vue web, le téléphone, ou en le demandant à Noah.",
11126
+ "next.paused.stopped": "L'équipe a été arrêtée en urgence depuis {since} : les programmes lancés par le pont ont été coupés, et rien ne démarre tant que tu ne l'as pas reprise.",
11011
11127
  "next.stop": "Rien d'indépendant ne reste : les points qui t'attendent bloquent la suite, les agents s'arrêtent là.",
11012
11128
  "next.morning": "Depuis ta dernière validation : {done} story(ies) terminée(s), {decided} point(s) décidé(s) par les agents, {waiting} point(s) qui t'attendent.",
11013
11129
  "docs.check.skipped": "Étape sautée (avertissement) : {path}:{line} : {code} : {message}",
@@ -11057,7 +11173,10 @@ const fr = {
11057
11173
  "update.done_pinned": "Le moteur {version} est installé (le produit l'épinglait déjà). Tes sessions ouvertes passent dessus à leur prochain appel.",
11058
11174
  "update.failed": "La mise à jour n'a pas eu lieu ({reason}). {message} Le moteur qui tourne n'a pas été touché.",
11059
11175
  "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.",
11176
+ "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.",
11177
+ "bridge.launcher.installing": "Récupération du pont (la version la plus récente)…",
11178
+ "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.",
11179
+ "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
11180
  "workflow.title": "Workflow Git (branches, CI, fusions, revue)",
11062
11181
  "workflow.recommended": "(recommandé)",
11063
11182
  "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 +11344,7 @@ const fr = {
11225
11344
  "init.sync.done": "Fichiers de tes outils IA écrits ({count} créés ou mis à jour).",
11226
11345
  "init.sync.skipped": "Pas de sync pour l'instant : lance `npx agentplugged sync` quand tu veux.",
11227
11346
  "init.done.noah": "C'est prêt. Ouvre {tool} dans ce dossier et écris : noah ?",
11347
+ "init.link.hint": "Pour le relier à ton application web : `npx agentplugged pair`",
11228
11348
  "init.done.noah.several": "C'est prêt. Ouvre l'un de tes outils ({tools}) dans ce dossier et écris : noah ?",
11229
11349
  "init.done.sync_first": "Ensuite : lance `npx agentplugged sync`, puis ouvre {tool} dans ce dossier et écris : noah ?",
11230
11350
  "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 +12039,16 @@ function questionToolOf(options) {
11919
12039
  * in the reference, section « Tool: <name> », and in the skills.
11920
12040
  */
11921
12041
  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"
12042
+ state: "Read-only. Actions: get (ONE option), next, trace, merge_order, environment. Ref: tool-state",
12043
+ 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",
12044
+ chat: "Ask the creator. Actions: ask, answer (only the creator's 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",
12045
+ 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",
12046
+ review: "Actions: start, submit, triage, get, publish, audit, critique, tests, qa, ready, export. Never review a story you built. Ref: tool-review",
12047
+ agent: "Actions: status, delegate (Noah only), summarize, pause, workshop. agent = your own id. Ref: tool-agent",
12048
+ guard: "Creator-only actions, sensitive data. Actions: request, check (refused means never), external_read, call, creator_action (only with their yes), read_sensitive, write_sensitive (never read salle/ or memory/ files directly). what = action. Ref: tool-guard",
12049
+ plan: "Actions: sprint (creator approves), defer, complete_deferred, course (change of mind). Never start a story an open deferred item locks. Ref: tool-plan",
12050
+ memory: "Lessons. Actions: read (before first answer), retrospective, record, promote_propose, promote. Never record or promote a lesson before the creator approved it. Ref: tool-memory",
12051
+ measure: "Actions: cost (never invent an amount), usage, requirements, proof (real results only), run (a command the creator accepted). Ref: tool-measure"
11932
12052
  };
11933
12053
  /** One field of a published schema: a type, and the values of a short enumeration. */
11934
12054
  function slim(field) {
@@ -13031,6 +13151,105 @@ async function findBridge(env, platform = process.platform) {
13031
13151
  return;
13032
13152
  }
13033
13153
  }
13154
+ /**
13155
+ * npm's own JavaScript program on Windows, where `npm` is a batch file that only runs through a
13156
+ * shell: the one next to Node, else the one that started this process. `undefined` when neither is
13157
+ * found.
13158
+ */
13159
+ function npmProgram(env) {
13160
+ return [join(dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js"), env.npm_execpath ?? ""].find((path) => path.endsWith("npm-cli.js") && existsSync(path));
13161
+ }
13162
+ /** Runs npm; no argument ever passes through a shell. */
13163
+ function realNpm(args, platform, env) {
13164
+ return new Promise((resolve) => {
13165
+ let output = "";
13166
+ const program = platform === "win32" ? npmProgram(env) : void 0;
13167
+ if (platform === "win32" && program === void 0) {
13168
+ resolve({
13169
+ code: -1,
13170
+ output: "npm was not found next to Node"
13171
+ });
13172
+ return;
13173
+ }
13174
+ const options = {
13175
+ env: {
13176
+ ...process.env,
13177
+ ...env
13178
+ },
13179
+ stdio: [
13180
+ "ignore",
13181
+ "pipe",
13182
+ "pipe"
13183
+ ],
13184
+ windowsHide: true
13185
+ };
13186
+ const child = program === void 0 ? spawn("npm", [...args], options) : spawn(process.execPath, [program, ...args], options);
13187
+ child.stdout.on("data", (chunk) => {
13188
+ output += chunk.toString("utf8");
13189
+ });
13190
+ child.stderr.on("data", (chunk) => {
13191
+ output += chunk.toString("utf8");
13192
+ });
13193
+ child.on("error", (error) => resolve({
13194
+ code: -1,
13195
+ output: error.message
13196
+ }));
13197
+ child.on("close", (code) => resolve({
13198
+ code: code ?? -1,
13199
+ output
13200
+ }));
13201
+ });
13202
+ }
13203
+ /**
13204
+ * `agentplugged bridge install`: gets the bridge, or its newest version, before the bridge itself
13205
+ * makes itself a service. The bridge is its own npm package, put in a folder of its own; the
13206
+ * pointer file then tells this launcher where it is. A bridge kept elsewhere
13207
+ * (`AGENTPLUGGED_BRIDGE_ENTRY`) is never touched. When the newest version cannot be fetched and a
13208
+ * bridge is already there, that one is used and the failure is said. Returns false when there is
13209
+ * no bridge at all at the end.
13210
+ */
13211
+ async function installBridgePackage(environment, t) {
13212
+ const { env } = environment;
13213
+ const platform = environment.platform ?? process.platform;
13214
+ if (env.AGENTPLUGGED_BRIDGE_ENTRY?.trim()) return await findBridge(env, platform) !== void 0;
13215
+ const dir = bridgeInstallDir(env, platform);
13216
+ const known = await findBridge(env, platform);
13217
+ const source = env.AGENTPLUGGED_BRIDGE_PACKAGE?.trim() || `agentplugged-bridge@latest`;
13218
+ if (dir === void 0 || !/^[^\s"'&|<>^%;$`-][^\s"'&|<>^%;$`]*$/.test(source)) {
13219
+ environment.stderr(`${t("bridge.launcher.install_failed", { reason: "folder" })}\n`);
13220
+ return known !== void 0;
13221
+ }
13222
+ const folder = join(dir, "package");
13223
+ environment.stdout(`${t("bridge.launcher.installing")}\n`);
13224
+ try {
13225
+ await mkdir(folder, { recursive: true });
13226
+ const manifest = join(folder, "package.json");
13227
+ if (!await isFile(manifest)) await writeFile(manifest, "{ \"private\": true }\n");
13228
+ const args = [
13229
+ "install",
13230
+ "--prefix",
13231
+ folder,
13232
+ "--omit=dev",
13233
+ "--no-audit",
13234
+ "--no-fund",
13235
+ "--loglevel=error",
13236
+ source
13237
+ ];
13238
+ const done = await (environment.runNpm ?? ((a) => realNpm(a, platform, env)))(args);
13239
+ if (done.code !== 0) throw new Error(done.output.trim().split("\n")[0] ?? "npm");
13240
+ const dependencies = JSON.parse(await readFile(manifest, "utf8")).dependencies;
13241
+ const name = Object.keys(dependencies ?? {})[0];
13242
+ if (name === void 0) throw new Error("no package");
13243
+ const entry = join(folder, "node_modules", name, "dist", "bin.js");
13244
+ if (!await isFile(entry)) throw new Error("no program");
13245
+ await writeFile(join(dir, BRIDGE_POINTER_FILE), `${JSON.stringify({ entry })}\n`);
13246
+ return true;
13247
+ } catch (error) {
13248
+ const reason = error instanceof Error ? error.message.slice(0, 200) : "unknown";
13249
+ environment.stderr(`${t(known === void 0 ? "bridge.launcher.install_failed" : "bridge.launcher.update_failed", { reason })}\n`);
13250
+ return known !== void 0;
13251
+ }
13252
+ }
13034
13253
  /** Runs the bridge's program with `args`; resolves with its exit code (1 when a signal ended it). */
13035
13254
  function runProgram(entry, args, environment, failed) {
13036
13255
  return new Promise((resolve) => {
@@ -13079,12 +13298,15 @@ function runProgram(entry, args, environment, failed) {
13079
13298
  * nothing is left half done: the pairing is entirely the bridge's.
13080
13299
  */
13081
13300
  async function runBridgeLauncher(environment, t) {
13301
+ if (environment.argv[0] === "bridge" && environment.argv[1] === "install") {
13302
+ if (!await installBridgePackage(environment, t)) return 1;
13303
+ }
13082
13304
  const entry = await findBridge(environment.env, environment.platform);
13083
13305
  if (entry === void 0) {
13084
13306
  environment.stderr(`${t("bridge.launcher.not_installed")}\n`);
13085
13307
  return 1;
13086
13308
  }
13087
- return runProgram(entry, environment.argv[0] === "pair" ? environment.argv : environment.argv.slice(1), environment, t("bridge.launcher.not_installed"));
13309
+ return runProgram(entry, environment.argv[0] === "pair" || environment.argv[0] === "device" ? environment.argv : environment.argv.slice(1), environment, t("bridge.launcher.not_installed"));
13088
13310
  }
13089
13311
  //#endregion
13090
13312
  //#region src/story-text.ts
@@ -14373,7 +14595,8 @@ const NO_KEYCHAIN = {
14373
14595
  writePresenceCredential: noKeychain,
14374
14596
  readProductSecret: noKeychain,
14375
14597
  writeProductSecret: noKeychain,
14376
- writeProductBackup: noKeychain
14598
+ writeProductBackup: noKeychain,
14599
+ readProductBackup: noKeychain
14377
14600
  };
14378
14601
  //#endregion
14379
14602
  //#region src/init-flow.ts
@@ -14528,11 +14751,18 @@ function formatProductKey(t, result, file) {
14528
14751
  const lines = [t("key.export.done", { key_id: result.key_id })];
14529
14752
  if (file === void 0) lines.push("", result.exported, "");
14530
14753
  else lines.push(t("key.export.file", { path: file }));
14754
+ if (result.key_ids !== void 0) lines.push(t("key.export.many", { count: String(result.key_ids.length) }));
14755
+ if (result.missing !== void 0) lines.push(t("key.export.missing", {
14756
+ count: String(result.missing.length),
14757
+ key_ids: result.missing.join(", ")
14758
+ }));
14531
14759
  lines.push(t("key.export.hint"), "");
14532
14760
  return lines.join("\n");
14533
14761
  }
14762
+ if (result.status === "older") return `${t("key.import.older", { key_id: result.key_id })}\n`;
14534
14763
  const lines = [t(result.status === "already" ? "key.import.already" : "key.import.done", { key_id: result.key_id })];
14535
14764
  if (result.replaced !== void 0) lines.push(t("key.import.replaced", { held_key_id: result.replaced }));
14765
+ if (result.key_ids !== void 0) lines.push(t("key.import.many", { key_ids: result.key_ids.join(", ") }));
14536
14766
  return `${lines.join("\n")}\n`;
14537
14767
  }
14538
14768
  function formatSeal(t, result) {
@@ -14576,6 +14806,48 @@ function formatInitProductKey(t, productKey) {
14576
14806
  }
14577
14807
  }
14578
14808
  //#endregion
14809
+ //#region src/link-hint.ts
14810
+ /**
14811
+ * The one line that ends `init` when this product is not linked to the web app yet: the command
14812
+ * that does it, nothing asked, nothing done. The method works alone either way. Whether the product
14813
+ * is already served is read from the bridge's own registry on this machine (a file the bridge
14814
+ * writes; this program never writes it), the way `bridge` finds its program: the command line only
14815
+ * launches the bridge and holds none of its logic.
14816
+ */
14817
+ /** Where the bridge keeps its files on each system (the same folders the bridge uses). */
14818
+ function bridgeDataDir(env, platform) {
14819
+ const given = env.AGENTPLUGGED_BRIDGE_HOME?.trim();
14820
+ if (given) return resolve(given);
14821
+ const home = env.USERPROFILE?.trim() || env.HOME?.trim() || homedir();
14822
+ const usable = (value) => {
14823
+ const trimmed = value?.trim();
14824
+ return trimmed && isAbsolute(trimmed) ? trimmed : void 0;
14825
+ };
14826
+ if (platform === "win32") return join(usable(env.LOCALAPPDATA) ?? join(home, "AppData", "Local"), "AgentPlugged", "bridge");
14827
+ if (platform === "darwin") return join(home, "Library", "Application Support", "AgentPlugged", "bridge");
14828
+ return join(usable(env.XDG_STATE_HOME) ?? join(home, ".local", "state"), "agentplugged", "bridge");
14829
+ }
14830
+ async function readJson(path) {
14831
+ try {
14832
+ return JSON.parse(await readFile(path, "utf8"));
14833
+ } catch {
14834
+ return;
14835
+ }
14836
+ }
14837
+ /** True when this machine is linked to an account and serves the product in `root`. */
14838
+ async function isLinkedToWebApp(root, env, platform) {
14839
+ const dir = bridgeDataDir(env, platform);
14840
+ if (await readJson(join(dir, "binding.json")) === void 0) return false;
14841
+ const registry = await readJson(join(dir, "products.json"));
14842
+ const same = (a, b) => platform === "win32" ? resolve(a).toLowerCase() === resolve(b).toLowerCase() : resolve(a) === resolve(b);
14843
+ return (registry?.products ?? []).some((entry) => typeof entry.path === "string" && same(entry.path, root));
14844
+ }
14845
+ /** The line, or nothing when the product is linked already. */
14846
+ async function linkHint(t, root, env, platform) {
14847
+ if (await isLinkedToWebApp(root, env, platform)) return void 0;
14848
+ return `\n${t("init.link.hint")}\n`;
14849
+ }
14850
+ //#endregion
14579
14851
  //#region src/migrate-text.ts
14580
14852
  /** One change of a step the creator should know, on one line. */
14581
14853
  function noteLine(t, note) {
@@ -15089,7 +15361,8 @@ function formatNext(t, result) {
15089
15361
  if (review.untriaged > 0) lines.push(t("next.review.untriaged", { count: review.untriaged }));
15090
15362
  }
15091
15363
  if (result.independent === true) lines.push(t("next.independent"));
15092
- if (result.stop === true) lines.push(t("next.stop"));
15364
+ if (result.paused !== void 0) lines.push(t(result.paused.reason === "emergency_stop" ? "next.paused.stopped" : "next.paused", { since: displayText(result.paused.since) }));
15365
+ else if (result.stop === true) lines.push(t("next.stop"));
15093
15366
  const morning = result.morning;
15094
15367
  if (morning !== void 0 && morning.done_total + morning.decided_total > 0) lines.push(t("next.morning", {
15095
15368
  done: morning.done_total,
@@ -15184,6 +15457,7 @@ function nextJson(result) {
15184
15457
  ...result.point === void 0 ? {} : { point: { ...result.point } },
15185
15458
  ...result.independent === true ? { independent: true } : {},
15186
15459
  ...result.stop === true ? { stop: true } : {},
15460
+ ...result.paused === void 0 ? {} : { paused: { ...result.paused } },
15187
15461
  ...result.pile === void 0 ? {} : { pile: {
15188
15462
  stack: [...result.pile.stack],
15189
15463
  apart: [...result.pile.apart],
@@ -16553,7 +16827,7 @@ async function runMcp(environment, t, files, engineAny) {
16553
16827
  },
16554
16828
  folders: new NodeFolderReader(),
16555
16829
  commonMemory: new NodeCommonMemory(),
16556
- usageTraces: new NodeUsageTraces({ root: environment.cwd }),
16830
+ usageTraces: new NodeUsageTraces({ root: productRootOf(environment.cwd) }),
16557
16831
  ciReader: ciReaderOf(environment),
16558
16832
  testReferences: new GitTestReferences({ cwd: environment.cwd }),
16559
16833
  proofRunner: new NodeProofRunner({ root: environment.cwd }),
@@ -16639,7 +16913,7 @@ async function runHook(environment, t, rest) {
16639
16913
  decision: "deny",
16640
16914
  reason: ANTIGRAVITY_UNCHECKED_REASON
16641
16915
  });
16642
- const root = productRootOf(environment.cwd);
16916
+ const root = productRootOf$1(environment.cwd);
16643
16917
  const home = environment.env.USERPROFILE?.trim() || environment.env.HOME?.trim() || homedir();
16644
16918
  const keys = keyStoreOf(environment.env);
16645
16919
  const journal = new GitStateStore({
@@ -16718,7 +16992,9 @@ const SYNC_WARNING_KEYS = {
16718
16992
  kept: "sync.warning.kept",
16719
16993
  description_too_long: "sync.warning.description_too_long",
16720
16994
  unknown_setting: "sync.warning.unknown_setting",
16721
- local_engine: "sync.warning.local_engine"
16995
+ local_engine: "sync.warning.local_engine",
16996
+ gemini_legacy: "sync.warning.gemini_legacy",
16997
+ gemini_unproven: "sync.warning.gemini_unproven"
16722
16998
  };
16723
16999
  /** Stands for the shipped method in commands that never read it. */
16724
17000
  const METHOD_UNAVAILABLE = {
@@ -16743,6 +17019,23 @@ function shippedMethodOrUnavailable() {
16743
17019
  return METHOD_UNAVAILABLE;
16744
17020
  }
16745
17021
  }
17022
+ /**
17023
+ * The environment the bridge is launched with: it also learns where this engine's program is, so
17024
+ * that it can run the same engine to make a product the creator asks for from a device. A value the
17025
+ * creator gave is kept; nothing is added when the program cannot be found (a test, a bundle).
17026
+ */
17027
+ function withEngineEntry(env) {
17028
+ if (env.AGENTPLUGGED_ENGINE_ENTRY?.trim()) return env;
17029
+ try {
17030
+ const entry = fileURLToPath(new URL("./bin.js", import.meta.url));
17031
+ return existsSync(entry) ? {
17032
+ ...env,
17033
+ AGENTPLUGGED_ENGINE_ENTRY: entry
17034
+ } : env;
17035
+ } catch {
17036
+ return env;
17037
+ }
17038
+ }
16746
17039
  /** Options that only change how the engine version is checked: left out of the quoted command. */
16747
17040
  const ENGINE_FLAGS = /* @__PURE__ */ new Set(["--engine-any", "--upgrade-engine"]);
16748
17041
  /**
@@ -16781,7 +17074,7 @@ const SYNC_GROUPS = [
16781
17074
  ];
16782
17075
  function groupTitle(t, group) {
16783
17076
  if (group === "shared") return t("sync.group.shared");
16784
- if (group === "antigravity") return "Antigravity CLI + Gemini CLI";
17077
+ if (group === "antigravity") return "Antigravity CLI";
16785
17078
  return TOOL_CATALOG.find((spec) => spec.id === group)?.name ?? group;
16786
17079
  }
16787
17080
  /**
@@ -16834,6 +17127,10 @@ function formatSync(t, root, result, locale = "en") {
16834
17127
  const fallbacks = result.fallbacks.map((fallback) => ` ${formatFallback(t, locale, fallback)}`);
16835
17128
  text += `\n${t("sync.fallbacks.title")}\n${fallbacks.join("\n")}\n`;
16836
17129
  }
17130
+ if (result.geminiCleanup !== void 0) {
17131
+ if (result.geminiCleanup.listed > 0) text += `\n${t("sync.gemini.confirm")}\n`;
17132
+ else if (result.entries.length === 0) text += `\n${t("sync.gemini.nothing")}\n`;
17133
+ }
16837
17134
  text += formatSyncRules(t, result.rules);
16838
17135
  if (result.codexTrustReminder) text += `\n${t("sync.codex_trust")}\n`;
16839
17136
  if (result.cursorHooksReminder) text += `\n${t("sync.cursor_hooks")}\n`;
@@ -17247,10 +17544,10 @@ async function main(rawEnvironment) {
17247
17544
  let environment = rawEnvironment;
17248
17545
  const locale = localeOf(environment.env, environment.systemLocale);
17249
17546
  const t = createTranslator(locale);
17250
- if (environment.argv[0] === "bridge" || environment.argv[0] === "pair") return await runBridgeLauncher({
17547
+ if (environment.argv[0] === "bridge" || environment.argv[0] === "pair" || environment.argv[0] === "device") return await runBridgeLauncher({
17251
17548
  argv: environment.argv,
17252
17549
  cwd: environment.cwd,
17253
- env: environment.env,
17550
+ env: withEngineEntry(environment.env),
17254
17551
  ...environment.platform === void 0 ? {} : { platform: environment.platform },
17255
17552
  stdout: environment.stdout,
17256
17553
  stderr: environment.stderr
@@ -17260,7 +17557,7 @@ async function main(rawEnvironment) {
17260
17557
  environment.stderr(formatError(t, reviewNotInteractive("update")));
17261
17558
  return 1;
17262
17559
  }
17263
- const root = productRootOf(environment.cwd);
17560
+ const root = productRootOf$1(environment.cwd);
17264
17561
  return await runUpdate({
17265
17562
  args: environment.argv.slice(1),
17266
17563
  cwd: root,
@@ -17285,7 +17582,7 @@ async function main(rawEnvironment) {
17285
17582
  }
17286
17583
  return await runEval({
17287
17584
  args: environment.argv.slice(1),
17288
- root: productRootOf(environment.cwd),
17585
+ root: productRootOf$1(environment.cwd),
17289
17586
  env: environment.env,
17290
17587
  ...methodDir === void 0 ? {} : { methodDir },
17291
17588
  stdout: environment.stdout,
@@ -17325,6 +17622,7 @@ async function main(rawEnvironment) {
17325
17622
  let rawOption = false;
17326
17623
  let unverifiedOption = false;
17327
17624
  let yesOption = false;
17625
+ let cleanGeminiOption = false;
17328
17626
  let toolsOption;
17329
17627
  let permissionsOption;
17330
17628
  let noSyncOption = false;
@@ -17395,6 +17693,7 @@ async function main(rawEnvironment) {
17395
17693
  type: "boolean",
17396
17694
  short: "y"
17397
17695
  },
17696
+ "clean-gemini": { type: "boolean" },
17398
17697
  tools: { type: "string" },
17399
17698
  permissions: { type: "string" },
17400
17699
  "no-sync": { type: "boolean" },
@@ -17455,6 +17754,7 @@ async function main(rawEnvironment) {
17455
17754
  rawOption = parsed.values.raw === true;
17456
17755
  unverifiedOption = parsed.values.unverified === true;
17457
17756
  yesOption = parsed.values.yes === true;
17757
+ cleanGeminiOption = parsed.values["clean-gemini"] === true;
17458
17758
  toolsOption = parsed.values.tools;
17459
17759
  permissionsOption = parsed.values.permissions;
17460
17760
  noSyncOption = parsed.values["no-sync"] === true;
@@ -17548,7 +17848,7 @@ async function main(rawEnvironment) {
17548
17848
  return 1;
17549
17849
  }
17550
17850
  try {
17551
- const root = productRootOf(environment.cwd);
17851
+ const root = productRootOf$1(environment.cwd);
17552
17852
  return await runMcp({
17553
17853
  ...environment,
17554
17854
  cwd: root
@@ -17586,7 +17886,7 @@ async function main(rawEnvironment) {
17586
17886
  return failCode;
17587
17887
  }
17588
17888
  const initOnly = [
17589
- ...yesOption ? ["--yes"] : [],
17889
+ ...yesOption && !(command === "sync" && cleanGeminiOption) ? ["--yes"] : [],
17590
17890
  ...toolsOption === void 0 ? [] : ["--tools"],
17591
17891
  ...noSyncOption ? ["--no-sync"] : []
17592
17892
  ];
@@ -17594,6 +17894,10 @@ async function main(rawEnvironment) {
17594
17894
  reportError(invalidArguments(`${command}: ${initOnly.join(" ")}`));
17595
17895
  return failCode;
17596
17896
  }
17897
+ if (cleanGeminiOption && command !== "sync" && registry.names().includes(command)) {
17898
+ reportError(invalidArguments(`${command}: --clean-gemini`));
17899
+ return failCode;
17900
+ }
17597
17901
  if (channelOption !== void 0 && command !== "init" && registry.names().includes(command)) {
17598
17902
  reportError(invalidArguments(`${command}: --channel`));
17599
17903
  return failCode;
@@ -17827,6 +18131,11 @@ async function main(rawEnvironment) {
17827
18131
  return failCode;
17828
18132
  }
17829
18133
  input = prepared;
18134
+ } else if (command === "sync") {
18135
+ if (cleanGeminiOption) input = {
18136
+ clean_gemini: true,
18137
+ ...yesOption ? { yes: true } : {}
18138
+ };
17830
18139
  } else if (command === "journal") {
17831
18140
  const [action, ...extra] = rest;
17832
18141
  if (action !== "sync" && action !== "status" || extra.length > 0) {
@@ -18107,6 +18416,8 @@ async function main(rawEnvironment) {
18107
18416
  } else environment.stdout(`\n${t("init.sync.skipped")}\n`);
18108
18417
  environment.stdout(`\n${formatNextStep(t, result.value.targetedTools, synced)}`);
18109
18418
  }
18419
+ const hint = await linkHint(t, files.root, environment.env, environment.platform ?? process.platform);
18420
+ if (hint !== void 0) environment.stdout(hint);
18110
18421
  if (scripted && machineReport?.blocking === true) {
18111
18422
  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
18423
  exitCode = 1;