@aiwg/cli 2026.10.4 → 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 (220) 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 +72 -9
  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 +146 -16
  14. package/dist/src/artifacts/index-files.js +15 -4
  15. package/dist/src/artifacts/index-preparation.js +91 -26
  16. package/dist/src/artifacts/index-reader.js +44 -0
  17. package/dist/src/artifacts/index-refresh.js +130 -56
  18. package/dist/src/artifacts/index-status.js +20 -5
  19. package/dist/src/artifacts/index-worker.mjs +9 -7
  20. package/dist/src/artifacts/memory-maintenance.js +503 -0
  21. package/dist/src/artifacts/prebuilt-relations.js +3 -1
  22. package/dist/src/artifacts/query-engine.js +263 -108
  23. package/dist/src/artifacts/relations-builder.js +2 -2
  24. package/dist/src/artifacts/source-graph.js +2 -2
  25. package/dist/src/artifacts/types.js +9 -1
  26. package/dist/src/cli/handlers/decision.js +19 -1
  27. package/dist/src/cli/handlers/guided-setup.js +470 -0
  28. package/dist/src/cli/handlers/help.js +2 -2
  29. package/dist/src/cli/handlers/housekeeper.js +1110 -0
  30. package/dist/src/cli/handlers/index.js +4 -2
  31. package/dist/src/cli/handlers/init.js +41 -6
  32. package/dist/src/cli/handlers/local-executor.js +5 -3
  33. package/dist/src/cli/handlers/mc.js +509 -53
  34. package/dist/src/cli/handlers/models.js +32 -2
  35. package/dist/src/cli/handlers/ralph-launcher.js +76 -4
  36. package/dist/src/cli/handlers/rules.js +1 -1
  37. package/dist/src/cli/handlers/script-runner.js +73 -2
  38. package/dist/src/cli/handlers/serve.js +5 -3
  39. package/dist/src/cli/handlers/sessions.js +40 -6
  40. package/dist/src/cli/handlers/setup.js +428 -1
  41. package/dist/src/cli/handlers/skill-lint.js +1 -1
  42. package/dist/src/cli/handlers/subcommands.js +118 -8
  43. package/dist/src/cli/handlers/use.js +279 -93
  44. package/dist/src/cli/handlers/workspace.js +3 -1
  45. package/dist/src/cli/prompt-utils.js +8 -0
  46. package/dist/src/cli/router.js +16 -1
  47. package/dist/src/config/aiwg-config.js +42 -0
  48. package/dist/src/config/cli.js +7 -3
  49. package/dist/src/config/decision-config.js +14 -1
  50. package/dist/src/config/native-sandbox-warnings.js +25 -0
  51. package/dist/src/contributors/validation.js +6 -5
  52. package/dist/src/decision/admission.js +7 -3
  53. package/dist/src/decision/benchmark.js +469 -0
  54. package/dist/src/decision/ledger.js +22 -3
  55. package/dist/src/decision/pricing.js +147 -0
  56. package/dist/src/decision/qualification/gate-evidence.js +18 -15
  57. package/dist/src/decision/qualification/load-staged.js +539 -0
  58. package/dist/src/decision/qualification/load.js +109 -33
  59. package/dist/src/decision/qualification/runner.js +5 -2
  60. package/dist/src/decision/review/service.js +6 -4
  61. package/dist/src/decision/review/validate.js +23 -2
  62. package/dist/src/decision/savings.js +8 -3
  63. package/dist/src/discovery/index.js +492 -0
  64. package/dist/src/discovery/interview.js +233 -0
  65. package/dist/src/discovery/plan-apply.js +571 -0
  66. package/dist/src/discovery/plan-store.js +171 -0
  67. package/dist/src/discovery/plan-types.js +2 -0
  68. package/dist/src/discovery/plan-validation.js +139 -0
  69. package/dist/src/discovery/types.js +2 -0
  70. package/dist/src/extensions/commands/definitions.js +49 -9
  71. package/dist/src/extensions/manifest.js +71 -44
  72. package/dist/src/extensions/project-local-discovery.js +1 -1
  73. package/dist/src/extensions/project-quickref.js +18 -17
  74. package/dist/src/extensions/validation.js +32 -29
  75. package/dist/src/housekeeper/daemon-config.js +148 -0
  76. package/dist/src/housekeeper/ipc.js +84 -0
  77. package/dist/src/housekeeper/lifecycle.js +148 -0
  78. package/dist/src/housekeeper/platform.js +35 -0
  79. package/dist/src/housekeeper/status.js +70 -0
  80. package/dist/src/housekeeper/units.js +114 -0
  81. package/dist/src/jobs/flow.js +22 -21
  82. package/dist/src/lint/rule-activation.js +20 -5
  83. package/dist/src/lint/runner.js +1 -1
  84. package/dist/src/mcp/cli.mjs +5 -6
  85. package/dist/src/mcp/config-file.mjs +6 -2
  86. package/dist/src/mcp/config-layers.mjs +23 -7
  87. package/dist/src/mcp/profiles.js +18 -31
  88. package/dist/src/mcp/profiles.mjs +18 -32
  89. package/dist/src/mcp/registry.js +7 -27
  90. package/dist/src/mcp/registry.mjs +7 -28
  91. package/dist/src/mcp/server.mjs +34 -1
  92. package/dist/src/mcp/tools/agentic-sandbox.mjs +8 -7
  93. package/dist/src/mcp/tools/command-run.mjs +3 -2
  94. package/dist/src/mcp/tools/decision.mjs +49 -48
  95. package/dist/src/mcp/tools/discovery.mjs +46 -21
  96. package/dist/src/mcp/tools/orchestration.mjs +22 -22
  97. package/dist/src/mcp/tools/subsystems.mjs +9 -8
  98. package/dist/src/mcp/tools/worker-invoke.mjs +17 -4
  99. package/dist/src/mcp/tools/writer-profiles.mjs +1 -1
  100. package/dist/src/memory/audit.js +719 -0
  101. package/dist/src/memory/canonical-context.js +392 -13
  102. package/dist/src/memory/canonical-maintenance.js +95 -0
  103. package/dist/src/memory/cli-result.js +22 -0
  104. package/dist/src/memory/cli.js +176 -0
  105. package/dist/src/memory/context-pack.js +57 -6
  106. package/dist/src/memory/cost.js +512 -0
  107. package/dist/src/memory/firewall-classification.d.mts +7 -0
  108. package/dist/src/memory/firewall-classification.mjs +32 -0
  109. package/dist/src/memory/index.js +8 -0
  110. package/dist/src/memory/line-maintenance.js +68 -0
  111. package/dist/src/memory/maintenance-cli.js +286 -0
  112. package/dist/src/memory/maintenance-contract.js +136 -0
  113. package/dist/src/memory/maintenance-index.js +18 -0
  114. package/dist/src/memory/maintenance-owner.js +2 -0
  115. package/dist/src/memory/maintenance-record.js +138 -0
  116. package/dist/src/memory/maintenance.js +254 -0
  117. package/dist/src/memory/provider-memory-adapter.js +154 -0
  118. package/dist/src/memory/recommend-cli.js +83 -0
  119. package/dist/src/memory/recommend.js +269 -0
  120. package/dist/src/memory/scheduled.js +81 -0
  121. package/dist/src/memory/taxonomy.js +44 -0
  122. package/dist/src/mission-protocol/codecs.js +19 -9
  123. package/dist/src/models/config-loader.js +11 -1
  124. package/dist/src/models/model-capabilities.v1.json +74 -50
  125. package/dist/src/models/provider-policy.js +125 -62
  126. package/dist/src/models/resolver.js +45 -8
  127. package/dist/src/models/worker-installation.d.mts +7 -0
  128. package/dist/src/models/worker-installation.mjs +169 -37
  129. package/dist/src/models/wrapper-route.js +1 -1
  130. package/dist/src/output-modes/registry.js +8 -7
  131. package/dist/src/plugin/metadata-validator.js +1 -1
  132. package/dist/src/providers/deploy-version.d.mts +1 -0
  133. package/dist/src/providers/deploy-version.mjs +17 -0
  134. package/dist/src/providers/provider-definitions.js +19 -16
  135. package/dist/src/providers/skill-ownership.d.mts +11 -2
  136. package/dist/src/providers/skill-ownership.mjs +35 -17
  137. package/dist/src/rules/activation.d.mts +11 -2
  138. package/dist/src/rules/activation.mjs +82 -6
  139. package/dist/src/rules/inventory.js +1 -1
  140. package/dist/src/rules/rule-frontmatter.schema.json +2 -0
  141. package/dist/src/schema/zod-validation.d.mts +6 -0
  142. package/dist/src/schema/zod-validation.mjs +50 -0
  143. package/dist/src/serve/executor-registry.js +297 -20
  144. package/dist/src/serve/executor-token.d.mts +1 -0
  145. package/dist/src/serve/executor-token.mjs +8 -0
  146. package/dist/src/serve/shared-host-scheduler.js +1102 -31
  147. package/dist/src/serve/worker-invocation.js +114 -15
  148. package/dist/src/sessions/adapters/claude.js +19 -18
  149. package/dist/src/sessions/adapters/codex.js +33 -19
  150. package/dist/src/sessions/adapters/copilot.js +14 -13
  151. package/dist/src/sessions/adapters/cursor.js +19 -18
  152. package/dist/src/sessions/adapters/deepseek-harness.js +9 -8
  153. package/dist/src/sessions/adapters/factory.js +11 -10
  154. package/dist/src/sessions/adapters/generic.js +32 -23
  155. package/dist/src/sessions/adapters/grokbot.js +35 -35
  156. package/dist/src/sessions/adapters/hermes.js +20 -19
  157. package/dist/src/sessions/adapters/muse.js +50 -49
  158. package/dist/src/sessions/adapters/omp.js +5 -4
  159. package/dist/src/sessions/adapters/openclaw.js +30 -29
  160. package/dist/src/sessions/adapters/opencode.js +26 -26
  161. package/dist/src/sessions/adapters/openhuman.js +24 -23
  162. package/dist/src/sessions/adapters/pi.js +5 -4
  163. package/dist/src/sessions/adapters/windsurf.js +8 -8
  164. package/dist/src/sessions/analytics.js +10 -9
  165. package/dist/src/sessions/batch-contracts.js +1 -1
  166. package/dist/src/sessions/batch-import.js +202 -2
  167. package/dist/src/sessions/candidates.js +7 -6
  168. package/dist/src/sessions/contracts.js +73 -54
  169. package/dist/src/sessions/coverage-preflight.js +26 -1
  170. package/dist/src/sessions/output-registration.js +11 -10
  171. package/dist/src/sessions/policy.js +18 -7
  172. package/dist/src/sessions/refresh.js +2 -3
  173. package/dist/src/sessions/repository.js +4 -2
  174. package/dist/src/sessions/workspace-discovery.js +92 -26
  175. package/dist/src/smiths/context-pipeline/aiwg-md.js +18 -1
  176. package/dist/src/smiths/context-pipeline/claude-hook.js +42 -6
  177. package/dist/src/smiths/context-pipeline/parallelism-section.js +72 -5
  178. package/dist/src/smiths/context-pipeline/workspace-context.js +106 -10
  179. package/dist/src/update/checker.d.mts +4 -0
  180. package/dist/src/update/checker.mjs +14 -0
  181. package/dist/src/writing/exemplar-selection.js +6 -6
  182. package/dist/src/writing/voice-evaluation.js +24 -23
  183. package/dist/src/writing/writer-migration.js +14 -13
  184. package/dist/src/writing/writer-profile.js +19 -18
  185. package/dist/src/writing/writing-brief.js +18 -17
  186. package/dist/src/writing/writing-receipt.js +47 -46
  187. package/package.json +5 -2
  188. package/schemas/decision/DecisionReview.schema.json +78 -1
  189. package/schemas/mission-v1.schema.json +3 -0
  190. package/tools/agents/deploy-agents.mjs +67 -39
  191. package/tools/agents/providers/antigravity.mjs +6 -1
  192. package/tools/agents/providers/base.mjs +19 -13
  193. package/tools/agents/providers/claude.mjs +1 -1
  194. package/tools/agents/providers/codex.mjs +50 -56
  195. package/tools/agents/providers/copilot.mjs +8 -2
  196. package/tools/agents/providers/cursor.mjs +1 -1
  197. package/tools/agents/providers/deepseek-harness.mjs +1 -1
  198. package/tools/agents/providers/factory.mjs +7 -1
  199. package/tools/agents/providers/grok-build.mjs +18 -2
  200. package/tools/agents/providers/grokbot.mjs +1 -1
  201. package/tools/agents/providers/hermes.mjs +7 -13
  202. package/tools/agents/providers/muse-hooks.mjs +21 -14
  203. package/tools/agents/providers/muse.mjs +7 -2
  204. package/tools/agents/providers/omp.mjs +28 -4
  205. package/tools/agents/providers/opencode.mjs +14 -5
  206. package/tools/agents/providers/openhuman.mjs +1 -1
  207. package/tools/agents/providers/pi.mjs +1 -1
  208. package/tools/agents/providers/provider-prepare-coordinator.mjs +29 -9
  209. package/tools/agents/providers/rule-delivery.mjs +263 -71
  210. package/tools/agents/providers/windsurf.mjs +7 -0
  211. package/tools/cli/workspace-status.mjs +5 -0
  212. package/tools/commands/deploy-prompts-codex.mjs +11 -8
  213. package/tools/ralph-external/lib/codex-adapter.mjs +6 -2
  214. package/tools/ralph-external/lib/muse-adapter.mjs +12 -2
  215. package/tools/ralph-external/lib/worker-health.mjs +1 -1
  216. package/tools/ralph-external/lib/worker-isolation.mjs +65 -9
  217. package/tools/ralph-external/process-monitor.mjs +7 -4
  218. package/tools/ralph-external/session-launcher.mjs +280 -32
  219. package/tools/skills/deploy-skills-codex.mjs +11 -7
  220. package/vscode-extension/schemas/aiwg.config.v1.json +11 -1
