@aiwg/cli 2026.10.5 → 2026.10.6

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 (212) 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 +3 -1
  6. package/dist/src/artifacts/browser-export.js +1 -0
  7. package/dist/src/artifacts/citation-parser.js +8 -1
  8. package/dist/src/artifacts/cli.js +57 -6
  9. package/dist/src/artifacts/fortemi-core-query-adapter.js +2 -0
  10. package/dist/src/artifacts/fortemi-core-sync.js +26 -8
  11. package/dist/src/artifacts/graph-query.js +18 -8
  12. package/dist/src/artifacts/index-adapters.js +339 -0
  13. package/dist/src/artifacts/index-builder.js +143 -14
  14. package/dist/src/artifacts/index-files.js +15 -4
  15. package/dist/src/artifacts/index-reader.js +44 -0
  16. package/dist/src/artifacts/index-refresh.js +114 -55
  17. package/dist/src/artifacts/index-status.js +20 -5
  18. package/dist/src/artifacts/memory-maintenance.js +503 -0
  19. package/dist/src/artifacts/prebuilt-relations.js +3 -1
  20. package/dist/src/artifacts/query-engine.js +263 -108
  21. package/dist/src/artifacts/relations-builder.js +2 -2
  22. package/dist/src/artifacts/source-graph.js +2 -2
  23. package/dist/src/artifacts/types.js +9 -1
  24. package/dist/src/cli/handlers/decision.js +19 -1
  25. package/dist/src/cli/handlers/guided-setup.js +470 -0
  26. package/dist/src/cli/handlers/help.js +2 -2
  27. package/dist/src/cli/handlers/housekeeper.js +1110 -0
  28. package/dist/src/cli/handlers/index.js +4 -2
  29. package/dist/src/cli/handlers/init.js +41 -6
  30. package/dist/src/cli/handlers/local-executor.js +5 -3
  31. package/dist/src/cli/handlers/mc.js +509 -53
  32. package/dist/src/cli/handlers/models.js +32 -2
  33. package/dist/src/cli/handlers/ralph-launcher.js +76 -4
  34. package/dist/src/cli/handlers/rules.js +1 -1
  35. package/dist/src/cli/handlers/script-runner.js +73 -2
  36. package/dist/src/cli/handlers/serve.js +5 -3
  37. package/dist/src/cli/handlers/sessions.js +1 -0
  38. package/dist/src/cli/handlers/setup.js +428 -1
  39. package/dist/src/cli/handlers/skill-lint.js +1 -1
  40. package/dist/src/cli/handlers/subcommands.js +118 -8
  41. package/dist/src/cli/handlers/use.js +279 -93
  42. package/dist/src/cli/handlers/workspace.js +3 -1
  43. package/dist/src/cli/prompt-utils.js +8 -0
  44. package/dist/src/cli/router.js +16 -1
  45. package/dist/src/config/aiwg-config.js +42 -0
  46. package/dist/src/config/cli.js +7 -3
  47. package/dist/src/config/decision-config.js +14 -1
  48. package/dist/src/config/native-sandbox-warnings.js +25 -0
  49. package/dist/src/contributors/validation.js +6 -5
  50. package/dist/src/decision/admission.js +7 -3
  51. package/dist/src/decision/benchmark.js +469 -0
  52. package/dist/src/decision/ledger.js +22 -3
  53. package/dist/src/decision/pricing.js +147 -0
  54. package/dist/src/decision/qualification/gate-evidence.js +18 -15
  55. package/dist/src/decision/qualification/load-staged.js +539 -0
  56. package/dist/src/decision/qualification/load.js +109 -33
  57. package/dist/src/decision/qualification/runner.js +5 -2
  58. package/dist/src/decision/review/service.js +6 -4
  59. package/dist/src/decision/review/validate.js +23 -2
  60. package/dist/src/decision/savings.js +8 -3
  61. package/dist/src/discovery/index.js +492 -0
  62. package/dist/src/discovery/interview.js +233 -0
  63. package/dist/src/discovery/plan-apply.js +571 -0
  64. package/dist/src/discovery/plan-store.js +171 -0
  65. package/dist/src/discovery/plan-types.js +2 -0
  66. package/dist/src/discovery/plan-validation.js +139 -0
  67. package/dist/src/discovery/types.js +2 -0
  68. package/dist/src/extensions/commands/definitions.js +49 -9
  69. package/dist/src/extensions/manifest.js +71 -44
  70. package/dist/src/extensions/project-local-discovery.js +1 -1
  71. package/dist/src/extensions/project-quickref.js +18 -17
  72. package/dist/src/extensions/validation.js +32 -29
  73. package/dist/src/housekeeper/daemon-config.js +148 -0
  74. package/dist/src/housekeeper/ipc.js +84 -0
  75. package/dist/src/housekeeper/lifecycle.js +148 -0
  76. package/dist/src/housekeeper/platform.js +35 -0
  77. package/dist/src/housekeeper/status.js +70 -0
  78. package/dist/src/housekeeper/units.js +114 -0
  79. package/dist/src/jobs/flow.js +22 -21
  80. package/dist/src/lint/rule-activation.js +20 -5
  81. package/dist/src/lint/runner.js +1 -1
  82. package/dist/src/mcp/cli.mjs +5 -6
  83. package/dist/src/mcp/config-file.mjs +6 -2
  84. package/dist/src/mcp/config-layers.mjs +23 -7
  85. package/dist/src/mcp/profiles.js +18 -31
  86. package/dist/src/mcp/profiles.mjs +18 -32
  87. package/dist/src/mcp/registry.js +7 -27
  88. package/dist/src/mcp/registry.mjs +7 -28
  89. package/dist/src/mcp/server.mjs +34 -1
  90. package/dist/src/mcp/tools/agentic-sandbox.mjs +8 -7
  91. package/dist/src/mcp/tools/command-run.mjs +3 -2
  92. package/dist/src/mcp/tools/decision.mjs +49 -48
  93. package/dist/src/mcp/tools/discovery.mjs +46 -21
  94. package/dist/src/mcp/tools/orchestration.mjs +22 -22
  95. package/dist/src/mcp/tools/subsystems.mjs +9 -8
  96. package/dist/src/mcp/tools/worker-invoke.mjs +17 -4
  97. package/dist/src/mcp/tools/writer-profiles.mjs +1 -1
  98. package/dist/src/memory/audit.js +719 -0
  99. package/dist/src/memory/canonical-context.js +392 -13
  100. package/dist/src/memory/canonical-maintenance.js +95 -0
  101. package/dist/src/memory/cli-result.js +22 -0
  102. package/dist/src/memory/cli.js +176 -0
  103. package/dist/src/memory/context-pack.js +57 -6
  104. package/dist/src/memory/cost.js +512 -0
  105. package/dist/src/memory/firewall-classification.d.mts +7 -0
  106. package/dist/src/memory/firewall-classification.mjs +32 -0
  107. package/dist/src/memory/index.js +8 -0
  108. package/dist/src/memory/line-maintenance.js +68 -0
  109. package/dist/src/memory/maintenance-cli.js +286 -0
  110. package/dist/src/memory/maintenance-contract.js +136 -0
  111. package/dist/src/memory/maintenance-index.js +18 -0
  112. package/dist/src/memory/maintenance-owner.js +2 -0
  113. package/dist/src/memory/maintenance-record.js +138 -0
  114. package/dist/src/memory/maintenance.js +254 -0
  115. package/dist/src/memory/provider-memory-adapter.js +154 -0
  116. package/dist/src/memory/recommend-cli.js +83 -0
  117. package/dist/src/memory/recommend.js +269 -0
  118. package/dist/src/memory/scheduled.js +81 -0
  119. package/dist/src/memory/taxonomy.js +44 -0
  120. package/dist/src/mission-protocol/codecs.js +19 -9
  121. package/dist/src/models/config-loader.js +11 -1
  122. package/dist/src/models/model-capabilities.v1.json +74 -50
  123. package/dist/src/models/provider-policy.js +125 -62
  124. package/dist/src/models/resolver.js +45 -8
  125. package/dist/src/models/worker-installation.d.mts +7 -0
  126. package/dist/src/models/worker-installation.mjs +169 -37
  127. package/dist/src/models/wrapper-route.js +1 -1
  128. package/dist/src/output-modes/registry.js +8 -7
  129. package/dist/src/plugin/metadata-validator.js +1 -1
  130. package/dist/src/providers/deploy-version.d.mts +1 -0
  131. package/dist/src/providers/deploy-version.mjs +17 -0
  132. package/dist/src/providers/provider-definitions.js +19 -16
  133. package/dist/src/providers/skill-ownership.d.mts +11 -2
  134. package/dist/src/providers/skill-ownership.mjs +35 -17
  135. package/dist/src/rules/activation.d.mts +11 -2
  136. package/dist/src/rules/activation.mjs +82 -6
  137. package/dist/src/rules/inventory.js +1 -1
  138. package/dist/src/rules/rule-frontmatter.schema.json +2 -0
  139. package/dist/src/schema/zod-validation.d.mts +6 -0
  140. package/dist/src/schema/zod-validation.mjs +50 -0
  141. package/dist/src/serve/executor-registry.js +297 -20
  142. package/dist/src/serve/executor-token.d.mts +1 -0
  143. package/dist/src/serve/executor-token.mjs +8 -0
  144. package/dist/src/serve/shared-host-scheduler.js +1102 -31
  145. package/dist/src/serve/worker-invocation.js +114 -15
  146. package/dist/src/sessions/adapters/claude.js +19 -18
  147. package/dist/src/sessions/adapters/codex.js +10 -9
  148. package/dist/src/sessions/adapters/copilot.js +14 -13
  149. package/dist/src/sessions/adapters/cursor.js +19 -18
  150. package/dist/src/sessions/adapters/deepseek-harness.js +9 -8
  151. package/dist/src/sessions/adapters/factory.js +11 -10
  152. package/dist/src/sessions/adapters/generic.js +32 -23
  153. package/dist/src/sessions/adapters/grokbot.js +35 -35
  154. package/dist/src/sessions/adapters/hermes.js +20 -19
  155. package/dist/src/sessions/adapters/muse.js +50 -49
  156. package/dist/src/sessions/adapters/omp.js +5 -4
  157. package/dist/src/sessions/adapters/openclaw.js +30 -29
  158. package/dist/src/sessions/adapters/opencode.js +26 -26
  159. package/dist/src/sessions/adapters/openhuman.js +24 -23
  160. package/dist/src/sessions/adapters/pi.js +5 -4
  161. package/dist/src/sessions/adapters/windsurf.js +8 -8
  162. package/dist/src/sessions/analytics.js +10 -9
  163. package/dist/src/sessions/candidates.js +7 -6
  164. package/dist/src/sessions/contracts.js +63 -53
  165. package/dist/src/sessions/output-registration.js +11 -10
  166. package/dist/src/sessions/workspace-discovery.js +3 -4
  167. package/dist/src/smiths/context-pipeline/aiwg-md.js +18 -1
  168. package/dist/src/smiths/context-pipeline/claude-hook.js +42 -6
  169. package/dist/src/smiths/context-pipeline/parallelism-section.js +72 -5
  170. package/dist/src/smiths/context-pipeline/workspace-context.js +106 -10
  171. package/dist/src/update/checker.d.mts +4 -0
  172. package/dist/src/update/checker.mjs +14 -0
  173. package/dist/src/writing/exemplar-selection.js +6 -6
  174. package/dist/src/writing/voice-evaluation.js +24 -23
  175. package/dist/src/writing/writer-migration.js +14 -13
  176. package/dist/src/writing/writer-profile.js +19 -18
  177. package/dist/src/writing/writing-brief.js +18 -17
  178. package/dist/src/writing/writing-receipt.js +47 -46
  179. package/package.json +5 -2
  180. package/schemas/decision/DecisionReview.schema.json +78 -1
  181. package/schemas/mission-v1.schema.json +3 -0
  182. package/tools/agents/deploy-agents.mjs +67 -39
  183. package/tools/agents/providers/antigravity.mjs +6 -1
  184. package/tools/agents/providers/base.mjs +19 -13
  185. package/tools/agents/providers/claude.mjs +1 -1
  186. package/tools/agents/providers/codex.mjs +50 -56
  187. package/tools/agents/providers/copilot.mjs +8 -2
  188. package/tools/agents/providers/cursor.mjs +1 -1
  189. package/tools/agents/providers/deepseek-harness.mjs +1 -1
  190. package/tools/agents/providers/factory.mjs +7 -1
  191. package/tools/agents/providers/grok-build.mjs +18 -2
  192. package/tools/agents/providers/grokbot.mjs +1 -1
  193. package/tools/agents/providers/hermes.mjs +7 -13
  194. package/tools/agents/providers/muse-hooks.mjs +21 -14
  195. package/tools/agents/providers/muse.mjs +7 -2
  196. package/tools/agents/providers/omp.mjs +28 -4
  197. package/tools/agents/providers/opencode.mjs +14 -5
  198. package/tools/agents/providers/openhuman.mjs +1 -1
  199. package/tools/agents/providers/pi.mjs +1 -1
  200. package/tools/agents/providers/provider-prepare-coordinator.mjs +29 -9
  201. package/tools/agents/providers/rule-delivery.mjs +263 -71
  202. package/tools/agents/providers/windsurf.mjs +7 -0
  203. package/tools/cli/workspace-status.mjs +5 -0
  204. package/tools/commands/deploy-prompts-codex.mjs +11 -8
  205. package/tools/ralph-external/lib/codex-adapter.mjs +6 -2
  206. package/tools/ralph-external/lib/muse-adapter.mjs +12 -2
  207. package/tools/ralph-external/lib/worker-health.mjs +1 -1
  208. package/tools/ralph-external/lib/worker-isolation.mjs +65 -9
  209. package/tools/ralph-external/process-monitor.mjs +7 -4
  210. package/tools/ralph-external/session-launcher.mjs +280 -32
  211. package/tools/skills/deploy-skills-codex.mjs +11 -7
  212. package/vscode-extension/schemas/aiwg.config.v1.json +11 -1
