agents-inc 0.171.0 → 0.173.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.
Files changed (93) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/{chunk-W4KAY26P.js → chunk-2RTBSLSR.js} +12 -3
  3. package/dist/{chunk-W4KAY26P.js.map → chunk-2RTBSLSR.js.map} +1 -1
  4. package/dist/{chunk-WM2N2D6Q.js → chunk-3N4FSTVX.js} +12 -6
  5. package/dist/{chunk-WM2N2D6Q.js.map → chunk-3N4FSTVX.js.map} +1 -1
  6. package/dist/{chunk-ZC6GC66J.js → chunk-3R3LHA4Q.js} +2 -2
  7. package/dist/{chunk-24OD7IP4.js → chunk-7OG635DK.js} +26 -4
  8. package/dist/chunk-7OG635DK.js.map +1 -0
  9. package/dist/{chunk-WDH6HHA3.js → chunk-A3ZAXL5T.js} +4 -5
  10. package/dist/{chunk-WDH6HHA3.js.map → chunk-A3ZAXL5T.js.map} +1 -1
  11. package/dist/{chunk-KMOCMVK5.js → chunk-AARQBW5L.js} +106 -60
  12. package/dist/chunk-AARQBW5L.js.map +1 -0
  13. package/dist/{chunk-WII6GOPM.js → chunk-BRZA7ZCX.js} +52 -31
  14. package/dist/chunk-BRZA7ZCX.js.map +1 -0
  15. package/dist/{chunk-AWWCRL5A.js → chunk-EHJIQDXR.js} +8 -6
  16. package/dist/{chunk-AWWCRL5A.js.map → chunk-EHJIQDXR.js.map} +1 -1
  17. package/dist/{chunk-RDXY4GRO.js → chunk-F437ICEG.js} +2 -2
  18. package/dist/chunk-G7NUK3BF.js +253 -0
  19. package/dist/chunk-G7NUK3BF.js.map +1 -0
  20. package/dist/{chunk-7IVLVEHX.js → chunk-ITQF35UQ.js} +3 -3
  21. package/dist/{chunk-QIR56IDM.js → chunk-LJQXQTFC.js} +29 -102
  22. package/dist/chunk-LJQXQTFC.js.map +1 -0
  23. package/dist/{chunk-A6OWEJGC.js → chunk-MHAQWMNJ.js} +35 -5
  24. package/dist/{chunk-A6OWEJGC.js.map → chunk-MHAQWMNJ.js.map} +1 -1
  25. package/dist/{chunk-YLUOGAW7.js → chunk-N33AKFLR.js} +2 -2
  26. package/dist/{chunk-TNFYBKVD.js → chunk-Q4UNHVPX.js} +25 -14
  27. package/dist/chunk-Q4UNHVPX.js.map +1 -0
  28. package/dist/chunk-Q6WRR4BN.js +195 -0
  29. package/dist/chunk-Q6WRR4BN.js.map +1 -0
  30. package/dist/{chunk-JGPE4RRE.js → chunk-SPQSNZMM.js} +2 -2
  31. package/dist/{chunk-EOKNEGRD.js → chunk-VR6QTK5Z.js} +8 -8
  32. package/dist/{chunk-S2SKVJT2.js → chunk-VSPC74SS.js} +48 -26
  33. package/dist/chunk-VSPC74SS.js.map +1 -0
  34. package/dist/{chunk-3YYHL76L.js → chunk-WVFBBZEP.js} +648 -394
  35. package/dist/chunk-WVFBBZEP.js.map +1 -0
  36. package/dist/commands/build/marketplace.js +16 -14
  37. package/dist/commands/build/marketplace.js.map +1 -1
  38. package/dist/commands/build/plugins.js +6 -6
  39. package/dist/commands/compile.js +12 -12
  40. package/dist/commands/doctor.js +87 -86
  41. package/dist/commands/doctor.js.map +1 -1
  42. package/dist/commands/edit.js +150 -152
  43. package/dist/commands/edit.js.map +1 -1
  44. package/dist/commands/eject.js +25 -30
  45. package/dist/commands/eject.js.map +1 -1
  46. package/dist/commands/init.js +19 -16
  47. package/dist/commands/list.js +14 -17
  48. package/dist/commands/list.js.map +1 -1
  49. package/dist/commands/new/marketplace.js +4 -4
  50. package/dist/commands/search.js +15 -13
  51. package/dist/commands/search.js.map +1 -1
  52. package/dist/commands/share.js +11 -11
  53. package/dist/commands/uninstall.js +145 -130
  54. package/dist/commands/uninstall.js.map +1 -1
  55. package/dist/commands/update.js +6 -6
  56. package/dist/components/common/scroll-affordance.js +2 -2
  57. package/dist/components/common/select-list.js +2 -2
  58. package/dist/components/common/skill-agent-summary.js +3 -4
  59. package/dist/components/common/summary-panel.js +11 -146
  60. package/dist/components/common/summary-panel.js.map +1 -1
  61. package/dist/hooks/init.js +39 -27
  62. package/dist/hooks/init.js.map +1 -1
  63. package/dist/load-agent-defs-E67DSYTN.js +14 -0
  64. package/dist/{recompile-project-agents-IQANWGOP.js → recompile-project-agents-6G6M2RS6.js} +8 -8
  65. package/dist/{source-loader-YGG7DY2W.js → source-loader-W7XCNKNA.js} +4 -4
  66. package/dist/src/agents/tester/web-tester/playbook.md +1 -1
  67. package/package.json +1 -1
  68. package/src/agents/tester/web-tester/playbook.md +1 -1
  69. package/dist/chunk-24OD7IP4.js.map +0 -1
  70. package/dist/chunk-3YYHL76L.js.map +0 -1
  71. package/dist/chunk-4RQKCV6I.js +0 -103
  72. package/dist/chunk-4RQKCV6I.js.map +0 -1
  73. package/dist/chunk-5FM77WKW.js +0 -69
  74. package/dist/chunk-5FM77WKW.js.map +0 -1
  75. package/dist/chunk-KMOCMVK5.js.map +0 -1
  76. package/dist/chunk-QIR56IDM.js.map +0 -1
  77. package/dist/chunk-R572RLTI.js +0 -108
  78. package/dist/chunk-R572RLTI.js.map +0 -1
  79. package/dist/chunk-S2SKVJT2.js.map +0 -1
  80. package/dist/chunk-TNFYBKVD.js.map +0 -1
  81. package/dist/chunk-WII6GOPM.js.map +0 -1
  82. package/dist/components/common/removal-plan-confirm.js +0 -10
  83. package/dist/load-agent-defs-UBWITIEI.js +0 -14
  84. package/dist/source-loader-YGG7DY2W.js.map +0 -1
  85. /package/dist/{chunk-ZC6GC66J.js.map → chunk-3R3LHA4Q.js.map} +0 -0
  86. /package/dist/{chunk-RDXY4GRO.js.map → chunk-F437ICEG.js.map} +0 -0
  87. /package/dist/{chunk-7IVLVEHX.js.map → chunk-ITQF35UQ.js.map} +0 -0
  88. /package/dist/{chunk-YLUOGAW7.js.map → chunk-N33AKFLR.js.map} +0 -0
  89. /package/dist/{chunk-JGPE4RRE.js.map → chunk-SPQSNZMM.js.map} +0 -0
  90. /package/dist/{chunk-EOKNEGRD.js.map → chunk-VR6QTK5Z.js.map} +0 -0
  91. /package/dist/{components/common/removal-plan-confirm.js.map → load-agent-defs-E67DSYTN.js.map} +0 -0
  92. /package/dist/{recompile-project-agents-IQANWGOP.js.map → recompile-project-agents-6G6M2RS6.js.map} +0 -0
  93. /package/dist/{load-agent-defs-UBWITIEI.js.map → source-loader-W7XCNKNA.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -7,6 +7,37 @@ Each release has detailed notes in its own file under [`changelogs/`](./changelo
7
7
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
8
8
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
9
9
 
10
+ ## [0.173.0] - 2026-10-23
11
+
12
+ **`doctor` downloads each marketplace on every run, the editor keeps a saved configuration per marketplace and its stack-switch question waits for the stack, and a sub-agent goes off with its last skill**
13
+
14
+ - REPO-44:
15
+ - The editor keeps a saved configuration per marketplace: loading another opens its own and leaves the one on screen saved with its marketplace, and a saved stack built on another marketplace loads that marketplace first.
16
+ - The question before an account's saved stack replaces changes waits for the stack and offers Retry when it cannot load. A sub-agent whose last skill goes switches off with the toast on a link the CLI minted.
17
+ - `doctor` passes a project holding a Claude and a Codex installation, and `doctor` and `uninstall` use the project's own provider's global where a home holds both. A marketplace skill with no `displayName` is skipped with a warning and the rest of the marketplace loads.
18
+ - CLI-925: `doctor` downloads each marketplace on every run, fails its row when only giget's saved tarball came back, and says when it replaced a saved copy that differed.
19
+ - CLI-915: the editor's preview shows a link's own description over its stack's, as the install does.
20
+ - CLI-865: the panel and terminal-poll specs wait for their settled result instead of sampling once after a fixed delay.
21
+
22
+ See [changelogs/0.173.0.md](./changelogs/0.173.0.md) for full details.
23
+
24
+ ## [0.172.0] - 2026-10-22
25
+
26
+ **`init --from`, `edit --from` and `uninstall` show the summary panel at the question, the editor names the sub-agents a skill switches and holds a project link's global entries, links are version 7, and agentsinc.sh/ opens the editor**
27
+
28
+ - REPO-44:
29
+ - The editor names the sub-agents a skill switches on or off in a toast, keeps a stack's sub-agents on with no skills, and holds the global entries of a link a bare `edit` mints in a project. Share links are version 7, so earlier links and saves must be made again.
30
+ - Text a link carries prints inert on one line, a marketplace value holding a line break is refused, and a carried file whose path leaves its folder is refused.
31
+ - Agent plugins version by the files they ship, `list` keeps long names whole, a carried skill's name may pass 30 characters, and remedies name the installation they act on.
32
+ - agentsinc.sh/ redirects to the editor, and the landing page is gone.
33
+ - CLI-925: `doctor` fails its marketplace row offline or on a refusal, lists no ejected skill as an orphan, and passes two healthy installations. Sub-agents install without a skill that fails to load. A local `AGENTS_INC_API_URL` selects the local editor and `AGENTS_INC_EDITOR_URL` is gone. `build marketplace` refuses an empty config, a global edit says it recompiles its registered projects, and a no-op `edit --from` without a terminal exits 0.
34
+ - CLI-908: `init --from`, `edit --from` and `uninstall` show the summary panel where they ask, marking a changed sub-agent `~` and a skill written over `↻`.
35
+ - CLI-915: `init --from` in a project writes the link's own description, or none, never the global installation's.
36
+ - EDITOR-97: a link the CLI mints also opens on a signed-in account's save it equals.
37
+ - Five items still fail in one case each (E1-d, E2, F5b, F9, FU2); the detailed notes list them under Backlog.
38
+
39
+ See [changelogs/0.172.0.md](./changelogs/0.172.0.md) for full details.
40
+
10
41
  ## [0.171.0] - 2026-10-22
11
42
 
12
43
  **`doctor` reads each installation, `edit --from` names what it deletes and overwrites, a link's carried skill cannot write outside its folder, and compiled sub-agents carry only the hooks they declare**
@@ -2,12 +2,12 @@
2
2
  import {
3
3
  chooseProviderForThisRun,
4
4
  detectInstallations
5
- } from "./chunk-3YYHL76L.js";
5
+ } from "./chunk-WVFBBZEP.js";
6
6
  import {
7
7
  CLI_INVOKE_COMMAND,
8
8
  EDITOR_URL,
9
9
  PROVIDERS
10
- } from "./chunk-A6OWEJGC.js";
10
+ } from "./chunk-MHAQWMNJ.js";
11
11
 
