@aiwg/cli 2026.10.5 → 2026.10.7

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 (263) hide show
  1. package/agentic/code/addons/composition-engine/lib/runtime.mjs +1401 -0
  2. package/agentic/code/addons/composition-engine/lib/validator.mjs +513 -0
  3. package/agentic/code/addons/composition-engine/schemas/flow-graph.schema.json +372 -0
  4. package/agentic/code/providers/model-capabilities.v1.json +74 -50
  5. package/bin/aiwg.mjs +7 -3
  6. package/dist/src/a2a/agent-card.js +11 -0
  7. package/dist/src/api/index.d.ts +1 -0
  8. package/dist/src/api/index.js +1 -0
  9. package/dist/src/artifacts/browser-export.js +1 -0
  10. package/dist/src/artifacts/citation-parser.js +8 -1
  11. package/dist/src/artifacts/cli.js +57 -6
  12. package/dist/src/artifacts/fortemi-core-query-adapter.js +2 -0
  13. package/dist/src/artifacts/fortemi-core-sync.js +26 -8
  14. package/dist/src/artifacts/fortemi-shard-contract/2.2.0/contract.json +103 -0
  15. package/dist/src/artifacts/fortemi-shard-contract/2.2.0/full-v1-embedding-config.schema.json +212 -0
  16. package/dist/src/artifacts/fortemi-shard-contract/2.2.0/full-v1-embedding-set.schema.json +240 -0
  17. package/dist/src/artifacts/fortemi-shard-contract/2.2.0/full-v1-manifest.schema.json +451 -0
  18. package/dist/src/artifacts/fortemi-shard-export.js +284 -0
  19. package/dist/src/artifacts/graph-query.js +18 -8
  20. package/dist/src/artifacts/index-adapters.js +339 -0
  21. package/dist/src/artifacts/index-builder.js +143 -14
  22. package/dist/src/artifacts/index-files.js +15 -4
  23. package/dist/src/artifacts/index-preparation.js +2 -0
  24. package/dist/src/artifacts/index-reader.js +44 -0
  25. package/dist/src/artifacts/index-refresh.js +114 -55
  26. package/dist/src/artifacts/index-status.js +20 -5
  27. package/dist/src/artifacts/memory-maintenance.js +503 -0
  28. package/dist/src/artifacts/prebuilt-relations.js +3 -1
  29. package/dist/src/artifacts/query-engine.js +263 -108
  30. package/dist/src/artifacts/relations-builder.js +2 -2
  31. package/dist/src/artifacts/source-graph.js +2 -2
  32. package/dist/src/artifacts/types.js +9 -1
  33. package/dist/src/auth/client.js +5 -1
  34. package/dist/src/auth/credential-store.js +5 -1
  35. package/dist/src/auth/sensitive-input.js +151 -0
  36. package/dist/src/channel/manager.mjs +3 -0
  37. package/dist/src/cli/handlers/agentcard.js +47 -25
  38. package/dist/src/cli/handlers/auth.js +22 -2
  39. package/dist/src/cli/handlers/decision.js +22 -3
  40. package/dist/src/cli/handlers/effect.js +4 -84
  41. package/dist/src/cli/handlers/guided-setup.js +470 -0
  42. package/dist/src/cli/handlers/help.js +2 -2
  43. package/dist/src/cli/handlers/housekeeper.js +1110 -0
  44. package/dist/src/cli/handlers/index.js +4 -2
  45. package/dist/src/cli/handlers/init.js +41 -6
  46. package/dist/src/cli/handlers/install.js +6 -0
  47. package/dist/src/cli/handlers/local-executor.js +5 -3
  48. package/dist/src/cli/handlers/marketplace.js +15 -4
  49. package/dist/src/cli/handlers/mc.js +509 -53
  50. package/dist/src/cli/handlers/models.js +32 -2
  51. package/dist/src/cli/handlers/ralph-launcher.js +76 -4
  52. package/dist/src/cli/handlers/rules.js +1 -1
  53. package/dist/src/cli/handlers/script-runner.js +73 -2
  54. package/dist/src/cli/handlers/serve.js +5 -3
  55. package/dist/src/cli/handlers/sessions.js +1 -0
  56. package/dist/src/cli/handlers/setup.js +432 -1
  57. package/dist/src/cli/handlers/skill-lint.js +1 -1
  58. package/dist/src/cli/handlers/subcommands.js +118 -8
  59. package/dist/src/cli/handlers/use.js +335 -107
  60. package/dist/src/cli/handlers/workspace.js +3 -1
  61. package/dist/src/cli/prompt-utils.js +81 -0
  62. package/dist/src/cli/router.js +16 -1
  63. package/dist/src/config/aiwg-config.js +42 -0
  64. package/dist/src/config/cli.js +7 -3
  65. package/dist/src/config/decision-config.js +14 -1
  66. package/dist/src/config/gitignore.js +4 -0
  67. package/dist/src/config/native-sandbox-warnings.js +25 -0
  68. package/dist/src/config/workspace.js +2 -1
  69. package/dist/src/contributors/validation.js +6 -5
  70. package/dist/src/decision/adapters/jev.js +20 -31
  71. package/dist/src/decision/admission.js +7 -3
  72. package/dist/src/decision/ask.js +6 -1
  73. package/dist/src/decision/benchmark.js +482 -0
  74. package/dist/src/decision/ledger.js +22 -3
  75. package/dist/src/decision/pricing.js +147 -0
  76. package/dist/src/decision/qualification/gate-evidence.js +23 -18
  77. package/dist/src/decision/qualification/load-staged.js +576 -0
  78. package/dist/src/decision/qualification/load.js +109 -33
  79. package/dist/src/decision/qualification/runner.js +12 -5
  80. package/dist/src/decision/review/service.js +6 -4
  81. package/dist/src/decision/review/validate.js +23 -2
  82. package/dist/src/decision/savings.js +8 -3
  83. package/dist/src/discovery/index.js +492 -0
  84. package/dist/src/discovery/interview.js +238 -0
  85. package/dist/src/discovery/plan-apply.js +567 -0
  86. package/dist/src/discovery/plan-store.js +171 -0
  87. package/dist/src/discovery/plan-types.js +2 -0
  88. package/dist/src/discovery/plan-validation.js +139 -0
  89. package/dist/src/discovery/types.js +2 -0
  90. package/dist/src/effects/host.js +91 -0
  91. package/dist/src/extensions/commands/definitions.js +49 -9
  92. package/dist/src/extensions/manifest.js +71 -44
  93. package/dist/src/extensions/project-local-discovery.js +1 -1
  94. package/dist/src/extensions/project-local-gitignore.js +2 -0
  95. package/dist/src/extensions/project-quickref.js +18 -17
  96. package/dist/src/extensions/validation.js +32 -29
  97. package/dist/src/housekeeper/daemon-config.js +148 -0
  98. package/dist/src/housekeeper/ipc.js +84 -0
  99. package/dist/src/housekeeper/lifecycle.js +148 -0
  100. package/dist/src/housekeeper/platform.js +35 -0
  101. package/dist/src/housekeeper/status.js +70 -0
  102. package/dist/src/housekeeper/units.js +114 -0
  103. package/dist/src/issues/cli.js +16 -5
  104. package/dist/src/issues/live.js +44 -12
  105. package/dist/src/jobs/flow.js +22 -21
  106. package/dist/src/lint/rule-activation.js +20 -5
  107. package/dist/src/lint/runner.js +1 -1
  108. package/dist/src/marketplace/exchange.js +18 -6
  109. package/dist/src/marketplace/provenance.js +3 -2
  110. package/dist/src/mcp/adapters/codex-runtime.js +46 -76
  111. package/dist/src/mcp/cli.mjs +22 -96
  112. package/dist/src/mcp/config-file.mjs +6 -2
  113. package/dist/src/mcp/config-layers.mjs +23 -7
  114. package/dist/src/mcp/grok-build-config.mjs +2 -1
  115. package/dist/src/mcp/muse-native-config.mjs +2 -1
  116. package/dist/src/mcp/profiles.js +18 -31
  117. package/dist/src/mcp/profiles.mjs +18 -32
  118. package/dist/src/mcp/registry.js +7 -27
  119. package/dist/src/mcp/registry.mjs +7 -28
  120. package/dist/src/mcp/server.mjs +34 -1
  121. package/dist/src/mcp/tools/agentic-sandbox.mjs +8 -7
  122. package/dist/src/mcp/tools/command-run.mjs +3 -2
  123. package/dist/src/mcp/tools/decision.mjs +49 -48
  124. package/dist/src/mcp/tools/discovery.mjs +46 -21
  125. package/dist/src/mcp/tools/orchestration.mjs +22 -22
  126. package/dist/src/mcp/tools/subsystems.mjs +9 -8
  127. package/dist/src/mcp/tools/worker-invoke.mjs +30 -6
  128. package/dist/src/mcp/tools/writer-profiles.mjs +1 -1
  129. package/dist/src/memory/audit.js +719 -0
  130. package/dist/src/memory/canonical-context.js +392 -13
  131. package/dist/src/memory/canonical-maintenance.js +95 -0
  132. package/dist/src/memory/cli-result.js +22 -0
  133. package/dist/src/memory/cli.js +176 -0
  134. package/dist/src/memory/context-pack.js +57 -6
  135. package/dist/src/memory/cost.js +512 -0
  136. package/dist/src/memory/firewall-classification.d.mts +7 -0
  137. package/dist/src/memory/firewall-classification.mjs +32 -0
  138. package/dist/src/memory/index.js +8 -0
  139. package/dist/src/memory/line-maintenance.js +68 -0
  140. package/dist/src/memory/maintenance-cli.js +286 -0
  141. package/dist/src/memory/maintenance-contract.js +136 -0
  142. package/dist/src/memory/maintenance-index.js +18 -0
  143. package/dist/src/memory/maintenance-owner.js +2 -0
  144. package/dist/src/memory/maintenance-record.js +138 -0
  145. package/dist/src/memory/maintenance.js +254 -0
  146. package/dist/src/memory/project-registry.js +2 -1
  147. package/dist/src/memory/provider-memory-adapter.js +154 -0
  148. package/dist/src/memory/recommend-cli.js +83 -0
  149. package/dist/src/memory/recommend.js +269 -0
  150. package/dist/src/memory/scheduled.js +81 -0
  151. package/dist/src/memory/taxonomy.js +44 -0
  152. package/dist/src/mission-protocol/codecs.js +19 -9
  153. package/dist/src/mission-protocol/worker-status.js +91 -1
  154. package/dist/src/models/config-loader.js +11 -1
  155. package/dist/src/models/model-capabilities.v1.json +74 -50
  156. package/dist/src/models/provider-policy.js +125 -62
  157. package/dist/src/models/resolver.js +45 -8
  158. package/dist/src/models/worker-installation.d.mts +8 -1
  159. package/dist/src/models/worker-installation.mjs +231 -38
  160. package/dist/src/models/wrapper-route.js +1 -1
  161. package/dist/src/output-modes/registry.js +8 -7
  162. package/dist/src/packages/adapters/git.js +99 -23
  163. package/dist/src/packages/adapters/gitea.js +8 -27
  164. package/dist/src/packages/adapters/github.js +7 -25
  165. package/dist/src/packages/registry.js +4 -4
  166. package/dist/src/plugin/metadata-validator.js +1 -1
  167. package/dist/src/process/cli-command.d.mts +5 -0
  168. package/dist/src/process/cli-command.mjs +42 -0
  169. package/dist/src/providers/deploy-version.d.mts +1 -0
  170. package/dist/src/providers/deploy-version.mjs +17 -0
  171. package/dist/src/providers/provider-definitions.js +19 -16
  172. package/dist/src/providers/skill-ownership.d.mts +11 -2
  173. package/dist/src/providers/skill-ownership.mjs +35 -17
  174. package/dist/src/rules/activation.d.mts +11 -2
  175. package/dist/src/rules/activation.mjs +82 -6
  176. package/dist/src/rules/inventory.js +1 -1
  177. package/dist/src/rules/rule-frontmatter.schema.json +2 -0
  178. package/dist/src/schema/zod-validation.d.mts +6 -0
  179. package/dist/src/schema/zod-validation.mjs +50 -0
  180. package/dist/src/serve/executor-registry.js +297 -20
  181. package/dist/src/serve/executor-token.d.mts +1 -0
  182. package/dist/src/serve/executor-token.mjs +8 -0
  183. package/dist/src/serve/shared-host-scheduler.js +1102 -31
  184. package/dist/src/serve/worker-invocation.js +124 -15
  185. package/dist/src/sessions/adapters/claude.js +19 -18
  186. package/dist/src/sessions/adapters/codex.js +10 -9
  187. package/dist/src/sessions/adapters/copilot.js +14 -13
  188. package/dist/src/sessions/adapters/cursor.js +19 -18
  189. package/dist/src/sessions/adapters/deepseek-harness.js +9 -8
  190. package/dist/src/sessions/adapters/factory.js +11 -10
  191. package/dist/src/sessions/adapters/generic.js +32 -23
  192. package/dist/src/sessions/adapters/grokbot.js +35 -35
  193. package/dist/src/sessions/adapters/hermes.js +20 -19
  194. package/dist/src/sessions/adapters/muse.js +50 -49
  195. package/dist/src/sessions/adapters/omp.js +5 -4
  196. package/dist/src/sessions/adapters/openclaw.js +30 -29
  197. package/dist/src/sessions/adapters/opencode.js +26 -26
  198. package/dist/src/sessions/adapters/openhuman.js +24 -23
  199. package/dist/src/sessions/adapters/pi.js +5 -4
  200. package/dist/src/sessions/adapters/windsurf.js +8 -8
  201. package/dist/src/sessions/analytics.js +10 -9
  202. package/dist/src/sessions/candidates.js +7 -6
  203. package/dist/src/sessions/contracts.js +63 -53
  204. package/dist/src/sessions/output-registration.js +11 -10
  205. package/dist/src/sessions/workspace-discovery.js +3 -4
  206. package/dist/src/smiths/context-pipeline/aiwg-md.js +18 -1
  207. package/dist/src/smiths/context-pipeline/claude-hook.js +46 -10
  208. package/dist/src/smiths/context-pipeline/context-file-safety.js +330 -9
  209. package/dist/src/smiths/context-pipeline/finalization.js +3 -2
  210. package/dist/src/smiths/context-pipeline/generator.js +7 -19
  211. package/dist/src/smiths/context-pipeline/legacy-inject.js +3 -10
  212. package/dist/src/smiths/context-pipeline/managed-hook.js +5 -5
  213. package/dist/src/smiths/context-pipeline/parallelism-section.js +72 -5
  214. package/dist/src/smiths/context-pipeline/workspace-context.js +110 -22
  215. package/dist/src/tracker/project-inputs.js +2 -0
  216. package/dist/src/update/checker.d.mts +4 -0
  217. package/dist/src/update/checker.mjs +14 -0
  218. package/dist/src/update/notifier.mjs +2 -4
  219. package/dist/src/writing/exemplar-selection.js +6 -6
  220. package/dist/src/writing/voice-evaluation.js +24 -23
  221. package/dist/src/writing/writer-migration.js +14 -13
  222. package/dist/src/writing/writer-profile.js +19 -18
  223. package/dist/src/writing/writing-brief.js +18 -17
  224. package/dist/src/writing/writing-receipt.js +47 -46
  225. package/package.json +5 -2
  226. package/schemas/decision/DecisionReview.schema.json +78 -1
  227. package/schemas/mission-v1.schema.json +3 -0
  228. package/tools/agents/deploy-agents.mjs +67 -39
  229. package/tools/agents/providers/antigravity.mjs +6 -1
  230. package/tools/agents/providers/base.mjs +24 -14
  231. package/tools/agents/providers/claude.mjs +6 -3
  232. package/tools/agents/providers/codex.mjs +54 -57
  233. package/tools/agents/providers/context-write.mjs +28 -0
  234. package/tools/agents/providers/copilot.mjs +13 -4
  235. package/tools/agents/providers/cursor.mjs +1 -1
  236. package/tools/agents/providers/deepseek-harness.mjs +1 -1
  237. package/tools/agents/providers/factory.mjs +7 -1
  238. package/tools/agents/providers/grok-build.mjs +18 -2
  239. package/tools/agents/providers/grokbot.mjs +1 -1
  240. package/tools/agents/providers/hermes.mjs +12 -15
  241. package/tools/agents/providers/muse-hooks.mjs +21 -14
  242. package/tools/agents/providers/muse.mjs +7 -2
  243. package/tools/agents/providers/omp.mjs +31 -5
  244. package/tools/agents/providers/opencode.mjs +14 -5
  245. package/tools/agents/providers/openhuman.mjs +1 -1
  246. package/tools/agents/providers/pi.mjs +1 -1
  247. package/tools/agents/providers/provider-prepare-coordinator.mjs +29 -9
  248. package/tools/agents/providers/rule-delivery.mjs +289 -80
  249. package/tools/agents/providers/warp.mjs +4 -1
  250. package/tools/agents/providers/windsurf.mjs +13 -3
  251. package/tools/cli/workspace-status.mjs +5 -0
  252. package/tools/commands/deploy-prompts-codex.mjs +11 -8
  253. package/tools/ralph-external/lib/codex-adapter.mjs +6 -2
  254. package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +26 -0
  255. package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +7 -1
  256. package/tools/ralph-external/lib/muse-adapter.mjs +12 -2
  257. package/tools/ralph-external/lib/recovery-probe.mjs +14 -4
  258. package/tools/ralph-external/lib/worker-health.mjs +1 -1
  259. package/tools/ralph-external/lib/worker-isolation.mjs +65 -9
  260. package/tools/ralph-external/process-monitor.mjs +49 -8
  261. package/tools/ralph-external/session-launcher.mjs +405 -35
  262. package/tools/skills/deploy-skills-codex.mjs +11 -7
  263. package/vscode-extension/schemas/aiwg.config.v1.json +11 -1
