@aiwg/cli 2026.9.21 → 2026.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/agentic/code/providers/capability-matrix.yaml +2 -1
  2. package/dist/src/artifacts/cli.js +23 -18
  3. package/dist/src/artifacts/discovery-shadow-evaluator.js +177 -0
  4. package/dist/src/artifacts/discovery-shadow.js +195 -0
  5. package/dist/src/artifacts/fortemi-core-query-adapter.js +6 -2
  6. package/dist/src/artifacts/index-builder.js +47 -9
  7. package/dist/src/artifacts/query-engine.js +108 -5
  8. package/dist/src/artifacts/types.js +1 -0
  9. package/dist/src/cli/handlers/decision.js +88 -0
  10. package/dist/src/cli/handlers/gates.js +154 -0
  11. package/dist/src/cli/handlers/index.js +5 -1
  12. package/dist/src/cli/handlers/sessions.js +10 -7
  13. package/dist/src/cli/handlers/utilities.js +20 -0
  14. package/dist/src/config/aiwg-config.js +15 -2
  15. package/dist/src/decision/acceptance.js +25 -0
  16. package/dist/src/decision/adapters/jev.js +24 -2
  17. package/dist/src/decision/calibration/registry.js +9 -0
  18. package/dist/src/decision/compose.js +74 -15
  19. package/dist/src/decision/context-live-promotion.js +344 -0
  20. package/dist/src/decision/context-live-qualification.js +591 -0
  21. package/dist/src/decision/context-pruning.js +847 -0
  22. package/dist/src/decision/driver.js +430 -0
  23. package/dist/src/decision/egress-live-qualification.js +874 -0
  24. package/dist/src/decision/ensemble/contract.js +64 -1
  25. package/dist/src/decision/ensemble/index.js +1 -0
  26. package/dist/src/decision/ensemble/report.js +8 -42
  27. package/dist/src/decision/ensemble/runtime.js +571 -0
  28. package/dist/src/decision/ensemble-study/artifacts.js +85 -0
  29. package/dist/src/decision/ensemble-study/calibration.js +443 -0
  30. package/dist/src/decision/ensemble-study/corpus.js +229 -0
  31. package/dist/src/decision/ensemble-study/multifact-artifacts.js +23 -0
  32. package/dist/src/decision/ensemble-study/multifact-study.js +596 -0
  33. package/dist/src/decision/ensemble-study/multifact.js +241 -0
  34. package/dist/src/decision/ensemble-study/protocol.js +77 -0
  35. package/dist/src/decision/ensemble-study/score.js +462 -0
  36. package/dist/src/decision/ensemble-study/staged.js +87 -0
  37. package/dist/src/decision/ensemble-study/statistics.js +84 -0
  38. package/dist/src/decision/evaluate.js +227 -14
  39. package/dist/src/decision/export.js +4 -0
  40. package/dist/src/decision/feature-export.js +1074 -0
  41. package/dist/src/decision/graph-index.js +16 -0
  42. package/dist/src/decision/graph-live-qualification.js +1041 -0
  43. package/dist/src/decision/graph-live-workload.js +245 -0
  44. package/dist/src/decision/graph-skill-bridge.js +21 -3
  45. package/dist/src/decision/heldout/calibration.js +140 -0
  46. package/dist/src/decision/heldout/collector.js +430 -0
  47. package/dist/src/decision/heldout/contract.js +309 -0
  48. package/dist/src/decision/heldout/d29-generator-ids.js +12 -0
  49. package/dist/src/decision/heldout/d29-passage-baseline-v2.js +93 -0
  50. package/dist/src/decision/heldout/d29-passage-baseline-v3.js +100 -0
  51. package/dist/src/decision/heldout/d29-passage-baseline.js +66 -0
  52. package/dist/src/decision/heldout/d29-pools-v8.js +575 -0
  53. package/dist/src/decision/heldout/d29-pools.js +288 -0
  54. package/dist/src/decision/heldout/d29-v6.js +169 -0
  55. package/dist/src/decision/heldout/d29-v7.js +202 -0
  56. package/dist/src/decision/heldout/d29-v8.js +586 -0
  57. package/dist/src/decision/heldout/generator-registry.js +67 -0
  58. package/dist/src/decision/heldout/generators.js +696 -0
  59. package/dist/src/decision/heldout/index.js +8 -0
  60. package/dist/src/decision/heldout/journal.js +346 -0
  61. package/dist/src/decision/heldout/study-generators.js +64 -0
  62. package/dist/src/decision/heldout/types.js +2 -0
  63. package/dist/src/decision/host-policy.js +61 -0
  64. package/dist/src/decision/index.js +11 -0
  65. package/dist/src/decision/interop-profile.v1.json +112 -0
  66. package/dist/src/decision/interop.js +653 -0
  67. package/dist/src/decision/issue-triage/index.js +3 -0
  68. package/dist/src/decision/issue-triage/runtime.js +1069 -0
  69. package/dist/src/decision/issue-triage/types.js +2 -0
  70. package/dist/src/decision/patterns/catalog.js +28 -8
  71. package/dist/src/decision/patterns/playground.js +28 -11
  72. package/dist/src/decision/patterns/specs.js +19 -10
  73. package/dist/src/decision/preprocessed-evidence.js +724 -0
  74. package/dist/src/decision/qualification/capture.js +8 -2
  75. package/dist/src/decision/qualification/gate-evidence.js +19 -4
  76. package/dist/src/decision/qualification/load.js +8 -1
  77. package/dist/src/decision/qualification/quality.js +57 -49
  78. package/dist/src/decision/qualification/release.js +76 -3
  79. package/dist/src/decision/qualification/runner.js +5 -2
  80. package/dist/src/decision/routing/contract.js +175 -0
  81. package/dist/src/decision/routing/index.js +5 -0
  82. package/dist/src/decision/routing/report.js +216 -0
  83. package/dist/src/decision/routing/runtime.js +685 -0
  84. package/dist/src/decision/routing/types.js +2 -0
  85. package/dist/src/decision/sdlc-screening.js +1157 -0
  86. package/dist/src/decision/sensitivity/comparative.js +154 -0
  87. package/dist/src/decision/sensitivity/contract.js +218 -0
  88. package/dist/src/decision/sensitivity/index.js +5 -0
  89. package/dist/src/decision/sensitivity/runtime.js +912 -0
  90. package/dist/src/decision/sensitivity/types.js +2 -0
  91. package/dist/src/decision/validate.js +26 -0
  92. package/dist/src/extensions/commands/definitions.js +38 -0
  93. package/dist/src/extensions/manifest.js +44 -0
  94. package/dist/src/gates/discovery.js +315 -0
  95. package/dist/src/gates/driver.js +388 -0
  96. package/dist/src/gates/evaluate.js +719 -0
  97. package/dist/src/gates/floors.js +255 -0
  98. package/dist/src/gates/index.js +17 -0
  99. package/dist/src/gates/providers/evidence.js +38 -0
  100. package/dist/src/gates/providers/index.js +21 -0
  101. package/dist/src/gates/providers/isolated-child-source.js +446 -0
  102. package/dist/src/gates/providers/loader.js +1069 -0
  103. package/dist/src/gates/providers/paired.js +52 -0
  104. package/dist/src/gates/providers/proportion.js +60 -0
  105. package/dist/src/gates/providers/registry.js +40 -0
  106. package/dist/src/gates/providers/scalar.js +41 -0
  107. package/dist/src/gates/providers/screening.js +53 -0
  108. package/dist/src/gates/providers/types.js +25 -0
  109. package/dist/src/gates/registry.js +1003 -0
  110. package/dist/src/gates/report.js +102 -0
  111. package/dist/src/gates/schema.js +56 -0
  112. package/dist/src/gates/stats/binomial.js +26 -0
  113. package/dist/src/gates/stats/bootstrap.js +62 -0
  114. package/dist/src/gates/stats/clopper-pearson.js +95 -0
  115. package/dist/src/gates/stats/digest.js +26 -0
  116. package/dist/src/gates/stats/error.js +5 -0
  117. package/dist/src/gates/stats/index.js +9 -0
  118. package/dist/src/gates/stats/normal.js +35 -0
  119. package/dist/src/gates/stats/paired.js +120 -0
  120. package/dist/src/gates/stats/splits.js +30 -0
  121. package/dist/src/gates/types.js +8 -0
  122. package/dist/src/governance/redaction.js +14 -4
  123. package/dist/src/mcp/muse-native-config.mjs +123 -0
  124. package/dist/src/mcp/tools/decision.mjs +188 -0
  125. package/dist/src/mcp/tools/subsystems.mjs +2 -0
  126. package/dist/src/providers/capability-matrix.yaml +2 -1
  127. package/dist/src/providers/provider-definitions.js +2 -1
  128. package/dist/src/sessions/adapters/muse.js +336 -39
  129. package/dist/src/sessions/batch-import.js +7 -0
  130. package/dist/src/sessions/workspace-discovery.js +13 -2
  131. package/package.json +1 -1
  132. package/schemas/decision/ConformalFrozenOpenData.v2.schema.json +371 -0
  133. package/schemas/decision/ConformalOpenDataReport.v2.schema.json +421 -0
  134. package/schemas/decision/ConformalPreregistration.v2.schema.json +529 -0
  135. package/schemas/decision/ContextPruningCandidate.v1.schema.json +47 -0
  136. package/schemas/decision/ContextPruningEvaluationReport.v1.schema.json +758 -0
  137. package/schemas/decision/ContextPruningPreregistration.v1.schema.json +175 -0
  138. package/schemas/decision/ContextPruningReceipt.v1.schema.json +72 -0
  139. package/schemas/decision/D17Multifact.v1.schema.json +1851 -0
  140. package/schemas/decision/D17StudyAnalysis.v1.schema.json +42 -0
  141. package/schemas/decision/D17StudyAnalysis.v2.schema.json +51 -0
  142. package/schemas/decision/D17StudyCalibration.v1.schema.json +819 -0
  143. package/schemas/decision/D17StudyDryRun.v1.schema.json +169 -0
  144. package/schemas/decision/D17StudyDryRun.v2.schema.json +239 -0
  145. package/schemas/decision/D17StudyGold.v1.schema.json +108 -0
  146. package/schemas/decision/D17StudyGuide.v1.schema.json +63 -0
  147. package/schemas/decision/D17StudyNativeTemplates.v1.schema.json +619 -0
  148. package/schemas/decision/D17StudyProtocol.v1.schema.json +241 -0
  149. package/schemas/decision/D17StudyReport.v1.schema.json +902 -0
  150. package/schemas/decision/D17StudyReport.v2.schema.json +1319 -0
  151. package/schemas/decision/D17StudyReview.v1.schema.json +175 -0
  152. package/schemas/decision/D17StudySplits.v1.schema.json +217 -0
  153. package/schemas/decision/D29Study.v1.schema.json +1903 -0
  154. package/schemas/decision/D29Study.v2.schema.json +1344 -0
  155. package/schemas/decision/D29Study.v3.schema.json +609 -0
  156. package/schemas/decision/D29Study.v4.schema.json +1133 -0
  157. package/schemas/decision/D29Study.v6.schema.json +1205 -0
  158. package/schemas/decision/D29Study.v7.schema.json +1471 -0
  159. package/schemas/decision/D29Study.v8.schema.json +671 -0
  160. package/schemas/decision/D29Study.v9.schema.json +778 -0
  161. package/schemas/decision/DecisionComparativeReplayAuditSample.v1.schema.json +137 -0
  162. package/schemas/decision/DecisionComparativeReplayCorpus.v1.schema.json +258 -0
  163. package/schemas/decision/DecisionComparativeReplayFreeze.v1.schema.json +74 -0
  164. package/schemas/decision/DecisionComparativeReplayGold.v1.schema.json +50 -0
  165. package/schemas/decision/DecisionComparativeReplayGoldAsset.v1.schema.json +37 -0
  166. package/schemas/decision/DecisionComparativeReplayIntegrity.v1.schema.json +81 -0
  167. package/schemas/decision/DecisionComparativeReplayMembers.v1.schema.json +52 -0
  168. package/schemas/decision/DecisionComparativeReplayPreregistration.v1.schema.json +113 -0
  169. package/schemas/decision/DecisionComparativeReplayReport.v1.schema.json +407 -0
  170. package/schemas/decision/DecisionComparativeReplayReviewPackets.v1.schema.json +260 -0
  171. package/schemas/decision/DecisionComparativeReplaySplit.v1.schema.json +84 -0
  172. package/schemas/decision/DecisionFeatureObservation.v1.schema.json +564 -0
  173. package/schemas/decision/DecisionFeatureSet.v1.schema.json +155 -0
  174. package/schemas/decision/DecisionInteropMapping.v1.schema.json +85 -0
  175. package/schemas/decision/DecisionIssueTriageEvaluationManifest.v1.schema.json +174 -0
  176. package/schemas/decision/DecisionIssueTriageEvaluationReport.v1.schema.json +280 -0
  177. package/schemas/decision/DecisionIssueTriagePilotPack.v1.schema.json +114 -0
  178. package/schemas/decision/DecisionRouteReceipt.v1.schema.json +155 -0
  179. package/schemas/decision/DecisionRoutingPolicy.v1.schema.json +132 -0
  180. package/schemas/decision/DecisionRoutingShadowReport.v1.schema.json +170 -0
  181. package/schemas/decision/DecisionRoutingTask.v1.schema.json +49 -0
  182. package/schemas/decision/DecisionRuleset.schema.json +8 -2
  183. package/schemas/decision/DecisionRuleset.v1alpha2.schema.json +8 -2
  184. package/schemas/decision/DecisionSensitivityPlan.v1.schema.json +191 -0
  185. package/schemas/decision/DecisionSensitivityReport.v1.schema.json +163 -0
  186. package/schemas/decision/HeldoutApproval.v1.schema.json +312 -0
  187. package/schemas/decision/HeldoutAttempt.v1.schema.json +211 -0
  188. package/schemas/decision/HeldoutBaseline.v1.schema.json +90 -0
  189. package/schemas/decision/HeldoutCalibrationPhase.v1.schema.json +87 -0
  190. package/schemas/decision/HeldoutCorpus.v1.schema.json +167 -0
  191. package/schemas/decision/HeldoutEvent.v1.schema.json +41 -0
  192. package/schemas/decision/HeldoutFrozen.v1.schema.json +142 -0
  193. package/schemas/decision/HeldoutPreregistration.v1.schema.json +222 -0
  194. package/schemas/decision/HeldoutSpendEvent.v1.schema.json +122 -0
  195. package/schemas/decision/HeldoutSpendHead.v1.schema.json +25 -0
  196. package/schemas/decision/HeldoutSpendHead.v2.schema.json +46 -0
  197. package/schemas/decision/HeldoutSummary.v1.schema.json +101 -0
  198. package/schemas/decision/OpaDecisionLogExport.v1.schema.json +65 -0
  199. package/schemas/decision/PreprocessedEvidence.v1.schema.json +306 -0
  200. package/schemas/decision/RulesetResult.v1alpha2.schema.json +175 -0
  201. package/schemas/decision/SdlcEvidenceScreening.v1.schema.json +499 -0
  202. package/schemas/decision/SdlcScreeningPreregistration.v1.schema.json +132 -0
  203. package/schemas/decision/SdlcScreeningPreregistration.v2.schema.json +138 -0
  204. package/schemas/decision/SdlcScreeningRelease.v1.schema.json +654 -0
  205. package/schemas/decision/SdlcScreeningRelease.v2.schema.json +654 -0
  206. package/tools/agents/deploy-agents.mjs +1 -1
  207. package/tools/agents/providers/base.mjs +26 -7
  208. package/tools/agents/providers/factory.mjs +10 -2
  209. package/tools/agents/providers/muse-hooks.mjs +1 -29
  210. package/tools/agents/providers/muse.mjs +6 -3
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Muse Code session adapter — manual export only, trajectory-first.
2
+ * Muse Code session adapter — explicit export plus evidence-gated native logs.
3
3
  *