@@ -13,6 +13,7 @@ import { getFrameworkRoot } from '../../channel/manager.mjs';
13
13
  import { maybePrintCommunityFooter } from '../../community/footer.js';
14
14
  import { buildDeploymentStatusProbe } from '../services/deployment-verification.js';
15
15
  import { detectScope } from '../scope-resolver.js';
16
+ import { readNativeSandboxWarnings } from '../../config/native-sandbox-warnings.js';
16
17
  function statusProjectRoot(args, fallback) {
17
18
  const valueFlags = new Set(['--scope', '--provider', '--bundle']);
18
19
  for (let index = 0; index < args.length; index += 1) {
@@ -57,9 +58,10 @@ export const statusHandler = {
57
58
  });
58
59
  const { inspectGrokBuildNative } = await import('../../mcp/grok-build-config.mjs');
59
60
  const grokBuildNative = await inspectGrokBuildNative({ projectDir: projectRoot });
61
+ const nativeSandboxWarnings = await readNativeSandboxWarnings(projectRoot);
60
62
  return {
61
63
  exitCode: probe.status === 'needs-repair' ? 1 : 0,
62
- message: JSON.stringify({ ...probe, grokBuildNative }, null, 2),
64
+ message: JSON.stringify({ ...probe, grokBuildNative, nativeSandboxWarnings }, null, 2),
63
65
  rawOutput: true,
64
66
  };
65
67
  }
