@aiwg/cli 2026.9.20 → 2026.9.21

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 (272) hide show
  1. package/agentic/code/providers/capability-matrix.yaml +58 -6
  2. package/agentic/code/providers/model-capabilities.v1.json +34 -0
  3. package/agentic/code/providers/model-catalog.v1.json +55 -13
  4. package/bin/aiwg.mjs +2 -0
  5. package/dist/src/api/index.d.ts +1 -0
  6. package/dist/src/api/index.js +1 -0
  7. package/dist/src/artifacts/enrichment/cli.js +1 -1
  8. package/dist/src/artifacts/views/cli.js +1 -1
  9. package/dist/src/audit/operator-decision.js +10 -0
  10. package/dist/src/auth/credential-store.js +127 -27
  11. package/dist/src/catalog/builtin-models.json +272 -40
  12. package/dist/src/catalog/cli.js +1 -1
  13. package/dist/src/catalog/cli.mjs +1 -1
  14. package/dist/src/cli/handlers/effect.js +872 -0
  15. package/dist/src/cli/handlers/help.js +2 -0
  16. package/dist/src/cli/handlers/index.js +4 -2
  17. package/dist/src/cli/handlers/models.js +41 -10
  18. package/dist/src/cli/handlers/ralph.js +1 -1
  19. package/dist/src/cli/handlers/sessions.js +113 -37
  20. package/dist/src/cli/handlers/subcommands.js +31 -0
  21. package/dist/src/cli/handlers/use.js +46 -9
  22. package/dist/src/cli/handlers/utilities.js +10 -0
  23. package/dist/src/cli/handlers/workspace.js +3 -1
  24. package/dist/src/cli/scope-resolver.js +112 -9
  25. package/dist/src/cli/services/deployment-verification.js +5 -0
  26. package/dist/src/config/aiwg-config.js +3 -0
  27. package/dist/src/decision/acceptance-rollout.js +93 -0
  28. package/dist/src/decision/acceptance.js +175 -0
  29. package/dist/src/decision/adapters/jev.js +234 -13
  30. package/dist/src/decision/adapters/llm-subagent.js +60 -12
  31. package/dist/src/decision/admission.js +550 -0
  32. package/dist/src/decision/batch-benchmark.js +47 -0
  33. package/dist/src/decision/batch-receipts/accounting.js +75 -0
  34. package/dist/src/decision/batch-receipts/export.js +40 -0
  35. package/dist/src/decision/batch-receipts/index.js +9 -0
  36. package/dist/src/decision/batch-receipts/protection.js +40 -0
  37. package/dist/src/decision/batch-receipts/receipt.js +44 -0
  38. package/dist/src/decision/batch-receipts/result-store.js +341 -0
  39. package/dist/src/decision/batch-receipts/store.js +362 -0
  40. package/dist/src/decision/batch-receipts/types.js +2 -0
  41. package/dist/src/decision/batch-receipts/validate.js +127 -0
  42. package/dist/src/decision/batch.js +68 -0
  43. package/dist/src/decision/calibration/index.js +4 -0
  44. package/dist/src/decision/calibration/receipts.js +130 -0
  45. package/dist/src/decision/calibration/registry.js +258 -0
  46. package/dist/src/decision/calibration/types.js +2 -0
  47. package/dist/src/decision/compile-cache/benchmark.js +62 -0
  48. package/dist/src/decision/compile-cache/compatibility.js +65 -0
  49. package/dist/src/decision/compile-cache/file-store.js +280 -0
  50. package/dist/src/decision/compile-cache/identity.js +26 -0
  51. package/dist/src/decision/compile-cache/index.js +9 -0
  52. package/dist/src/decision/compile-cache/prefix.js +21 -0
  53. package/dist/src/decision/compile-cache/records.js +86 -0
  54. package/dist/src/decision/compile-cache/runtime.js +68 -0
  55. package/dist/src/decision/compile-cache/store.js +108 -0
  56. package/dist/src/decision/compile-cache/types.js +2 -0
  57. package/dist/src/decision/context-plan.js +234 -0
  58. package/dist/src/decision/context-qualification.js +60 -0
  59. package/dist/src/decision/ensemble/aggregate.js +215 -0
  60. package/dist/src/decision/ensemble/contract.js +316 -0
  61. package/dist/src/decision/ensemble/drift.js +51 -0
  62. package/dist/src/decision/ensemble/index.js +6 -0
  63. package/dist/src/decision/ensemble/report.js +71 -0
  64. package/dist/src/decision/ensemble/types.js +2 -0
  65. package/dist/src/decision/evaluate.js +1024 -78
  66. package/dist/src/decision/file-lifecycle-store.js +168 -0
  67. package/dist/src/decision/graph-beam.js +40 -0
  68. package/dist/src/decision/graph-budget.js +110 -0
  69. package/dist/src/decision/graph-decision-bridge.js +93 -0
  70. package/dist/src/decision/graph-evidence.js +123 -0
  71. package/dist/src/decision/graph-flow-adapter.js +56 -0
  72. package/dist/src/decision/graph-flow.js +105 -0
  73. package/dist/src/decision/graph-parallel.js +79 -0
  74. package/dist/src/decision/graph-patterns.js +20 -0
  75. package/dist/src/decision/graph-run-store.js +66 -0
  76. package/dist/src/decision/graph-run.js +166 -0
  77. package/dist/src/decision/graph-skill-bridge.js +91 -0
  78. package/dist/src/decision/graph-templates.js +56 -0
  79. package/dist/src/decision/graph.js +115 -0
  80. package/dist/src/decision/index.js +35 -0
  81. package/dist/src/decision/job-accounting.js +93 -0
  82. package/dist/src/decision/job-contract.js +186 -0
  83. package/dist/src/decision/job-effects.js +95 -0
  84. package/dist/src/decision/job-evaluate.js +80 -0
  85. package/dist/src/decision/job-gateway.js +121 -0
  86. package/dist/src/decision/job-http.js +194 -0
  87. package/dist/src/decision/job-payload-store.js +258 -0
  88. package/dist/src/decision/job-poll-limiter.js +92 -0
  89. package/dist/src/decision/job-quota.js +158 -0
  90. package/dist/src/decision/job-runtime.js +240 -0
  91. package/dist/src/decision/job-scheduler.js +26 -0
  92. package/dist/src/decision/job-service.js +117 -0
  93. package/dist/src/decision/job-store.js +264 -0
  94. package/dist/src/decision/job-worker.js +141 -0
  95. package/dist/src/decision/lifecycle.js +148 -0
  96. package/dist/src/decision/patterns/artifacts.js +173 -0
  97. package/dist/src/decision/patterns/catalog.js +108 -0
  98. package/dist/src/decision/patterns/durable-review.js +237 -0
  99. package/dist/src/decision/patterns/index.js +8 -0
  100. package/dist/src/decision/patterns/playground.js +401 -0
  101. package/dist/src/decision/patterns/recorded.js +43 -0
  102. package/dist/src/decision/patterns/specs.js +174 -0
  103. package/dist/src/decision/patterns/types.js +2 -0
  104. package/dist/src/decision/portable-secrets.js +53 -0
  105. package/dist/src/decision/projection.js +210 -0
  106. package/dist/src/decision/qualification/capture.js +67 -0
  107. package/dist/src/decision/qualification/drift.js +68 -0
  108. package/dist/src/decision/qualification/gate-evidence.js +172 -0
  109. package/dist/src/decision/qualification/gates.js +83 -0
  110. package/dist/src/decision/qualification/index.js +12 -0
  111. package/dist/src/decision/qualification/load.js +275 -0
  112. package/dist/src/decision/qualification/manifest.js +37 -0
  113. package/dist/src/decision/qualification/privacy.js +41 -0
  114. package/dist/src/decision/qualification/quality.js +213 -0
  115. package/dist/src/decision/qualification/release.js +116 -0
  116. package/dist/src/decision/qualification/runner.js +408 -0
  117. package/dist/src/decision/qualification/types.js +2 -0
  118. package/dist/src/decision/receipts.js +30 -7
  119. package/dist/src/decision/result-cache/index.js +6 -0
  120. package/dist/src/decision/result-cache/integrity.js +28 -0
  121. package/dist/src/decision/result-cache/key.js +28 -0
  122. package/dist/src/decision/result-cache/service.js +92 -0
  123. package/dist/src/decision/result-cache/store.js +327 -0
  124. package/dist/src/decision/result-cache/types.js +3 -0
  125. package/dist/src/decision/review/authorization.js +110 -0
  126. package/dist/src/decision/review/effect-ledger-adapter.js +321 -0
  127. package/dist/src/decision/review/index.js +12 -0
  128. package/dist/src/decision/review/migrate.js +34 -0
  129. package/dist/src/decision/review/operator-audit.js +59 -0
  130. package/dist/src/decision/review/recovery-adapters.js +252 -0
  131. package/dist/src/decision/review/recovery.js +33 -0
  132. package/dist/src/decision/review/service.js +498 -0
  133. package/dist/src/decision/review/store.js +219 -0
  134. package/dist/src/decision/review/types.js +2 -0
  135. package/dist/src/decision/review/validate.js +205 -0
  136. package/dist/src/decision/scheduler.js +115 -0
  137. package/dist/src/decision/telemetry/context.js +42 -0
  138. package/dist/src/decision/telemetry/debug-sidecar.js +152 -0
  139. package/dist/src/decision/telemetry/exporter.js +77 -0
  140. package/dist/src/decision/telemetry/file-debug-backend.js +112 -0
  141. package/dist/src/decision/telemetry/index.js +13 -0
  142. package/dist/src/decision/telemetry/mapping.js +146 -0
  143. package/dist/src/decision/telemetry/metrics.js +164 -0
  144. package/dist/src/decision/telemetry/otlp-http.js +183 -0
  145. package/dist/src/decision/telemetry/redaction.js +93 -0
  146. package/dist/src/decision/telemetry/retention.js +109 -0
  147. package/dist/src/decision/telemetry/runtime.js +310 -0
  148. package/dist/src/decision/telemetry/trace.js +158 -0
  149. package/dist/src/decision/telemetry/types.js +3 -0
  150. package/dist/src/decision/validate.js +135 -5
  151. package/dist/src/effects/checkpoint-sinks.js +94 -0
  152. package/dist/src/effects/checkpoint.js +76 -0
  153. package/dist/src/effects/decision-links.js +54 -0
  154. package/dist/src/effects/errors.js +48 -0
  155. package/dist/src/effects/identity.js +178 -0
  156. package/dist/src/effects/index.js +25 -0
  157. package/dist/src/effects/keyring.js +160 -0
  158. package/dist/src/effects/keys.js +130 -0
  159. package/dist/src/effects/ledger.js +435 -0
  160. package/dist/src/effects/lifecycle.js +110 -0
  161. package/dist/src/effects/lock-recovery.js +269 -0
  162. package/dist/src/effects/reader.js +103 -0
  163. package/dist/src/effects/records.js +114 -0
  164. package/dist/src/effects/redaction.js +51 -0
  165. package/dist/src/effects/schema.js +73 -0
  166. package/dist/src/effects/store.js +239 -0
  167. package/dist/src/effects/types.js +49 -0
  168. package/dist/src/effects/verifiers/decision.js +168 -0
  169. package/dist/src/effects/verifiers/file.js +106 -0
  170. package/dist/src/effects/verifiers/git.js +206 -0
  171. package/dist/src/effects/verifiers/index.js +90 -0
  172. package/dist/src/effects/verifiers/registry.js +148 -0
  173. package/dist/src/effects/verifiers/review.js +123 -0
  174. package/dist/src/effects/verifiers/tracker.js +299 -0
  175. package/dist/src/effects/verifiers/types.js +21 -0
  176. package/dist/src/effects/verify.js +295 -0
  177. package/dist/src/evidence/bundle.js +2 -0
  178. package/dist/src/extensions/commands/definitions.js +28 -0
  179. package/dist/src/extensions/manifest.js +1 -0
  180. package/dist/src/marketplace/provenance.js +25 -27
  181. package/dist/src/mcp/cli.mjs +11 -1
  182. package/dist/src/mcp/grok-build-config.mjs +189 -0
  183. package/dist/src/mcp/registry.js +21 -1
  184. package/dist/src/mcp/registry.mjs +20 -1
  185. package/dist/src/models/grok-build-models.js +356 -0
  186. package/dist/src/models/index.js +1 -0
  187. package/dist/src/models/model-capabilities.v1.json +34 -0
  188. package/dist/src/models/model-catalog.v1.json +55 -13
  189. package/dist/src/models/model-discovery.js +41 -5
  190. package/dist/src/models/provider-policy.js +3 -2
  191. package/dist/src/plugin/skill-command-translator.js +1 -0
  192. package/dist/src/providers/capability-matrix.yaml +58 -6
  193. package/dist/src/providers/grok-build-acp.js +192 -0
  194. package/dist/src/providers/grok-build-dispatch.js +251 -0
  195. package/dist/src/providers/grok-build-headless.js +170 -0
  196. package/dist/src/providers/muse-paths.js +105 -0
  197. package/dist/src/providers/provider-definitions.js +93 -7
  198. package/dist/src/providers/provider-definitions.mjs +21 -1
  199. package/dist/src/providers/provider-inventory.js +3 -0
  200. package/dist/src/security/artifact-attestation.js +4 -8
  201. package/dist/src/security/signing.js +119 -0
  202. package/dist/src/sessions/adapters/grok-build.js +187 -0
  203. package/dist/src/sessions/adapters/muse.js +412 -0
  204. package/dist/src/sessions/contracts.js +1 -1
  205. package/dist/src/sessions/grok-build-cli.js +196 -0
  206. package/dist/src/sessions/index.js +3 -0
  207. package/dist/src/sessions/workspace-discovery.js +9 -5
  208. package/dist/src/skills/deployer.js +33 -5
  209. package/dist/src/smiths/context-pipeline/claude-hook.js +2 -0
  210. package/dist/src/smiths/context-pipeline/context-file-safety.js +18 -0
  211. package/dist/src/smiths/context-pipeline/finalization.js +1 -32
  212. package/dist/src/smiths/context-pipeline/generator.js +12 -0
  213. package/dist/src/smiths/context-pipeline/index.js +1 -1
  214. package/dist/src/smiths/context-pipeline/managed-hook.js +2 -0
  215. package/dist/src/smiths/context-pipeline/muse-bridge.js +50 -0
  216. package/dist/src/smiths/context-pipeline/provider-policy.js +5 -0
  217. package/dist/src/smiths/context-pipeline/workspace-context.js +22 -16
  218. package/dist/src/smiths/hook-bridge/grok-build-translator.js +64 -0
  219. package/dist/src/smiths/hook-bridge/index.js +3 -0
  220. package/dist/src/smiths/hook-bridge/shim.js +2 -0
  221. package/dist/src/smiths/hook-bridge/types.js +5 -0
  222. package/dist/src/smiths/skillsmith/collision-detector.js +1 -0
  223. package/dist/src/storage/protected-files.js +102 -0
  224. package/dist/src/tracker/forge-http.js +371 -0
  225. package/dist/src/tracker/project-inputs.js +41 -0
  226. package/package.json +2 -1
  227. package/schemas/decision/BatchReceipt.v1.schema.json +50 -0
  228. package/schemas/decision/CalibrationArtifact.v1.schema.json +76 -0
  229. package/schemas/decision/CalibrationCompatibility.v1.schema.json +18 -0
  230. package/schemas/decision/CalibrationGovernanceReceipt.v1.schema.json +44 -0
  231. package/schemas/decision/DecisionAdmissionEvidence.v1.schema.json +43 -0
  232. package/schemas/decision/DecisionBinding.schema.json +309 -0
  233. package/schemas/decision/DecisionBinding.v1alpha2.schema.json +369 -0
  234. package/schemas/decision/DecisionCacheTelemetry.v1.schema.json +20 -0
  235. package/schemas/decision/DecisionChampionChallenger.v1.schema.json +100 -0
  236. package/schemas/decision/DecisionCompileCacheEntry.v1.schema.json +35 -0
  237. package/schemas/decision/DecisionCompileCacheIdentity.v1.schema.json +26 -0
  238. package/schemas/decision/DecisionCompileCacheTombstone.v1.schema.json +31 -0
  239. package/schemas/decision/DecisionContextEvidence.v1.schema.json +136 -0
  240. package/schemas/decision/DecisionDefinition.schema.json +159 -0
  241. package/schemas/decision/DecisionDefinition.v1alpha2.schema.json +203 -0
  242. package/schemas/decision/DecisionDriftResponse.v1.schema.json +55 -0
  243. package/schemas/decision/DecisionEnsembleAggregate.v1.schema.json +86 -0
  244. package/schemas/decision/DecisionEnsembleIntegrityReport.v1.schema.json +64 -0
  245. package/schemas/decision/DecisionEnsemblePolicy.v1.schema.json +130 -0
  246. package/schemas/decision/DecisionGraph.v1.schema.json +77 -0
  247. package/schemas/decision/DecisionJob.v1.schema.json +71 -0
  248. package/schemas/decision/DecisionLifecyclePolicy.v1.schema.json +52 -0
  249. package/schemas/decision/DecisionProjectionPolicy.v1.schema.json +65 -0
  250. package/schemas/decision/DecisionProviderPrefixCompatibility.v1.schema.json +45 -0
  251. package/schemas/decision/DecisionProviderPrefixEvidence.v1.schema.json +17 -0
  252. package/schemas/decision/DecisionProviderPrefixIdentity.v1.schema.json +36 -0
  253. package/schemas/decision/DecisionResult.schema.json +524 -0
  254. package/schemas/decision/DecisionResult.v1alpha2.schema.json +619 -0
  255. package/schemas/decision/DecisionResultCacheEntry.v1.schema.json +53 -0
  256. package/schemas/decision/DecisionReview.schema.json +29 -0
  257. package/schemas/decision/DecisionRuleset.schema.json +313 -0
  258. package/schemas/decision/DecisionRuleset.v1alpha2.schema.json +313 -0
  259. package/schemas/decision/DecisionTelemetryTrace.v1.schema.json +95 -0
  260. package/schemas/decision/RulesetResult.schema.json +721 -0
  261. package/schemas/decision/RulesetResult.v1alpha2.schema.json +891 -0
  262. package/schemas/security/pr-evidence-receipt.v1.schema.json +77 -0
  263. package/schemas/security/threat-assessment-report.v1.schema.json +71 -1
  264. package/tools/agents/deploy-agents.mjs +21 -6
  265. package/tools/agents/providers/base.mjs +7 -4
  266. package/tools/agents/providers/codex.mjs +1 -1
  267. package/tools/agents/providers/grok-build.d.mts +7 -0
  268. package/tools/agents/providers/grok-build.mjs +249 -9
  269. package/tools/agents/providers/model-role.mjs +6 -3
  270. package/tools/agents/providers/muse-hooks.mjs +785 -0
  271. package/tools/agents/providers/muse-paths.mjs +112 -0
  272. package/tools/agents/providers/muse.mjs +336 -0