12
12
  // src/cli/lib/installation/provider-flag.ts
13
13
  import os from "os";
@@ -50,6 +50,14 @@ async function refuseAnAmbiguousInstallation(cwd, subject, named, onAmbiguous) {
50
50
  if (providers.length <= 1) return;
51
51
  onAmbiguous(ambiguousInstallation(subject, providers, scopeRoot));
52
52
  }
53
+ async function providersInPlay(cwd) {
54
+ return (await installationsInPlay(cwd)).providers;
55
+ }
56
+ async function installationToName(cwd, named) {
57
+ if (named !== void 0) return named;
58
+ const providers = await providersInPlay(cwd);
59
+ return providers.length > 1 ? providers : void 0;
60
+ }
53
61
  async function ambiguityFinding(cwd) {
54
62
  const { scopeRoot, providers } = await installationsInPlay(cwd);
55
63
  if (providers.length <= 1) return null;
@@ -67,7 +75,8 @@ export {
67
75
  providerNamedBy,
68
76
  providerNeedsAConfigurationToInstall,
69
77
  refuseAnAmbiguousInstallation,
78
+ installationToName,
70
79
  ambiguityFinding,
71
80
  otherInstallationsInThisScope
72
81
  };
73
- //# sourceMappingURL=chunk-W4KAY26P.js.map
82
+ //# sourceMappingURL=chunk-2RTBSLSR.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/lib/installation/provider-flag.ts"],"sourcesContent":["/**\n * `--provider`: names the installation where the folder cannot — a greenfield `init --from`, or a\n * scope holding both providers, where acting commands refuse until it is given.\n */\n\nimport os from \"os\";\n\nimport { Flags } from \"@oclif/core\";\n\nimport { PROVIDERS, EDITOR_URL, CLI_INVOKE_COMMAND, type Provider } from \"../../consts.js\";\nimport { detectInstallations, type DetectedInstallation } from \"./detect-installations.js\";\nimport { chooseProviderForThisRun } from \"./install-layout.js\";\n\n/** A factory because oclif mutates flag definitions, so commands must not share one. */\nexport function providerFlag() {\n return Flags.string({\n description: \"Which provider's installation this run is about\",\n helpValue: `<${PROVIDERS.join(\"|\")}>`,\n options: [...PROVIDERS],\n });\n}\n\n/** oclif has already rejected unlisted values; this only narrows. */\nexport function providerNamedBy(flagValue: string | undefined): Provider | undefined {\n if (flagValue === undefined) return undefined;\n return PROVIDERS.find((provider) => provider === flagValue);\n}\n\nexport function providerNeedsAConfigurationToInstall(): string {\n return (\n `--provider names which installation to create and needs the configuration to create it ` +\n `from, so it is only meaningful beside --from. Build one at ${EDITOR_URL}, then run ` +\n `'${CLI_INVOKE_COMMAND} init --from <id> --provider <provider>'.`\n );\n}\n\nfunction ambiguousInstallation(\n subject: string,\n providers: readonly Provider[],\n scopeRoot: string,\n): string {\n return (\n `${scopeRoot} holds ${providers.length} installations — ${providers.join(\" and \")} — so ` +\n `${subject} cannot tell which one you mean. Name it with --provider <${providers.join(\"|\")}>. ` +\n `Nothing has been changed.`\n );\n}\n\ntype InstallationsInPlay = {\n scopeRoot: string;\n providers: Provider[];\n};\n\n/** The project's installations, or the global ones only when the project has none. */\nasync function installationsInPlay(cwd: string): Promise<InstallationsInPlay> {\n const found = await detectInstallations(cwd);\n const inTheProject = atScope(found, \"project\");\n\n if (inTheProject.length > 0) return { scopeRoot: cwd, providers: providersOf(inTheProject) };\n return { scopeRoot: os.homedir(), providers: providersOf(atScope(found, \"global\")) };\n}\n\nfunction atScope(\n found: readonly DetectedInstallation[],\n scope: DetectedInstallation[\"scope\"],\n): DetectedInstallation[] {\n return found.filter((installation) => installation.scope === scope);\n}\n\nfunction providersOf(installations: readonly DetectedInstallation[]): Provider[] {\n return installations.map((installation) => installation.provider);\n}\n\n/**\n * A named provider is committed for the run; two installations and no flag call `onAmbiguous`\n * (the command's `this.error`); otherwise nothing happens.\n */\nexport async function refuseAnAmbiguousInstallation(\n cwd: string,\n subject: string,\n named: Provider | undefined,\n onAmbiguous: (message: string) => never,\n): Promise<void> {\n if (named !== undefined) {\n chooseProviderForThisRun(named);\n return;\n }\n\n const { scopeRoot, providers } = await installationsInPlay(cwd);\n if (providers.length <= 1) return;\n\n onAmbiguous(ambiguousInstallation(subject, providers, scopeRoot));\n}\n\n/** The non-refusing form, for `doctor`. */\nexport async function ambiguityFinding(cwd: string): Promise<string | null> {\n const { scopeRoot, providers } = await installationsInPlay(cwd);\n if (providers.length <= 1) return null;\n\n return ambiguousInstallation(\"every command that acts on one\", providers, scopeRoot);\n}\n\n/** For `list`: names the other installation in the scope, or `null` when there is none. */\nexport async function otherInstallationsInThisScope(\n cwd: string,\n showing: Provider,\n): Promise<string | null> {\n const { scopeRoot, providers } = await installationsInPlay(cwd);\n const others = providers.filter((provider) => provider !== showing);\n if (others.length === 0) return null;\n\n return (\n `${scopeRoot} holds ${providers.length} installations — ${providers.join(\" and \")} — and this ` +\n `is the ${showing} one. Show another with --provider <${providers.join(\"|\")}>.`\n );\n}\n"],"mappings":";;;;;;;;;;;;AAKA,OAAO,QAAQ;AAEf,SAAS,aAAa;AAOf,SAAS,eAAe;AAC7B,SAAO,MAAM,OAAO;AAAA,IAClB,aAAa;AAAA,IACb,WAAW,IAAI,UAAU,KAAK,GAAG,CAAC;AAAA,IAClC,SAAS,CAAC,GAAG,SAAS;AAAA,EACxB,CAAC;AACH;AAGO,SAAS,gBAAgB,WAAqD;AACnF,MAAI,cAAc,OAAW,QAAO;AACpC,SAAO,UAAU,KAAK,CAAC,aAAa,aAAa,SAAS;AAC5D;AAEO,SAAS,uCAA+C;AAC7D,SACE,qJAC8D,UAAU,eACpE,kBAAkB;AAE1B;AAEA,SAAS,sBACP,SACA,WACA,WACQ;AACR,SACE,GAAG,SAAS,UAAU,UAAU,MAAM,yBAAoB,UAAU,KAAK,OAAO,CAAC,cAC9E,OAAO,6DAA6D,UAAU,KAAK,GAAG,CAAC;AAG9F;AAQA,eAAe,oBAAoB,KAA2C;AAC5E,QAAM,QAAQ,MAAM,oBAAoB,GAAG;AAC3C,QAAM,eAAe,QAAQ,OAAO,SAAS;AAE7C,MAAI,aAAa,SAAS,EAAG,QAAO,EAAE,WAAW,KAAK,WAAW,YAAY,YAAY,EAAE;AAC3F,SAAO,EAAE,WAAW,GAAG,QAAQ,GAAG,WAAW,YAAY,QAAQ,OAAO,QAAQ,CAAC,EAAE;AACrF;AAEA,SAAS,QACP,OACA,OACwB;AACxB,SAAO,MAAM,OAAO,CAAC,iBAAiB,aAAa,UAAU,KAAK;AACpE;AAEA,SAAS,YAAY,eAA4D;AAC/E,SAAO,cAAc,IAAI,CAAC,iBAAiB,aAAa,QAAQ;AAClE;AAMA,eAAsB,8BACpB,KACA,SACA,OACA,aACe;AACf,MAAI,UAAU,QAAW;AACvB,6BAAyB,KAAK;AAC9B;AAAA,EACF;AAEA,QAAM,EAAE,WAAW,UAAU,IAAI,MAAM,oBAAoB,GAAG;AAC9D,MAAI,UAAU,UAAU,EAAG;AAE3B,cAAY,sBAAsB,SAAS,WAAW,SAAS,CAAC;AAClE;AAGA,eAAsB,iBAAiB,KAAqC;AAC1E,QAAM,EAAE,WAAW,UAAU,IAAI,MAAM,oBAAoB,GAAG;AAC9D,MAAI,UAAU,UAAU,EAAG,QAAO;AAElC,SAAO,sBAAsB,kCAAkC,WAAW,SAAS;AACrF;AAGA,eAAsB,8BACpB,KACA,SACwB;AACxB,QAAM,EAAE,WAAW,UAAU,IAAI,MAAM,oBAAoB,GAAG;AAC9D,QAAM,SAAS,UAAU,OAAO,CAAC,aAAa,aAAa,OAAO;AAClE,MAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,SACE,GAAG,SAAS,UAAU,UAAU,MAAM,yBAAoB,UAAU,KAAK,OAAO,CAAC,2BACvE,OAAO,uCAAuC,UAAU,KAAK,GAAG,CAAC;AAE/E;","names":[]}
1
+ {"version":3,"sources":["../src/cli/lib/installation/provider-flag.ts"],"sourcesContent":["/**\n * `--provider`: names the installation where the folder cannot — a greenfield `init --from`, or a\n * scope holding both providers, where acting commands refuse until it is given.\n */\n\nimport os from \"os\";\n\nimport { Flags } from \"@oclif/core\";\n\nimport { PROVIDERS, EDITOR_URL, CLI_INVOKE_COMMAND, type Provider } from \"../../consts.js\";\nimport { detectInstallations, type DetectedInstallation } from \"./detect-installations.js\";\nimport { chooseProviderForThisRun } from \"./install-layout.js\";\n\n/** A factory because oclif mutates flag definitions, so commands must not share one. */\nexport function providerFlag() {\n return Flags.string({\n description: \"Which provider's installation this run is about\",\n helpValue: `<${PROVIDERS.join(\"|\")}>`,\n options: [...PROVIDERS],\n });\n}\n\n/** oclif has already rejected unlisted values; this only narrows. */\nexport function providerNamedBy(flagValue: string | undefined): Provider | undefined {\n if (flagValue === undefined) return undefined;\n return PROVIDERS.find((provider) => provider === flagValue);\n}\n\nexport function providerNeedsAConfigurationToInstall(): string {\n return (\n `--provider names which installation to create and needs the configuration to create it ` +\n `from, so it is only meaningful beside --from. Build one at ${EDITOR_URL}, then run ` +\n `'${CLI_INVOKE_COMMAND} init --from <id> --provider <provider>'.`\n );\n}\n\nfunction ambiguousInstallation(\n subject: string,\n providers: readonly Provider[],\n scopeRoot: string,\n): string {\n return (\n `${scopeRoot} holds ${providers.length} installations — ${providers.join(\" and \")} — so ` +\n `${subject} cannot tell which one you mean. Name it with --provider <${providers.join(\"|\")}>. ` +\n `Nothing has been changed.`\n );\n}\n\ntype InstallationsInPlay = {\n scopeRoot: string;\n providers: Provider[];\n};\n\n/** The project's installations, or the global ones only when the project has none. */\nasync function installationsInPlay(cwd: string): Promise<InstallationsInPlay> {\n const found = await detectInstallations(cwd);\n const inTheProject = atScope(found, \"project\");\n\n if (inTheProject.length > 0) return { scopeRoot: cwd, providers: providersOf(inTheProject) };\n return { scopeRoot: os.homedir(), providers: providersOf(atScope(found, \"global\")) };\n}\n\nfunction atScope(\n found: readonly DetectedInstallation[],\n scope: DetectedInstallation[\"scope\"],\n): DetectedInstallation[] {\n return found.filter((installation) => installation.scope === scope);\n}\n\nfunction providersOf(installations: readonly DetectedInstallation[]): Provider[] {\n return installations.map((installation) => installation.provider);\n}\n\n/**\n * A named provider is committed for the run; two installations and no flag call `onAmbiguous`\n * (the command's `this.error`); otherwise nothing happens.\n */\nexport async function refuseAnAmbiguousInstallation(\n cwd: string,\n subject: string,\n named: Provider | undefined,\n onAmbiguous: (message: string) => never,\n): Promise<void> {\n if (named !== undefined) {\n chooseProviderForThisRun(named);\n return;\n }\n\n const { scopeRoot, providers } = await installationsInPlay(cwd);\n if (providers.length <= 1) return;\n\n onAmbiguous(ambiguousInstallation(subject, providers, scopeRoot));\n}\n\n/** The non-refusing read the remedies hand a command out from, so they and the refusal agree. */\nexport async function providersInPlay(cwd: string): Promise<Provider[]> {\n return (await installationsInPlay(cwd)).providers;\n}\n\n/**\n * Which installation a handed-out acting command must name: the one the run named, else the choice\n * where two are in play, since a bare one refuses there.\n */\nexport async function installationToName(\n cwd: string,\n named: Provider | undefined,\n): Promise<Provider | Provider[] | undefined> {\n if (named !== undefined) return named;\n\n const providers = await providersInPlay(cwd);\n return providers.length > 1 ? providers : undefined;\n}\n\n/** The non-refusing form, for `doctor`. */\nexport async function ambiguityFinding(cwd: string): Promise<string | null> {\n const { scopeRoot, providers } = await installationsInPlay(cwd);\n if (providers.length <= 1) return null;\n\n return ambiguousInstallation(\"every command that acts on one\", providers, scopeRoot);\n}\n\n/** For `list`: names the other installation in the scope, or `null` when there is none. */\nexport async function otherInstallationsInThisScope(\n cwd: string,\n showing: Provider,\n): Promise<string | null> {\n const { scopeRoot, providers } = await installationsInPlay(cwd);\n const others = providers.filter((provider) => provider !== showing);\n if (others.length === 0) return null;\n\n return (\n `${scopeRoot} holds ${providers.length} installations — ${providers.join(\" and \")} — and this ` +\n `is the ${showing} one. Show another with --provider <${providers.join(\"|\")}>.`\n );\n}\n"],"mappings":";;;;;;;;;;;;AAKA,OAAO,QAAQ;AAEf,SAAS,aAAa;AAOf,SAAS,eAAe;AAC7B,SAAO,MAAM,OAAO;AAAA,IAClB,aAAa;AAAA,IACb,WAAW,IAAI,UAAU,KAAK,GAAG,CAAC;AAAA,IAClC,SAAS,CAAC,GAAG,SAAS;AAAA,EACxB,CAAC;AACH;AAGO,SAAS,gBAAgB,WAAqD;AACnF,MAAI,cAAc,OAAW,QAAO;AACpC,SAAO,UAAU,KAAK,CAAC,aAAa,aAAa,SAAS;AAC5D;AAEO,SAAS,uCAA+C;AAC7D,SACE,qJAC8D,UAAU,eACpE,kBAAkB;AAE1B;AAEA,SAAS,sBACP,SACA,WACA,WACQ;AACR,SACE,GAAG,SAAS,UAAU,UAAU,MAAM,yBAAoB,UAAU,KAAK,OAAO,CAAC,cAC9E,OAAO,6DAA6D,UAAU,KAAK,GAAG,CAAC;AAG9F;AAQA,eAAe,oBAAoB,KAA2C;AAC5E,QAAM,QAAQ,MAAM,oBAAoB,GAAG;AAC3C,QAAM,eAAe,QAAQ,OAAO,SAAS;AAE7C,MAAI,aAAa,SAAS,EAAG,QAAO,EAAE,WAAW,KAAK,WAAW,YAAY,YAAY,EAAE;AAC3F,SAAO,EAAE,WAAW,GAAG,QAAQ,GAAG,WAAW,YAAY,QAAQ,OAAO,QAAQ,CAAC,EAAE;AACrF;AAEA,SAAS,QACP,OACA,OACwB;AACxB,SAAO,MAAM,OAAO,CAAC,iBAAiB,aAAa,UAAU,KAAK;AACpE;AAEA,SAAS,YAAY,eAA4D;AAC/E,SAAO,cAAc,IAAI,CAAC,iBAAiB,aAAa,QAAQ;AAClE;AAMA,eAAsB,8BACpB,KACA,SACA,OACA,aACe;AACf,MAAI,UAAU,QAAW;AACvB,6BAAyB,KAAK;AAC9B;AAAA,EACF;AAEA,QAAM,EAAE,WAAW,UAAU,IAAI,MAAM,oBAAoB,GAAG;AAC9D,MAAI,UAAU,UAAU,EAAG;AAE3B,cAAY,sBAAsB,SAAS,WAAW,SAAS,CAAC;AAClE;AAGA,eAAsB,gBAAgB,KAAkC;AACtE,UAAQ,MAAM,oBAAoB,GAAG,GAAG;AAC1C;AAMA,eAAsB,mBACpB,KACA,OAC4C;AAC5C,MAAI,UAAU,OAAW,QAAO;AAEhC,QAAM,YAAY,MAAM,gBAAgB,GAAG;AAC3C,SAAO,UAAU,SAAS,IAAI,YAAY;AAC5C;AAGA,eAAsB,iBAAiB,KAAqC;AAC1E,QAAM,EAAE,WAAW,UAAU,IAAI,MAAM,oBAAoB,GAAG;AAC9D,MAAI,UAAU,UAAU,EAAG,QAAO;AAElC,SAAO,sBAAsB,kCAAkC,WAAW,SAAS;AACrF;AAGA,eAAsB,8BACpB,KACA,SACwB;AACxB,QAAM,EAAE,WAAW,UAAU,IAAI,MAAM,oBAAoB,GAAG;AAC9D,QAAM,SAAS,UAAU,OAAO,CAAC,aAAa,aAAa,OAAO;AAClE,MAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,SACE,GAAG,SAAS,UAAU,UAAU,MAAM,yBAAoB,UAAU,KAAK,OAAO,CAAC,2BACvE,OAAO,uCAAuC,UAAU,KAAK,GAAG,CAAC;AAE/E;","names":[]}
@@ -14,7 +14,7 @@ import {
14
14
  readFileOptional,
15
15
  unexpressibleOnCodexMessage,
16
16
  writeFile
17
- } from "./chunk-3YYHL76L.js";
17
+ } from "./chunk-WVFBBZEP.js";
18
18
 