@@ -1,5 +1,6 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import { z } from 'zod';
3
+ import { integer, dateTime, number } from '../schema/zod-validation.mjs';
3
4
  import { redactSessionText, redactSessionValue } from './policy.js';
4
5
  export const SESSION_CONTRACT_VERSION = '1.0.0';
5
6
  export const SESSION_PROVIDER_IDS = [
@@ -20,9 +21,18 @@ export const SessionRuntimeIdentitySchema = z.object({
20
21
  canonicalRoot: z.string().nullable(),
21
22
  diagnostics: z.array(z.string()),
22
23
  });
24
+ export const SessionProviderScopeWarningSchema = z.object({
25
+ code: z.literal('CONFIGURED_PROVIDERS_OUTSIDE_SCOPE'),
26
+ configuredProviders: z.array(ExpectedSessionProviderSchema),
27
+ expectedProviders: z.array(ExpectedSessionProviderSchema),
28
+ missingProviders: z.array(ExpectedSessionProviderSchema),
29
+ message: z.string(),
30
+ });
23
31
  export const SessionCoveragePreflightSchema = z.object({
24
32
  expectedProviders: z.array(ExpectedSessionProviderSchema).min(1),
25
- expectedProviderBasis: z.enum(['explicit', 'declared-default', 'legacy']),
33
+ expectedProviderBasis: z.enum(['explicit', 'workspace-config', 'declared-default', 'legacy']),
34
+ configuredProviders: z.array(ExpectedSessionProviderSchema).optional(),
35
+ scopeWarnings: z.array(SessionProviderScopeWarningSchema).optional(),
26
36
  supportedProviders: z.array(ExpectedSessionProviderSchema),
27
37
  runtime: SessionRuntimeIdentitySchema,
28
38
  status: z.enum(['partial', 'complete']),
@@ -37,7 +47,7 @@ export const SessionCoveragePreflightSchema = z.object({
37
47
  adapterVersion: z.string().nullable(),
38
48
  supportedOperations: z.array(z.string()),
39
49
  acquisitionModes: z.array(z.string()),
40
- sourceCount: z.number().int().nonnegative(),
50
+ sourceCount: integer().nonnegative(),
41
51
  boundaries: z.array(z.string()),
42
52
  remediation: z.string().nullable(),
43
53
  })),
@@ -71,7 +81,7 @@ export const SessionErrorCodeSchema = z.enum([
71
81
  ]);
72
82
  const VersionSchema = z.string().regex(/^\d+\.\d+\.\d+(?:[-+].+)?$/);
73
83
  const DigestSchema = z.string().regex(/^sha256:[a-f0-9]{64}$/);
74
- const NativeExtensionsSchema = z.record(z.unknown()).superRefine((value, context) => {
84
+ const NativeExtensionsSchema = z.record(z.string(), z.unknown()).superRefine((value, context) => {
75
85
  for (const key of Object.keys(value)) {
76
86
  if (!key.startsWith('native.')) {
77
87
  context.addIssue({ code: z.ZodIssueCode.custom, message: `native extension must use native.<provider>: ${key}` });
@@ -90,8 +100,8 @@ export const SessionSourceSchema = z.object({
90
100
  disposition: CapabilityDispositionSchema,
91
101
  operationalState: OperationalStateSchema,
92
102
  consistency: ConsistencyStateSchema,
93
- authorizedAt: z.string().datetime({ offset: true }),
94
- extensions: NativeExtensionsSchema.default({}),
103
+ authorizedAt: dateTime({ offset: true }),
104
+ extensions: NativeExtensionsSchema.prefault({}),
95
105
  });
96
106
  export const SessionEventSchema = z.object({
97
107
  contractVersion: z.literal(SESSION_CONTRACT_VERSION),
@@ -100,7 +110,7 @@ export const SessionEventSchema = z.object({
100
110
  sourceId: z.string().min(1),
101
111
  importRunId: z.string().min(1),
102
112
  nativeId: z.string().min(1).nullable(),
103
- sequence: z.number().int().nonnegative(),
113
+ sequence: integer().nonnegative(),
104
114
  kind: z.string().min(1),
105
115
  role: z.string().min(1).nullable(),
106
116
  participant: z.string().min(1).nullable().default(null),
@@ -109,7 +119,7 @@ export const SessionEventSchema = z.object({
109
119
  model: z.string().min(1).nullable().default(null),
110
120
  entities: z.array(z.string().min(1)).default([]),
111
121
  extractionState: z.string().min(1).nullable().default(null),
112
- occurredAt: z.string().datetime({ offset: true }).nullable(),
122
+ occurredAt: dateTime({ offset: true }).nullable(),
113
123
  activityBoundary: z.enum(['pause', 'resume', 'continuation', 'end']).nullable().default(null),
114
124
  activityBoundaryBasis: z.string().min(1).nullable().default(null),
115
125
  activityBoundaryConfidence: z.enum(['low', 'medium', 'high']).nullable().default(null),
@@ -123,8 +133,8 @@ export const SessionEventSchema = z.object({
123
133
  digest: DigestSchema,
124
134
  rawReference: z.object({
125
135
  locatorClass: z.string().min(1),
126
- offset: z.number().int().nonnegative().optional(),
127
- sequence: z.number().int().nonnegative().optional(),
136
+ offset: integer().nonnegative().optional(),
137
+ sequence: integer().nonnegative().optional(),
128
138
  }),
129
139
  adapterVersion: VersionSchema,
130
140
  consistency: ConsistencyStateSchema,
@@ -133,7 +143,7 @@ export const SessionEventSchema = z.object({
133
143
  classes: z.array(z.string().min(1)),
134
144
  }),
135
145
  opaque: z.boolean().default(false),
136
- extensions: NativeExtensionsSchema.default({}),
146
+ extensions: NativeExtensionsSchema.prefault({}),
137
147
  });
138
148
  export const SessionSchema = z.object({
139
149
  contractVersion: z.literal(SESSION_CONTRACT_VERSION),
@@ -142,8 +152,8 @@ export const SessionSchema = z.object({
142
152
  provider: CompatibleSessionProviderIdSchema,
143
153
  nativeSessionId: z.string().min(1),
144
154
  workspaceId: z.string().min(1),
145
- startedAt: z.string().datetime({ offset: true }).nullable(),
146
- updatedAt: z.string().datetime({ offset: true }).nullable(),
155
+ startedAt: dateTime({ offset: true }).nullable(),
156
+ updatedAt: dateTime({ offset: true }).nullable(),
147
157
  consistency: ConsistencyStateSchema,
148
158
  lifecycle: z.enum([
149
159
  'active', 'inactive', 'paused', 'complete', 'interrupted', 'archived',
@@ -152,10 +162,10 @@ export const SessionSchema = z.object({
152
162
  intent: z.object({
153
163
  status: z.enum(['selected', 'absent', 'unknown']),
154
164
  eventId: z.string().min(1).nullable(),
155
- sequence: z.number().int().nonnegative().nullable(),
165
+ sequence: integer().nonnegative().nullable(),
156
166
  title: z.string().nullable(),
157
167
  summary: z.string().nullable(),
158
- }).default({
168
+ }).prefault({
159
169
  status: 'unknown',
160
170
  eventId: null,
161
171
  sequence: null,
@@ -163,12 +173,12 @@ export const SessionSchema = z.object({
163
173
  summary: null,
164
174
  }),
165
175
  sourceDigest: DigestSchema,
166
- extensions: NativeExtensionsSchema.default({}),
176
+ extensions: NativeExtensionsSchema.prefault({}),
167
177
  });
168
178
  export const ImportCheckpointSchema = z.object({
169
179
  cursor: z.string(),
170
- recordsRead: z.number().int().nonnegative(),
171
- bytesRead: z.number().int().nonnegative(),
180
+ recordsRead: integer().nonnegative(),
181
+ bytesRead: integer().nonnegative(),
172
182
  checkpointVersion: z.literal('2').optional(),
173
183
  positionKind: z.enum(['record-index', 'byte-offset', 'provider-native']).optional(),
174
184
  sourceGeneration: z.string().min(1).optional(),
@@ -182,8 +192,8 @@ export const ImportCheckpointSchema = z.object({
182
192
  'unchanged-replay',
183
193
  'unverified',
184
194
  ]).optional(),
185
- sourceSize: z.number().int().nonnegative().optional(),
186
- sourceMtimeMs: z.number().nonnegative().optional(),
195
+ sourceSize: integer().nonnegative().optional(),
196
+ sourceMtimeMs: number().check(z.gte(0)).meta({ type: 'number', minimum: 0 }).optional(),
187
197
  sourceFileIdentity: z.string().min(1).optional(),
188
198
  prefixDigest: DigestSchema.optional(),
189
199
  });
@@ -197,8 +207,8 @@ export const ImportRunSchema = z.object({
197
207
  consistency: ConsistencyStateSchema,
198
208
  status: z.enum(['running', 'committed', 'rolled-back', 'failed']),
199
209
  checkpoint: ImportCheckpointSchema,
200
- startedAt: z.string().datetime({ offset: true }),
201
- completedAt: z.string().datetime({ offset: true }).nullable(),
210
+ startedAt: dateTime({ offset: true }),
211
+ completedAt: dateTime({ offset: true }).nullable(),
202
212
  errorCode: SessionErrorCodeSchema.nullable(),
203
213
  });
204
214
  export const ProvenanceEdgeSchema = z.object({
@@ -211,7 +221,7 @@ export const ProvenanceEdgeSchema = z.object({
211
221
  fromId: z.string().min(1),
212
222
  toId: z.string().min(1),
213
223
  importRunId: z.string().min(1),
214
- createdAt: z.string().datetime({ offset: true }),
224
+ createdAt: dateTime({ offset: true }),
215
225
  });
216
226
  export const IntelligenceCandidateTypeSchema = z.enum([
217
227
  'decision', 'requirement', 'constraint', 'preference', 'task', 'discovery',
@@ -222,29 +232,29 @@ export const CandidateSecurityWarningSchema = z.enum([
222
232
  'instruction-like', 'structure-breaking', 'control-character', 'bidi-control',
223
233
  'unicode-confusable', 'active-content', 'secret-bearing',
224
234
  ]);
225
- export const CandidateSecuritySchema = z.object({
235
+ export const CandidateSecuritySchema = z.strictObject({
226
236
  disposition: z.enum(['clear', 'suspicious']),
227
237
  warnings: z.array(CandidateSecurityWarningSchema),
228
238
  requiresAcknowledgement: z.boolean(),
229
239
  acknowledged: z.boolean(),
230
240
  policyVersion: VersionSchema,
231
- }).strict();
232
- export const IntelligenceCandidateSchema = z.object({
241
+ });
242
+ export const IntelligenceCandidateSchema = z.strictObject({
233
243
  contractVersion: z.literal(SESSION_CONTRACT_VERSION),
234
244
  candidateId: z.string().min(1),
235
- version: z.number().int().positive(),
245
+ version: integer().positive(),
236
246
  type: IntelligenceCandidateTypeSchema,
237
247
  assertion: z.string().min(1),
238
248
  subject: z.string().min(1).nullable(),
239
249
  predicate: z.string().min(1).nullable(),
240
250
  object: z.string().min(1).nullable(),
241
- evidence: z.array(z.object({
251
+ evidence: z.array(z.strictObject({
242
252
  eventId: z.string().min(1),
243
- start: z.number().int().nonnegative(),
244
- end: z.number().int().positive(),
253
+ start: integer().nonnegative(),
254
+ end: integer().positive(),
245
255
  quoteDigest: DigestSchema,
246
256
  quote: z.string().min(1).optional(),
247
- }).strict()).min(1),
257
+ })).min(1),
248
258
  confidence: z.number().min(0).max(1),
249
259
  temporalScope: z.string().min(1),
250
260
  projectScope: z.string().min(1),
@@ -253,7 +263,7 @@ export const IntelligenceCandidateSchema = z.object({
253
263
  extractionPolicyVersion: VersionSchema,
254
264
  model: z.string().min(1).nullable(),
255
265
  sensitivity: z.enum(['none', 'sensitive']),
256
- security: CandidateSecuritySchema.default({
266
+ security: CandidateSecuritySchema.prefault({
257
267
  disposition: 'clear',
258
268
  warnings: [],
259
269
  requiresAcknowledgement: false,
@@ -265,8 +275,8 @@ export const IntelligenceCandidateSchema = z.object({
265
275
  ]),
266
276
  conflictsWith: z.array(z.string().min(1)).default([]),
267
277
  supersedes: z.array(z.string().min(1)).default([]),
268
- createdAt: z.string().datetime({ offset: true }),
269
- }).strict().superRefine((candidate, context) => {
278
+ createdAt: dateTime({ offset: true }),
279
+ }).superRefine((candidate, context) => {
270
280
  if (candidate.type === 'relationship'
271
281
  && (!candidate.subject || !candidate.predicate || !candidate.object)) {
272
282
  context.addIssue({
@@ -275,11 +285,11 @@ export const IntelligenceCandidateSchema = z.object({
275
285
  });
276
286
  }
277
287
  });
278
- export const CandidateReviewReceiptSchema = z.object({
288
+ export const CandidateReviewReceiptSchema = z.strictObject({
279
289
  contractVersion: z.literal(SESSION_CONTRACT_VERSION),
280
290
  receiptId: z.string().min(1),
281
291
  candidateId: z.string().min(1),
282
- candidateVersion: z.number().int().positive(),
292
+ candidateVersion: integer().positive(),
283
293
  fromState: z.enum([
284
294
  'pending', 'accepted', 'rejected', 'deferred', 'promoted', 'superseded',
285
295
  ]),
@@ -290,18 +300,18 @@ export const CandidateReviewReceiptSchema = z.object({
290
300
  reason: z.string().min(1),
291
301
  securityWarnings: z.array(CandidateSecurityWarningSchema).default([]),
292
302
  securityAcknowledged: z.boolean().default(false),
293
- occurredAt: z.string().datetime({ offset: true }),
294
- }).strict();
295
- export const PromotionReceiptSchema = z.object({
303
+ occurredAt: dateTime({ offset: true }),
304
+ });
305
+ export const PromotionReceiptSchema = z.strictObject({
296
306
  contractVersion: z.literal(SESSION_CONTRACT_VERSION),
297
307
  receiptId: z.string().min(1),
298
308
  operationId: z.string().min(1),
299
309
  candidateId: z.string().min(1),
300
- candidateVersion: z.number().int().positive(),
310
+ candidateVersion: integer().positive(),
301
311
  consumer: z.string().min(1),
302
312
  destinationRef: z.string().min(1),
303
313
  reviewer: z.string().min(1),
304
- approvedAt: z.string().datetime({ offset: true }),
314
+ approvedAt: dateTime({ offset: true }),
305
315
  evidenceEventIds: z.array(z.string().min(1)).min(1),
306
316
  conflictsWith: z.array(z.string().min(1)),
307
317
  supersedes: z.array(z.string().min(1)),
@@ -309,27 +319,27 @@ export const PromotionReceiptSchema = z.object({
309
319
  afterHash: DigestSchema,
310
320
  dryRun: z.boolean(),
311
321
  duplicate: z.boolean(),
312
- }).strict();
313
- export const DeletionReceiptSchema = z.object({
322
+ });
323
+ export const DeletionReceiptSchema = z.strictObject({
314
324
  contractVersion: z.literal(SESSION_CONTRACT_VERSION),
315
325
  receiptId: z.string().min(1),
316
326
  operationId: z.string().min(1),
317
327
  scopeClass: z.string().min(1),
318
- counts: z.record(z.number().int().nonnegative()),
328
+ counts: z.record(z.string(), integer().nonnegative()),
319
329
  survivingDependentIds: z.array(z.string().min(1)),
320
330
  actorClass: z.string().min(1),
321
331
  reasonCode: z.string().min(1),
322
- orphanCounts: z.record(z.number().int().nonnegative()),
332
+ orphanCounts: z.record(z.string(), integer().nonnegative()),
323
333
  outcome: z.enum(['preview', 'committed', 'failed']),
324
- occurredAt: z.string().datetime({ offset: true }),
325
- }).strict();
326
- export const PromotionDependencyDecisionSchema = z.object({
334
+ occurredAt: dateTime({ offset: true }),
335
+ });
336
+ export const PromotionDependencyDecisionSchema = z.strictObject({
327
337
  dependentId: z.string().min(1),
328
338
  action: z.enum([
329
339
  'revoke', 'supersede', 'retain', 'origin_unavailable', 'delete', 'abort',
330
340
  ]),
331
341
  basis: z.string().min(1),
332
- }).strict();
342
+ });
333
343
  export function assertSessionProviderId(value) {
334
344
  const canonical = SESSION_PROVIDER_ALIASES[value] ?? value;
335
345
  const parsed = SessionProviderIdSchema.safeParse(canonical);
@@ -364,7 +374,7 @@ function stableId(prefix, ...parts) {
364
374
  return `${prefix}_${createHash('sha256').update(parts.join('\0')).digest('hex')}`;
365
375
  }
366
376
  export const SessionRejectionDetailSchema = z.union([
367
- z.object({ limit: z.string(), configured: z.number(), observed: z.number(),
377
+ z.object({ limit: z.string(), configured: number(), observed: number(),
368
378
  setting: z.string().optional(), origin: z.enum(['flag', 'env', 'config', 'default']).optional() }),
369
379
  z.object({ issues: z.array(z.object({ path: z.string(), code: z.string() })) }),
370
380
  ]);
@@ -381,16 +391,25 @@ export function assertSessionResourceLimit(limit, configured, observed) {
381
391
  /** Extract schema locations and validator codes without messages or input values. */
382
392
  export function schemaRejectionDetail(error) {
383
393
  const issues = [];
384
- const visit = (entries) => {
394
+ const visit = (entries, prefix = []) => {
385
395
  for (const issue of entries) {
386
396
  if (issues.length >= 20)
387
397
  return;
388
- if (issue.code === 'invalid_union') {
389
- for (const branch of issue.unionErrors)
390
- visit(branch.issues);
398
+ const path = [...prefix, ...issue.path];
399
+ if (issue.code === 'invalid_union' && issue.errors.length === 0) {
400
+ issues.push({ path: path.join('.') || '<root>', code: 'invalid_union_discriminator' });
401
+ }
402
+ else if (issue.code === 'invalid_union') {
403
+ // Native union branches carry paths relative to their parent union.
404
+ for (const branch of issue.errors)
405
+ visit(branch, path);
391
406
  }
392
407
  else {
393
- issues.push({ path: issue.path.join('.') || '<root>', code: issue.code });
408
+ // Keep the published diagnostic codes stable across validator versions.
409
+ const code = issue.code === 'invalid_value'
410
+ ? (issue.values.length === 1 ? 'invalid_literal' : 'invalid_enum_value')
411
+ : issue.code === 'invalid_format' ? 'invalid_string' : issue.code;
412
+ issues.push({ path: path.join('.') || '<root>', code });
394
413
  }
395
414
  }
396
415
  };
@@ -19,6 +19,29 @@ export function expectedSessionProviders(values) {
19
19
  }
20
20
  return [...new Set(providers)].sort();
21
21
  }
22
+ export function providerScopeWarnings(configured, expected, recorded = []) {
23
+ const configuredProviders = configured.length ? expectedSessionProviders(configured) : [];
24
+ const expectedProviders = expected.length ? expectedSessionProviders(expected) : [];
25
+ const missingProviders = configuredProviders.filter(provider => !expectedProviders.includes(provider));
26
+ const current = missingProviders.length ? [{
27
+ code: 'CONFIGURED_PROVIDERS_OUTSIDE_SCOPE', configuredProviders, expectedProviders, missingProviders,
28
+ message: `Configured providers outside discovery scope: ${missingProviders.join(', ')}. Rediscover or refresh with current workspace config; verify authorized roots before rebuilding.`,
29
+ }] : [];
30
+ return [...recorded, ...current].filter((warning, index, all) => all.findIndex(item => JSON.stringify(item) === JSON.stringify(warning)) === index);
31
+ }
32
+ /** Explicit scope applies once; maintenance combines current config with saved root grants. */
33
+ export function resolveSessionProviderScope(configured, explicit, authorized) {
34
+ const configuredProviders = configured.length ? expectedSessionProviders(configured) : [];
35
+ const values = [...configuredProviders, ...(authorized ?? [])];
36
+ const expectedProviders = expectedSessionProviders(explicit ?? (values.length ? values : SESSION_PROVIDER_IDS));
37
+ return {
38
+ expectedProviders,
39
+ expectedProviderBasis: explicit ? 'explicit' : configuredProviders.length ? 'workspace-config'
40
+ : authorized?.length ? 'explicit' : 'declared-default',
41
+ configuredProviders,
42
+ scopeWarnings: providerScopeWarnings(configuredProviders, expectedProviders),
43
+ };
44
+ }
22
45
  /** Resolve the code actually loaded, independently of cwd, AIWG_ROOT and corpus redirects. */
23
46
  export function sessionRuntimeIdentity() {
24
47
  const packageRoot = findPackageRoot(dirname(fileURLToPath(import.meta.url)));
@@ -103,6 +126,8 @@ export function coveragePreflight(options = {}) {
103
126
  return SessionCoveragePreflightSchema.parse({
104
127
  expectedProviders,
105
128
  expectedProviderBasis: options.expectedProviderBasis ?? (options.expectedProviders ? 'explicit' : 'declared-default'),
129
+ ...(options.configuredProviders ? { configuredProviders: options.configuredProviders } : {}),
130
+ ...(options.scopeWarnings ? { scopeWarnings: options.scopeWarnings } : {}),
106
131
  supportedProviders: adapters.map((adapter) => adapter.provider), runtime,
107
132
  status: 'partial', unresolvedProviders: expectedProviders, ledger,
108
133
  });
@@ -127,7 +152,7 @@ export function reconcileCoveragePreflight(preflight, sources) {
127
152
  const runtimeGap = ['mismatch', 'stale', 'unknown'].includes(preflight.runtime.installationState);
128
153
  return {
129
154
  ...preflight, ledger, unresolvedProviders,
130
- status: unresolvedProviders.length > 0 || runtimeGap || preflight.expectedProviderBasis !== 'explicit'
155
+ status: unresolvedProviders.length > 0 || runtimeGap || !['explicit', 'workspace-config'].includes(preflight.expectedProviderBasis)
131
156
  ? 'partial' : 'complete',
132
157
  };
133
158
  }
@@ -2,34 +2,35 @@ import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameS
2
2
  import { createHash, randomUUID } from 'node:crypto';
3
3
  import { dirname, relative, resolve, sep } from 'node:path';
4
4
  import { z } from 'zod';
5
+ import { integer } from '../schema/zod-validation.mjs';
5
6
  import { SessionContractError, sha256 } from './contracts.js';
6
7
  const DigestSchema = z.string().regex(/^sha256:[0-9a-f]{64}$/);
7
8
  const ReferenceSchema = z.string().min(1).max(512).refine(value => !/[\r\n\0]/.test(value), 'references must be single-line inert locators');
8
- export const OutputSourceReferenceSchema = z.object({
9
+ export const OutputSourceReferenceSchema = z.strictObject({
9
10
  kind: z.enum(['file', 'url', 'note', 'session', 'artifact', 'context-pack']),
10
11
  ref: ReferenceSchema,
11
12
  digest: DigestSchema.nullable().default(null),
12
- span: z.object({
13
- start: z.number().int().nonnegative(),
14
- end: z.number().int().positive(),
13
+ span: z.strictObject({
14
+ start: integer().nonnegative(),
15
+ end: integer().positive(),
15
16
  quoteDigest: DigestSchema,
16
- }).strict().nullable().default(null),
17
- }).strict().superRefine((value, context) => {
17
+ }).nullable().default(null),
18
+ }).superRefine((value, context) => {
18
19
  if (value.span && value.span.end <= value.span.start) {
19
20
  context.addIssue({ code: z.ZodIssueCode.custom, message: 'source span end must exceed start' });
20
21
  }
21
22
  });
22
- export const OutputRegistrationRequestSchema = z.object({
23
+ export const OutputRegistrationRequestSchema = z.strictObject({
23
24
  outputPath: z.string().min(1),
24
25
  mediaType: z.string().min(1).max(128),
25
- contextPack: z.object({
26
+ contextPack: z.strictObject({
26
27
  id: ReferenceSchema,
27
28
  digest: DigestSchema,
28
29
  sources: z.array(OutputSourceReferenceSchema).min(1).max(256),
29
- }).strict(),
30
+ }),
30
31
  supersedes: z.array(ReferenceSchema).max(128).default([]),
31
32
  conflictsWith: z.array(ReferenceSchema).max(128).default([]),
32
- }).strict();
33
+ });
33
34
  /**
34
35
  * Minimal incremental index sink. Each registration is independently atomic,
35
36
  * discoverable, and replay-safe; corpus-wide index builders can consume these
@@ -56,20 +56,31 @@ async function safeRealpath(path, root = false) {
56
56
  throw new SessionContractError('SOURCE_NOT_AUTHORIZED', root ? 'an authorized source root is inaccessible' : 'selected session source is inaccessible');
57
57
  }
58
58
  }
59
+ // Newline gaps are bounded and each repetition consumes a line break, keeping
60
+ // indentation scans disjoint even on large malformed records (#3273, #3404).
61
+ const VALUE_GAP = /[ \t]*(?:\r?\n[ \t]*){0,2}/.source;
62
+ const NEXT_LINE_GAP = /[ \t]*(?:\r?\n[ \t]*){1,2}/.source;
63
+ const QUOTED_VALUE = /"(?:\\[^\r\n]|[^"\\\r\n])+"|'(?:\\[^\r\n]|[^'\\\r\n])+'|`(?!`)(?:\\[^\r\n]|[^`\\\r\n])+`(?!`)/.source;
64
+ const GENERATED_VALUE = /(?=[A-Za-z0-9._~+/=-]*[0-9])(?=[A-Za-z0-9._~+/=-]*[A-Za-z])[A-Za-z0-9._~+/=-]{20,}/.source;
65
+ function assignmentPattern(key, separator, sameLineValue) {
66
+ // Only the next-line branch needs stronger evidence: quoted text or a long
67
+ // generated value. In particular, YAML lists and Markdown fences are prose.
68
+ return new RegExp(`\\b${key}[ \\t]*${separator}(?:${NEXT_LINE_GAP}(?:${QUOTED_VALUE}|${GENERATED_VALUE})|[ \\t]*(?:${QUOTED_VALUE}|${sameLineValue}))`, 'gi');
69
+ }
59
70
  // Ambiguous token components are bounded; whitespace and key blocks use disjoint scans.
60
71
  const SECRET_PATTERNS = [
61
- ['bearer-token', /\bBearer[ \t]+[A-Za-z0-9._~+/=-]{12,}/gi],
62
- ['authorization', /\bAuthorization[ \t]*:[ \t]*[^\r\n]+/gi],
63
- ['cookie', /\b(?:Cookie|Set-Cookie)[ \t]*:[ \t]*[^\r\n]+/gi],
64
- ['environment-assignment', /\b(?:AWS_SECRET_ACCESS_KEY|[A-Z][A-Z0-9_]*(?:TOKEN|SECRET|PASSWORD|PASSWD|API_KEY))[ \t]*=[ \t]*(?:"[^"\r\n]+"|'[^'\r\n]+'|[^\s]+)/gi],
65
- ['credential', /\b(?:api[_-]?key|token|password|secret)[ \t]*[:=][ \t]*["']?[^\s"',;]{6,}/gi],
72
+ ['bearer-token', new RegExp(`\\bBearer(?:[ \\t]+|${NEXT_LINE_GAP})(?:${QUOTED_VALUE}|\\\\"[A-Za-z0-9._~+/=-]{12,}\\\\"|[A-Za-z0-9._~+/=-]{12,})`, 'gi')],
73
+ ['authorization', new RegExp(`\\bAuthorization[ \\t]*:${VALUE_GAP}[^\\s][^\\r\\n]*`, 'gi')],
74
+ ['cookie', new RegExp(`\\b(?:Cookie|Set-Cookie)[ \\t]*:${VALUE_GAP}[^\\s][^\\r\\n]*`, 'gi')],
75
+ ['environment-assignment', assignmentPattern('(?:AWS_SECRET_ACCESS_KEY|[A-Z][A-Z0-9_]*(?:TOKEN|SECRET|PASSWORD|PASSWD|API_KEY))', '=', /[^\s]+/.source)],
76
+ ['credential', assignmentPattern('(?:api[_-]?key|token|password|secret)', '[:=]', /["'`]?[^\s"'`,;]{6,}/.source)],
66
77
  ['credential', /^[ \t]*password[ \t]+[^\s]+[ \t]*$/gim],
67
78
  // Space-separated values only when they look generated (20+ chars, letters and digits), so prose stays.
68
- ['credential', /\b(?:api[_-]?key|token|secret)[ \t]+(?=[A-Za-z0-9._~+/=-]*[0-9])(?=[A-Za-z0-9._~+/=-]*[A-Za-z])[A-Za-z0-9._~+/=-]{20,}/gi],
79
+ ['credential', new RegExp(`\\b(?:api[_-]?key|token|secret)[ \\t]+${GENERATED_VALUE}`, 'gi')],
69
80
  ['provider-token', /\b(?:sk-(?:ant-|proj-)?|[sr]k_(?:live|test)_|gh[pousr]_|github_pat_|glpat-|xai-|npm_|hf_|xox[baprs]-|AKIA|AIza)[A-Za-z0-9._~+/=-]{8,}/g],
70
81
  ['provider-token', /https:\/\/hooks\.slack\.com\/services\/[A-Za-z0-9_-]+\/[A-Za-z0-9_-]+\/[A-Za-z0-9_-]+/g],
71
82
  ['connection-string', /\b(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis):\/\/[^\s]+/gi],
72
- ['credential-url', /\bhttps?:\/\/[^/\s:@]+:[^/\s@]+@[^\s]+/gi],
83
+ ['credential-url', new RegExp(`\\bhttps?://${VALUE_GAP}[^/\\s:@]+:${VALUE_GAP}(?:${QUOTED_VALUE}|[^/\\s@]+)@${VALUE_GAP}[^\\s"'\x60<>\\\\]+`, 'gi')],
73
84
  ['fixture-credential', /\bredaction-canary-[A-Za-z0-9_-]+\b/gi],
74
85
  ['email', /\b[A-Z0-9._%+-]{1,64}@[A-Z0-9.-]{1,253}\.[A-Z]{2,63}\b/gi],
75
86
  ];
@@ -20,7 +20,7 @@ export function sessionRefreshAvailable() {
20
20
  return false;
21
21
  }
22
22
  }
23
- /** Refresh an existing catalog without inferring or granting provider access. */
23
+ /** Refresh current configured scope within saved provider root grants. */
24
24
  export async function refreshSessionCatalog(workspace, full, waitMs, signal, workspaceAliases = [], flags = {}) {
25
25
  const canonicalWorkspace = realpathSync(workspace);
26
26
  const config = await readAiwgConfig(canonicalWorkspace);
@@ -56,8 +56,7 @@ export async function refreshSessionCatalog(workspace, full, waitMs, signal, wor
56
56
  const manifest = await discoverWorkspaceHistories({
57
57
  workspace: canonicalWorkspace,
58
58
  workspaceAliases: [workspace, ...workspaceAliases],
59
- expectedProviders: providers,
60
- authorizedRoots,
59
+ refreshFrom: { ...previous, authorizedRoots },
61
60
  registry: createSessionAdapterRegistry(limits),
62
61
  exclude,
63
62
  knownSources: previous.sources,
@@ -13,7 +13,7 @@ const VISIBLE_SESSION_PREDICATE = `s.lifecycle != 'tombstoned' AND EXISTS (
13
13
  )`;
14
14
  export class SessionRepository {
15
15
  db;
16
- constructor(path = ':memory:') {
16
+ constructor(path = ':memory:', options = {}) {
17
17
  let Database;
18
18
  try {
19
19
  Database = requireFeaturePackage('better-sqlite3');
@@ -23,7 +23,9 @@ export class SessionRepository {
23
23
  'run `aiwg features install sqlite`, then retry. If the native build fails, install ' +
24
24
  'Python 3, make, and a C/C++ compiler supported by node-gyp.', { cause });
25
25
  }
26
- this.db = new Database(path);
26
+ this.db = new Database(path, options.readonly ? { readonly: true, fileMustExist: true } : undefined);
27
+ if (options.readonly)
28
+ return;
27
29
  this.db.pragma('foreign_keys = ON');
28
30
  this.db.pragma('journal_mode = WAL');
29
31
  this.db.pragma('busy_timeout = 5000');