4
4
  * Muse Code journals model calls, tool runs, and approvals to an append-only
5
5
  * session log and projects it into a self-contained JSON document via
@@ -9,12 +9,10 @@
9
9
  * fail closed with `UNKNOWN_SCHEMA_MAJOR`, as with peer native-export
10
10
  * adapters.
11
11
  *
12
- * Auto-discovery is unsupported and must never scrape home directories or
13
- * invent session roots. The documented candidate native root
14
- * (`$XDG_DATA_HOME/muse/sessions/YYYY/MM/DD/<session-id>/session.jsonl`,
15
- * default `~/.local/share/muse/sessions`) is NOT authorized or implemented
16
- * here; a future evidence-gated `--muse-root` discover path remains the
17
- * route to native discovery (#222 PR B).
12
+ * Auto-discovery must never scrape home directories or invent session roots.
13
+ * Native discovery is available only when the operator explicitly authorizes
14
+ * a Muse sessions root with `--muse-root`; the adapter then enumerates only
15
+ * `$root/YYYY/MM/DD/<session-id>/session.jsonl`.
18
16
  *
19
17
  * Trajectory shape follows the documented export format at
20
18
  * https://dev.meta.ai/docs/cookbook/audit-agent-sessions: top-level
@@ -41,13 +39,17 @@
41
39
  * @see docs/providers/muse-sessions.md
42
40
  * @issue #232
43
41
  */
42
+ import { opendir } from 'node:fs/promises';
43
+ import { resolve } from 'node:path';
44
44
  import { z } from 'zod';
45
45
  import { SessionContractError, assertSupportedSchemaMajor, } from '../contracts.js';
46
- import { readBoundedJson } from '../readers.js';
46
+ import { readBoundedJson, readBoundedJsonLines, } from '../readers.js';
47
47
  export const MUSE_ADAPTER_VERSION = '1.0.0';
48
48
  export const MUSE_EXPORT_SCHEMA_VERSION = '1.0.0';
49
49
  export const MUSE_EXPORT_SCHEMA_MAJOR = 1;
50
50
  export const MUSE_LOCATOR_CLASS = 'manual-export';
51
+ export const MUSE_NATIVE_LOCATOR_CLASS = 'muse-native-session-log';
52
+ export const MUSE_NATIVE_SCHEMA_VERSION = '1.0.0';
51
53
  const Rfc3339Schema = z.string().refine((value) => /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/.test(value)
52
54
  && !Number.isNaN(Date.parse(value)), 'timestamp must be RFC 3339 with an explicit UTC offset');
53
55
  /**
@@ -119,7 +121,10 @@ const MuseDiagnosticsSchema = z.object({
119
121
  unknown_payload_kinds: z.number().int().nonnegative().optional(),
120
122
  gaps: z.number().int().nonnegative().optional(),
121
123
  omitted_live_only: z.number().int().nonnegative().optional(),
124
+ omitted_records: z.number().int().nonnegative().optional(),
122
125
  duplicate_records: z.number().int().nonnegative().optional(),
126
+ retained_frames: z.number().int().nonnegative().optional(),
127
+ retained_frame_children: z.number().int().nonnegative().optional(),
123
128
  }).passthrough();
124
129
  const MuseTrajectorySchema = z.object({
125
130
  export_schema_version: z.number().int().nonnegative(),
@@ -134,24 +139,53 @@ const MuseTrajectorySchema = z.object({
134
139
  function isRecordEvent(event) {
135
140
  return event.kind === 'record';
136
141
  }
142
+ const MuseRetainedFrameSchema = z.object({
143
+ retained_frame: z.string().min(1),
144
+ frame_schema_version: z.number().int().nonnegative().optional(),
145
+ outer_log_ordinal: z.number().int().nonnegative().optional(),
146
+ transaction_id: z.string().optional(),
147
+ content_sha256: z.string().optional(),
148
+ children: z.array(z.object({
149
+ child_index: z.number().int().nonnegative().optional(),
150
+ record_json: z.string().min(1),
151
+ }).passthrough()),
152
+ }).passthrough();
137
153
  export class MuseSessionAdapter {
138
154
  limits;
155
+ maxFiles;
139
156
  provider = 'muse';
140
157
  adapterVersion = MUSE_ADAPTER_VERSION;
141
- disposition = 'manual-only';
142
- supportedOperations = ['inspect', 'stream'];
143
- acquisitionModes = ['manual-export'];
144
- constructor(limits) {
158
+ disposition = 'implemented';
159
+ supportedOperations = ['discover', 'inspect', 'stream'];
160
+ acquisitionModes = ['manual-export', 'jsonl'];
161
+ constructor(limits, maxFiles = 10_000) {
145
162
  this.limits = limits;
163
+ this.maxFiles = maxFiles;
146
164
  }
147
- async *discover(_scope) {
148
- throw new SessionContractError('UNSUPPORTED_OPERATION', 'Muse Code session auto-discover is unsupported: the native log under '
149
- + '$XDG_DATA_HOME/muse/sessions uses an internal format. Run `muse export --session '
150
- + '<id-or-session.jsonl>` and select that trajectory file. AIWG does not scrape home '
151
- + 'directories for this provider.');
165
+ async *discover(scope) {
166
+ if (scope.allowedRoots.length === 0) {
167
+ throw unsupportedNativeDiscovery();
168
+ }
169
+ let count = 0;
170
+ for (const root of [...scope.allowedRoots].sort()) {
171
+ for await (const locator of museNativeSessionLogs(resolve(root))) {
172
+ if (++count > this.maxFiles) {
173
+ throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Muse native session discovery exceeded the authorized file limit');
174
+ }
175
+ yield { provider: 'muse', locator, locatorClass: MUSE_NATIVE_LOCATOR_CLASS };
176
+ }
177
+ }
152
178
  }
153
179
  async inspect(source) {
154
- this.assertManualExport(source);
180
+ if (source.locatorClass === MUSE_NATIVE_LOCATOR_CLASS) {
181
+ const native = await this.readNative(source);
182
+ return {
183
+ sourceSchemaVersion: MUSE_NATIVE_SCHEMA_VERSION,
184
+ consistency: native.complete ? 'complete' : 'provisional',
185
+ operationalState: 'available',
186
+ };
187
+ }
188
+ this.assertSupportedLocator(source);
155
189
  const { trajectory } = await this.readTrajectory(source);
156
190
  for (const event of trajectory.events)
157
191
  this.parseEvent(event);
@@ -162,10 +196,38 @@ export class MuseSessionAdapter {
162
196
  };
163
197
  }
164
198
  async *stream(source, cursor) {
165
- this.assertManualExport(source);
199
+ if (source.locatorClass === MUSE_NATIVE_LOCATOR_CLASS) {
200
+ const native = await this.readNative(source);
201
+ const start = parseEventCursor(cursor?.value);
202
+ let outputIndex = 0;
203
+ for (const record of native.records) {
204
+ const position = outputIndex;
205
+ outputIndex += 1;
206
+ if (position < start)
207
+ continue;
208
+ const mapped = this.toProviderRecord(native.context, record.event.envelope, record.event, position);
209
+ mapped.rawReference = {
210
+ locatorClass: MUSE_NATIVE_LOCATOR_CLASS,
211
+ offset: record.line.byteOffset,
212
+ sequence: record.line.sequence,
213
+ };
214
+ mapped.sourceCursor = String(outputIndex);
215
+ mapped.extensions = {
216
+ ...mapped.extensions,
217
+ 'native.muse': compactObject({
218
+ ...(mapped.extensions?.['native.muse'] ?? {}),
219
+ retainedFrame: record.retainedFrame,
220
+ retainedChildIndex: record.retainedChildIndex,
221
+ }),
222
+ };
223
+ yield mapped;
224
+ }
225
+ return;
226
+ }
227
+ this.assertSupportedLocator(source);
166
228
  const { trajectory, bytesRead } = await this.readTrajectory(source);
167
229
  const start = parseEventCursor(cursor?.value);
168
- const spawns = acceptedSpawnsById(trajectory);
230
+ const context = contextFromTrajectory(trajectory, bytesRead);
169
231
  let index = 0;
170
232
  for (const event of trajectory.events) {
171
233
  // Cursor positions are raw event positions so resume stays aligned
@@ -178,7 +240,7 @@ export class MuseSessionAdapter {
178
240
  // fabricate a ProviderRecord for one.
179
241
  if (!isRecordEvent(event))
180
242
  continue;
181
- yield this.toProviderRecord(trajectory, bytesRead, event.envelope, spawns, event, position);
243
+ yield this.toProviderRecord(context, event.envelope, event, position);
182
244
  }
183
245
  }
184
246
  async readTrajectory(source) {
@@ -203,12 +265,12 @@ export class MuseSessionAdapter {
203
265
  parseEvent(event) {
204
266
  eventKindOf(event);
205
267
  }
206
- toProviderRecord(trajectory, bytesRead, envelope, spawns, event, index) {
268
+ toProviderRecord(context, envelope, event, index) {
207
269
  // Attribute by the event's own stream id; fall back to the document's
208
270
  // first session summary only when the stream block is absent. Live
209
271
  // evidence (Muse Code 1.3.0) shows merged events always carry the parent
210
272
  // id here, so never assume sessions[0] without reading the envelope.
211
- const nativeSessionId = streamSessionIdOf(envelope) ?? trajectory.sessions[0].session_id;
273
+ const nativeSessionId = streamSessionIdOf(envelope) ?? context.fallbackSessionId;
212
274
  const payload = envelope.payload ?? {};
213
275
  const payloadRecord = payload;
214
276
  const eventKind = eventKindOf(event);
@@ -219,7 +281,7 @@ export class MuseSessionAdapter {
219
281
  const approvalOutcome = stringField(payloadRecord, 'outcome');
220
282
  const decisionSource = objectField(payloadRecord, 'decision_source');
221
283
  const linkage = subagentLinkageOf(payloadRecord);
222
- const spawnContext = spawnContextOf(spawns, envelope.payload_type, linkage.subagentId);
284
+ const spawnContext = spawnContextOf(context.spawns, envelope.payload_type, linkage.subagentId);
223
285
  return {
224
286
  nativeSessionId,
225
287
  nativeEventId: `muse-seq-${envelope.sequence}`,
@@ -232,14 +294,15 @@ export class MuseSessionAdapter {
232
294
  model: undefined,
233
295
  entities: [],
234
296
  occurredAt: occurredAtOf(envelope.recorded_at) ?? undefined,
235
- text: describeEvent(eventKind, envelope.sequence, {
297
+ text: describeEvent(context.sourceLabel, eventKind, envelope.sequence, {
236
298
  operation, policyDecision, decision, approvalOutcome, decisionSource,
237
299
  }),
238
- rawReference: { locatorClass: MUSE_LOCATOR_CLASS, sequence: index },
300
+ rawReference: { locatorClass: context.locatorClass, sequence: index },
239
301
  sourceCursor: String(index + 1),
240
- sourceBytes: bytesRead,
302
+ sourceBytes: context.bytesRead,
241
303
  extensions: {
242
304
  'native.muse': compactObject({
305
+ acquisition: context.locatorClass,
243
306
  eventKind,
244
307
  recordType: event.kind,
245
308
  payloadType: envelope.payload_type,
@@ -249,11 +312,11 @@ export class MuseSessionAdapter {
249
312
  envelopeSequence: envelope.sequence,
250
313
  envelopeId: envelope.id,
251
314
  causationId: envelope.causation_id,
252
- exportSchemaVersion: trajectory.export_schema_version,
253
- redaction: trajectory.redaction,
254
- exporterVersion: trajectory.exporter_version?.display,
255
- sessionBuild: trajectory.session_build?.display,
256
- terminatedAbnormally: trajectory.session_terminated_abnormally,
315
+ exportSchemaVersion: context.exportSchemaVersion,
316
+ redaction: context.redaction,
317
+ exporterVersion: context.exporterVersion,
318
+ sessionBuild: context.sessionBuild,
319
+ terminatedAbnormally: context.terminatedAbnormally,
257
320
  operation,
258
321
  policyDecision,
259
322
  decision,
@@ -261,17 +324,246 @@ export class MuseSessionAdapter {
261
324
  approvalOutcome,
262
325
  ...linkage,
263
326
  ...spawnContext,
264
- diagnostics: trajectory.diagnostics,
327
+ diagnostics: context.diagnostics,
265
328
  }),
266
329
  },
267
330
  };
268
331
  }
269
- assertManualExport(source) {
270
- if (source.locatorClass !== MUSE_LOCATOR_CLASS) {
271
- throw new SessionContractError('UNSUPPORTED_OPERATION', `Muse Code supports only locatorClass "${MUSE_LOCATOR_CLASS}" because its native log format is internal `
272
- + `(got "${source.locatorClass}"). Select an explicit \`muse export\` trajectory file.`);
332
+ async readNative(source) {
333
+ this.assertSupportedLocator(source);
334
+ let input;
335
+ try {
336
+ input = await readBoundedJsonLines({ selectedPath: source.locator, allowedRoots: source.authorizedScope.allowedRoots }, { consistency: 'complete', limits: this.limits });
273
337
  }
338
+ catch (error) {
339
+ if (error instanceof SessionContractError && error.code === 'SCHEMA_DRIFT') {
340
+ throw new SessionContractError('MALFORMED_SOURCE', 'Muse native session log contains malformed JSONL');
341
+ }
342
+ throw error;
343
+ }
344
+ const diagnostics = {};
345
+ const records = [];
346
+ let fallbackSessionId = nativeSessionIdFromLocator(source.locator) ?? source.sourceId;
347
+ let complete = false;
348
+ for (const line of input.records) {
349
+ const value = line.value;
350
+ if (isOmissionMarker(value)) {
351
+ diagnostics.omitted_records = (diagnostics.omitted_records ?? 0) + 1;
352
+ if (asObject(value).retained_marker === 'omitted_live_only') {
353
+ diagnostics.omitted_live_only = (diagnostics.omitted_live_only ?? 0) + 1;
354
+ }
355
+ continue;
356
+ }
357
+ const retained = MuseRetainedFrameSchema.safeParse(value);
358
+ if (retained.success) {
359
+ diagnostics.retained_frames = (diagnostics.retained_frames ?? 0) + 1;
360
+ for (const child of retained.data.children) {
361
+ let decoded;
362
+ try {
363
+ decoded = JSON.parse(child.record_json);
364
+ }
365
+ catch {
366
+ throw new SessionContractError('MALFORMED_SOURCE', 'Muse retained frame child record is malformed JSON');
367
+ }
368
+ const event = recordEventFromEnvelope(decoded);
369
+ if (!event) {
370
+ throw new SessionContractError('MALFORMED_SOURCE', 'Muse retained frame child record is malformed');
371
+ }
372
+ fallbackSessionId = streamSessionIdOf(event.envelope) ?? fallbackSessionId;
373
+ complete ||= event.envelope.payload_type === 'session.end';
374
+ diagnostics.retained_frame_children = (diagnostics.retained_frame_children ?? 0) + 1;
375
+ records.push({
376
+ event,
377
+ line,
378
+ retainedFrame: retained.data.retained_frame,
379
+ retainedChildIndex: child.child_index,
380
+ });
381
+ }
382
+ continue;
383
+ }
384
+ const event = recordEventFromEnvelope(value);
385
+ if (!event) {
386
+ throw new SessionContractError('MALFORMED_SOURCE', 'Muse native session log line is not a supported record shape');
387
+ }
388
+ fallbackSessionId = streamSessionIdOf(event.envelope) ?? fallbackSessionId;
389
+ complete ||= event.envelope.payload_type === 'session.end';
390
+ records.push({ event, line });
391
+ }
392
+ if (records.length === 0) {
393
+ throw new SessionContractError('MALFORMED_SOURCE', 'Muse native session log contains no record envelopes');
394
+ }
395
+ return {
396
+ records,
397
+ complete,
398
+ context: {
399
+ locatorClass: MUSE_NATIVE_LOCATOR_CLASS,
400
+ sourceLabel: 'muse native session log',
401
+ bytesRead: input.bytesRead,
402
+ fallbackSessionId,
403
+ spawns: new Map(),
404
+ diagnostics,
405
+ },
406
+ };
274
407
  }
408
+ assertSupportedLocator(source) {
409
+ if (source.locatorClass !== MUSE_LOCATOR_CLASS && source.locatorClass !== MUSE_NATIVE_LOCATOR_CLASS) {
410
+ throw new SessionContractError('UNSUPPORTED_OPERATION', `Muse Code supports locatorClass "${MUSE_LOCATOR_CLASS}" and explicitly authorized `
411
+ + `"${MUSE_NATIVE_LOCATOR_CLASS}" sources (got "${source.locatorClass}").`);
412
+ }
413
+ }
414
+ }
415
+ function unsupportedNativeDiscovery() {
416
+ return new SessionContractError('UNSUPPORTED_OPERATION', 'Muse Code session auto-discover is unsupported: the native log under '
417
+ + '$XDG_DATA_HOME/muse/sessions uses an internal format. Run `muse export --session '
418
+ + '<id-or-session.jsonl>` and select that trajectory file. AIWG does not scrape home '
419
+ + 'directories for this provider.');
420
+ }
421
+ function contextFromTrajectory(trajectory, bytesRead) {
422
+ return {
423
+ locatorClass: MUSE_LOCATOR_CLASS,
424
+ sourceLabel: 'muse export trajectory',
425
+ bytesRead,
426
+ fallbackSessionId: trajectory.sessions[0].session_id,
427
+ spawns: acceptedSpawnsById(trajectory),
428
+ exportSchemaVersion: trajectory.export_schema_version,
429
+ redaction: trajectory.redaction,
430
+ exporterVersion: trajectory.exporter_version?.display,
431
+ sessionBuild: trajectory.session_build?.display,
432
+ terminatedAbnormally: trajectory.session_terminated_abnormally,
433
+ diagnostics: trajectory.diagnostics,
434
+ };
435
+ }
436
+ async function* museNativeSessionLogs(root) {
437
+ let years;
438
+ try {
439
+ years = await opendir(root);
440
+ }
441
+ catch {
442
+ return;
443
+ }
444
+ for await (const year of years) {
445
+ if (!year.isDirectory() || !/^\d{4}$/.test(year.name))
446
+ continue;
447
+ const yearPath = resolve(root, year.name);
448
+ let months;
449
+ try {
450
+ months = await opendir(yearPath);
451
+ }
452
+ catch {
453
+ continue;
454
+ }
455
+ for await (const month of months) {
456
+ if (!month.isDirectory() || !/^(0[1-9]|1[0-2])$/.test(month.name))
457
+ continue;
458
+ const monthPath = resolve(yearPath, month.name);
459
+ let days;
460
+ try {
461
+ days = await opendir(monthPath);
462
+ }
463
+ catch {
464
+ continue;
465
+ }
466
+ for await (const day of days) {
467
+ if (!day.isDirectory() || !/^(0[1-9]|[12]\d|3[01])$/.test(day.name))
468
+ continue;
469
+ const dayPath = resolve(monthPath, day.name);
470
+ let sessions;
471
+ try {
472
+ sessions = await opendir(dayPath);
473
+ }
474
+ catch {
475
+ continue;
476
+ }
477
+ for await (const session of sessions) {
478
+ if (!session.isDirectory() || !/^[A-Za-z0-9._-]+$/.test(session.name))
479
+ continue;
480
+ const sessionPath = resolve(dayPath, session.name);
481
+ let entries;
482
+ try {
483
+ entries = await opendir(sessionPath);
484
+ }
485
+ catch {
486
+ continue;
487
+ }
488
+ for await (const entry of entries) {
489
+ if (entry.isFile() && entry.name === 'session.jsonl') {
490
+ yield resolve(sessionPath, entry.name);
491
+ }
492
+ }
493
+ }
494
+ }
495
+ }
496
+ }
497
+ }
498
+ export async function museNativeSourceMatchesWorkspace(source, workspacePath) {
499
+ let input;
500
+ try {
501
+ input = await readBoundedJsonLines({ selectedPath: source.locator, allowedRoots: source.authorizedScope.allowedRoots }, { consistency: 'complete', limits: { maxRecords: 100, maxRecordBytes: 8 * 1024 * 1024 } });
502
+ }
503
+ catch {
504
+ return false;
505
+ }
506
+ for (const line of input.records) {
507
+ for (const envelope of nativeEnvelopesFromLine(line.value)) {
508
+ const candidate = workspaceEvidenceOf(envelope);
509
+ if (!candidate)
510
+ continue;
511
+ if (workspacePathEquals(candidate, workspacePath))
512
+ return true;
513
+ }
514
+ }
515
+ return false;
516
+ }
517
+ function nativeEnvelopesFromLine(value) {
518
+ if (isOmissionMarker(value))
519
+ return [];
520
+ const event = recordEventFromEnvelope(value);
521
+ if (event)
522
+ return [event.envelope];
523
+ const retained = MuseRetainedFrameSchema.safeParse(value);
524
+ if (!retained.success)
525
+ return [];
526
+ const envelopes = [];
527
+ for (const child of retained.data.children) {
528
+ try {
529
+ const childEvent = recordEventFromEnvelope(JSON.parse(child.record_json));
530
+ if (childEvent)
531
+ envelopes.push(childEvent.envelope);
532
+ }
533
+ catch {
534
+ return [];
535
+ }
536
+ }
537
+ return envelopes;
538
+ }
539
+ function recordEventFromEnvelope(value) {
540
+ const envelope = MuseEnvelopeSchema.safeParse(value);
541
+ return envelope.success ? { kind: 'record', envelope: envelope.data } : null;
542
+ }
543
+ function isOmissionMarker(value) {
544
+ const record = asObject(value);
545
+ return Object.prototype.hasOwnProperty.call(record, 'omitted_record')
546
+ || record.retained_marker === 'omitted_live_only';
547
+ }
548
+ function workspaceEvidenceOf(envelope) {
549
+ const payload = asObject(envelope.payload);
550
+ const record = asObject(payload.record);
551
+ for (const candidate of [record.workspace_root, record.cwd]) {
552
+ if (typeof candidate === 'string' && candidate.length > 0)
553
+ return candidate;
554
+ }
555
+ return null;
556
+ }
557
+ function workspacePathEquals(candidate, workspacePath) {
558
+ return resolve(candidate) === workspacePath;
559
+ }
560
+ function nativeSessionIdFromLocator(locator) {
561
+ const parts = locator.replaceAll('\\', '/').split('/');
562
+ const leaf = parts.at(-1);
563
+ if (leaf !== 'session.jsonl')
564
+ return null;
565
+ const sessionId = parts.at(-2);
566
+ return sessionId && /^[A-Za-z0-9._-]+$/.test(sessionId) ? sessionId : null;
275
567
  }
276
568
  /**
277
569
  * Effective event kind per the documented jq projection:
@@ -371,6 +663,11 @@ function objectField(payload, key) {
371
663
  ? value
372
664
  : null;
373
665
  }
666
+ function asObject(value) {
667
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
668
+ ? value
669
+ : {};
670
+ }
374
671
  function occurredAtOf(recordedAt) {
375
672
  if (typeof recordedAt === 'number') {
376
673
  // Epoch microseconds (Muse Code 1.4.0 export and native log).
@@ -381,8 +678,8 @@ function occurredAtOf(recordedAt) {
381
678
  return null;
382
679
  return Rfc3339Schema.safeParse(recordedAt).success ? recordedAt : null;
383
680
  }
384
- function describeEvent(eventKind, sequence, provenance) {
385
- const parts = [`muse export trajectory event ${eventKind} (sequence ${sequence})`];
681
+ function describeEvent(sourceLabel, eventKind, sequence, provenance) {
682
+ const parts = [`${sourceLabel} event ${eventKind} (sequence ${sequence})`];
386
683
  if (provenance.operation)
387
684
  parts.push(`operation=${provenance.operation}`);
388
685
  if (provenance.policyDecision)
@@ -5,6 +5,7 @@ import { CLAUDE_ADAPTER_VERSION, ClaudeSessionAdapter, } from './adapters/claude
5
5
  import { CODEX_ADAPTER_VERSION, CodexSessionAdapter, } from './adapters/codex.js';
6
6
  import { CURSOR_ADAPTER_VERSION, CursorSessionAdapter, } from './adapters/cursor.js';
7
7
  import { FACTORY_ADAPTER_VERSION, FactorySessionAdapter, } from './adapters/factory.js';
8
+ import { MUSE_ADAPTER_VERSION, MuseSessionAdapter, } from './adapters/muse.js';
8
9
  import { SESSION_CONTRACT_VERSION, SessionContractError, SessionSourceSchema, sha256, } from './contracts.js';
9
10
  import { BATCH_IMPORT_VERSION, coverageFromBatchRun, } from './batch-contracts.js';
10
11
  import { IncrementalSessionImporter, SessionImportFailure } from './importer.js';
@@ -211,6 +212,8 @@ function adapterFor(provider) {
211
212
  return new CursorSessionAdapter();
212
213
  if (provider === 'factory')
213
214
  return new FactorySessionAdapter();
215
+ if (provider === 'muse')
216
+ return new MuseSessionAdapter();
214
217
  throw new SessionContractError('UNSUPPORTED_OPERATION', `batch discovery import is not implemented for ${provider}`);
215
218
  }
216
219
  async function sessionSource(selected, adapter) {
@@ -244,6 +247,8 @@ function adapterVersion(provider) {
244
247
  return CURSOR_ADAPTER_VERSION;
245
248
  if (provider === 'factory')
246
249
  return FACTORY_ADAPTER_VERSION;
250
+ if (provider === 'muse')
251
+ return MUSE_ADAPTER_VERSION;
247
252
  return '1.0.0';
248
253
  }
249
254
  function providerProfile(provider, locatorClass) {
@@ -262,6 +267,8 @@ function providerProfile(provider, locatorClass) {
262
267
  }
263
268
  if (provider === 'factory')
264
269
  return 'documented-project-jsonl';
270
+ if (provider === 'muse')
271
+ return 'muse-native-session-log-v1';
265
272
  return 'manual-interchange';
266
273
  }
267
274
  function importErrorCode(error) {
@@ -7,6 +7,7 @@ import { ClaudeSessionAdapter } from './adapters/claude.js';
7
7
  import { CodexSessionAdapter } from './adapters/codex.js';
8
8
  import { CursorSessionAdapter } from './adapters/cursor.js';
9
9
  import { FactorySessionAdapter } from './adapters/factory.js';
10
+ import { MuseSessionAdapter, museNativeSourceMatchesWorkspace } from './adapters/muse.js';
10
11
  import { OmpSessionAdapter, readOmpSessionHeader } from './adapters/omp.js';
11
12
  import { resolveOmpPaths } from '../providers/omp-paths.mjs';
12
13
  import { PiSessionAdapter } from './adapters/pi.js';
@@ -17,7 +18,7 @@ import { fingerprintSourceFile } from './readers.js';
17
18
  export const DISCOVERY_MANIFEST_VERSION = '1.0.0';
18
19
  const MANUAL_EXPORT_PROVIDERS = new Set([
19
20
  'copilot', 'hermes', 'opencode', 'openclaw', 'openhuman', 'grokbot', 'grok-build',
20
- 'warp', 'devin-desktop', 'muse', 'generic',
21
+ 'warp', 'devin-desktop', 'generic',
21
22
  ]);
22
23
  export async function discoverWorkspaceHistories(options) {
23
24
  const workspacePath = await canonicalPath(options.workspace);
@@ -32,6 +33,8 @@ export async function discoverWorkspaceHistories(options) {
32
33
  { provider: 'omp', adapter: new OmpSessionAdapter(), roots: options.ompRoot
33
34
  ? [resolve(options.ompRoot)] : options.providerHome
34
35
  ? [resolveOmpPaths({ home: resolve(options.providerHome), cwd: workspacePath }).sessionsDir] : [] },
36
+ { provider: 'muse', adapter: new MuseSessionAdapter(), roots: options.museRoot
37
+ ? [resolve(options.museRoot)] : [] },
35
38
  {
36
39
  provider: 'claude',
37
40
  adapter: new ClaudeSessionAdapter(),
@@ -79,7 +82,8 @@ export async function discoverWorkspaceHistories(options) {
79
82
  availableRoots.push(await canonicalPath(root));
80
83
  }
81
84
  if (availableRoots.length === 0) {
82
- const codexNeedsAuthorization = (entry.provider === 'codex' || entry.provider === 'omp' || entry.provider === 'deepseek-harness')
85
+ const codexNeedsAuthorization = (entry.provider === 'codex' || entry.provider === 'omp'
86
+ || entry.provider === 'deepseek-harness' || entry.provider === 'muse')
83
87
  && entry.roots.length === 0;
84
88
  reports.set(entry.provider, providerReport(entry.provider, codexNeedsAuthorization ? 'export-required' : 'unavailable', codexNeedsAuthorization ? 'manual-export' : 'discoverable', [], codexNeedsAuthorization
85
89
  ? 'SHARED_ROOT_AUTHORIZATION_REQUIRED'
@@ -98,6 +102,13 @@ export async function discoverWorkspaceHistories(options) {
98
102
  if (entry.provider === 'codex'
99
103
  && !await codexSourceMatchesWorkspace(locator, workspacePath))
100
104
  continue;
105
+ if (entry.provider === 'muse'
106
+ && !await museNativeSourceMatchesWorkspace({
107
+ ...descriptor,
108
+ sourceId: 'discovery',
109
+ authorizedScope: scope,
110
+ }, workspacePath))
111
+ continue;
101
112
  const ompHeader = entry.provider === 'omp' ? await readOmpSessionHeader({ ...descriptor, sourceId: 'discovery', authorizedScope: scope }) : undefined;
102
113
  if (ompHeader && resolve(ompHeader.cwd) !== workspacePath)
103
114
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiwg/cli",
3
- "version": "2026.9.21",
3
+ "version": "2026.10.0",
4
4
  "description": "Lightweight AIWG CLI for signed, versioned web-backed resources.",
5
5
  "type": "module",
6
6
  "license": "MIT",