19
19
  // src/cli/lib/hosts/claude-project-trust.ts
20
20
  import path from "path";
@@ -226,13 +226,19 @@ async function holdsProjectRoles(projectDir) {
226
226
 
227
227
  // src/cli/lib/hosts/host-compile-notices.ts
228
228
  async function hostCompileNotices(provider, projectDir) {
229
- return [
230
- ...await codexCompileNotices(provider, projectDir),
231
- ...await claudeCompileNotices(provider, projectDir)
232
- ];
229
+ switch (provider) {
230
+ case "claude":
231
+ return claudeCompileNotices(provider, projectDir);
232
+ case "codex":
233
+ return codexCompileNotices(provider, projectDir);
234
+ default: {
235
+ const _exhaustive = provider;
236
+ return _exhaustive;
237
+ }
238
+ }
233
239
  }
234
240
 
235
241
  export {
236
242
  hostCompileNotices
237
243
  };
238
- //# sourceMappingURL=chunk-WM2N2D6Q.js.map
244
+ //# sourceMappingURL=chunk-3N4FSTVX.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/lib/hosts/claude-project-trust.ts","../src/cli/lib/hosts/codex-project-trust.ts","../src/cli/lib/hosts/codex-compile-notices.ts","../src/cli/lib/hosts/host-compile-notices.ts"],"sourcesContent":["import path from \"path\";\nimport { realpath } from \"fs/promises\";\n\nimport { z } from \"zod\";\n\nimport { agentCodec, agentsDir, claudeStateFile } from \"../installation/install-layout.js\";\nimport { isHomeDirectory } from \"../installation/is-home-directory.js\";\nimport { fileExists, glob, readFile, readFileOptional } from \"../../utils/fs.js\";\nimport { extractFrontmatter } from \"../../utils/frontmatter.js\";\nimport type { Provider } from \"../../consts.js\";\n\n/**\n * Warns when Claude Code will drop a project sub-agent's hooks, on every event: project hooks run\n * only once `~/.claude.json` records `projects[<key>].hasTrustDialogAccepted`, keyed by the git\n * repository root (a linked worktree's main checkout). Reads that state, never writes it.\n */\n\nconst claudeStateSchema = z.object({ projects: z.record(z.string(), z.unknown()) });\n\nconst trustedProjectSchema = z.object({ hasTrustDialogAccepted: z.literal(true) });\n\n/** Claude Code reads only a top-level `hooks:` key: event name to its definitions. */\nconst declaredHooksSchema = z.object({ hooks: z.record(z.string(), z.array(z.unknown())) });\n\nconst GIT_ENTRY = \".git\";\nconst GITDIR_PREFIX = \"gitdir:\";\nconst COMMONDIR_FILE = \"commondir\";\nconst BACK_LINK_FILE = \"gitdir\";\nconst WORKTREES_DIR = \"worktrees\";\n\n/** \"never asks\": a folder above is trusted, so no prompt appears and only the record can fix it. */\ntype ClaudeTrust =\n | { readonly kind: \"trusted\" }\n | { readonly kind: \"asks\" }\n | { readonly kind: \"never asks\"; readonly recordKey: string };\n\ntype TrustRecord = (folder: string) => boolean;\n\n/** Empty from the home directory: `~/.claude/agents/` is trusted unconditionally. */\nexport async function claudeCompileNotices(\n provider: Provider,\n projectDir: string,\n): Promise<string[]> {\n if (provider !== \"claude\") return [];\n if (isHomeDirectory(projectDir)) return [];\n\n const agentsWithHooks = await countProjectAgentsDeclaringHooks(projectDir);\n if (agentsWithHooks === 0) return [];\n\n const trust = await claudeTrustOf(projectDir);\n switch (trust.kind) {\n case \"trusted\":\n return [];\n case \"asks\":\n return [claudeProjectNeedsTrustMessage(projectDir, agentsWithHooks)];\n case \"never asks\":\n return [claudeProjectNeverAskedMessage(trust.recordKey, agentsWithHooks)];\n default: {\n const _exhaustive: never = trust;\n return _exhaustive;\n }\n }\n}\n\nexport function claudeProjectNeedsTrustMessage(projectDir: string, count: number): string {\n return (\n `Claude Code runs a project sub-agent's hooks only once you trust the folder: open Claude ` +\n `Code in ${projectDir} and accept the trust prompt. Until then, ${hooksOf(count)} will not ` +\n `run, and nothing will say so.`\n );\n}\n\nexport function claudeProjectNeverAskedMessage(recordKey: string, count: number): string {\n return (\n `Claude Code runs ${hooksOf(count)} only once you trust the folder, and will not ask here: ` +\n `set projects[${JSON.stringify(recordKey)}].hasTrustDialogAccepted to true in ` +\n `${claudeStateFile()}.`\n );\n}\n\nfunction hooksOf(count: number): string {\n return count === 1 ? \"1 sub-agent's hooks\" : `${count} sub-agents' hooks`;\n}\n\nasync function claudeTrustOf(projectDir: string): Promise<ClaudeTrust> {\n const [isTrusted, repositoryRoot] = await Promise.all([\n trustRecord(),\n gitRepositoryRoot(projectDir),\n ]);\n const recordKey =\n repositoryRoot === undefined ? projectDir : await canonicalRepositoryRoot(repositoryRoot);\n if (isTrusted(recordKey)) return { kind: \"trusted\" };\n\n const promptSuppressed = foldersUpTo(projectDir, repositoryRoot).some(isTrusted);\n return promptSuppressed ? { kind: \"never asks\", recordKey } : { kind: \"asks\" };\n}\n\n/** Unreadable counts as untrusted: a wrong \"untrusted\" costs one line of advice. */\nasync function trustRecord(): Promise<TrustRecord> {\n const stateFile = claudeStateFile();\n if (!(await fileExists(stateFile))) return () => false;\n\n const state = claudeStateSchema.safeParse(parsedOrUndefined(await readFile(stateFile)));\n if (!state.success) return () => false;\n\n const { projects } = state.data;\n return (folder) => trustedProjectSchema.safeParse(projects[folder]).success;\n}\n\nfunction parsedOrUndefined(json: string): unknown {\n try {\n return JSON.parse(json);\n } catch {\n return undefined;\n }\n}\n\nfunction foldersUpTo(folder: string, top?: string): string[] {\n const parent = path.dirname(folder);\n if (folder === top || parent === folder) return [folder];\n return [folder, ...foldersUpTo(parent, top)];\n}\n\nasync function gitRepositoryRoot(folder: string): Promise<string | undefined> {\n const candidates = foldersUpTo(folder);\n const holdsGit = await Promise.all(\n candidates.map((candidate) => fileExists(path.join(candidate, GIT_ENTRY))),\n );\n return candidates.find((_, index) => holdsGit[index]);\n}\n\n/**\n * A linked worktree (`.git` file pointing into `<main>/.git/worktrees/`, which points back) is\n * keyed by its main checkout; anything else by `root` itself.\n */\nasync function canonicalRepositoryRoot(root: string): Promise<string> {\n // A `.git` directory reads as empty, as a missing file does.\n const pointer = (await readFileOptional(path.join(root, GIT_ENTRY))).trim();\n if (!pointer.startsWith(GITDIR_PREFIX)) return root;\n\n const gitDir = path.resolve(root, pointer.slice(GITDIR_PREFIX.length).trim());\n const [commonDir, backLink] = await Promise.all([\n pathRecordedIn(gitDir, COMMONDIR_FILE),\n pathRecordedIn(gitDir, BACK_LINK_FILE),\n ]);\n const isLinkedWorktree =\n path.dirname(gitDir) === path.join(commonDir, WORKTREES_DIR) &&\n (await pointsBackAt(backLink, root));\n if (!isLinkedWorktree) return root;\n\n // A worktree of a bare repository is keyed by the bare repository's own folder.\n return path.basename(commonDir) === GIT_ENTRY ? path.dirname(commonDir) : commonDir;\n}\n\nasync function pathRecordedIn(dir: string, file: string): Promise<string> {\n return path.resolve(dir, (await readFileOptional(path.join(dir, file))).trim());\n}\n\nasync function pointsBackAt(backLink: string, root: string): Promise<boolean> {\n const [linked, realRoot] = await Promise.all([\n realpathOrUndefined(backLink),\n realpathOrUndefined(root),\n ]);\n return realRoot !== undefined && linked === path.join(realRoot, GIT_ENTRY);\n}\n\nasync function realpathOrUndefined(file: string): Promise<string | undefined> {\n try {\n return await realpath(file);\n } catch {\n return undefined;\n }\n}\n\nasync function countProjectAgentsDeclaringHooks(projectDir: string): Promise<number> {\n const dir = agentsDir(\"claude\", \"project\", projectDir);\n const files = await glob(agentCodec(\"claude\").listGlob, dir);\n const agents = await Promise.all(files.map((file) => readFile(path.join(dir, file))));\n return agents.filter(declaresAHook).length;\n}\n\n/** An event with no definition runs nothing, so it is not a hook to warn about. */\nfunction declaresAHook(agentMarkdown: string): boolean {\n const frontmatter = declaredHooksSchema.safeParse(extractFrontmatter(agentMarkdown));\n return (\n frontmatter.success &&\n Object.values(frontmatter.data.hooks).some((definitions) => definitions.length > 0)\n );\n}\n","import path from \"path\";\n\nimport { codexGlobalConfigFile } from \"../installation/install-layout.js\";\nimport { ensureDir, fileExists, readFile, writeFile } from \"../../utils/fs.js\";\n\n/**\n * Codex reads `<project>/.codex/agents/*.toml` only while the GLOBAL `config.toml` holds\n * `[projects.\"<abs path>\"] trust_level = \"trusted\"`, failing silently otherwise. The install writes\n * that entry and says so, but never overrides a level the user already set.\n */\n\nconst TRUST_KEY = \"trust_level\";\nconst TRUSTED = \"trusted\";\nconst TRUST_ASSIGNMENT = `${TRUST_KEY} = \"${TRUSTED}\"`;\n\nexport type CodexProjectTrust =\n | { readonly kind: \"already trusted\" }\n | { readonly kind: \"trusted now\"; readonly configFile: string }\n | {\n readonly kind: \"left as the user set it\";\n readonly configFile: string;\n readonly level: string;\n };\n\n/**\n * Merged into the user's file, never rewritten: a second table for the same path would make Codex\n * refuse the whole file. `path.resolve` gives the one spelling Codex matches (no trailing slash).\n */\nexport async function trustCodexProject(projectDir: string): Promise<CodexProjectTrust> {\n const configFile = codexGlobalConfigFile();\n const dir = path.resolve(projectDir);\n const config = (await fileExists(configFile)) ? await readFile(configFile) : \"\";\n\n if (declaresTrust(config, dir)) return { kind: \"already trusted\" };\n\n const level = declaredLevel(config, dir);\n if (level !== undefined) return { kind: \"left as the user set it\", configFile, level };\n\n await ensureDir(path.dirname(configFile));\n await writeFile(configFile, withTrustFor(config, dir));\n return { kind: \"trusted now\", configFile };\n}\n\nexport function codexProjectTrustMessage(\n projectDir: string,\n trust: CodexProjectTrust,\n): string | undefined {\n const table = projectTableHeader(path.resolve(projectDir));\n\n switch (trust.kind) {\n case \"already trusted\":\n return undefined;\n case \"trusted now\":\n return (\n `Trusted this project in your Codex configuration, so Codex reads its sub-agents: added ` +\n `${table} with ${TRUST_KEY} = \"${TRUSTED}\" to ${trust.configFile}.`\n );\n case \"left as the user set it\":\n return (\n `Codex reads this project's sub-agents only once it is trusted, and ${trust.configFile} ` +\n `sets ${TRUST_KEY} = \"${trust.level}\" under ${table}. Left as you set it — change it to ` +\n `\"${TRUSTED}\" for Codex to read them.`\n );\n default: {\n const _exhaustive: never = trust;\n return _exhaustive;\n }\n }\n}\n\n/** Hand-read, not TOML-parsed; any other spelling reads as untrusted, the safe direction. */\nfunction declaresTrust(config: string, projectDir: string): boolean {\n return linesForProject(config, projectDir).includes(TRUST_ASSIGNMENT);\n}\n\nconst TRUST_LEVEL_LINE = new RegExp(`^${TRUST_KEY}\\\\s*=\\\\s*\"([^\"]*)\"$`);\n\n/** The user's own `trust_level` for this project, which is never overwritten. */\nfunction declaredLevel(config: string, projectDir: string): string | undefined {\n return linesForProject(config, projectDir)\n .map((line) => TRUST_LEVEL_LINE.exec(line)?.[1])\n .find((level) => level !== undefined);\n}\n\n/** Trimmed: the lines under the project's table header, then its dotted keys with the prefix cut. */\nfunction linesForProject(config: string, projectDir: string): string[] {\n const lines = config.split(\"\\n\").map((line) => line.trim());\n const dottedPrefix = `projects.\"${projectDir}\".`;\n const dotted = lines\n .filter((line) => line.startsWith(dottedPrefix))\n .map((line) => line.slice(dottedPrefix.length));\n\n return [...linesUnderProjectTable(lines, projectDir), ...dotted];\n}\n\nfunction linesUnderProjectTable(lines: readonly string[], projectDir: string): readonly string[] {\n const header = lines.indexOf(projectTableHeader(projectDir));\n if (header === -1) return [];\n\n const after = lines.slice(header + 1);\n const nextTable = after.findIndex(opensATable);\n return nextTable === -1 ? after : after.slice(0, nextTable);\n}\n\nfunction opensATable(line: string): boolean {\n return line.startsWith(\"[\");\n}\n\nfunction projectTableHeader(projectDir: string): string {\n return `[projects.\"${projectDir}\"]`;\n}\n\nfunction withTrustFor(config: string, projectDir: string): string {\n const lines = config.split(\"\\n\");\n const header = lines.findIndex((line) => line.trim() === projectTableHeader(projectDir));\n\n if (header !== -1) {\n return [...lines.slice(0, header + 1), TRUST_ASSIGNMENT, ...lines.slice(header + 1)].join(\"\\n\");\n }\n\n const theirs = config.trimEnd();\n const table = `${projectTableHeader(projectDir)}\\n${TRUST_ASSIGNMENT}\\n`;\n return theirs === \"\" ? table : `${theirs}\\n\\n${table}`;\n}\n","import {\n agentsLeftOutOfCodexMessage,\n unexpressibleOnCodexMessage,\n} from \"@workspace/compile/agent-source\";\n\nimport { codexProjectTrustMessage, trustCodexProject } from \"./codex-project-trust.js\";\nimport { agentCodec, agentsDir } from \"../installation/install-layout.js\";\nimport { glob } from \"../../utils/fs.js\";\nimport type { Provider } from \"../../consts.js\";\n\n/** Once per run, not per sub-agent or scope: each notice is true of the whole installation. */\nexport async function codexCompileNotices(\n provider: Provider,\n projectDir: string,\n): Promise<string[]> {\n if (provider !== \"codex\") return [];\n\n return [\n agentsLeftOutOfCodexMessage(),\n unexpressibleOnCodexMessage(),\n ...(await trustNotice(projectDir)),\n ];\n}\n\n/** Only when role files exist: trusting a project with nothing for Codex to read grants nothing. */\nasync function trustNotice(projectDir: string): Promise<string[]> {\n if (!(await holdsProjectRoles(projectDir))) return [];\n\n const said = codexProjectTrustMessage(projectDir, await trustCodexProject(projectDir));\n return said === undefined ? [] : [said];\n}\n\nasync function holdsProjectRoles(projectDir: string): Promise<boolean> {\n const roles = await glob(agentCodec(\"codex\").listGlob, agentsDir(\"codex\", \"project\", projectDir));\n\n return roles.length > 0;\n}\n","import { claudeCompileNotices } from \"./claude-project-trust.js\";\nimport { codexCompileNotices } from \"./codex-compile-notices.js\";\nimport type { Provider } from \"../../consts.js\";\n\n/** The one source `init` and `compile` share, so they cannot say different things. */\nexport async function hostCompileNotices(\n provider: Provider,\n projectDir: string,\n): Promise<string[]> {\n return [\n ...(await codexCompileNotices(provider, projectDir)),\n ...(await claudeCompileNotices(provider, projectDir)),\n ];\n}\n"],"mappings":"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","names":["path","path"]}
1
+ {"version":3,"sources":["../src/cli/lib/hosts/claude-project-trust.ts","../src/cli/lib/hosts/codex-project-trust.ts","../src/cli/lib/hosts/codex-compile-notices.ts","../src/cli/lib/hosts/host-compile-notices.ts"],"sourcesContent":["import path from \"path\";\nimport { realpath } from \"fs/promises\";\n\nimport { z } from \"zod\";\n\nimport { agentCodec, agentsDir, claudeStateFile } from \"../installation/install-layout.js\";\nimport { isHomeDirectory } from \"../installation/is-home-directory.js\";\nimport { fileExists, glob, readFile, readFileOptional } from \"../../utils/fs.js\";\nimport { extractFrontmatter } from \"../../utils/frontmatter.js\";\nimport type { Provider } from \"../../consts.js\";\n\n/**\n * Warns when Claude Code will drop a project sub-agent's hooks, on every event: project hooks run\n * only once `~/.claude.json` records `projects[<key>].hasTrustDialogAccepted`, keyed by the git\n * repository root (a linked worktree's main checkout). Reads that state, never writes it.\n */\n\nconst claudeStateSchema = z.object({ projects: z.record(z.string(), z.unknown()) });\n\nconst trustedProjectSchema = z.object({ hasTrustDialogAccepted: z.literal(true) });\n\n/** Claude Code reads only a top-level `hooks:` key: event name to its definitions. */\nconst declaredHooksSchema = z.object({ hooks: z.record(z.string(), z.array(z.unknown())) });\n\nconst GIT_ENTRY = \".git\";\nconst GITDIR_PREFIX = \"gitdir:\";\nconst COMMONDIR_FILE = \"commondir\";\nconst BACK_LINK_FILE = \"gitdir\";\nconst WORKTREES_DIR = \"worktrees\";\n\n/** \"never asks\": a folder above is trusted, so no prompt appears and only the record can fix it. */\ntype ClaudeTrust =\n | { readonly kind: \"trusted\" }\n | { readonly kind: \"asks\" }\n | { readonly kind: \"never asks\"; readonly recordKey: string };\n\ntype TrustRecord = (folder: string) => boolean;\n\n/** Empty from the home directory: `~/.claude/agents/` is trusted unconditionally. */\nexport async function claudeCompileNotices(\n provider: Provider,\n projectDir: string,\n): Promise<string[]> {\n if (provider !== \"claude\") return [];\n if (isHomeDirectory(projectDir)) return [];\n\n const agentsWithHooks = await countProjectAgentsDeclaringHooks(projectDir);\n if (agentsWithHooks === 0) return [];\n\n const trust = await claudeTrustOf(projectDir);\n switch (trust.kind) {\n case \"trusted\":\n return [];\n case \"asks\":\n return [claudeProjectNeedsTrustMessage(projectDir, agentsWithHooks)];\n case \"never asks\":\n return [claudeProjectNeverAskedMessage(trust.recordKey, agentsWithHooks)];\n default: {\n const _exhaustive: never = trust;\n return _exhaustive;\n }\n }\n}\n\nexport function claudeProjectNeedsTrustMessage(projectDir: string, count: number): string {\n return (\n `Claude Code runs a project sub-agent's hooks only once you trust the folder: open Claude ` +\n `Code in ${projectDir} and accept the trust prompt. Until then, ${hooksOf(count)} will not ` +\n `run, and nothing will say so.`\n );\n}\n\nexport function claudeProjectNeverAskedMessage(recordKey: string, count: number): string {\n return (\n `Claude Code runs ${hooksOf(count)} only once you trust the folder, and will not ask here: ` +\n `set projects[${JSON.stringify(recordKey)}].hasTrustDialogAccepted to true in ` +\n `${claudeStateFile()}.`\n );\n}\n\nfunction hooksOf(count: number): string {\n return count === 1 ? \"1 sub-agent's hooks\" : `${count} sub-agents' hooks`;\n}\n\nasync function claudeTrustOf(projectDir: string): Promise<ClaudeTrust> {\n const [isTrusted, repositoryRoot] = await Promise.all([\n trustRecord(),\n gitRepositoryRoot(projectDir),\n ]);\n const recordKey =\n repositoryRoot === undefined ? projectDir : await canonicalRepositoryRoot(repositoryRoot);\n if (isTrusted(recordKey)) return { kind: \"trusted\" };\n\n const promptSuppressed = foldersUpTo(projectDir, repositoryRoot).some(isTrusted);\n return promptSuppressed ? { kind: \"never asks\", recordKey } : { kind: \"asks\" };\n}\n\n/** Unreadable counts as untrusted: a wrong \"untrusted\" costs one line of advice. */\nasync function trustRecord(): Promise<TrustRecord> {\n const stateFile = claudeStateFile();\n if (!(await fileExists(stateFile))) return () => false;\n\n const state = claudeStateSchema.safeParse(parsedOrUndefined(await readFile(stateFile)));\n if (!state.success) return () => false;\n\n const { projects } = state.data;\n return (folder) => trustedProjectSchema.safeParse(projects[folder]).success;\n}\n\nfunction parsedOrUndefined(json: string): unknown {\n try {\n return JSON.parse(json);\n } catch {\n return undefined;\n }\n}\n\nfunction foldersUpTo(folder: string, top?: string): string[] {\n const parent = path.dirname(folder);\n if (folder === top || parent === folder) return [folder];\n return [folder, ...foldersUpTo(parent, top)];\n}\n\nasync function gitRepositoryRoot(folder: string): Promise<string | undefined> {\n const candidates = foldersUpTo(folder);\n const holdsGit = await Promise.all(\n candidates.map((candidate) => fileExists(path.join(candidate, GIT_ENTRY))),\n );\n return candidates.find((_, index) => holdsGit[index]);\n}\n\n/**\n * A linked worktree (`.git` file pointing into `<main>/.git/worktrees/`, which points back) is\n * keyed by its main checkout; anything else by `root` itself.\n */\nasync function canonicalRepositoryRoot(root: string): Promise<string> {\n // A `.git` directory reads as empty, as a missing file does.\n const pointer = (await readFileOptional(path.join(root, GIT_ENTRY))).trim();\n if (!pointer.startsWith(GITDIR_PREFIX)) return root;\n\n const gitDir = path.resolve(root, pointer.slice(GITDIR_PREFIX.length).trim());\n const [commonDir, backLink] = await Promise.all([\n pathRecordedIn(gitDir, COMMONDIR_FILE),\n pathRecordedIn(gitDir, BACK_LINK_FILE),\n ]);\n const isLinkedWorktree =\n path.dirname(gitDir) === path.join(commonDir, WORKTREES_DIR) &&\n (await pointsBackAt(backLink, root));\n if (!isLinkedWorktree) return root;\n\n // A worktree of a bare repository is keyed by the bare repository's own folder.\n return path.basename(commonDir) === GIT_ENTRY ? path.dirname(commonDir) : commonDir;\n}\n\nasync function pathRecordedIn(dir: string, file: string): Promise<string> {\n return path.resolve(dir, (await readFileOptional(path.join(dir, file))).trim());\n}\n\nasync function pointsBackAt(backLink: string, root: string): Promise<boolean> {\n const [linked, realRoot] = await Promise.all([\n realpathOrUndefined(backLink),\n realpathOrUndefined(root),\n ]);\n return realRoot !== undefined && linked === path.join(realRoot, GIT_ENTRY);\n}\n\nasync function realpathOrUndefined(file: string): Promise<string | undefined> {\n try {\n return await realpath(file);\n } catch {\n return undefined;\n }\n}\n\nasync function countProjectAgentsDeclaringHooks(projectDir: string): Promise<number> {\n const dir = agentsDir(\"claude\", \"project\", projectDir);\n const files = await glob(agentCodec(\"claude\").listGlob, dir);\n const agents = await Promise.all(files.map((file) => readFile(path.join(dir, file))));\n return agents.filter(declaresAHook).length;\n}\n\n/** An event with no definition runs nothing, so it is not a hook to warn about. */\nfunction declaresAHook(agentMarkdown: string): boolean {\n const frontmatter = declaredHooksSchema.safeParse(extractFrontmatter(agentMarkdown));\n return (\n frontmatter.success &&\n Object.values(frontmatter.data.hooks).some((definitions) => definitions.length > 0)\n );\n}\n","import path from \"path\";\n\nimport { codexGlobalConfigFile } from \"../installation/install-layout.js\";\nimport { ensureDir, fileExists, readFile, writeFile } from \"../../utils/fs.js\";\n\n/**\n * Codex reads `<project>/.codex/agents/*.toml` only while the GLOBAL `config.toml` holds\n * `[projects.\"<abs path>\"] trust_level = \"trusted\"`, failing silently otherwise. The install writes\n * that entry and says so, but never overrides a level the user already set.\n */\n\nconst TRUST_KEY = \"trust_level\";\nconst TRUSTED = \"trusted\";\nconst TRUST_ASSIGNMENT = `${TRUST_KEY} = \"${TRUSTED}\"`;\n\nexport type CodexProjectTrust =\n | { readonly kind: \"already trusted\" }\n | { readonly kind: \"trusted now\"; readonly configFile: string }\n | {\n readonly kind: \"left as the user set it\";\n readonly configFile: string;\n readonly level: string;\n };\n\n/**\n * Merged into the user's file, never rewritten: a second table for the same path would make Codex\n * refuse the whole file. `path.resolve` gives the one spelling Codex matches (no trailing slash).\n */\nexport async function trustCodexProject(projectDir: string): Promise<CodexProjectTrust> {\n const configFile = codexGlobalConfigFile();\n const dir = path.resolve(projectDir);\n const config = (await fileExists(configFile)) ? await readFile(configFile) : \"\";\n\n if (declaresTrust(config, dir)) return { kind: \"already trusted\" };\n\n const level = declaredLevel(config, dir);\n if (level !== undefined) return { kind: \"left as the user set it\", configFile, level };\n\n await ensureDir(path.dirname(configFile));\n await writeFile(configFile, withTrustFor(config, dir));\n return { kind: \"trusted now\", configFile };\n}\n\nexport function codexProjectTrustMessage(\n projectDir: string,\n trust: CodexProjectTrust,\n): string | undefined {\n const table = projectTableHeader(path.resolve(projectDir));\n\n switch (trust.kind) {\n case \"already trusted\":\n return undefined;\n case \"trusted now\":\n return (\n `Trusted this project in your Codex configuration, so Codex reads its sub-agents: added ` +\n `${table} with ${TRUST_KEY} = \"${TRUSTED}\" to ${trust.configFile}.`\n );\n case \"left as the user set it\":\n return (\n `Codex reads this project's sub-agents only once it is trusted, and ${trust.configFile} ` +\n `sets ${TRUST_KEY} = \"${trust.level}\" under ${table}. Left as you set it — change it to ` +\n `\"${TRUSTED}\" for Codex to read them.`\n );\n default: {\n const _exhaustive: never = trust;\n return _exhaustive;\n }\n }\n}\n\n/** Hand-read, not TOML-parsed; any other spelling reads as untrusted, the safe direction. */\nfunction declaresTrust(config: string, projectDir: string): boolean {\n return linesForProject(config, projectDir).includes(TRUST_ASSIGNMENT);\n}\n\nconst TRUST_LEVEL_LINE = new RegExp(`^${TRUST_KEY}\\\\s*=\\\\s*\"([^\"]*)\"$`);\n\n/** The user's own `trust_level` for this project, which is never overwritten. */\nfunction declaredLevel(config: string, projectDir: string): string | undefined {\n return linesForProject(config, projectDir)\n .map((line) => TRUST_LEVEL_LINE.exec(line)?.[1])\n .find((level) => level !== undefined);\n}\n\n/** Trimmed: the lines under the project's table header, then its dotted keys with the prefix cut. */\nfunction linesForProject(config: string, projectDir: string): string[] {\n const lines = config.split(\"\\n\").map((line) => line.trim());\n const dottedPrefix = `projects.\"${projectDir}\".`;\n const dotted = lines\n .filter((line) => line.startsWith(dottedPrefix))\n .map((line) => line.slice(dottedPrefix.length));\n\n return [...linesUnderProjectTable(lines, projectDir), ...dotted];\n}\n\nfunction linesUnderProjectTable(lines: readonly string[], projectDir: string): readonly string[] {\n const header = lines.indexOf(projectTableHeader(projectDir));\n if (header === -1) return [];\n\n const after = lines.slice(header + 1);\n const nextTable = after.findIndex(opensATable);\n return nextTable === -1 ? after : after.slice(0, nextTable);\n}\n\nfunction opensATable(line: string): boolean {\n return line.startsWith(\"[\");\n}\n\nfunction projectTableHeader(projectDir: string): string {\n return `[projects.\"${projectDir}\"]`;\n}\n\nfunction withTrustFor(config: string, projectDir: string): string {\n const lines = config.split(\"\\n\");\n const header = lines.findIndex((line) => line.trim() === projectTableHeader(projectDir));\n\n if (header !== -1) {\n return [...lines.slice(0, header + 1), TRUST_ASSIGNMENT, ...lines.slice(header + 1)].join(\"\\n\");\n }\n\n const theirs = config.trimEnd();\n const table = `${projectTableHeader(projectDir)}\\n${TRUST_ASSIGNMENT}\\n`;\n return theirs === \"\" ? table : `${theirs}\\n\\n${table}`;\n}\n","import {\n agentsLeftOutOfCodexMessage,\n unexpressibleOnCodexMessage,\n} from \"@workspace/compile/agent-source\";\n\nimport { codexProjectTrustMessage, trustCodexProject } from \"./codex-project-trust.js\";\nimport { agentCodec, agentsDir } from \"../installation/install-layout.js\";\nimport { glob } from \"../../utils/fs.js\";\nimport type { Provider } from \"../../consts.js\";\n\n/** Once per run, not per sub-agent or scope: each notice is true of the whole installation. */\nexport async function codexCompileNotices(\n provider: Provider,\n projectDir: string,\n): Promise<string[]> {\n if (provider !== \"codex\") return [];\n\n return [\n agentsLeftOutOfCodexMessage(),\n unexpressibleOnCodexMessage(),\n ...(await trustNotice(projectDir)),\n ];\n}\n\n/** Only when role files exist: trusting a project with nothing for Codex to read grants nothing. */\nasync function trustNotice(projectDir: string): Promise<string[]> {\n if (!(await holdsProjectRoles(projectDir))) return [];\n\n const said = codexProjectTrustMessage(projectDir, await trustCodexProject(projectDir));\n return said === undefined ? [] : [said];\n}\n\nasync function holdsProjectRoles(projectDir: string): Promise<boolean> {\n const roles = await glob(agentCodec(\"codex\").listGlob, agentsDir(\"codex\", \"project\", projectDir));\n\n return roles.length > 0;\n}\n","import { claudeCompileNotices } from \"./claude-project-trust.js\";\nimport { codexCompileNotices } from \"./codex-compile-notices.js\";\nimport type { Provider } from \"../../consts.js\";\n\n/** The one source `init` and `compile` share, so they cannot say different things. */\nexport async function hostCompileNotices(\n provider: Provider,\n projectDir: string,\n): Promise<string[]> {\n switch (provider) {\n case \"claude\":\n return claudeCompileNotices(provider, projectDir);\n case \"codex\":\n return codexCompileNotices(provider, projectDir);\n default: {\n const _exhaustive: never = provider;\n return _exhaustive;\n }\n }\n}\n"],"mappings":"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","names":["path","path"]}
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  CLI_COLORS,
4
4
  UI_SYMBOLS
5
- } from "./chunk-A6OWEJGC.js";
5
+ } from "./chunk-MHAQWMNJ.js";
6
6
 
