@aiwg/cli 2026.10.10 → 2026.10.12
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.
- package/agentic/code/providers/model-capabilities.v1.json +78 -14
- package/agentic/code/providers/model-catalog.v1.json +62 -12
- package/dist/src/artifacts/binding-target-identity.js +51 -0
- package/dist/src/artifacts/checksum-manifest.js +12 -0
- package/dist/src/artifacts/index-builder.js +11 -13
- package/dist/src/artifacts/query-engine.js +5 -11
- package/dist/src/cli/handlers/doctor-help.js +32 -0
- package/dist/src/cli/handlers/gates.js +19 -18
- package/dist/src/cli/handlers/models-help.js +7 -1
- package/dist/src/cli/handlers/models.js +3 -3
- package/dist/src/cli/handlers/script-runner.js +8 -5
- package/dist/src/cli/handlers/sessions-intake.js +104 -0
- package/dist/src/cli/handlers/sessions-tail.js +172 -0
- package/dist/src/cli/handlers/sessions.js +287 -31
- package/dist/src/cli/handlers/skill-lint.js +10 -3
- package/dist/src/cli/handlers/steward-format.js +100 -0
- package/dist/src/cli/handlers/steward-models.js +167 -0
- package/dist/src/cli/handlers/steward.js +14 -248
- package/dist/src/cli/handlers/use-bundle-counts.js +61 -0
- package/dist/src/cli/handlers/use.js +18 -28
- package/dist/src/cli/handlers/utilities.js +1 -24
- package/dist/src/config/aiwg-config.js +7 -0
- package/dist/src/config/authorization-cli.js +89 -0
- package/dist/src/config/cli-help.js +1 -0
- package/dist/src/config/cli.js +10 -1
- package/dist/src/config/worker-context.js +337 -0
- package/dist/src/decision/context-pruning.js +3 -2
- package/dist/src/decision/ensemble/contract.js +15 -4
- package/dist/src/decision/ensemble-study/artifacts.js +5 -0
- package/dist/src/decision/ensemble-study/score.js +4 -3
- package/dist/src/decision/feature-export.js +3 -9
- package/dist/src/decision/heldout/collector.js +2 -2
- package/dist/src/decision/issue-triage/runtime.js +3 -9
- package/dist/src/decision/qualification/gates.js +2 -1
- package/dist/src/decision/qualification/release.js +2 -3
- package/dist/src/decision/routing/report.js +2 -0
- package/dist/src/decision/sdlc-screening.js +3 -5
- package/dist/src/decision/sensitivity/comparative.js +5 -3
- package/dist/src/gates/driver.js +6 -77
- package/dist/src/gates/evaluate.js +4 -11
- package/dist/src/gates/floors.js +4 -4
- package/dist/src/gates/index.js +3 -3
- package/dist/src/gates/lattice.js +26 -0
- package/dist/src/gates/registry.js +2 -1
- package/dist/src/gates/report.js +19 -7
- package/dist/src/issues/audit-cli.js +120 -0
- package/dist/src/issues/audit-contract.js +64 -0
- package/dist/src/issues/audit-local.js +82 -0
- package/dist/src/issues/audit.js +220 -0
- package/dist/src/lint/rule-activation.js +15 -1
- package/dist/src/mcp/tools/worker-invoke.mjs +108 -10
- package/dist/src/mission-protocol/canonical-codecs.js +270 -0
- package/dist/src/mission-protocol/codecs.js +22 -550
- package/dist/src/mission-protocol/health-trace-codecs.js +281 -0
- package/dist/src/mission-protocol/health-trace-types.js +43 -0
- package/dist/src/mission-protocol/types.js +2 -42
- package/dist/src/mission-protocol/worker-contract-json.js +10 -0
- package/dist/src/mission-protocol/worker-review-gate.js +100 -0
- package/dist/src/mission-protocol/worker-review-types.js +2 -0
- package/dist/src/models/catalog-policy.js +280 -0
- package/dist/src/models/index.js +1 -1
- package/dist/src/models/model-capabilities.v1.json +78 -14
- package/dist/src/models/model-catalog.v1.json +62 -12
- package/dist/src/models/policy-resources.js +28 -0
- package/dist/src/models/provider-policy.js +10 -539
- package/dist/src/models/resolver.js +26 -8
- package/dist/src/models/router.js +15 -2
- package/dist/src/models/tiers.js +13 -0
- package/dist/src/models/types.js +0 -6
- package/dist/src/models/worker-ceilings.js +59 -0
- package/dist/src/models/worker-invocation-policy.js +243 -0
- package/dist/src/models/worker-plan.js +16 -20
- package/dist/src/models/worker-review-lineage.js +55 -0
- package/dist/src/models/worker-selection-policy.js +1 -1
- package/dist/src/models/wrapper-route.js +6 -3
- package/dist/src/policy/authorization.js +30 -1
- package/dist/src/policy/hitl-config.js +63 -0
- package/dist/src/policy/hitl-receipt.js +57 -0
- package/dist/src/policy/hitl-types.js +4 -0
- package/dist/src/policy/hitl-validation.js +39 -0
- package/dist/src/policy/hitl.js +117 -0
- package/dist/src/process/aiwg-probe-command.d.mts +15 -0
- package/dist/src/process/aiwg-probe-command.mjs +37 -0
- package/dist/src/rules/activation.d.mts +1 -1
- package/dist/src/rules/activation.mjs +0 -2
- package/dist/src/rules/gate-coverage.js +51 -0
- package/dist/src/rules/gate-references.js +16 -0
- package/dist/src/rules/rule-frontmatter.schema.json +7 -1
- package/dist/src/serve/worker-command-request.js +21 -4
- package/dist/src/serve/worker-invocation-preparation.js +3 -1
- package/dist/src/serve/worker-invocation.js +21 -10
- package/dist/src/sessions/adapters/deepseek-harness.js +1 -0
- package/dist/src/sessions/adapters/grok-build-native.js +269 -0
- package/dist/src/sessions/adapters/grok-build.js +57 -15
- package/dist/src/sessions/adapters/grokbot.js +7 -0
- package/dist/src/sessions/adapters/hermes-state-db.js +252 -0
- package/dist/src/sessions/adapters/hermes.js +42 -3
- package/dist/src/sessions/adapters/warp.js +1 -1
- package/dist/src/sessions/batch-import.js +44 -6
- package/dist/src/sessions/contracts.js +20 -1
- package/dist/src/sessions/coverage-preflight.js +7 -1
- package/dist/src/sessions/discovery-capability.js +38 -0
- package/dist/src/sessions/fortemi-export-mapping.js +33 -3
- package/dist/src/sessions/host-catalog.js +157 -0
- package/dist/src/sessions/image-blobs.js +141 -0
- package/dist/src/sessions/importer.js +9 -232
- package/dist/src/sessions/index.js +6 -0
- package/dist/src/sessions/intake-dir.js +71 -0
- package/dist/src/sessions/normalization.js +251 -0
- package/dist/src/sessions/refresh.js +25 -2
- package/dist/src/sessions/repository.js +164 -22
- package/dist/src/sessions/tail.js +91 -0
- package/dist/src/sessions/workspace-discovery.js +88 -9
- package/dist/src/skills/agent-skill-sidecar.js +28 -0
- package/dist/src/skills/agent-skills.js +4 -23
- package/dist/src/skills/claude-surface-projection.js +25 -0
- package/dist/src/skills/deployer.js +8 -288
- package/dist/src/skills/deployment-policy.js +114 -0
- package/dist/src/skills/deployment-projection.js +152 -0
- package/dist/src/skills/deployment-types.js +20 -0
- package/dist/src/skills/exporter.js +8 -31
- package/dist/src/skills/provider-extensions.js +41 -0
- package/dist/src/skills/run.js +6 -0
- package/dist/src/skills/types.js +0 -8
- package/dist/src/skills/validator-resources.js +68 -0
- package/dist/src/skills/validator.js +6 -55
- package/dist/src/storage/cli-migrate-options.js +125 -0
- package/dist/src/storage/cli-migrate.js +111 -0
- package/dist/src/storage/cli.js +4 -279
- package/dist/src/storage/migration-adapter.js +79 -0
- package/dist/src/storage/migration-copy.js +108 -0
- package/dist/src/storage/migration-protocol.js +14 -197
- package/dist/src/storage/migration-records.js +186 -0
- package/dist/src/storage/migration-types.js +12 -0
- package/dist/src/tracker/forge-http.js +2 -1
- package/dist/src/tracker/issue-pages.js +110 -0
- package/package.json +7 -1
- package/schemas/mission-v1.schema.json +335 -0
- package/schemas/models/model-catalog.v1.schema.json +19 -1
- package/schemas/models/model-config-compatibility.v1.schema.json +3 -2
- package/schemas/models/model-policy.v1.schema.json +1 -1
- package/tools/agents/providers/provider-paths-staging.mjs +35 -0
- package/tools/agents/providers/rule-binding-targets.mjs +146 -0
- package/tools/agents/providers/rule-delivery.mjs +7 -126
- package/tools/ralph-external/lib/muse-adapter.mjs +10 -0
- package/tools/ralph-external/lib/worker-context.mjs +237 -0
- package/tools/ralph-external/lib/worker-invocation-ancestry.mjs +132 -0
- package/tools/ralph-external/lib/worker-invocation-processes.mjs +123 -0
- package/tools/ralph-external/lib/worker-isolation-status.mjs +48 -0
- package/tools/ralph-external/lib/worker-isolation.mjs +17 -29
- package/tools/ralph-external/lib/worker-launch-cli.mjs +3 -1
- package/tools/ralph-external/lib/worker-overflow.mjs +48 -13
- package/tools/ralph-external/lib/worker-retry-evidence.mjs +103 -0
- package/tools/ralph-external/lib/worker-termination.mjs +82 -0
- package/tools/ralph-external/session-launcher.mjs +51 -96
- package/vscode-extension/schemas/aiwg.config.v1.json +177 -0
|
@@ -178,6 +178,13 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
178
178
|
import { mcpError, mcpJson } from '../helpers.mjs';
|
|
179
179
|
import { buildShellStopControl, waitForUnitTermination } from './worker-shell-control.mjs';
|
|
180
180
|
import { launchPreparedShellWorker, sweepWorkerStdin } from './worker-stdin-runtime.mjs';
|
|
181
|
+
// NOTE: no static import of ../../config/worker-context.js here. That
|
|
182
|
+
// module is TypeScript: a literal relative import resolves under vitest
|
|
183
|
+
// but throws ERR_MODULE_NOT_FOUND under raw node (e.g. `node
|
|
184
|
+
// src/mcp/cli.mjs`, which test/unit/mcp exercises directly). The
|
|
185
|
+
// request-time loader below resolves it through importImpl (dist when
|
|
186
|
+
// built, source otherwise), so merely loading this bridge never touches
|
|
187
|
+
// it. See tools/_resolve-impl.mjs (#3062).
|
|
181
188
|
|
|
182
189
|
const execFileAsync = promisify(execFile);
|
|
183
190
|
|
|
@@ -642,6 +649,64 @@ function describeGateFailures(failures) {
|
|
|
642
649
|
return `worker dispatch gate blocked: ${failures.map(f => `${f.signal} (${f.reason})`).join('; ')}`;
|
|
643
650
|
}
|
|
644
651
|
|
|
652
|
+
/** Request-time loader for the TypeScript worker-context module (see the
|
|
653
|
+
* import note above): resolved through importImpl so production uses the
|
|
654
|
+
* compiled `dist` tree while a checkout falls back to source. Cached for
|
|
655
|
+
* the process lifetime; only request paths that actually ensure worker
|
|
656
|
+
* context ever trigger the load. */
|
|
657
|
+
let cachedWorkerContextModule = null;
|
|
658
|
+
async function loadWorkerContextModule() {
|
|
659
|
+
if (!cachedWorkerContextModule) cachedWorkerContextModule = await importImpl('config/worker-context.js');
|
|
660
|
+
return cachedWorkerContextModule;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/** Map the worker CLI to its provider and ensure its bootstrap is present
|
|
664
|
+
* in the worker workdir (#3685 round 2). Deploys the resolved union set
|
|
665
|
+
* (config providers plus orchestration CLIs) in one pass when the worker
|
|
666
|
+
* provider's bootstrap is missing; an unmappable CLI refuses with the
|
|
667
|
+
* typed diagnostic, since no deploy could target it. */
|
|
668
|
+
async function ensureWorkerContextForInvocation({ invocation, config }) {
|
|
669
|
+
const { ensureWorkerContextBootstrap, mapCliToProviderId, resolveWorkerContextProvidersFromConfig, WorkerContextBootstrapError } =
|
|
670
|
+
await loadWorkerContextModule();
|
|
671
|
+
const cli = invocation?.selected?.cli;
|
|
672
|
+
const mapped = mapCliToProviderId(cli, config?.parallelism);
|
|
673
|
+
if (!('provider' in mapped) || !mapped.provider) {
|
|
674
|
+
throw new WorkerContextBootstrapError(
|
|
675
|
+
`cannot ensure worker context: CLI '${cli}' maps to no AIWG provider (${mapped.skipped ?? 'unmapped'})`,
|
|
676
|
+
`configure parallelism.clis.${cli} with a providers:<id> adapter, or dispatch a CLI whose adapter maps to a known provider`,
|
|
677
|
+
{ workdir: invocation?.cwd },
|
|
678
|
+
);
|
|
679
|
+
}
|
|
680
|
+
let providers = [mapped.provider];
|
|
681
|
+
try {
|
|
682
|
+
providers = [...new Set([...resolveWorkerContextProvidersFromConfig(config).providers, mapped.provider])];
|
|
683
|
+
} catch {
|
|
684
|
+
providers = [mapped.provider];
|
|
685
|
+
}
|
|
686
|
+
return ensureWorkerContextBootstrap({ workdir: invocation?.cwd, provider: mapped.provider, providers });
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
/** Refuse a failed bootstrap ensure as a typed blocked diagnostic that
|
|
690
|
+
* names the remedy — never a bare string the operator cannot act on.
|
|
691
|
+
* `code`/`remedy`/`provider`/`workdir` survive on any error object that
|
|
692
|
+
* carries them (the tools-side ensure throws a duck-typed refusal, not
|
|
693
|
+
* necessarily this module's class instance); only genuinely bare failures
|
|
694
|
+
* fall back to the generic code and remedy. */
|
|
695
|
+
function toWorkerContextDiagnostic(error) {
|
|
696
|
+
const fields = (error !== null && typeof error === 'object') ? error : {};
|
|
697
|
+
// Duck-typed on purpose: the worker-context module loads lazily (see
|
|
698
|
+
// above), so no class identity is available at module scope. Every
|
|
699
|
+
// refusal path sets `code`/`remedy` on the thrown object instead.
|
|
700
|
+
const code = (typeof fields.code === 'string' && fields.code ? fields.code : 'OG_WORKER_CONTEXT_UNAVAILABLE');
|
|
701
|
+
const remedy = (typeof fields.remedy === 'string' && fields.remedy ? fields.remedy
|
|
702
|
+
: 'ensure the worker CLI maps to a known AIWG provider and the aiwg CLI is installed (AIWG_BIN), then retry the run');
|
|
703
|
+
return { code,
|
|
704
|
+
message: error instanceof Error ? error.message : String(error?.message ?? error),
|
|
705
|
+
remedy,
|
|
706
|
+
...(fields.provider !== undefined ? { provider: fields.provider } : {}),
|
|
707
|
+
...(fields.workdir !== undefined ? { workdir: fields.workdir } : {}) };
|
|
708
|
+
}
|
|
709
|
+
|
|
645
710
|
// Audited observer; refresh the historical baseline graph after rebase.
|
|
646
711
|
const waitForUnitTerminationBaseline = waitForUnitTermination;
|
|
647
712
|
export { waitForUnitTerminationBaseline as __testOnlyWaitForUnitTerminationBaseline };
|
|
@@ -758,6 +823,7 @@ export class ChildProcessTransport {
|
|
|
758
823
|
// cap since a long-lived connection could otherwise grow it unbounded.
|
|
759
824
|
this._rawResponses = new Map();
|
|
760
825
|
this._buffer = undefined;
|
|
826
|
+
this._bufferBytes = 0;
|
|
761
827
|
}
|
|
762
828
|
|
|
763
829
|
async start() {
|
|
@@ -769,7 +835,7 @@ export class ChildProcessTransport {
|
|
|
769
835
|
try {
|
|
770
836
|
// Check each frame BEFORE concatenation or UTF-8 decoding.
|
|
771
837
|
let offset = 0;
|
|
772
|
-
let frameBytes = this.
|
|
838
|
+
let frameBytes = this._bufferBytes;
|
|
773
839
|
while (offset < chunk.length) {
|
|
774
840
|
const newline = chunk.indexOf(10, offset);
|
|
775
841
|
const end = newline === -1 ? chunk.length : newline;
|
|
@@ -782,8 +848,7 @@ export class ChildProcessTransport {
|
|
|
782
848
|
frameBytes = 0;
|
|
783
849
|
offset = newline + 1;
|
|
784
850
|
}
|
|
785
|
-
this.
|
|
786
|
-
this._drain();
|
|
851
|
+
this._drain(chunk);
|
|
787
852
|
} catch (error) { this.onerror?.(error); }
|
|
788
853
|
});
|
|
789
854
|
child.stdout?.on('error', error => this.onerror?.(error));
|
|
@@ -799,6 +864,7 @@ export class ChildProcessTransport {
|
|
|
799
864
|
if (this._closed) return;
|
|
800
865
|
this._closed = true;
|
|
801
866
|
this._buffer = undefined;
|
|
867
|
+
this._bufferBytes = 0;
|
|
802
868
|
this._rawResponses.clear();
|
|
803
869
|
this.onclose?.();
|
|
804
870
|
}
|
|
@@ -807,6 +873,7 @@ export class ChildProcessTransport {
|
|
|
807
873
|
if (this._failure) return;
|
|
808
874
|
this._failure = Object.assign(new Error(code), { code });
|
|
809
875
|
this._buffer = undefined;
|
|
876
|
+
this._bufferBytes = 0;
|
|
810
877
|
this._rawResponses.clear();
|
|
811
878
|
// Start stopping before pipe closure can exit the leader; onclose rejects
|
|
812
879
|
// pending SDK requests immediately while termination proof is awaited.
|
|
@@ -825,14 +892,26 @@ export class ChildProcessTransport {
|
|
|
825
892
|
// (own-property-preserving, retained in `_rawResponses` — see
|
|
826
893
|
// constructor doc) and once through the SDK's own `JSONRPCMessageSchema`
|
|
827
894
|
// (routed to `onmessage`, unchanged behavior for the Client/Protocol).
|
|
828
|
-
_drain() {
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
895
|
+
_drain(chunk) {
|
|
896
|
+
// Retain fragments without copying or rescanning the growing partial
|
|
897
|
+
// frame on every pipe read. Join once, only when a newline arrives.
|
|
898
|
+
let offset = 0;
|
|
899
|
+
while (offset < chunk.length) {
|
|
900
|
+
const newline = chunk.indexOf(10, offset);
|
|
901
|
+
const end = newline === -1 ? chunk.length : newline;
|
|
902
|
+
if (end > offset) {
|
|
903
|
+
(this._buffer ??= []).push(chunk.subarray(offset, end));
|
|
904
|
+
this._bufferBytes += end - offset;
|
|
905
|
+
}
|
|
906
|
+
if (newline === -1) return;
|
|
907
|
+
const frame = this._buffer?.length === 1
|
|
908
|
+
? this._buffer[0] : Buffer.concat(this._buffer ?? [], this._bufferBytes);
|
|
909
|
+
const line = frame.toString('utf8').replace(/\r$/, '');
|
|
910
|
+
this._buffer = undefined;
|
|
911
|
+
this._bufferBytes = 0;
|
|
834
912
|
this._handleLine(line);
|
|
835
|
-
if (this.
|
|
913
|
+
if (this._closed || this._failure) return;
|
|
914
|
+
offset = newline + 1;
|
|
836
915
|
}
|
|
837
916
|
}
|
|
838
917
|
|
|
@@ -905,6 +984,7 @@ export class ChildProcessTransport {
|
|
|
905
984
|
try { signalChild(child, 'SIGKILL'); } catch { /* already gone */ }
|
|
906
985
|
}
|
|
907
986
|
this._buffer = undefined;
|
|
987
|
+
this._bufferBytes = 0;
|
|
908
988
|
}
|
|
909
989
|
}
|
|
910
990
|
|
|
@@ -1745,6 +1825,24 @@ export async function registerWorkerInvokeToolset(server, options = {}) {
|
|
|
1745
1825
|
}
|
|
1746
1826
|
const { root, snapshot, drivers, invocation } = prefix;
|
|
1747
1827
|
|
|
1828
|
+
// #3685 round 2: the worker CLI's AIWG bootstrap must be present in
|
|
1829
|
+
// the worker workdir before dispatch — a context-free worker would run
|
|
1830
|
+
// with no project rules/skills/hooks. Present: no-op. Missing: exactly
|
|
1831
|
+
// one `aiwg use all` pass into the workdir (never elsewhere). A failed
|
|
1832
|
+
// ensure refuses as `blocked` with the typed diagnostic (never a
|
|
1833
|
+
// launch). Default on; `ensureWorkerContext: false` skips (synthetic
|
|
1834
|
+
// tests), a function value replaces the ensure.
|
|
1835
|
+
if (options.ensureWorkerContext !== false) {
|
|
1836
|
+
try {
|
|
1837
|
+
const ensure = typeof options.ensureWorkerContext === 'function'
|
|
1838
|
+
? options.ensureWorkerContext
|
|
1839
|
+
: ensureWorkerContextForInvocation;
|
|
1840
|
+
await ensure({ invocation, config: snapshot.config });
|
|
1841
|
+
} catch (error) {
|
|
1842
|
+
return markTerminal({ status: 'blocked', termination: 'confirmed', diagnostics: [toWorkerContextDiagnostic(error)] });
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1748
1846
|
// =========================================================================
|
|
1749
1847
|
// #2915 round 8 (D6): ONE decision, immediately after the prefix, from
|
|
1750
1848
|
// the launcher's own pure eligibility predicate,
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
// Canonical Mission projections and legacy transport codecs.
|
|
2
|
+
import { assertMissionWorkerHandoff } from './codecs.js';
|
|
3
|
+
import { MISSION_API_VERSION } from './types.js';
|
|
4
|
+
const TERMINAL = new Set(['completed', 'failed', 'incomplete', 'cancelled']);
|
|
5
|
+
function object(value, label = 'Mission input') {
|
|
6
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
7
|
+
throw new Error(`${label} must be an object.`);
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
function string(value) {
|
|
11
|
+
return typeof value === 'string' && value.length ? value : undefined;
|
|
12
|
+
}
|
|
13
|
+
function requiredId(record) {
|
|
14
|
+
const metadata = record.metadata && typeof record.metadata === 'object' ? record.metadata : {};
|
|
15
|
+
const id = string(record.missionId) ?? string(record.mission_id) ?? string(record.id)
|
|
16
|
+
?? string(record.taskId) ?? string(record.task_id) ?? string(record.responseId) ?? string(metadata.id);
|
|
17
|
+
if (!id)
|
|
18
|
+
throw new Error('Mission source is missing a stable identifier.');
|
|
19
|
+
return id;
|
|
20
|
+
}
|
|
21
|
+
export function normalizeMissionState(nativeState) {
|
|
22
|
+
const state = String(nativeState ?? 'unknown').toLowerCase().replace(/_/g, '-');
|
|
23
|
+
if (['done', 'completed', 'succeeded', 'success'].includes(state))
|
|
24
|
+
return 'completed';
|
|
25
|
+
if (['aborted', 'cancelled', 'canceled'].includes(state))
|
|
26
|
+
return 'cancelled';
|
|
27
|
+
if (['failed', 'error', 'rejected', 'timed-out'].includes(state))
|
|
28
|
+
return 'failed';
|
|
29
|
+
if (['incomplete', 'budget-exhausted', 'max-iterations', 'max-tokens'].includes(state))
|
|
30
|
+
return 'incomplete';
|
|
31
|
+
if (['running', 'in-progress', 'working', 'started', 'assigned', 'admitted', 'starting'].includes(state))
|
|
32
|
+
return 'running';
|
|
33
|
+
if (['pending', 'submitted', 'queued', 'runnable', 'scheduled'].includes(state))
|
|
34
|
+
return 'pending';
|
|
35
|
+
if (['blocked', 'blocked-hitl', 'input-required', 'auth-required', 'paused', 'suspended'].includes(state))
|
|
36
|
+
return 'blocked';
|
|
37
|
+
if (['operator-review', 'operator-review-required', 'manual-review'].includes(state))
|
|
38
|
+
return 'operator-review';
|
|
39
|
+
if (['unknown', 'disconnected', 'detached', 'unreachable'].includes(state))
|
|
40
|
+
return 'unknown';
|
|
41
|
+
return 'unknown';
|
|
42
|
+
}
|
|
43
|
+
function knownKeysFor(source) {
|
|
44
|
+
const common = ['id', 'missionId', 'mission_id', 'taskId', 'task_id', 'responseId', 'title', 'goal', 'objective', 'prompt', 'completion', 'completionCriterion', 'completion_criterion', 'status', 'state', 'nativeState', 'createdAt', 'created_at', 'updatedAt', 'updated_at', 'metadata', 'spec', 'provenance', 'extensions', 'artifacts', 'output', 'partialOutput', 'error', 'checkpoint', 'cycles', 'activityLog', 'totalCost', 'runtimesUsed', 'apiVersion', 'api_version', 'schemaVersion', 'schema_version', 'kind', 'session_id', 'previous_response_id'];
|
|
45
|
+
if (source === 'uhp-2026-08-11')
|
|
46
|
+
common.push('object', 'model', 'incomplete_details', 'store', 'usage');
|
|
47
|
+
return new Set(common);
|
|
48
|
+
}
|
|
49
|
+
function extensions(record, source) {
|
|
50
|
+
const explicit = record.extensions && typeof record.extensions === 'object' ? structuredClone(record.extensions) : {};
|
|
51
|
+
if (record.metadata && typeof record.metadata === 'object')
|
|
52
|
+
explicit.metadata = structuredClone(record.metadata);
|
|
53
|
+
if (record.status && typeof record.status === 'object')
|
|
54
|
+
explicit.nativeStatus = structuredClone(record.status);
|
|
55
|
+
for (const [key, value] of Object.entries(record))
|
|
56
|
+
if (!knownKeysFor(source).has(key))
|
|
57
|
+
explicit[key] = structuredClone(value);
|
|
58
|
+
return explicit;
|
|
59
|
+
}
|
|
60
|
+
function artifacts(record) {
|
|
61
|
+
const values = Array.isArray(record.artifacts) ? record.artifacts : [];
|
|
62
|
+
return values.flatMap((item, index) => {
|
|
63
|
+
if (!item || typeof item !== 'object')
|
|
64
|
+
return [];
|
|
65
|
+
const artifact = item;
|
|
66
|
+
const id = string(artifact.id) ?? string(artifact.fileId) ?? string(artifact.file_id) ?? string(artifact.uri) ?? `artifact-${index}`;
|
|
67
|
+
return [{
|
|
68
|
+
id,
|
|
69
|
+
kind: string(artifact.kind) ?? 'other',
|
|
70
|
+
...(string(artifact.uri) ? { uri: string(artifact.uri) } : {}),
|
|
71
|
+
...(string(artifact.sha256) ? { sha256: string(artifact.sha256) } : {}),
|
|
72
|
+
...(string(artifact.mediaType) ?? string(artifact.media_type) ? { mediaType: string(artifact.mediaType) ?? string(artifact.media_type) } : {}),
|
|
73
|
+
extensions: structuredClone(artifact),
|
|
74
|
+
}];
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function uhpOutputArtifacts(record) {
|
|
78
|
+
const found = new Map();
|
|
79
|
+
function visit(value) {
|
|
80
|
+
if (Array.isArray(value)) {
|
|
81
|
+
value.forEach(visit);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (!value || typeof value !== 'object')
|
|
85
|
+
return;
|
|
86
|
+
const item = value;
|
|
87
|
+
const id = string(item.file_id);
|
|
88
|
+
if (id)
|
|
89
|
+
found.set(id, { id, kind: 'uhp-file', ...(string(item.media_type) ? { mediaType: string(item.media_type) } : {}), extensions: { 'uhp.file': structuredClone(item) } });
|
|
90
|
+
Object.values(item).forEach(visit);
|
|
91
|
+
}
|
|
92
|
+
visit(record.output);
|
|
93
|
+
return [...found.values()];
|
|
94
|
+
}
|
|
95
|
+
function nativeStateFor(source, record, statusRecord) {
|
|
96
|
+
const explicit = string(statusRecord.state) ?? string(record.nativeState) ?? string(record.status)
|
|
97
|
+
?? string(record.state) ?? string(record.observed_state) ?? string(record.observedState) ?? string(record.nodeState);
|
|
98
|
+
if (explicit)
|
|
99
|
+
return explicit;
|
|
100
|
+
if (source === 'mission-ledger' && record.checkpoint && typeof record.checkpoint === 'object') {
|
|
101
|
+
const checkpoint = record.checkpoint;
|
|
102
|
+
if (Array.isArray(checkpoint.pending) && checkpoint.pending.length)
|
|
103
|
+
return 'running';
|
|
104
|
+
if (Array.isArray(checkpoint.failed) && checkpoint.failed.length)
|
|
105
|
+
return 'failed';
|
|
106
|
+
if (Array.isArray(checkpoint.completed) && checkpoint.completed.length)
|
|
107
|
+
return 'completed';
|
|
108
|
+
}
|
|
109
|
+
return 'unknown';
|
|
110
|
+
}
|
|
111
|
+
function sourceVersion(source, record) {
|
|
112
|
+
if (source === 'canonical')
|
|
113
|
+
return string(record.apiVersion) ?? 'unknown';
|
|
114
|
+
if (source === 'uhp-2026-08-11')
|
|
115
|
+
return '2026-08-11';
|
|
116
|
+
if (source === 'executor-v1')
|
|
117
|
+
return 'executor.aiwg.io/v1';
|
|
118
|
+
if (source === 'fleet-workload-v1')
|
|
119
|
+
return 'fleet-workload/v1';
|
|
120
|
+
if (source === 'graph-flow-v1')
|
|
121
|
+
return 'graph.flow.aiwg.io/v1';
|
|
122
|
+
if (source === 'activity-v1')
|
|
123
|
+
return 'activity.aiwg.io/v1';
|
|
124
|
+
return string(record.apiVersion) ?? string(record.api_version) ?? string(record.schemaVersion) ?? string(record.schema_version) ?? 'unversioned';
|
|
125
|
+
}
|
|
126
|
+
function assertSupported(version) {
|
|
127
|
+
const supported = new Set(['unversioned', MISSION_API_VERSION, '2026-08-11', 'executor.aiwg.io/v1', 'fleet-workload/v1', 'graph.flow.aiwg.io/v1', 'activity.aiwg.io/v1']);
|
|
128
|
+
if (supported.has(version))
|
|
129
|
+
return;
|
|
130
|
+
const major = version.match(/(?:^|\/)v(\d+)(?:$|[.-])/)?.[1];
|
|
131
|
+
if (major && major !== '1')
|
|
132
|
+
throw new Error(`Unsupported Mission source major version '${version}'; supported major is v1.`);
|
|
133
|
+
throw new Error(`Unsupported Mission source version '${version}'.`);
|
|
134
|
+
}
|
|
135
|
+
export function validateCanonicalMission(value) {
|
|
136
|
+
const record = object(value, 'Canonical Mission');
|
|
137
|
+
assertMissionWorkerHandoff(record, 'canonical');
|
|
138
|
+
if (record.apiVersion !== MISSION_API_VERSION)
|
|
139
|
+
throw new Error(`Unsupported canonical Mission version '${String(record.apiVersion)}'.`);
|
|
140
|
+
if (record.kind !== 'Mission')
|
|
141
|
+
throw new Error("Canonical Mission kind must be 'Mission'.");
|
|
142
|
+
const metadata = object(record.metadata, 'Mission metadata');
|
|
143
|
+
const spec = object(record.spec, 'Mission spec');
|
|
144
|
+
const status = object(record.status, 'Mission status');
|
|
145
|
+
const provenance = object(record.provenance, 'Mission provenance');
|
|
146
|
+
if (!string(metadata.id) || !string(spec.objective) || !string(provenance.sourceContract) || !string(provenance.sourceVersion))
|
|
147
|
+
throw new Error('Canonical Mission is missing required identity, objective, or provenance.');
|
|
148
|
+
const state = normalizeMissionState(status.state);
|
|
149
|
+
if (status.state !== state)
|
|
150
|
+
throw new Error(`Canonical Mission state '${String(status.state)}' is not normalized.`);
|
|
151
|
+
if (status.terminal !== TERMINAL.has(state))
|
|
152
|
+
throw new Error(`Canonical Mission terminal flag contradicts state '${state}'.`);
|
|
153
|
+
if (!Array.isArray(status.artifacts))
|
|
154
|
+
throw new Error('Canonical Mission artifacts must be an array.');
|
|
155
|
+
return structuredClone(value);
|
|
156
|
+
}
|
|
157
|
+
export function decodeMission(input, source, workerConsumer) {
|
|
158
|
+
const record = object(input);
|
|
159
|
+
assertMissionWorkerHandoff(record, source, workerConsumer);
|
|
160
|
+
if (source === 'canonical') {
|
|
161
|
+
const value = validateCanonicalMission(record);
|
|
162
|
+
return { value, sourceVersion: MISSION_API_VERSION, warnings: [], preservedExtensions: structuredClone(value.extensions ?? {}), lossReport: [] };
|
|
163
|
+
}
|
|
164
|
+
const version = sourceVersion(source, record);
|
|
165
|
+
assertSupported(version);
|
|
166
|
+
const statusRecord = record.status && typeof record.status === 'object' ? record.status : {};
|
|
167
|
+
const nativeState = nativeStateFor(source, record, statusRecord);
|
|
168
|
+
const state = normalizeMissionState(nativeState);
|
|
169
|
+
const objective = string(record.goal) ?? string(record.objective) ?? string(record.title) ?? string(record.prompt) ?? '(legacy mission objective unavailable)';
|
|
170
|
+
const completionCriterion = string(record.completionCriterion) ?? string(record.completion_criterion) ?? string(record.completion);
|
|
171
|
+
const preserved = extensions(record, source);
|
|
172
|
+
const warnings = [];
|
|
173
|
+
const lossReport = [];
|
|
174
|
+
if (objective.startsWith('(legacy'))
|
|
175
|
+
warnings.push('Source did not contain a mission objective; placeholder retained.');
|
|
176
|
+
if (state === 'unknown' && nativeState !== 'unknown')
|
|
177
|
+
warnings.push(`Unknown native state '${nativeState}' preserved beside normalized unknown state.`);
|
|
178
|
+
const sourceArtifacts = artifacts(record);
|
|
179
|
+
if (source === 'uhp-2026-08-11') {
|
|
180
|
+
const ids = new Set(sourceArtifacts.map(artifact => artifact.id));
|
|
181
|
+
for (const artifact of uhpOutputArtifacts(record))
|
|
182
|
+
if (!ids.has(artifact.id))
|
|
183
|
+
sourceArtifacts.push(artifact);
|
|
184
|
+
}
|
|
185
|
+
const budgets = record.budgets && typeof record.budgets === 'object' ? record.budgets : undefined;
|
|
186
|
+
const lineage = Array.isArray(record.lineage) ? record.lineage.flatMap(item => {
|
|
187
|
+
if (!item || typeof item !== 'object')
|
|
188
|
+
return [];
|
|
189
|
+
const entry = item;
|
|
190
|
+
return string(entry.relation) && string(entry.id) ? [{ relation: string(entry.relation), id: string(entry.id) }] : [];
|
|
191
|
+
}) : undefined;
|
|
192
|
+
const value = {
|
|
193
|
+
apiVersion: MISSION_API_VERSION,
|
|
194
|
+
kind: 'Mission',
|
|
195
|
+
metadata: {
|
|
196
|
+
id: requiredId(record),
|
|
197
|
+
...(string(record.createdAt) ?? string(record.created_at) ? { createdAt: string(record.createdAt) ?? string(record.created_at) } : {}),
|
|
198
|
+
...(string(record.updatedAt) ?? string(record.updated_at) ? { updatedAt: string(record.updatedAt) ?? string(record.updated_at) } : {}),
|
|
199
|
+
...(string(record.previous_response_id) ? { previousId: string(record.previous_response_id) } : {}),
|
|
200
|
+
...(lineage?.length ? { lineage } : {}),
|
|
201
|
+
},
|
|
202
|
+
spec: { objective, ...(completionCriterion ? { completionCriterion } : {}), ...(budgets ? { budgets: structuredClone(budgets) } : {}) },
|
|
203
|
+
status: {
|
|
204
|
+
state,
|
|
205
|
+
terminal: TERMINAL.has(state),
|
|
206
|
+
nativeState,
|
|
207
|
+
artifacts: sourceArtifacts,
|
|
208
|
+
...(record.output !== undefined || record.partialOutput !== undefined || record.partial_output !== undefined ? { partialOutput: structuredClone(record.partialOutput ?? record.partial_output ?? record.output) } : {}),
|
|
209
|
+
},
|
|
210
|
+
provenance: { sourceContract: source, sourceVersion: version, ...(source === 'a2a' || source.startsWith('uhp') ? { transport: source.split('-')[0] } : {}), sourceId: requiredId(record) },
|
|
211
|
+
...(Object.keys(preserved).length ? { extensions: { [`aiwg.source.${source}`]: preserved } } : {}),
|
|
212
|
+
};
|
|
213
|
+
return { value, sourceVersion: version, warnings, preservedExtensions: preserved, lossReport };
|
|
214
|
+
}
|
|
215
|
+
function projectionLosses(value, target) {
|
|
216
|
+
const losses = [];
|
|
217
|
+
if (value.status.verification?.length)
|
|
218
|
+
losses.push({ path: '/status/verification', reason: `${target} has no native verification ledger`, severity: 'warning' });
|
|
219
|
+
if (value.metadata.lineage?.length && !['mission-ledger', 'fleet-workload-v1', 'canonical'].includes(target))
|
|
220
|
+
losses.push({ path: '/metadata/lineage', reason: `${target} cannot represent full lineage`, severity: 'required' });
|
|
221
|
+
if (value.spec.budgets && !['fleet-workload-v1', 'canonical'].includes(target))
|
|
222
|
+
losses.push({ path: '/spec/budgets', reason: `${target} cannot represent every canonical budget`, severity: 'warning' });
|
|
223
|
+
return losses;
|
|
224
|
+
}
|
|
225
|
+
export function encodeMission(value, target, options = {}) {
|
|
226
|
+
assertMissionWorkerHandoff(value, target, options.workerConsumer);
|
|
227
|
+
const mission = validateCanonicalMission(value);
|
|
228
|
+
if (target === 'canonical')
|
|
229
|
+
return { value: mission, targetVersion: MISSION_API_VERSION, warnings: [], lossReport: [] };
|
|
230
|
+
const lossReport = projectionLosses(mission, target);
|
|
231
|
+
const required = lossReport.filter(loss => loss.severity === 'required');
|
|
232
|
+
if (required.length && !options.allowLoss)
|
|
233
|
+
throw new Error(`Projection to ${target} would silently lose required semantics: ${required.map(loss => loss.path).join(', ')}.`);
|
|
234
|
+
const base = {
|
|
235
|
+
missionId: mission.metadata.id,
|
|
236
|
+
goal: mission.spec.objective,
|
|
237
|
+
completionCriterion: mission.spec.completionCriterion,
|
|
238
|
+
status: mission.status.nativeState ?? mission.status.state,
|
|
239
|
+
artifacts: structuredClone(mission.status.artifacts),
|
|
240
|
+
partialOutput: structuredClone(mission.status.partialOutput),
|
|
241
|
+
lineage: structuredClone(mission.metadata.lineage ?? []),
|
|
242
|
+
extensions: {
|
|
243
|
+
'aiwg.mission.canonical': { apiVersion: mission.apiVersion, state: mission.status.state, lossReport },
|
|
244
|
+
...(mission.extensions ?? {}),
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
let projected = base;
|
|
248
|
+
if (target === 'mission-plan')
|
|
249
|
+
projected = { missionId: base.missionId, goal: base.goal, completionCriterion: base.completionCriterion ?? '', cycles: [], extensions: base.extensions };
|
|
250
|
+
else if (target === 'mission-ledger')
|
|
251
|
+
projected = { ...base, activityLog: [], cycles: [], totalCost: 0, checkpoint: { completed: [], pending: [], failed: [] }, runtimesUsed: [] };
|
|
252
|
+
else if (target === 'uhp-2026-08-11')
|
|
253
|
+
projected = { id: mission.provenance.sourceId ?? mission.metadata.id, object: 'response', created_at: 0, status: base.status, model: '', output: mission.status.partialOutput ?? [], metadata: base.extensions };
|
|
254
|
+
else if (target === 'a2a')
|
|
255
|
+
projected = { id: mission.provenance.sourceId ?? mission.metadata.id, status: { state: base.status }, artifacts: base.artifacts, partialOutput: base.partialOutput, metadata: base.extensions };
|
|
256
|
+
else if (target === 'graph-flow-v1')
|
|
257
|
+
projected = { schemaVersion: 'graph.flow.aiwg.io/v1', runId: mission.metadata.id, nodeState: mission.status.state, metadata: base.extensions };
|
|
258
|
+
else if (target === 'cockpit')
|
|
259
|
+
projected = { id: mission.metadata.id, session_id: mission.metadata.id, source: mission.provenance.transport ?? mission.provenance.sourceContract, title: mission.spec.objective, completion: mission.spec.completionCriterion, status: mission.status.state, artifacts: base.artifacts, partialOutput: base.partialOutput, extensions: base.extensions };
|
|
260
|
+
else if (target === 'activity-v1')
|
|
261
|
+
projected = { event: 'mission.projected', missionId: mission.metadata.id, objective: mission.spec.objective, state: mission.status.state, metadata: base.extensions };
|
|
262
|
+
else if (target === 'executor-v1')
|
|
263
|
+
projected = { mission_id: mission.metadata.id, objective: mission.spec.objective, completion_criterion: mission.spec.completionCriterion, state: base.status, artifacts: base.artifacts, partial_output: base.partialOutput, metadata: base.extensions };
|
|
264
|
+
else if (target === 'fleet-workload-v1')
|
|
265
|
+
projected = { mission_id: mission.metadata.id, objective: mission.spec.objective, completion_criterion: mission.spec.completionCriterion, observed_state: base.status, budgets: mission.spec.budgets, artifacts: base.artifacts, partial_output: base.partialOutput, lineage: base.lineage, metadata: base.extensions };
|
|
266
|
+
else if (target === 'mission-control-session')
|
|
267
|
+
projected = { id: mission.metadata.id, objective: mission.spec.objective, status: mission.status.state, completion: mission.spec.completionCriterion, artifacts: base.artifacts, partialOutput: base.partialOutput, extensions: base.extensions };
|
|
268
|
+
return { value: projected, targetVersion: target, warnings: lossReport.map(loss => `${loss.path}: ${loss.reason}`), lossReport };
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=canonical-codecs.js.map
|