@@ -16,6 +16,7 @@
16
16
  * migration mechanical.
17
17
  */
18
18
  import readline from 'readline';
19
+ import { Writable } from 'node:stream';
19
20
  import * as ui from './ui.js';
20
21
  /**
21
22
  * Resolve the prompt timeout from env. Falsy / non-numeric / non-positive
@@ -36,6 +37,13 @@ export function createPromptInterface() {
36
37
  output: process.stdout,
37
38
  });
38
39
  }
40
+ /** Readline still owns timeout/cancellation; discard terminal echo for secret input. */
41
+ export function createSecretPromptInterface() {
42
+ const output = new Writable({ write(_chunk, _encoding, done) { done(); } });
43
+ const rl = readline.createInterface({ input: process.stdin, output, terminal: true });
44
+ rl.once('close', () => output.destroy());
45
+ return rl;
46
+ }
39
47
  /**
40
48
  * Ask a single question with a hard timeout. On timeout, resolves to `fallback`
41
49
  * and emits a warn-level UI message describing what default was used.
@@ -176,6 +176,20 @@ export async function run(args, options = {}) {
176
176
  }
177
177
  // Build context for handler and hooks
178
178
  const ctx = await buildContext(commandArgs, args, options);
179
+ // Read-only memory views (audit, cost, recommend, plan, verify, --preview) cannot invoke mutation-capable hooks or append command telemetry.
180
+ // Keep dispatch through the existing memory handler and strict parser.
181
+ if (commandId === 'memory' && (['audit', 'cost', 'recommend', 'plan', 'verify'].includes(commandArgs[0]) || commandArgs.includes('--preview'))) {
182
+ const result = await handler.execute(ctx);
183
+ if (result.message) {
184
+ if (result.exitCode !== 0)
185
+ ui.error(result.message);
186
+ else
187
+ ui.info(result.message);
188
+ }
189
+ if (result.exitCode !== 0)
190
+ process.exit(result.exitCode);
191
+ return;
192
+ }
179
193
  // Build hook context
180
194
  const hookCtx = {
181
195
  event: 'pre-command',
@@ -332,8 +346,9 @@ async function buildContext(args, rawArgs, options) {
332
346
  const readOnlyRuleInventory = rawArgs[0] === 'rules' && ['inventory', 'list'].includes(args[0]);
333
347
  const readOnlyOffloadReport = (['doctor', '-doctor', '--doctor'].includes(rawArgs[0] ?? '') && args.includes('--decision-offload'))
334
348
  || (rawArgs[0] === 'steward' && args[0] === 'decision-offload');
349
+ const readOnlyMemoryAudit = rawArgs[0] === 'memory' && (['audit', 'cost', 'recommend', 'plan', 'verify'].includes(args[0]) || args.includes('--preview') || args.includes('--help') || args.includes('-h'));
335
350
  const frameworkRoot = await getFrameworkRoot({
336
- createIfMissing: !args.includes('--dry-run') && !readOnlyRuleInventory && !readOnlyOffloadReport,
351
+ createIfMissing: !args.includes('--dry-run') && !readOnlyRuleInventory && !readOnlyOffloadReport && !readOnlyMemoryAudit,
337
352
  });
338
353
  const ctx = {
339
354
  args,
@@ -201,6 +201,17 @@ export function validateParallelismConfig(value) {
201
201
  error(`clis/${id}/adapter`, 'Unknown provider binding');
202
202
  }
203
203
  for (const [id, group] of Object.entries(policy.groups ?? {})) {
204
+ if (group.execution?.launchMode === 'native-sandbox'
205
+ && (!['read-only', 'workspace-write'].includes(group.execution.sandbox ?? '')
206
+ || (group.execution.transport ?? 'shell') !== 'shell')) {
207
+ error(`groups/${id}/execution/launchMode`, 'native-sandbox requires an enforcing read-only or workspace-write shell sandbox');
208
+ }
209
+ if (group.execution?.launchMode === 'native-sandbox') {
210
+ if (group.execution.approval === 'on-request')
211
+ error(`groups/${id}/execution/approval`, 'native-sandbox requires approval="never"');
212
+ if (group.execution.network === 'allowlisted')
213
+ error(`groups/${id}/execution/network`, 'native-sandbox requires network="deny"');
214
+ }
204
215
  const ids = new Set();
205
216
  for (const member of group.members) {
206
217
  if (ids.has(member.id))
@@ -208,6 +219,10 @@ export function validateParallelismConfig(value) {
208
219
  ids.add(member.id);
209
220
  if (!policy.clis?.[member.cli] && !builtinIds.has(member.cli))
210
221
  error(`groups/${id}/members/${member.id}/cli`, 'Unknown installation');
222
+ if (group.execution?.launchMode === 'native-sandbox'
223
+ && (policy.clis?.[member.cli]?.adapter ?? `providers:${member.cli}`) !== 'providers:codex') {
224
+ error(`groups/${id}/members/${member.id}/cli`, 'native-sandbox requires a codex adapter');
225
+ }
211
226
  }
212
227
  for (const member of group.fallback ?? [])
213
228
  if (!ids.has(member))
@@ -461,6 +476,33 @@ export function validateIndexConfig(index) {
461
476
  if (indexObject.graphBackend !== undefined && !GRAPH_BACKENDS.includes(indexObject.graphBackend)) {
462
477
  errors.push(`index.graphBackend: must be one of ${GRAPH_BACKENDS.join(' | ')}`);
463
478
  }
479
+ if (indexObject.freshness !== undefined) {
480
+ const policies = indexObject.freshness;
481
+ if (!policies || typeof policies !== 'object' || Array.isArray(policies)) {
482
+ errors.push('index.freshness: must map adapter names to policies');
483
+ }
484
+ else
485
+ for (const [name, policy] of Object.entries(policies)) {
486
+ const where = `index.freshness.${name}`;
487
+ if (!policy || typeof policy !== 'object' || Array.isArray(policy)) {
488
+ errors.push(`${where}: must be an object`);
489
+ continue;
490
+ }
491
+ for (const [key, value] of Object.entries(policy)) {
492
+ if (key === 'measureConvergence') {
493
+ if (typeof value !== 'boolean')
494
+ errors.push(`${where}.${key}: must be a boolean`);
495
+ }
496
+ else if (key === 'targetStaleAfterMs' || key === 'maxRetriesPerDay') {
497
+ if (!Number.isSafeInteger(value) || value < (key === 'targetStaleAfterMs' ? 1 : 0)) {
498
+ errors.push(`${where}.${key}: must be a ${key === 'targetStaleAfterMs' ? 'positive' : 'non-negative'} integer`);
499
+ }
500
+ }
501
+ else
502
+ errors.push(`${where}.${key}: unknown policy key`);
503
+ }
504
+ }
505
+ }
464
506
  const isStringArray = (v) => Array.isArray(v) && v.every((x) => typeof x === 'string');
465
507
  errors.push(...validateIndexGraphOverrides(indexObject.graphOverrides));
466
508
  const graphs = indexObject.graphs;
@@ -24,6 +24,7 @@ import { normalizeProviderDefinitionId } from '../providers/provider-definitions
24
24
  import { UserConfig } from './user-config.js';
25
25
  import { AiwgError, EXIT_CODES } from '../cli/errors.js';
26
26
  import { isInteractive } from '../cli/env.js';
27
+ import { splitParams } from '../cli/agent-spawn.js';
27
28
  import { exitCodeForSpawnResult } from '../cli/child-process-result.js';
28
29
  import { projectControlPath, resolveProjectAiwgDir } from './project-artifacts.js';
29
30
  const _scriptDir = path.dirname(fileURLToPath(import.meta.url));
@@ -400,7 +401,7 @@ async function projectConfigSet(key, raw, args, quiet = false) {
400
401
  }
401
402
  value = n;
402
403
  }
403
- if (key === 'decision.ask.cost.llm_per_mtok' || key === 'decision.ask.cost.jev_per_mtok') {
404
+ if (['decision.ask.cost.llm_per_mtok', 'decision.ask.cost.jev_per_mtok', 'decision.ask.cost.jev_input_per_mtok', 'decision.ask.cost.jev_output_per_mtok'].includes(key)) {
404
405
  const n = Number(raw);
405
406
  if (!raw.trim() || !Number.isFinite(n) || n < 0 || n > 1_000_000) {
406
407
  throw new AiwgError({ code: 'ERR_INVALID_VALUE', message: `${key} must be a non-negative number <= 1000000`, exitCode: EXIT_CODES.USAGE });
@@ -733,14 +734,17 @@ async function handleEdit(config, args = []) {
733
734
  const editor = process.env.EDITOR || process.env.VISUAL || 'vi';
734
735
  // Ensure the config file exists before opening
735
736
  await config.ensureDir();
736
- const { execSync } = await import('child_process');
737
+ const { execFileSync } = await import('child_process');
737
738
  try {
739
+ const [executable, ...editorArgs] = splitParams(editor);
740
+ if (!executable)
741
+ throw new Error('Editor command is empty');
738
742
  // sync-spawn: interactive editor-launch — launches $EDITOR/$VISUAL on the
739
743
  // config file; the user interacts with it directly (see tools/testing/
740
744
  // sync-spawn-allowlist.json). Reached only when isInteractive() is true
741
745
  // (#3062) — the no-terminal path above refuses before spawning anything.
742
746
  // Not a candidate for a bounded timeout.
743
- execSync(`${editor} "${configPath}"`, { stdio: 'inherit' });
747
+ execFileSync(executable, [...editorArgs, configPath], { stdio: 'inherit', shell: false });
744
748
  }
745
749
  catch (err) {
746
750
  throw new AiwgError({
@@ -57,10 +57,23 @@ export function validateDecisionConfig(value) {
57
57
  sampling.push(`decision.ask.${section} must be an object`);
58
58
  continue;
59
59
  }
60
- const allowed = section === 'cost' ? ['llm_per_mtok', 'jev_per_mtok'] : ['caller_model_class', 'reasoning_tokens', 'output_tokens'];
60
+ const allowed = section === 'cost' ? ['llm_per_mtok', 'jev_per_mtok', 'jev_input_per_mtok', 'jev_output_per_mtok', 'source', 'checked_at', 'jev_model'] : ['caller_model_class', 'reasoning_tokens', 'output_tokens'];
61
61
  for (const [key, value] of Object.entries(settings)) {
62
62
  if (!allowed.includes(key))
63
63
  sampling.push(`unknown decision.ask.${section}.${key}`);
64
+ else if (key === 'source') {
65
+ if (!['typesafe-docs', 'manual', 'typesafe-snapshot'].includes(value))
66
+ sampling.push('decision.ask.cost.source must be typesafe-docs, manual or typesafe-snapshot');
67
+ }
68
+ else if (key === 'checked_at') {
69
+ if (typeof value !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(value)
70
+ || !Number.isFinite(Date.parse(value)) || new Date(value).toISOString().slice(0, 10) !== value)
71
+ sampling.push('decision.ask.cost.checked_at must be an ISO date (YYYY-MM-DD)');
72
+ }
73
+ else if (key === 'jev_model') {
74
+ if (typeof value !== 'string' || !/^jev-\d+\.\d+\.\d+$/.test(value))
75
+ sampling.push('decision.ask.cost.jev_model must be a versioned Jev model (jev-X.Y.Z)');
76
+ }
64
77
  else if (key === 'caller_model_class') {
65
78
  if (value !== 'standard' && value !== 'reasoning')
66
79
  sampling.push('decision.ask.savings.caller_model_class must be standard or reasoning');
@@ -0,0 +1,25 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import { getConfigPath, readAiwgConfig } from './aiwg-config.js';
4
+ import { projectAiwgPath } from './project-artifacts.js';
5
+ /** Advisory only: native-sandbox bypasses the systemd launcher boundary. */
6
+ export function nativeSandboxWarnings(config, projectDir) {
7
+ const groups = Object.entries(config?.parallelism?.groups ?? {})
8
+ .filter(([, group]) => group.execution?.launchMode === 'native-sandbox')
9
+ .map(([id]) => id);
10
+ if (groups.length === 0)
11
+ return [];
12
+ // Match readAiwgConfig's repository-control-plane-first compatibility lookup.
13
+ const localPath = getConfigPath(projectDir);
14
+ const configPath = resolve(existsSync(localPath) ? localPath : projectAiwgPath(projectDir, 'aiwg.config'));
15
+ return groups.map(group => ({
16
+ code: 'NATIVE_SANDBOX_ISOLATION',
17
+ group,
18
+ configPath,
19
+ message: `Group "${group}" selects launchMode: native-sandbox in ${configPath}; systemd-unit isolation and its memory limit do not apply; only the worker CLI's own sandbox applies.`,
20
+ }));
21
+ }
22
+ export async function readNativeSandboxWarnings(projectDir) {
23
+ return nativeSandboxWarnings(await readAiwgConfig(projectDir), projectDir);
24
+ }
25
+ //# sourceMappingURL=native-sandbox-warnings.js.map
@@ -9,13 +9,14 @@
9
9
  * @issue #938