7
7
  // src/cli/components/common/select-list.tsx
8
8
  import { useCallback as useCallback2 } from "react";
@@ -103,4 +103,4 @@ function SelectList({
103
103
  export {
104
104
  SelectList
105
105
  };
106
- //# sourceMappingURL=chunk-ZC6GC66J.js.map
106
+ //# sourceMappingURL=chunk-3R3LHA4Q.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  seatCatalog
4
- } from "./chunk-A6OWEJGC.js";
4
+ } from "./chunk-MHAQWMNJ.js";
5
5
 
6
6
  // src/cli/utils/string.ts
7
7
  var OSC = /\u001B\][\s\S]*?(?:\u0007|\u001B\\|$)/;
@@ -16,6 +16,9 @@ var TERMINAL_CONTROLS = anyOf([OSC, CSI, OTHER_ESCAPE, C1, C0]);
16
16
  function stripTerminalControls(text) {
17
17
  return text.replace(TERMINAL_CONTROLS, "");
18
18
  }
19
+ function inertLine(text) {
20
+ return stripTerminalControls(text).replaceAll("\n", " ");
21
+ }
19
22
  function truncateText(text, maxLength) {
20
23
  const inert = stripTerminalControls(text);
21
24
  if (inert.length <= maxLength) return inert;
@@ -9344,14 +9347,29 @@ function getSkillById(id) {
9344
9347
  return skill;
9345
9348
  }
9346
9349
  function getSkillDisplayName(id) {
9347
- return stripTerminalControls(matrix.skills[id]?.displayName ?? id);
9350
+ return inertLine(matrix.skills[id]?.displayName ?? id);
9348
9351
  }
9349
9352
  function getCategoryDomain(category) {
9350
9353
  return matrix.categories[category]?.domain;
9351
9354
  }
9352
9355
 
9356
+ // src/cli/utils/typed-object.ts
9357
+ function typedEntries(obj) {
9358
+ return Object.entries(obj);
9359
+ }
9360
+ function typedKeys(obj) {
9361
+ return Object.keys(obj);
9362
+ }
9363
+ function typedFromEntries(entries) {
9364
+ return Object.fromEntries(entries);
9365
+ }
9366
+ function typedValues(obj) {
9367
+ return Object.values(obj).filter((value) => value !== void 0);
9368
+ }
9369
+
9353
9370
  export {
9354
9371
  stripTerminalControls,
9372
+ inertLine,
9355
9373
  truncateText,
9356
9374
  plural,
9357
9375
  toTitleCase,
@@ -9360,6 +9378,10 @@ export {
9360
9378
  initializeMatrix,
9361
9379
  getSkillById,
9362
9380
  getSkillDisplayName,
9363
- getCategoryDomain
9381
+ getCategoryDomain,
9382
+ typedEntries,
9383
+ typedKeys,
9384
+ typedFromEntries,
9385
+ typedValues
9364
9386
  };
9365
- //# sourceMappingURL=chunk-24OD7IP4.js.map
9387
+ //# sourceMappingURL=chunk-7OG635DK.js.map