@@ -0,0 +1,170 @@
1
+ /** Bounded Grok Build headless transport. The caller owns task authorization. */
2
+ import { spawn } from 'node:child_process';
3
+ const MAX_TIMEOUT_MS = 10 * 60_000;
4
+ const DEFAULT_TIMEOUT_MS = 2 * 60_000;
5
+ const DEFAULT_MAX_OUTPUT = 8 * 1024 * 1024;
6
+ export function redactGrokOutput(value, env = process.env) {
7
+ let redacted = value
8
+ .replace(/\b(Bearer\s+)[A-Za-z0-9._~+/-]+/gi, '$1[REDACTED]')
9
+ .replace(/\b(xai-[A-Za-z0-9_-]{8,})\b/g, '[REDACTED]')
10
+ .replace(/\b((?:api[_-]?key|access[_-]?token|authorization)\s*[:=]\s*)[^\s,}"']+/gi, '$1[REDACTED]');
11
+ for (const key of ['XAI_API_KEY', 'GROK_CODE_XAI_API_KEY']) {
12
+ const secret = env[key];
13
+ if (secret && secret.length >= 4)
14
+ redacted = redacted.split(secret).join('[REDACTED]');
15
+ }
16
+ return redacted;
17
+ }
18
+ function scrubEvent(event, env) {
19
+ // JSON roundtrip scrubs nested provider event payloads before any callback.
20
+ return JSON.parse(redactGrokOutput(JSON.stringify(event), env));
21
+ }
22
+ function isTerminal(event) {
23
+ return ['result', 'error', 'complete', 'completed'].includes(String(event.type ?? event.event ?? ''));
24
+ }
25
+ function isError(event) {
26
+ return event.is_error === true || event.error !== undefined || ['error', 'failed'].includes(String(event.type ?? event.event ?? ''));
27
+ }
28
+ function stopProcess(child) {
29
+ if (child.pid && process.platform !== 'win32') {
30
+ try {
31
+ process.kill(-child.pid, 'SIGTERM');
32
+ return;
33
+ }
34
+ catch { /* process already exited */ }
35
+ }
36
+ child.kill('SIGTERM');
37
+ }
38
+ export async function runGrokHeadless(options) {
39
+ if (!options.prompt.trim())
40
+ throw new Error('Grok Build prompt is required');
41
+ const format = options.format ?? 'streaming-json';
42
+ if (!['plain', 'json', 'streaming-json'].includes(format))
43
+ throw new Error(`Unsupported Grok output format: ${format}`);
44
+ const timeoutMs = Math.min(Math.max(options.timeoutMs ?? DEFAULT_TIMEOUT_MS, 1), MAX_TIMEOUT_MS);
45
+ const maxBytes = Math.min(Math.max(options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT, 1024), DEFAULT_MAX_OUTPUT);
46
+ const env = options.env ?? process.env;
47
+ const args = [...(options.prefixArgs ?? []), '--no-auto-update', ...(options.disableSubagents ? ['--no-subagents'] : []), '-p', options.prompt, '--output-format', format];
48
+ return new Promise((resolve, reject) => {
49
+ const child = spawn(options.command ?? 'grok', args, {
50
+ cwd: options.cwd,
51
+ env,
52
+ stdio: ['ignore', 'pipe', 'pipe'],
53
+ detached: process.platform !== 'win32',
54
+ shell: false,
55
+ });
56
+ let stdout = '';
57
+ let stderr = '';
58
+ let pending = '';
59
+ let bytes = 0;
60
+ let settled = false;
61
+ let terminalSeen = false;
62
+ let terminalError = false;
63
+ const events = [];
64
+ let drainTimer;
65
+ const finish = (error, code = 0) => {
66
+ if (settled)
67
+ return;
68
+ settled = true;
69
+ clearTimeout(timer);
70
+ if (drainTimer)
71
+ clearTimeout(drainTimer);
72
+ options.signal?.removeEventListener('abort', abort);
73
+ if (error) {
74
+ stopProcess(child);
75
+ reject(error);
76
+ return;
77
+ }
78
+ const cleanStdout = redactGrokOutput(stdout, env);
79
+ const cleanStderr = redactGrokOutput(stderr, env);
80
+ if (code !== 0 || terminalError) {
81
+ reject(new Error(`Grok Build headless failed (exit ${code}): ${cleanStderr || 'provider error event'}`));
82
+ return;
83
+ }
84
+ if (format === 'streaming-json' && !terminalSeen) {
85
+ reject(new Error('Grok Build streaming-json ended without a terminal event'));
86
+ return;
87
+ }
88
+ if (format === 'json') {
89
+ try {
90
+ const parsed = JSON.parse(cleanStdout);
91
+ if (isError(parsed))
92
+ throw new Error('Grok Build returned a JSON error result');
93
+ events.push(parsed);
94
+ }
95
+ catch (cause) {
96
+ reject(cause instanceof Error ? cause : new Error('Invalid Grok Build JSON result'));
97
+ return;
98
+ }
99
+ }
100
+ resolve({ format, text: cleanStdout, events, exitCode: code, stderr: cleanStderr });
101
+ };
102
+ const abort = () => finish(new Error('Grok Build headless aborted'));
103
+ const timer = setTimeout(() => finish(new Error(`Grok Build headless timed out after ${timeoutMs}ms`)), timeoutMs);
104
+ options.signal?.addEventListener('abort', abort, { once: true });
105
+ if (options.signal?.aborted)
106
+ abort();
107
+ child.on('error', error => finish(new Error(`Grok Build headless launch failed: ${error.message}`)));
108
+ child.stdout.on('data', (chunk) => {
109
+ bytes += chunk.length;
110
+ if (bytes > maxBytes) {
111
+ finish(new Error(`Grok Build headless output exceeded ${maxBytes} bytes`));
112
+ return;
113
+ }
114
+ const part = chunk.toString('utf8');
115
+ stdout += part;
116
+ if (format !== 'streaming-json')
117
+ return;
118
+ pending += part;
119
+ let end;
120
+ while ((end = pending.indexOf('\n')) >= 0) {
121
+ const line = pending.slice(0, end).trim();
122
+ pending = pending.slice(end + 1);
123
+ if (!line)
124
+ continue;
125
+ let event;
126
+ try {
127
+ event = JSON.parse(line);
128
+ }
129
+ catch {
130
+ finish(new Error('Invalid Grok Build streaming-json event'));
131
+ return;
132
+ }
133
+ const safe = scrubEvent(event, env);
134
+ events.push(safe);
135
+ options.onEvent?.(safe);
136
+ if (isError(safe))
137
+ terminalError = true;
138
+ if (isTerminal(safe)) {
139
+ terminalSeen = true;
140
+ // Some provider builds leave background work attached after the
141
+ // result. Allow a short drain, then terminate the process group.
142
+ drainTimer ??= setTimeout(() => { stopProcess(child); finish(undefined, terminalError ? 1 : 0); }, 300);
143
+ }
144
+ }
145
+ });
146
+ child.stderr.on('data', (chunk) => {
147
+ stderr += chunk.toString('utf8');
148
+ if (Buffer.byteLength(stderr) > maxBytes)
149
+ finish(new Error(`Grok Build stderr exceeded ${maxBytes} bytes`));
150
+ });
151
+ child.on('close', code => {
152
+ if (format === 'streaming-json' && pending.trim()) {
153
+ try {
154
+ const event = scrubEvent(JSON.parse(pending), env);
155
+ events.push(event);
156
+ if (isError(event))
157
+ terminalError = true;
158
+ if (isTerminal(event))
159
+ terminalSeen = true;
160
+ }
161
+ catch {
162
+ finish(new Error('Invalid trailing Grok Build streaming-json event'));
163
+ return;
164
+ }
165
+ }
166
+ finish(undefined, code ?? 1);
167
+ });
168
+ });
169
+ }
170
+ //# sourceMappingURL=grok-build-headless.js.map
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Muse Code skill-root resolution — documented roots only, fail-closed on bad metadata.
3
+ *
4
+ * Muse Code's documented user skill root is `$XDG_CONFIG_HOME/muse/skills`
5
+ * (default `~/.config/muse/skills` when XDG_CONFIG_HOME is unset). The
6
+ * project skill root (`<repo>/.agents/skills`) is static provider metadata
7
+ * on the `muse` skillNamespace; this module resolves only the XDG user root
8
+ * at deploy time.
9
+ *
10
+ * Unlike Grok Bot (AIWG_GROKBOT_SKILLS_DIR, fail-closed until configured),
11
+ * the Muse user root is documented, so an unset XDG_CONFIG_HOME falls back
12
+ * to the documented default — but malformed metadata (relative
13
+ * XDG_CONFIG_HOME, bare `~`, NUL bytes, root-only resolution) fails closed
14
+ * so the deployer never invents a bogus tree.
15
+ *
16
+ * Never invent `~/.muse`, `~/.config/muse` siblings outside `muse/skills`,
17
+ * or `~/.agents/skills` as a write target.
18
+ *
19
+ * @see docs/architecture/adr-muse-provider-target.md
20
+ * @issue #234
21
+ */
22
+ import { homedir } from 'node:os';
23
+ import * as path from 'node:path';
24
+ /** Muse's documented user skills subtree below the XDG config root. */
25
+ export const MUSE_XDG_SKILLS_SUBDIR = path.join('muse', 'skills');
26
+ /**
27
+ * Expand a leading `~/` against the operator home directory.
28
+ * Bare `~` is rejected — it would invent a home skill root.
29
+ */
30
+ function expandHomePrefix(raw, userHome = homedir()) {
31
+ if (raw === '~')
32
+ return raw;
33
+ if (raw.startsWith('~/'))
34
+ return path.join(userHome, raw.slice(2));
35
+ return raw;
36
+ }
37
+ /**
38
+ * Validate and resolve the Muse XDG user skills directory.
39
+ * Returns a structured result so the deployer can fail closed on bad metadata.
40
+ */
41
+ export function resolveMuseXdgSkillsDirResult(env = process.env, userHome = homedir()) {
42
+ const raw = (env.XDG_CONFIG_HOME || '').trim();
43
+ if (!raw) {
44
+ // Documented default: ~/.config/muse/skills when XDG_CONFIG_HOME is unset.
45
+ return {
46
+ ok: true,
47
+ path: path.join(userHome, '.config', MUSE_XDG_SKILLS_SUBDIR),
48
+ source: 'default',
49
+ };
50
+ }
51
+ const expanded = expandHomePrefix(raw, userHome);
52
+ if (expanded === '~' || expanded.startsWith('~')) {
53
+ return {
54
+ ok: false,
55
+ reason: 'not-absolute',
56
+ message: `XDG_CONFIG_HOME must be an absolute path (got '${raw}'). Bare '~' is rejected so AIWG never invents a Muse home layout.`,
57
+ };
58
+ }
59
+ if (!path.isAbsolute(expanded)) {
60
+ return {
61
+ ok: false,
62
+ reason: 'not-absolute',
63
+ message: `XDG_CONFIG_HOME must be an absolute path (got '${raw}'). Relative values are rejected.`,
64
+ };
65
+ }
66
+ if (raw.includes('\0') || expanded.includes('\0')) {
67
+ return {
68
+ ok: false,
69
+ reason: 'traversal',
70
+ message: 'XDG_CONFIG_HOME contains an invalid path character.',
71
+ };
72
+ }
73
+ // Defensive: refuse a config root that collapses to the filesystem root;
74
+ // deploying skills to /muse/skills is never the operator's intent.
75
+ const normalized = path.normalize(expanded);
76
+ if (normalized === path.sep) {
77
+ return {
78
+ ok: false,
79
+ reason: 'empty',
80
+ message: 'XDG_CONFIG_HOME resolves to the filesystem root; refuse to deploy skills there.',
81
+ };
82
+ }
83
+ return {
84
+ ok: true,
85
+ path: path.join(normalized, MUSE_XDG_SKILLS_SUBDIR),
86
+ source: 'env',
87
+ };
88
+ }
89
+ /**
90
+ * Absolute Muse XDG user skills dir when the metadata is sane; otherwise
91
+ * null (fail closed). Never invents ~/.muse.
92
+ */
93
+ export function resolveMuseXdgSkillsDir(env = process.env, userHome = homedir()) {
94
+ const resolution = resolveMuseXdgSkillsDirResult(env, userHome);
95
+ return resolution.ok ? resolution.path : null;
96
+ }
97
+ /**
98
+ * User-facing remediation for bad Muse XDG metadata.
99
+ * Shared by the deployer so a blocked deploy explains the fix.
100
+ */
101
+ export function museXdgSkillsDirRemediation(env = process.env, userHome = homedir()) {
102
+ const resolution = resolveMuseXdgSkillsDirResult(env, userHome);
103
+ return resolution.ok ? '' : resolution.message;
104
+ }
105
+ //# sourceMappingURL=muse-paths.js.map
@@ -23,6 +23,7 @@ const ProviderDefinitionSchema = z.object({
23
23
  'grokbot',
24
24
  'grok-build',
25
25
  'hermes',
26
+ 'muse',
26
27
  'opencode',
27
28
  'openclaw',
28
29
  'openhuman',
@@ -146,6 +147,7 @@ export const PROVIDER_IDS = [
146
147
  'grokbot',
147
148
  'grok-build',
148
149
  'hermes',
150
+ 'muse',
149
151
  'opencode',
150
152
  'openclaw',
151
153
  'openhuman',
@@ -244,6 +246,20 @@ const CONTEXT_CONTRACTS = {
244
246
  bootstrapTargets: ['.hermes.md', 'AGENTS.md'], maxContextBytes: null, recommendedMaxLines: 30, nestedContext: false, support: 'degraded',
245
247
  verification: { method: 'AIWG Hermes adapter contract; on-demand artifact-read required', source: 'agentic/code/providers/capability-matrix.yaml', lastVerified: VERIFIED_ON },
246
248
  },
249
+ // #225: Muse Code prefers AGENTS.md over CLAUDE.md at each directory level;
250
+ // project AGENTS.md loads only after the workspace is explicitly trusted
251
+ // (first-run trust prompt). AIWG deploys a discover-first AGENTS.md bridge.
252
+ muse: {
253
+ startupFiles: ['AGENTS.md'],
254
+ precedence: ['provider/system', 'project AGENTS.md once the workspace is trusted', 'explicit aiwg discover/show'],
255
+ loadMode: 'prose-directive', includeSyntax: null, configRegistration: null,
256
+ bootstrapTargets: ['AGENTS.md'], maxContextBytes: null, recommendedMaxLines: null, nestedContext: false, support: 'supported',
257
+ verification: {
258
+ method: 'ADR-locked surfaces; discover-first AGENTS.md bridge per official Muse Code docs (trust-gated load)',
259
+ source: 'docs/architecture/adr-muse-provider-target.md',
260
+ lastVerified: '2026-09-24',
261
+ },
262
+ },
247
263
  opencode: {
248
264
  startupFiles: ['AGENTS.md', 'CLAUDE.md', 'opencode.json#instructions'], precedence: ['provider/system', 'nearest AGENTS.md', 'CLAUDE compatibility', 'registered instructions'],
249
265
  loadMode: 'config-registration', includeSyntax: null, configRegistration: { file: 'opencode.json', key: 'instructions' },
@@ -669,16 +685,14 @@ const BUILT_IN_SEEDS = [
669
685
  surfaces: {
670
686
  primary: 'grok-build',
671
687
  compatibility: [],
672
- // Agents/rules native writers deferred #2577; host still discovers those dirs.
673
- precedence: ['AGENTS.md', '.grok/skills/', '.grok/rules/ (host; AIWG writer deferred #2577)', '.grok/config.toml (config only)', '$GROK_HOME'],
688
+ precedence: ['AGENTS.md', '.grok/agents/ (qualified model workers)', '.grok/skills/', '.grok/rules/ (host)', '.grok/config.toml (config only)', '$GROK_HOME'],
674
689
  related: [],
675
690
  },
676
691
  detection: { env: ['GROK_HOME'], process: ['grok'], capabilityId: 'grok-build' },
677
692
  paths: {
678
693
  deployTarget: 'mixed',
679
694
  artifacts: {
680
- // Wave 1 writes skills + AGENTS.md only; agents/rules indexed until #2577.
681
- agents: null,
695
+ agents: '.grok/agents',
682
696
  commands: null,
683
697
  skills: '.grok/skills',
684
698
  rules: null,
@@ -695,7 +709,7 @@ const BUILT_IN_SEEDS = [
695
709
  contextFiles: { aiwgMd: true, agentsMd: true, claudeMdHook: false, hookFile: null, contextFile: 'AGENTS.md' },
696
710
  },
697
711
  smithPaths: {
698
- agents: null,
712
+ agents: '.grok/agents',
699
713
  commands: null,
700
714
  skills: '.grok/skills',
701
715
  rules: null,
@@ -711,8 +725,8 @@ const BUILT_IN_SEEDS = [
711
725
  },
712
726
  adapters: {
713
727
  agentFormat: 'agents-md',
714
- hookBridge: null,
715
- mcpInjection: null,
728
+ hookBridge: 'grok-build',
729
+ mcpInjection: 'grok-build',
716
730
  contextAggregation: 'agents-md',
717
731
  ruleFormat: 'agents-md-section',
718
732
  },
@@ -764,6 +778,78 @@ const BUILT_IN_SEEDS = [
764
778
  },
765
779
  matrixRef: 'hermes',
766
780
  },
781
+ {
782
+ id: 'muse',
783
+ displayName: 'Muse Code',
784
+ // #225: ADR fixes the canonical id as `muse` with no aliases.
785
+ aliases: [],
786
+ status: 'experimental',
787
+ builtIn: true,
788
+ surfaces: {
789
+ primary: 'muse',
790
+ compatibility: [],
791
+ precedence: ['AGENTS.md', '.agents/skills/'],
792
+ related: [],
793
+ },
794
+ // Fail-closed: no env or process signals. A bare `muse` process name collides
795
+ // with unrelated software, so it is not evidence of Muse Code. The `muse`
796
+ // CLI binary name is a documented fact, not a detection claim
797
+ // (docs/architecture/adr-muse-provider-target.md).
798
+ detection: { env: [], process: [], capabilityId: 'muse' },
799
+ paths: {
800
+ deployTarget: 'mixed',
801
+ artifacts: {
802
+ // Skills are written natively; agents, commands, and rules stay
803
+ // indexed (aiwg discover/show) behind the AGENTS.md bridge.
804
+ agents: null,
805
+ commands: null,
806
+ skills: '.agents/skills',
807
+ rules: null,
808
+ behaviors: null,
809
+ },
810
+ kernelSkills: '.agents/skills',
811
+ contextDiscovery: {
812
+ agents: null,
813
+ skills: '.agents/skills',
814
+ rules: null,
815
+ behaviors: null,
816
+ },
817
+ configFile: null,
818
+ contextFiles: { aiwgMd: true, agentsMd: true, claudeMdHook: false, hookFile: null, contextFile: 'AGENTS.md' },
819
+ },
820
+ smithPaths: {
821
+ agents: null,
822
+ commands: null,
823
+ skills: '.agents/skills',
824
+ rules: null,
825
+ fileExtension: '.md',
826
+ configFile: null,
827
+ aggregated: false,
828
+ },
829
+ // Project skill root only: the namespace default resolves to
830
+ // <repo>/.agents/skills — a project tree, never a home-dir tree — so the
831
+ // deployer cannot invent ~/.muse, ~/.config/muse siblings outside
832
+ // muse/skills, or ~/.agents/skills from this metadata alone. The XDG
833
+ // user root ($XDG_CONFIG_HOME/muse/skills, default ~/.config/muse/skills)
834
+ // is not a static namespace default; it resolves dynamically at deploy
835
+ // time via resolveMuseXdgSkillsDir (src/providers/muse-paths.ts, #234),
836
+ // which fails closed on bad XDG metadata. Never write ~/.muse or
837
+ // silently mirror into ~/.agents/skills (#226).
838
+ skillNamespace: {
839
+ deploymentGroup: 'deep-recursion',
840
+ pathType: 'project',
841
+ skillsBaseDir: '.agents/skills',
842
+ subdirLayout: true,
843
+ },
844
+ adapters: {
845
+ agentFormat: 'agents-md',
846
+ hookBridge: null,
847
+ mcpInjection: null,
848
+ contextAggregation: 'agents-md',
849
+ ruleFormat: 'agents-md-section',
850
+ },
851
+ matrixRef: 'muse',
852
+ },
767
853
  {
768
854
  id: 'opencode',
769
855
  aliases: [],
@@ -1,6 +1,6 @@
1
1
  import { resolveOmpPaths } from './omp-paths.mjs';
2
2
  import { homedir } from 'os';
3
- import { resolve } from 'path';
3
+ import { isAbsolute, join, resolve } from 'path';
4
4
 
5
5
  const MCP_INJECTION_DEFINITIONS = [
6
6
  {
@@ -72,6 +72,19 @@ const MCP_INJECTION_DEFINITIONS = [
72
72
  supportsEphemeral: true,
73
73
  },
74
74
  },
75
+ {
76
+ id: 'grok-build', aliases: [],
77
+ mcp: {
78
+ providerId: 'grok-build',
79
+ includeInSupportedProviders: true,
80
+ configFormat: 'toml',
81
+ serverConfigFormat: 'grok-build',
82
+ serversKey: null,
83
+ configPath: { scope: 'project', path: '.grok/config.toml' },
84
+ supportsEphemeral: false,
85
+ unsupportedReason: 'Grok Build project MCP configuration is trust-scoped and must remain in its reviewed config layer.',
86
+ },
87
+ },
75
88
  {
76
89
  id: 'opencode',
77
90
  aliases: [],
@@ -172,6 +185,13 @@ export function resolveMcpConfigPath(provider, projectDir = '.', options = {}) {
172
185
  if (normalizeRuntimeProviderId(provider) === 'omp' && options.scope === 'user') {
173
186
  return resolve(resolveOmpPaths(options).agentDir, 'mcp.json');
174
187
  }
188
+ if (normalizeRuntimeProviderId(provider) === 'grok-build' && options.scope === 'user') {
189
+ const userHome = process.env.HOME || process.env.USERPROFILE || homedir();
190
+ const raw = process.env.GROK_HOME || join(userHome, '.grok');
191
+ const home = raw.startsWith('~/') ? join(userHome, raw.slice(2)) : raw;
192
+ if (!isAbsolute(home) || resolve(home) === resolve(home, '..')) throw new Error('GROK_HOME must be an absolute non-root path for MCP injection');
193
+ return resolve(home, 'config.toml');
194
+ }
175
195
  const definition = getMcpInjectionDefinition(provider);
176
196
  if (!definition) return '';
177
197
 
@@ -13,7 +13,10 @@ const PROVIDER_EXECUTABLES = {
13
13
  'deepseek-harness': ['dsh'],
14
14
  factory: ['droid'],
15
15
  // Grok Bot has no verified CLI executable name; omit rather than invent.
16
+ // Muse Code's documented CLI binary is `muse`; the bare process name is
17
+ // deliberately NOT a detection signal (fail-closed per ADR).
16
18
  'grok-build': ['grok'],
19
+ muse: ['muse'],
17
20
  hermes: ['hermes'],
18
21
  opencode: ['opencode'],
19
22
  openclaw: ['openclaw'],
@@ -1,5 +1,6 @@
1
- import { createPrivateKey, createPublicKey, sign as signBytes, } from 'node:crypto';
2
- import { canonicalJson, dssePae, publicKeyFingerprint, sha256 } from './artifact-trust.js';
1
+ import { createPrivateKey, createPublicKey, } from 'node:crypto';
2
+ import { canonicalJson, sha256 } from './artifact-trust.js';
3
+ import { signDsseEnvelope } from './signing.js';
3
4
  export const ARTIFACT_ATTESTATION_MEDIA_TYPE = 'application/vnd.aiwg.artifact-attestation.v1+json';
4
5
  export const ARTIFACT_PROVENANCE_PREDICATE_TYPE = 'https://aiwg.io/attestations/artifact-provenance/v1';
5
6
  export const IN_TOTO_STATEMENT_V1 = 'https://in-toto.io/Statement/v1';
@@ -87,14 +88,9 @@ export function createArtifactAttestation(options) {
87
88
  const publicKeyPem = publicKey.export({ type: 'spki', format: 'pem' }).toString();
88
89
  const statement = createArtifactProvenanceStatement(options);
89
90
  const payload = Buffer.from(canonicalJson(statement), 'utf8');
90
- const signature = signBytes(null, dssePae(DSSE_IN_TOTO_PAYLOAD_TYPE, payload), privateKey);
91
91
  return {
92
92
  mediaType: ARTIFACT_ATTESTATION_MEDIA_TYPE,
93
- envelope: {
94
- payloadType: DSSE_IN_TOTO_PAYLOAD_TYPE,
95
- payload: payload.toString('base64'),
96
- signatures: [{ keyid: publicKeyFingerprint(publicKeyPem), sig: signature.toString('base64') }],
97
- },
93
+ envelope: signDsseEnvelope(DSSE_IN_TOTO_PAYLOAD_TYPE, payload, privateKey),
98
94
  verificationMaterial: {
99
95
  kind: 'public-key',
100
96
  algorithm: 'ed25519',
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Ed25519 signing helpers shared across subsystems.
3
+ *
4
+ * Two shapes are provided:
5
+ *
6
+ * - canonical-document signatures: an Ed25519 signature over the canonical JSON
7
+ * of a document, with its SHA-256 and signer SPKI carried alongside;
8
+ * - DSSE envelopes: an Ed25519 signature over the DSSE pre-authentication
9
+ * encoding (`artifact-trust.dssePae`) of exact payload bytes.
10
+ *
11
+ * Canonicalization defaults to the RFC 8785 implementation in
12
+ * `artifact-trust.canonicalJson`. A caller whose stored signatures were made
13
+ * over a different canonical form can bind its own canonicalizer through
14
+ * `createCanonicalSigner`, so existing signatures keep verifying byte for byte.
15
+ */
16
+ import { createHash, createPrivateKey, createPublicKey, sign as cryptoSign, verify as cryptoVerify, } from 'node:crypto';
17
+ import { canonicalJson, decodeBase64, dssePae, publicKeyFingerprint, publicKeyObject, verifyBytes } from './artifact-trust.js';
18
+ export const DEFAULT_KEY_TYPE_ERROR_MESSAGE = 'Signing keys must use Ed25519';
19
+ function sha256Hex(value) {
20
+ return createHash('sha256').update(value).digest('hex');
21
+ }
22
+ function publicKeyFromBase64(value) {
23
+ return createPublicKey({ key: Buffer.from(value, 'base64'), format: 'der', type: 'spki' });
24
+ }
25
+ /** Bind the canonical-document signing helpers to one canonicalizer and error message. */
26
+ export function createCanonicalSigner(options = {}) {
27
+ const canonicalize = options.canonicalize ?? canonicalJson;
28
+ const keyTypeError = options.keyTypeErrorMessage ?? DEFAULT_KEY_TYPE_ERROR_MESSAGE;
29
+ function publicKeyDer(key) {
30
+ const object = typeof key === 'string'
31
+ ? createPublicKey(key)
32
+ : key.type === 'public' ? key : createPublicKey(key);
33
+ if (object.asymmetricKeyType !== 'ed25519')
34
+ throw new Error(keyTypeError);
35
+ return object.export({ format: 'der', type: 'spki' });
36
+ }
37
+ function signingKeyId(publicKey) {
38
+ return `ed25519:${sha256Hex(publicKeyDer(publicKey)).slice(0, 32)}`;
39
+ }
40
+ function signCanonicalDocument(document, privateKeyPem, signOptions = {}) {
41
+ const privateKey = createPrivateKey(privateKeyPem);
42
+ if (privateKey.asymmetricKeyType !== 'ed25519')
43
+ throw new Error(keyTypeError);
44
+ const publicKey = signOptions.publicKeyPem ? createPublicKey(signOptions.publicKeyPem) : createPublicKey(privateKey);
45
+ const payload = canonicalize(document);
46
+ return {
47
+ keyId: signOptions.keyId ?? signingKeyId(publicKey),
48
+ algorithm: 'ed25519',
49
+ publicKey: publicKeyDer(publicKey).toString('base64'),
50
+ signedAt: signOptions.signedAt ?? new Date().toISOString(),
51
+ payloadSha256: sha256Hex(payload),
52
+ signature: cryptoSign(null, Buffer.from(payload), privateKey).toString('base64'),
53
+ };
54
+ }
55
+ function verifyCanonicalSignature(document, signature) {
56
+ const payload = canonicalize(document);
57
+ return signature.algorithm === 'ed25519'
58
+ && signature.payloadSha256 === sha256Hex(payload)
59
+ && cryptoVerify(null, Buffer.from(payload), publicKeyFromBase64(signature.publicKey), Buffer.from(signature.signature, 'base64'));
60
+ }
61
+ return { signCanonicalDocument, verifyCanonicalSignature, signingKeyId, publicKeyDer };
62
+ }
63
+ const defaultSigner = createCanonicalSigner();
64
+ /** Sign the RFC 8785 canonical JSON of `document` with an Ed25519 private key. */
65
+ export const signCanonicalDocument = defaultSigner.signCanonicalDocument;
66
+ /** Verify a signature made by `signCanonicalDocument` over the RFC 8785 canonical JSON. */
67
+ export const verifyCanonicalSignature = defaultSigner.verifyCanonicalSignature;
68
+ /** Stable identifier for an Ed25519 public key: `ed25519:` plus 32 hex chars of its SPKI SHA-256. */
69
+ export const signingKeyId = defaultSigner.signingKeyId;
70
+ function ed25519PrivateKey(privateKey, message) {
71
+ const key = typeof privateKey === 'string' ? createPrivateKey(privateKey) : privateKey;
72
+ if (key.asymmetricKeyType !== 'ed25519')
73
+ throw new Error(message);
74
+ return key;
75
+ }
76
+ /**
77
+ * Sign exact payload bytes as a single-signature DSSE envelope. The keyid is the
78
+ * SHA-256 of the signer's SPKI DER (`artifact-trust.publicKeyFingerprint`).
79
+ */
80
+ export function signDsseEnvelope(payloadType, payload, privateKey, options = {}) {
81
+ const key = ed25519PrivateKey(privateKey, options.keyTypeErrorMessage ?? DEFAULT_KEY_TYPE_ERROR_MESSAGE);
82
+ const publicKeyPem = createPublicKey(key).export({ type: 'spki', format: 'pem' }).toString();
83
+ const body = Buffer.from(payload);
84
+ const signature = cryptoSign(null, dssePae(payloadType, body), key);
85
+ return {
86
+ payloadType,
87
+ payload: body.toString('base64'),
88
+ signatures: [{ keyid: publicKeyFingerprint(publicKeyPem), sig: signature.toString('base64') }],
89
+ };
90
+ }
91
+ /**
92
+ * Verify that at least one envelope signature is a valid Ed25519 signature by
93
+ * `publicKey` (PEM or base64 SPKI DER) over the DSSE PAE of the envelope's
94
+ * payload type and payload. Keyids are lookup hints and are not trusted.
95
+ * Malformed input verifies as false rather than throwing.
96
+ */
97
+ export function verifyDsseEnvelope(envelope, publicKey) {
98
+ let payload;
99
+ try {
100
+ if (typeof envelope?.payloadType !== 'string' || !Array.isArray(envelope.signatures))
101
+ return false;
102
+ if (publicKeyObject(publicKey).asymmetricKeyType !== 'ed25519')
103
+ return false;
104
+ payload = decodeBase64(envelope.payload, 'DSSE payload');
105
+ }
106
+ catch {
107
+ return false;
108
+ }
109
+ const pae = dssePae(envelope.payloadType, payload);
110
+ return envelope.signatures.some((signature) => {
111
+ try {
112
+ return verifyBytes('ed25519', publicKey, pae, decodeBase64(signature.sig, 'DSSE signature'));
113
+ }
114
+ catch {
115
+ return false;
116
+ }
117
+ });
118
+ }
119
+ //# sourceMappingURL=signing.js.map