@@ -0,0 +1,151 @@
1
+ import { constants } from 'node:fs';
2
+ import { lstat, open } from 'node:fs/promises';
3
+ import { isInteractive } from '../cli/env.js';
4
+ import { askMultilineSecret, askString, createSecretPromptInterface } from '../cli/prompt-utils.js';
5
+ import { createSecretStore } from './credential-store.js';
6
+ /** Named raw values share the native store used by auth login, in a separate service. */
7
+ export const SENSITIVE_VALUE_SERVICE = 'aiwg.sensitive-values';
8
+ export function namedSensitiveStore(name) {
9
+ if (!/^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$/.test(name)) {
10
+ throw new Error('Sensitive value store name must contain only letters, digits, dots, underscores or hyphens (1–128 characters).');
11
+ }
12
+ return createSecretStore({ service: SENSITIVE_VALUE_SERVICE, account: name });
13
+ }
14
+ /** Extract references, never literal values, from the standard command options. */
15
+ export function sensitiveInputOptions(args, prefix = 'value') {
16
+ const result = { prefix };
17
+ for (let index = 0; index < args.length; index += 1) {
18
+ const token = args[index];
19
+ if (token === '--')
20
+ break;
21
+ for (const source of ['file', 'store', 'env']) {
22
+ const flag = `--${prefix}-${source}`;
23
+ if (token !== flag && !token.startsWith(`${flag}=`))
24
+ continue;
25
+ const value = token === flag ? args[++index] : token.slice(flag.length + 1);
26
+ if (!value || value.startsWith('--'))
27
+ throw new Error(`${flag} requires a value`);
28
+ if (result[source] !== undefined)
29
+ throw new Error(`${flag} may only be given once`);
30
+ result[source] = value;
31
+ }
32
+ if (token === `--${prefix}-stdin`)
33
+ result.stdin = true;
34
+ if (token === `--${prefix}-interactive`)
35
+ result.interactive = true;
36
+ }
37
+ return result;
38
+ }
39
+ /** Extracted from MCP profile login: validate the opened descriptor, never a later path read. */
40
+ export async function readPrivateValueFile(filePath, flag = '--value-file') {
41
+ if (process.platform === 'win32')
42
+ throw new Error(`${flag}: private-file input requires native ACL validation on Windows; use stdin or the OS store.`);
43
+ try {
44
+ const pre = await lstat(filePath);
45
+ if (pre.isSymbolicLink())
46
+ throw new Error('file is a symlink; refusing to follow it');
47
+ // Reject FIFOs/devices before open, which could otherwise wait indefinitely.
48
+ if (!pre.isFile())
49
+ throw new Error('not a regular file');
50
+ }
51
+ catch (error) {
52
+ const code = error.code;
53
+ throw new Error(`${flag}: ${code === 'ENOENT' ? 'file does not exist' : code ? 'cannot stat private file' : error.message}.`);
54
+ }
55
+ let handle;
56
+ try {
57
+ handle = await open(filePath, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0));
58
+ }
59
+ catch {
60
+ throw new Error(`${flag}: cannot open private file (symlinks are refused).`);
61
+ }
62
+ try {
63
+ const stat = await handle.stat();
64
+ if (!stat.isFile())
65
+ throw new Error(`${flag}: not a regular file.`);
66
+ if (stat.nlink !== 1)
67
+ throw new Error(`${flag}: more than one hard link; refusing to read it.`);
68
+ if (typeof process.getuid === 'function' && stat.uid !== process.getuid()) {
69
+ throw new Error(`${flag}: file is not owned by the current user.`);
70
+ }
71
+ if ((stat.mode & 0o077) !== 0)
72
+ throw new Error(`${flag}: file must not allow group or other access (chmod 600).`);
73
+ return (await handle.readFile({ encoding: 'utf8' })).trim();
74
+ }
75
+ finally {
76
+ await handle.close();
77
+ }
78
+ }
79
+ async function readStdin() {
80
+ const chunks = [];
81
+ for await (const chunk of process.stdin)
82
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
83
+ return Buffer.concat(chunks).toString('utf8');
84
+ }
85
+ /**
86
+ * Explicit entry, stdin, private file, native-store reference, named shell variable.
87
+ * No implicit stdin consumption, env discovery or store probing. An empty selected
88
+ * source is an error, never permission to try a less preferred source.
89
+ */
90
+ export async function resolveSensitiveInput(options = {}, dependencies = {}) {
91
+ const prefix = options.prefix ?? 'value';
92
+ const terminal = dependencies.isTTY ?? isInteractive();
93
+ const choices = `--${prefix}-interactive, --${prefix}-stdin, --${prefix}-file <path>, --${prefix}-store <name>, or --${prefix}-env <name>`;
94
+ const explicitSource = options.stdin || options.file !== undefined || options.store !== undefined || options.env !== undefined;
95
+ let value;
96
+ let source;
97
+ if (options.interactive || (!explicitSource && terminal)) {
98
+ if (!terminal)
99
+ throw new Error(`An interactive terminal is required; supply ${choices}.`);
100
+ source = `--${prefix}-interactive`;
101
+ if (dependencies.prompt)
102
+ value = await dependencies.prompt(prefix);
103
+ else {
104
+ const rl = createSecretPromptInterface();
105
+ try {
106
+ process.stderr.write(`Enter ${prefix} (hidden${options.multiline ? '; finish with an empty line' : ''}): `);
107
+ value = options.multiline ? await askMultilineSecret(rl, options.signal) : await askString(rl, '', '', options.signal);
108
+ }
109
+ finally {
110
+ rl.close();
111
+ process.stderr.write('\n');
112
+ }
113
+ }
114
+ }
115
+ else if (options.stdin) {
116
+ source = `--${prefix}-stdin`;
117
+ if (dependencies.stdinIsTTY ?? dependencies.isTTY ?? Boolean(process.stdin.isTTY))
118
+ throw new Error(`${source} requires piped input, not a terminal.`);
119
+ value = await (dependencies.readStdin ?? readStdin)();
120
+ }
121
+ else if (options.file !== undefined) {
122
+ source = `--${prefix}-file`;
123
+ value = await (dependencies.readFile ? dependencies.readFile(options.file) : readPrivateValueFile(options.file, source));
124
+ }
125
+ else if (options.store !== undefined) {
126
+ source = `--${prefix}-store`;
127
+ try {
128
+ value = await (dependencies.readStore ? dependencies.readStore(options.store) : namedSensitiveStore(options.store).loadSecret());
129
+ }
130
+ catch {
131
+ throw new Error(`${source}: native store entry could not be read.`);
132
+ }
133
+ }
134
+ else if (options.env !== undefined) {
135
+ source = `--${prefix}-env`;
136
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(options.env))
137
+ throw new Error(`${source} requires a shell variable name.`);
138
+ value = dependencies.readEnv ? dependencies.readEnv(options.env) : (dependencies.environment ?? process.env)[options.env];
139
+ }
140
+ else {
141
+ throw new Error(`A sensitive value requires an interactive terminal, or a key supplied via ${choices}.`);
142
+ }
143
+ const trimmed = value?.trim();
144
+ if (!trimmed)
145
+ throw new Error(`${source} received no key (input is empty or not set${options.env && source.endsWith('-env') ? `: ${options.env}` : ''}).`);
146
+ const controls = options.multiline ? /[\u0000-\u0009\u000b\u000c\u000e-\u001f\u007f]/ : /[\u0000-\u001f\u007f]/;
147
+ if (trimmed.length > 16384 || controls.test(trimmed))
148
+ throw new Error(`${source} requires ${options.multiline ? 'non-empty text without control characters' : 'one non-empty line'} (at most 16384 characters).`);
149
+ return trimmed;
150
+ }
151
+ //# sourceMappingURL=sensitive-input.js.map
@@ -18,6 +18,7 @@ import { spawn } from 'child_process';
18
18
  import os from 'os';