10
10
  */
11
11
  import { z } from 'zod';
12
+ import { integer } from '../schema/zod-validation.mjs';
12
13
  /**
13
14
  * Detection spec — declarative globs + counts. Common to every kind.
14
15
  */
15
16
  const DetectionSpecSchema = z.object({
16
17
  glob: z.array(z.string()).min(1, 'detect.glob must have at least one pattern'),
17
- minCount: z.number().int().positive().optional(),
18
- conditions: z.record(z.string()).optional(),
18
+ minCount: integer().positive().optional(),
19
+ conditions: z.record(z.string(), z.string()).optional(),
19
20
  });
20
21
  /**
21
22
  * Base frontmatter shared by every kind. Per-kind schemas extend this.
@@ -39,7 +40,7 @@ export const StatusContributorSchema = ContributorBaseSchema.extend({
39
40
  * code-driven; the aggregator reads these to populate the report block.
40
41
  */
41
42
  fields: z
42
- .record(z.object({
43
+ .record(z.string(), z.object({
43
44
  type: z.enum(['string', 'number', 'date']),
44
45
  source: z.string(),
45
46
  regex: z.string().optional(),
@@ -60,7 +61,7 @@ export const ResearchContributorSchema = ContributorBaseSchema.extend({
60
61
  })
61
62
  .optional(),
62
63
  focus_areas: z.array(z.string()).min(1, 'research contributors must declare at least one focus area'),
63
- recency_default_months: z.number().int().positive().optional(),
64
+ recency_default_months: integer().positive().optional(),
64
65
  });
65
66
  /**
66
67
  * Schema registry. Adding a new kind means adding its schema here — no other
@@ -108,7 +109,7 @@ export function validateContributor(data) {
108
109
  if (!result.success) {
109
110
  return {
110
111
  ok: false,
111
- errors: result.error.errors.map(e => `${e.path.join('.') || '<root>'}: ${e.message}`),
112
+ errors: result.error.issues.map(e => `${e.path.join('.') || '<root>'}: ${e.message}`),
112
113
  };
113
114
  }
114
115
  return { ok: true, data: result.data };
@@ -43,9 +43,13 @@ export class DecisionAdmissionController {
43
43
  this.now = now;
44
44
  this.options = options;
45
45
  }
46
- /** Aggregate counts only; suitable for load harness sampling. */
47
- snapshot() {
48
- return { active: this.active, queued: this.queuedCount() };
46
+ /** Host-only counts for load sampling; omitting a scope returns aggregate counts. */
47
+ snapshot(scope) {
48
+ const principal = scope?.principalId;
49
+ const provider = scope?.providerId;
50
+ const active = principal && provider ? this.activePrincipalProvider.get(`${provider}\u0000${principal}`) ?? 0
51
+ : principal ? this.activePrincipal.get(principal) ?? 0 : provider ? this.activeProvider.get(provider) ?? 0 : this.active;
52
+ return { active, queued: this.queuedCount(request => (!principal || request.principalId === principal) && (!provider || request.providerId === provider)) };
49
53
  }
50
54
  /** Bounded, metadata-only breaker transition history, oldest first. */
51
55
  breakerTransitions() {