19
19
  import { resolveUserConfigDir } from '../config/user-config-dir.mjs';
20
20
  import { boundedExecFileSync } from '../process/bounded-child-process.mjs';
21
+ import { helperEnvironment } from '../process/cli-command.mjs';
21
22
  import {
22
23
  assertCanonicalInstallation,
23
24
  createInstallationIdentity,
@@ -594,10 +595,12 @@ export async function getVersionInfo() {
594
595
  try {
595
596
  const gitHash = boundedExecFileSync('git', ['rev-parse', '--short', 'HEAD'], 'quick', {
596
597
  cwd: config.edgePath,
598
+ env: helperEnvironment(),
597
599
  encoding: 'utf8',
598
600
  }).trim();
599
601
  const gitBranch = boundedExecFileSync('git', ['branch', '--show-current'], 'quick', {
600
602
  cwd: config.edgePath,
603
+ env: helperEnvironment(),
601
604
  encoding: 'utf8',
602
605
  }).trim();
603
606
  info.edgePath = config.edgePath;
@@ -10,6 +10,7 @@
10
10
  * @issue #1253
11
11
  */
12
12
  import { fetchAgentCard } from '../../a2a/agent-card.js';
13
+ import { resolveSensitiveInput, sensitiveInputOptions } from '../../auth/sensitive-input.js';
13
14
  import { loadJwkSet } from '../../a2a/jws.js';
14
15
  import { AiwgError, EXIT_CODES, handlerResultFromError } from '../errors.js';
15
16
  function parseVerifyArgs(args) {
@@ -39,6 +40,9 @@ function parseVerifyArgs(args) {
39
40
  }
40
41
  const jwks = get('--jwks');
41
42
  const bearer = get('--bearer');
43
+ if (args.includes('--bearer') && (!bearer || bearer.startsWith('--'))) {
44
+ throw new AiwgError({ code: 'ERR_AGENTCARD_BEARER', message: '--bearer requires a value; prefer --bearer-stdin, --bearer-file, --bearer-store or --bearer-env.', exitCode: EXIT_CODES.USAGE });
45
+ }
42
46
  const skipVerify = args.includes('--skip-verify');
43
47
  const json = args.includes('--json');
44
48
  if (!jwks && !skipVerify) {
@@ -73,36 +77,49 @@ async function loadJwksFromSource(source) {
73
77
  }
74
78
  async function handleVerify(args) {
75
79
  const parsed = parseVerifyArgs(args);
80
+ const sources = sensitiveInputOptions(args, 'bearer');
81
+ const hasSource = sources.interactive || sources.stdin || sources.file !== undefined || sources.store !== undefined || sources.env !== undefined;
82
+ if (parsed.bearer !== undefined) {
83
+ console.error('Warning: --bearer is deprecated and exposes the value on argv; use --bearer-interactive, --bearer-stdin, --bearer-file, --bearer-store or --bearer-env.');
84
+ }
85
+ // No source intentionally means public/unauthenticated access, even at a TTY.
86
+ const bearer = hasSource
87
+ ? await resolveSensitiveInput(sources)
88
+ : parsed.bearer === undefined ? undefined : await resolveSensitiveInput({ prefix: 'bearer', env: 'LEGACY_BEARER' }, { readEnv: () => parsed.bearer });
89
+ const redact = (text) => bearer ? text.split(bearer).join('[REDACTED]') : text;
90
+ const log = (text) => console.log(redact(text));
91
+ const error = (text) => console.error(redact(text));
92
+ const jsonReplacer = (_key, value) => typeof value === 'string' ? redact(value) : value;
76
93
  const opts = {
77
94
  skipVerify: parsed.skipVerify,
78
95
  };
79
- if (parsed.bearer !== undefined)
80
- opts.bearer = parsed.bearer;
81
- if (parsed.jwks !== undefined && !parsed.skipVerify) {
82
- opts.jwks = await loadJwksFromSource(parsed.jwks);
83
- }
96
+ if (bearer !== undefined)
97
+ opts.bearer = bearer;
84
98
  let verified;
85
99
  try {
100
+ if (parsed.jwks !== undefined && !parsed.skipVerify) {
101
+ opts.jwks = await loadJwksFromSource(parsed.jwks);
102
+ }
86
103
  verified = await fetchAgentCard(parsed.host, parsed.instance, opts);
87
104
  }
88
105
  catch (err) {
89
106
  const message = err.message;
90
107
  if (parsed.json) {
91
- console.log(JSON.stringify({
108
+ log(JSON.stringify({
92
109
  ok: false,
93
110
  host: parsed.host,
94
111
  instance: parsed.instance,
95
112
  error: message,
96
- }, null, 2));
113
+ }, jsonReplacer, 2));
97
114
  }
98
115
  else {
99
- console.error(`AgentCard verification FAILED for ${parsed.host}/${parsed.instance}`);
100
- console.error(` ${message}`);
116
+ error(`AgentCard verification FAILED for ${parsed.host}/${parsed.instance}`);
117
+ error(` ${message}`);
101
118
  }
102
119
  return { exitCode: EXIT_CODES.GENERAL };
103
120
  }
104
121
  if (parsed.json) {
105
- console.log(JSON.stringify({
122
+ log(JSON.stringify({
106
123
  ok: true,
107
124
  host: parsed.host,
108
125
  instance: parsed.instance,
@@ -118,38 +135,38 @@ async function handleVerify(args) {
118
135
  capabilities: verified.card.capabilities,
119
136
  skills: verified.card.skills,
120
137
  },
121
- }, null, 2));
138
+ }, jsonReplacer, 2));
122
139
  }
123
140
  else {
124
141
  const banner = parsed.skipVerify ? '(verification SKIPPED)' : 'VERIFIED';
125
- console.log(`AgentCard ${banner} for ${parsed.host}/${parsed.instance}`);
126
- console.log(` name: ${verified.card.name}`);
127
- console.log(` protocolVersion: ${verified.card.protocolVersion}`);
128
- console.log(` url: ${verified.card.url}`);
129
- console.log(` version: ${verified.card.version}`);
142
+ log(`AgentCard ${banner} for ${parsed.host}/${parsed.instance}`);
143
+ log(` name: ${verified.card.name}`);
144
+ log(` protocolVersion: ${verified.card.protocolVersion}`);
145
+ log(` url: ${verified.card.url}`);
146
+ log(` version: ${verified.card.version}`);
130
147
  if (verified.card.preferredTransport) {
131
- console.log(` preferredTransport: ${verified.card.preferredTransport}`);
148
+ log(` preferredTransport: ${verified.card.preferredTransport}`);
132
149
  }
133
150
  if (verified.kid) {
134
- console.log(` signing kid: ${verified.kid}`);
151
+ log(` signing kid: ${verified.kid}`);
135
152
  }
136
- console.log(` verifiedAt: ${verified.verifiedAt}`);
153
+ log(` verifiedAt: ${verified.verifiedAt}`);
137
154
  const exts = verified.card.capabilities?.extensions ?? [];
138
155
  if (exts.length > 0) {
139
- console.log(` extensions:`);
156
+ log(` extensions:`);
140
157
  for (const e of exts) {
141
158
  const tag = e.required ? '[required]' : '[optional]';
142
- console.log(` ${tag} ${e.uri}`);
159
+ log(` ${tag} ${e.uri}`);
143
160
  }
144
161
  }
145
162
  const skills = verified.card.skills ?? [];
146
163
  if (skills.length > 0) {
147
- console.log(` skills (${skills.length}):`);
164
+ log(` skills (${skills.length}):`);
148
165
  for (const s of skills.slice(0, 5)) {
149
- console.log(` - ${s.id}${s.name ? ' (' + s.name + ')' : ''}`);
166
+ log(` - ${s.id}${s.name ? ' (' + s.name + ')' : ''}`);
150
167
  }
151
168
  if (skills.length > 5)
152
- console.log(` ... and ${skills.length - 5} more`);
169
+ log(` ... and ${skills.length - 5} more`);
153
170
  }
154
171
  }
155
172
  return { exitCode: 0 };
@@ -164,7 +181,12 @@ function printUsage() {
164
181
  console.log(' --host <url> Executor host (e.g. https://exec.test)');
165
182
  console.log(' --instance <id> Instance id (UUIDv7)');
166
183
  console.log(' --jwks <path|url> JWKS file path or URL (required unless --skip-verify)');
167
- console.log(' --bearer <token> Optional bearer token for the card endpoint');
184
+ console.log(' --bearer-interactive Read optional bearer in a terminal without echo');
185
+ console.log(' --bearer-stdin Read optional bearer from piped stdin');
186
+ console.log(' --bearer-file <path> Read optional bearer from an owner-only private file');
187
+ console.log(' --bearer-store <name> Read optional bearer from a named OS store entry');
188
+ console.log(' --bearer-env <NAME> Read optional bearer from a named shell variable');
189
+ console.log(' --bearer <token> Deprecated: exposes the value on argv');
168
190
  console.log(' --skip-verify Skip JWS verification (NOT recommended)');
169
191
  console.log(' --json Emit JSON output');
170
192
  }
@@ -1,3 +1,4 @@
1
+ import { namedSensitiveStore, resolveSensitiveInput, sensitiveInputOptions } from '../../auth/sensitive-input.js';
1
2
  import { AuthClient, defaultBrowserOpener } from "../../auth/client.js";
2
3
  import { authConfigFromEnvironment } from "../../auth/config.js";
3
4
  import { createCredentialStore } from "../../auth/credential-store.js";
@@ -5,6 +6,8 @@ function usage() {
5
6
  return [
6
7
  "Usage:",
7
8
  " aiwg auth login [--device] [--device-label <label>] [--store native|file] [--allow-file-store]",
9
+ " aiwg auth secret set <name> [--value-interactive | --value-stdin | --value-file <path> | --value-store <name> | --value-env <name>]",
10
+ " aiwg auth secret delete <name>",
8
11
  " aiwg auth status [--json] [--store native|file] [--allow-file-store]",
9
12
  " aiwg auth logout [--all] [--store native|file] [--allow-file-store]",
10
13
  "",
@@ -46,9 +49,25 @@ export function createAuthHandler(dependencies = {}) {
46
49
  return { exitCode: 0 };
47
50
  }
48
51
  const [subcommand, ...args] = ctx.args;
49
- if (!["login", "status", "logout"].includes(subcommand))
52
+ if (!["login", "status", "logout", "secret"].includes(subcommand))
50
53
  return { exitCode: 2, message: usage() };
51
54
  try {
55
+ if (subcommand === "secret") {
56
+ const [operation, name, ...inputArgs] = args;
57
+ if (!["set", "delete"].includes(operation) || !name || name.startsWith('--'))
58
+ return { exitCode: 2, message: usage() };
59
+ const store = (dependencies.secretStore ?? namedSensitiveStore)(name);
60
+ if (operation === "delete")
61
+ await store.deleteSecret();
62
+ else {
63
+ const secret = await resolveSensitiveInput({ ...sensitiveInputOptions(inputArgs), signal: ctx.signal }, {
64
+ environment: dependencies.env, ...dependencies.sensitiveInput,
65
+ });
66
+ await store.saveSecret(secret);
67
+ }
68
+ console.log(operation === "delete" ? "Named sensitive value removed." : "Named sensitive value stored.");
69
+ return { exitCode: 0 };
70
+ }
52
71
  const storeMode = value(args, "--store") || "native";
53
72
  if (!["native", "file"].includes(storeMode))
54
73
  return { exitCode: 2, message: "--store must be native or file" };
@@ -119,7 +138,8 @@ export function createAuthHandler(dependencies = {}) {
119
138
  return { exitCode: 0 };
120
139
  }
121
140
  catch (error) {
122
- return { exitCode: classify(error), message: error instanceof Error ? error.message : String(error) };
141
+ return { exitCode: classify(error), message: subcommand === 'secret' && !/^(--value-|A sensitive value|An interactive terminal|Sensitive value store name)/.test(error instanceof Error ? error.message : '')
142
+ ? 'Native sensitive value store operation failed.' : error instanceof Error ? error.message : String(error) };
123
143
  }
124
144
  },
125
145
  };
@@ -1,10 +1,12 @@
1
+ import { resolveSensitiveInput, sensitiveInputOptions } from '../../auth/sensitive-input.js';
2
+ import { decisionPricing } from '../../decision/pricing.js';
1
3
  import { ATTRIBUTION_FIELD_PATTERN, DecisionAskUsageError, decisionCapabilities, DecisionLedgerSinceError, decisionLedgerHistory, decisionLedgerStats, evaluateRequestPath, listPatterns, livePlan, MAX_ATTRIBUTION_FIELD_LENGTH, materializeSyntheticClassificationSetup, parseDecisionLedgerSince, readDecisionContextFile, runDecisionOffloadCheckpoint, runOfflinePattern, setupJev, showPattern, syntheticClassificationSetup, validateDecisionInput, } from '../../decision/driver.js';
2
4
  function jsonResult(value, exitCode = 0) {
3
5
  return { exitCode, message: JSON.stringify(value, null, 2), rawOutput: true };
4
6
  }
5
7
  function usage() {
6
8
  return [
7
- 'Usage: aiwg decision <capabilities|status|patterns|validate|evaluate|setup|history|stats> [options]',
9
+ 'Usage: aiwg decision <capabilities|status|patterns|validate|evaluate|setup|history|stats|pricing> [options]',
8
10
  ' aiwg decision ask --question "<q>" (--yes-no | --choices a,b,c | --scale 1-5) [--context <text> | --context-file <path> | --context-stdin] [--threshold 0.8] [--timeout-ms 15000] [--passes N] [--escalation-passes N] [--provider <id>] [--session <id>] [--caller <tag>] [--record-text] [--json]',
9
11
  '',
10
12
  'Commands:',
@@ -16,9 +18,10 @@ function usage() {
16
18
  ' validate <request|definition|ruleset|binding> <path>',
17
19
  ' evaluate --request <path> [--host-policy-module <path>]',
18
20
  ' setup synthetic-classification [--output-dir <dir>]',
19
- ' setup jev [--token-stdin] [--region <r>] [--endpoint <url>] [--verify] [--remove]',
21
+ ' setup jev [--token-interactive | --token-stdin | --token-file <path> | --token-store <name> | --token-env <name>] [--region <r>] [--endpoint <url>] [--verify] [--remove]',
20
22
  ' ask --question "<q>" (--yes-no | --choices a,b,c | --scale 1-5) [--provider <id>] [--session <id>] [--caller <tag>] [--record-text]',
21
23
  ' history [--since <date>] [--provider <id>] [--session <id>] [--kind yes-no|choices|scale] [--status answered|fallback] [--caller <tag>|<prefix>* | --no-caller] [--json]',
24
+ ' pricing [--refresh --model jev-X.Y.Z] [--dry-run] [--offline | --allow-snapshot] [--json]',
22
25
  ' stats [--since <date>] [--provider <id>] [--session <id>] [--kind yes-no|choices|scale] [--status answered|fallback] [--caller <tag>|<prefix>* | --no-caller] [--group-by provider|session|kind|caller|passes|escalation] [--json]',
23
26
  '',
24
27
  'Notes:',
@@ -99,7 +102,7 @@ function takeAttributionOption(args, name, reason) {
99
102
  return value;
100
103
  }
101
104
  async function decisionSetupJev(rest) {
102
- const token = rest.includes('--token-stdin') ? (await readStdin()).trim() : undefined;
105
+ const token = rest.includes('--remove') ? undefined : await resolveSensitiveInput(sensitiveInputOptions(rest, 'token'));
103
106
  const result = await setupJev({
104
107
  token,
105
108
  region: takeOption(rest, '--region'),
@@ -314,6 +317,7 @@ async function decisionStats(ctx) {
314
317
  ` jev usage: input=${group.jevUsage.inputTokens} output=${group.jevUsage.outputTokens}`,
315
318
  ` tokens per answered decision=${group.tokensPerAnsweredDecision?.toFixed(2) ?? '-'}`,
316
319
  ` llm_tokens_avoided=${group.llm_tokens_avoided} jev_tokens=${group.jev_tokens} cost_weighted_net_usd=${group.cost_weighted_net_usd.toFixed(6)}`,
320
+ ...group.ratesUsed.map(rate => ` rates used (${rate.calls} calls): ${JSON.stringify(rate.method)} source=${rate.method.source ?? 'manual'} checked_at=${rate.method.checked_at ?? 'unknown'}`),
317
321
  ` v1 comparison only: estimated LLM tokens avoided=${group.estimatedLlmTokensAvoidedTotal} net savings=${group.netSavingsTokens}`,
318
322
  ...(group.legacyReestimatedCalls ? [` v1 records re-estimated=${group.legacyReestimatedCalls} weights=${JSON.stringify(result.legacyEstimationWeights)}`] : []),
319
323
  ]);
@@ -331,6 +335,21 @@ async function executeDecision(ctx) {
331
335
  return await decisionAsk(ctx);
332
336
  if (command === 'history')
333
337
  return await decisionHistory(ctx);
338
+ if (command === 'pricing') {
339
+ const args = ctx.args.slice(1);
340
+ assertLedgerArgs(args, ['--model'], ['--refresh', '--dry-run', '--offline', '--allow-snapshot', '--json']);
341
+ const result = await decisionPricing({ cwd: ctx.cwd, refresh: args.includes('--refresh'), dryRun: args.includes('--dry-run'),
342
+ offline: args.includes('--offline'), allowSnapshot: args.includes('--allow-snapshot'), model: args.includes('--model') ? takeRequiredOption(args, '--model') : undefined });
343
+ if (args.includes('--json'))
344
+ return jsonResult(result);
345
+ return { exitCode: 0, rawOutput: true, message: [
346
+ `decision.ask.cost: ${JSON.stringify(result.current)}`,
347
+ `Source URL: ${result.sourceUrl}`,
348
+ ...('snapshotDate' in result && result.snapshotDate ? [`Bundled snapshot dated ${result.snapshotDate}`] : []),
349
+ ...('warning' in result && result.warning ? [`Warning: ${result.warning}`] : []),
350
+ ...('diff' in result ? [`${result.written ? 'Written' : 'Dry run; config unchanged'}: ${JSON.stringify(result.diff)}`] : []),
351
+ ].join('\n') };
352
+ }
334
353
  if (command === 'stats')
335
354
  return await decisionStats(ctx);
336
355
  if (command === 'patterns') {
@@ -19,10 +19,8 @@
19
19
  * @see docs/contracts/effect-ledger.v1.md
20
20
  */
21
21
  import { readFile } from 'node:fs/promises';
22
- import { basename, resolve } from 'node:path';
23
- import { createSecretStore } from '../../auth/credential-store.js';
24
- import { readAiwgConfig } from '../../config/aiwg-config.js';
25
- import { CORE_EFFECT_KINDS, DEFAULT_LEDGER_KEY_SERVICE, EFFECT_EXIT_CODES, EFFECT_SUBSYSTEMS, EffectLedgerError, LEDGER_TEST_KEY_ENV, LedgerSigningKey, activeKey, containsRestrictedMaterial, createBuiltinVerifierRegistry, createTrackerVerifiers, credentialStoreKeyProvider, effectId as deriveEffectId, effectOutputJson, environmentTestKeyProvider, generateLedgerKeySecret, initLedgerKeyring, inspectLedgerLocks, isValidEffectId, ledgerLockRecoveryVerifier, lookupEffect, openEffectLedger, payloadDigest, readLedgerKeyring, reconcileEffect, recordIntent, recordOutcome, recordReconciled, recoverStaleLedgerLock, rotateKey, runVerifier, staticKeyProvider, verifyDecisionLinks, verifyLedger, writeCheckpoint, } from '../../effects/index.js';
22
+ import { resolve } from 'node:path';
23
+ import { CORE_EFFECT_KINDS, EFFECT_EXIT_CODES, EFFECT_SUBSYSTEMS, EffectLedgerError, LedgerSigningKey, activeKey, containsRestrictedMaterial, createBuiltinVerifierRegistry, createTrackerVerifiers, effectId as deriveEffectId, effectOutputJson, generateLedgerKeySecret, initLedgerKeyring, inspectLedgerLocks, isValidEffectId, ledgerLockRecoveryVerifier, lookupEffect, payloadDigest, readLedgerKeyring, reconcileEffect, recordIntent, recordOutcome, recordReconciled, recoverStaleLedgerLock, rotateKey, runVerifier, staticKeyProvider, verifyDecisionLinks, verifyLedger, writeCheckpoint, } from '../../effects/index.js';
26
24
  import { parseLedgerPrivateKey } from '../../effects/keys.js';
27
25
  import { JsonlOperatorDecisionStore, verifyDecisionChain } from '../../audit/operator-decision.js';
28
26
  import { readConfig, readGitRemoteUrls } from '../../tracker/project-inputs.js';
@@ -166,77 +164,7 @@ function keyValue(entry, flag) {
166
164
  throw usage(`--${flag} expects key=value`, 'invalid-key-value');
167
165
  return [entry.slice(0, eq), entry.slice(eq + 1)];
168
166
  }
169
- const IDENTIFIER = /^[A-Za-z0-9][A-Za-z0-9._:/@-]{0,255}$/;
170
- function defaultProject(projectDir) {
171
- const cleaned = basename(resolve(projectDir)).replace(/[^A-Za-z0-9._:/@-]/g, '-').replace(/^[^A-Za-z0-9]+/, '');
172
- return cleaned && IDENTIFIER.test(cleaned) ? cleaned : 'project';
173
- }
174
- async function hostConfig(projectDir) {
175
- let config;
176
- try {
177
- config = await readAiwgConfig(projectDir);
178
- }
179
- catch {
180
- throw new EffectLedgerError('usage', 'aiwg.config could not be read', 'config-unreadable');
181
- }
182
- const effects = config?.effects;
183
- if (effects === undefined || effects === null)
184
- return {};
185
- if (typeof effects !== 'object' || Array.isArray(effects))
186
- throw usage('aiwg.config effects must be an object', 'config-invalid');
187
- return effects;
188
- }
189
- function testContext(env) {
190
- return env.VITEST === 'true' || env.NODE_ENV === 'test' || env.CI === 'true' || env.CI === '1';
191
- }
192
- function keyStore(session, role) {
193
- const { deps, config, account } = session;
194
- if (deps.keyStore)
195
- return deps.keyStore(role, account);
196
- if (session.env[LEDGER_TEST_KEY_ENV] && testContext(session.env))
197
- return null;
198
- const provider = config.keyProvider ?? {};
199
- try {
200
- if (provider.type === 'file') {
201
- if (!provider.path)
202
- throw new Error('missing path');
203
- const pathname = resolve(session.projectDir, provider.path);
204
- return createSecretStore({ useFile: true, allowFile: true, pathname: role === 'next' ? `${pathname}.next` : pathname, service: DEFAULT_LEDGER_KEY_SERVICE, account });
205
- }
206
- if (provider.type !== undefined && provider.type !== 'credential-store')
207
- throw new Error('unknown provider');
208
- return createSecretStore({ service: provider.service ?? DEFAULT_LEDGER_KEY_SERVICE, account: role === 'next' ? `${account}.next` : account });
209
- }
210
- catch {
211
- throw new EffectLedgerError('key-unavailable', 'Effect ledger key provider is not configured correctly on this host', 'key-provider-invalid');
212
- }
213
- }
214
- function keyProvider(session) {
215
- const store = keyStore(session, 'current');
216
- if (!store)
217
- return environmentTestKeyProvider(session.env);
218
- return credentialStoreKeyProvider({ account: session.account, store });
219
- }
220
- function describeKeyProvider(session) {
221
- if (session.deps.keyStore)
222
- return { type: 'injected', account: session.account };
223
- if (session.env[LEDGER_TEST_KEY_ENV] && testContext(session.env))
224
- return { type: 'environment-test-key' };
225
- const provider = session.config.keyProvider ?? {};
226
- if (provider.type === 'file')
227
- return { type: 'file', account: session.account };
228
- return { type: 'credential-store', service: provider.service ?? DEFAULT_LEDGER_KEY_SERVICE, account: session.account };
229
- }
230
- function openLedger(session, registry) {
231
- const writer = session.config.writer ?? 'cli';
232
- return openEffectLedger({
233
- projectDir: session.projectDir, scope: session.scope, writer, keyProvider: keyProvider(session),
234
- ...(session.deps.clock ? { clock: session.deps.clock } : {}),
235
- ...(session.deps.sink ? { sink: session.deps.sink } : {}),
236
- ...(registry ? { verifiers: registry } : {}),
237
- ...(session.deps.lockTimeoutMs ? { lockTimeoutMs: session.deps.lockTimeoutMs } : {}),
238
- });
239
- }
167
+ import { effectSession, keyStore, describeKeyProvider, openLedger } from '../../effects/host.js';
240
168
  /**
241
169
  * The one place the CLI builds its verifier registry: the built-ins, lock
242
170
  * recovery, the tracker verifiers (#2719) and any injected extensions.
@@ -804,15 +732,7 @@ async function execute(ctx, deps) {
804
732
  throw usage('--format must be json or text', 'invalid-format');
805
733
  const projectDir = resolve(one(parsed, 'project-dir') ?? ctx.cwd ?? process.cwd());
806
734
  const subsystem = resolveSubsystem(parsed);
807
- const config = await hostConfig(projectDir);
808
- const tenant = config.tenant ?? 'local';
809
- const project = config.project ?? defaultProject(projectDir);
810
- if (!IDENTIFIER.test(tenant) || !IDENTIFIER.test(project))
811
- throw usage('aiwg.config effects tenant and project must be identifiers', 'config-invalid');
812
- const scope = { tenant, project, subsystem };
813
- const env = deps.env ?? process.env;
814
- const account = config.keyProvider?.account ?? `ledger/${tenant}/${project}/${subsystem}`;
815
- const session = { projectDir, scope, config, account, deps, env };
735
+ const session = await effectSession(projectDir, subsystem, deps);
816
736
  let rendered;
817
737
  switch (sub) {
818
738
  case 'id':