@aiwg/cli 2026.8.19 → 2026.8.25
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/THIRD_PARTY_NOTICES.md +12 -0
- package/dist/src/api/index.d.ts +2 -0
- package/dist/src/api/index.js +2 -0
- package/dist/src/artifacts/backend-runtime.js +26 -0
- package/dist/src/artifacts/backends/sqlite-backend.js +204 -28
- package/dist/src/artifacts/dep-graph.js +27 -5
- package/dist/src/artifacts/graph-backend.js +2 -2
- package/dist/src/artifacts/graph-query.js +21 -9
- package/dist/src/artifacts/index-builder.js +15 -0
- package/dist/src/artifacts/index-status.js +4 -1
- package/dist/src/artifacts/stats.js +4 -1
- package/dist/src/artifacts/types.js +13 -1
- package/dist/src/cli/handlers/artifact-verify.js +3 -0
- package/dist/src/cli/handlers/help.js +2 -0
- package/dist/src/cli/handlers/index.js +6 -2
- package/dist/src/cli/handlers/mission.js +27 -0
- package/dist/src/cli/handlers/refresh.js +37 -2
- package/dist/src/cli/handlers/runtime-info.js +29 -0
- package/dist/src/cli/handlers/steward.js +12 -0
- package/dist/src/cli/handlers/subcommands.js +26 -20
- package/dist/src/cli/handlers/uhp.js +88 -0
- package/dist/src/cli/handlers/utilities.js +3 -0
- package/dist/src/cli/router.js +27 -0
- package/dist/src/config/aiwg-config.js +10 -0
- package/dist/src/extensions/commands/definitions.js +38 -0
- package/dist/src/installation/manager-command.mjs +10 -1
- package/dist/src/mission-protocol/codecs.js +265 -0
- package/dist/src/mission-protocol/index.js +3 -0
- package/dist/src/mission-protocol/types.js +2 -0
- package/dist/src/storage/backend-contract.js +64 -0
- package/dist/src/storage/index.js +2 -0
- package/dist/src/storage/migration-protocol.js +378 -0
- package/dist/src/uhp/client.js +374 -0
- package/dist/src/uhp/config.js +130 -0
- package/dist/src/uhp/errors.js +63 -0
- package/dist/src/uhp/index.js +7 -0
- package/dist/src/uhp/mission.js +111 -0
- package/dist/src/uhp/sse.js +76 -0
- package/dist/src/uhp/types.js +2 -0
- package/dist/src/update/service.mjs +2 -5
- package/package.json +1 -1
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { UHP_VERSION } from './types.js';
|
|
2
|
+
import { decodeMission } from '../mission-protocol/index.js';
|
|
3
|
+
function collectArtifacts(response) {
|
|
4
|
+
const artifacts = new Map();
|
|
5
|
+
const visit = (value) => {
|
|
6
|
+
if (Array.isArray(value)) {
|
|
7
|
+
value.forEach(visit);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
if (!value || typeof value !== 'object')
|
|
11
|
+
return;
|
|
12
|
+
const object = value;
|
|
13
|
+
if (typeof object.file_id === 'string')
|
|
14
|
+
artifacts.set(object.file_id, {
|
|
15
|
+
fileId: object.file_id,
|
|
16
|
+
...(typeof object.container_id === 'string' ? { containerId: object.container_id } : {}),
|
|
17
|
+
...(typeof object.filename === 'string' ? { filename: object.filename } : {}),
|
|
18
|
+
...(typeof object.media_type === 'string' ? { mediaType: object.media_type } : {}),
|
|
19
|
+
source: structuredClone(object),
|
|
20
|
+
});
|
|
21
|
+
for (const child of Object.values(object))
|
|
22
|
+
visit(child);
|
|
23
|
+
};
|
|
24
|
+
visit(response.output);
|
|
25
|
+
return [...artifacts.values()];
|
|
26
|
+
}
|
|
27
|
+
function collectInputFiles(request) {
|
|
28
|
+
const files = [];
|
|
29
|
+
const visit = (value) => {
|
|
30
|
+
if (Array.isArray(value)) {
|
|
31
|
+
value.forEach(visit);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (!value || typeof value !== 'object')
|
|
35
|
+
return;
|
|
36
|
+
const object = value;
|
|
37
|
+
if (object.type === 'input_file')
|
|
38
|
+
files.push({
|
|
39
|
+
...(typeof object.file_id === 'string' ? { fileId: object.file_id } : {}),
|
|
40
|
+
...(typeof object.filename === 'string' ? { filename: object.filename } : {}),
|
|
41
|
+
...(typeof object.file_data === 'string' && object.file_data.startsWith('data:') ? { mediaType: object.file_data.slice(5).split(/[;,]/, 1)[0] } : {}),
|
|
42
|
+
source: structuredClone(object),
|
|
43
|
+
});
|
|
44
|
+
for (const child of Object.values(object))
|
|
45
|
+
visit(child);
|
|
46
|
+
};
|
|
47
|
+
visit(request.input);
|
|
48
|
+
return files;
|
|
49
|
+
}
|
|
50
|
+
export function projectUhpResponseToMission(profile, response, request = { input: '' }, event) {
|
|
51
|
+
const known = ['in_progress', 'completed', 'failed', 'incomplete', 'cancelled'].includes(response.status);
|
|
52
|
+
const state = response.status === 'in_progress' ? 'running' : known ? response.status : 'unknown';
|
|
53
|
+
const metadata = response.metadata ?? {};
|
|
54
|
+
const artifacts = collectArtifacts(response);
|
|
55
|
+
const knownKeys = new Set(['id', 'object', 'created_at', 'status', 'model', 'previous_response_id', 'output', 'error', 'incomplete_details', 'metadata', 'store', 'usage']);
|
|
56
|
+
return {
|
|
57
|
+
transport: 'uhp',
|
|
58
|
+
protocolVersion: UHP_VERSION,
|
|
59
|
+
endpointProfile: profile,
|
|
60
|
+
state,
|
|
61
|
+
nativeState: response.status,
|
|
62
|
+
observationState: known ? 'authoritative' : 'unknown',
|
|
63
|
+
responseId: response.id,
|
|
64
|
+
previousResponseId: response.previous_response_id ?? request.previous_response_id,
|
|
65
|
+
sessionId: metadata.session_id,
|
|
66
|
+
harness: {
|
|
67
|
+
requested: request.metadata?.harness_id,
|
|
68
|
+
actual: metadata.harness_id,
|
|
69
|
+
substitutionReason: typeof metadata.harness_substitution_reason === 'string' ? metadata.harness_substitution_reason : undefined,
|
|
70
|
+
},
|
|
71
|
+
model: {
|
|
72
|
+
requested: request.model,
|
|
73
|
+
actual: response.model,
|
|
74
|
+
substitutionReason: metadata.model_substitution_reason ?? (typeof metadata.model_fallback_reason === 'string' ? metadata.model_fallback_reason : undefined),
|
|
75
|
+
},
|
|
76
|
+
containerId: metadata.container_id,
|
|
77
|
+
eventSequence: event?.sequence_number,
|
|
78
|
+
terminalEvent: event && /^response\.(?:completed|failed|incomplete|cancelled)$/.test(event.type) ? event.type : undefined,
|
|
79
|
+
artifactIds: artifacts.map(artifact => artifact.fileId),
|
|
80
|
+
inputFiles: collectInputFiles(request),
|
|
81
|
+
artifacts,
|
|
82
|
+
partialOutput: response.status !== 'completed' && Boolean(response.output?.length),
|
|
83
|
+
extensions: Object.fromEntries(Object.entries(response).filter(([key]) => !knownKeys.has(key))),
|
|
84
|
+
...(known ? {} : { diagnostic: `Unknown UHP response state '${String(response.status)}'` }),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
export function unknownUhpMissionEvidence(profile, diagnostic, responseId, lastSequence) {
|
|
88
|
+
return {
|
|
89
|
+
transport: 'uhp', protocolVersion: UHP_VERSION, endpointProfile: profile,
|
|
90
|
+
state: 'unknown', nativeState: 'unknown', observationState: 'unknown', responseId,
|
|
91
|
+
harness: {}, model: {}, eventSequence: lastSequence, artifactIds: [], inputFiles: [], artifacts: [], partialOutput: false,
|
|
92
|
+
extensions: {}, diagnostic,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/** Canonical Mission adapter consumed by UHP; the legacy evidence projection remains a compatibility view. */
|
|
96
|
+
export function projectUhpResponseToCanonicalMission(profile, response, request = { input: '' }, event) {
|
|
97
|
+
const evidence = projectUhpResponseToMission(profile, response, request, event);
|
|
98
|
+
return decodeMission({
|
|
99
|
+
...evidence,
|
|
100
|
+
objective: typeof request.input === 'string' && request.input.length ? request.input : 'UHP task',
|
|
101
|
+
status: evidence.nativeState,
|
|
102
|
+
artifacts: evidence.artifacts.map(artifact => ({
|
|
103
|
+
id: artifact.fileId,
|
|
104
|
+
kind: 'uhp-file',
|
|
105
|
+
...(artifact.mediaType ? { mediaType: artifact.mediaType } : {}),
|
|
106
|
+
...(artifact.source.sha256 ? { sha256: artifact.source.sha256 } : {}),
|
|
107
|
+
extensions: { 'uhp.file': artifact.source },
|
|
108
|
+
})),
|
|
109
|
+
}, 'uhp-2026-08-11');
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=mission.js.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { UhpError, redactUhpText } from './errors.js';
|
|
2
|
+
const TERMINAL_EVENTS = new Set(['response.completed', 'response.failed', 'response.incomplete', 'response.cancelled']);
|
|
3
|
+
export async function* parseUhpEventStream(body, options) {
|
|
4
|
+
const reader = body.getReader();
|
|
5
|
+
const decoder = new TextDecoder();
|
|
6
|
+
let buffer = '';
|
|
7
|
+
let expectedSequence = 0;
|
|
8
|
+
let terminalCount = 0;
|
|
9
|
+
let first = true;
|
|
10
|
+
const read = async () => {
|
|
11
|
+
let timer;
|
|
12
|
+
try {
|
|
13
|
+
return await Promise.race([
|
|
14
|
+
reader.read(),
|
|
15
|
+
new Promise((_, reject) => {
|
|
16
|
+
timer = setTimeout(() => reject(new UhpError('stream_inactivity_timeout', 'UHP stream became inactive; remote task state is unknown', { retryable: true, remoteState: 'unknown' })), options.inactivityTimeoutMs);
|
|
17
|
+
}),
|
|
18
|
+
]);
|
|
19
|
+
}
|
|
20
|
+
finally {
|
|
21
|
+
if (timer)
|
|
22
|
+
clearTimeout(timer);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const decodeBlock = (block) => {
|
|
26
|
+
const data = block.split(/\r?\n/).filter(line => line.startsWith('data:')).map(line => line.slice(5).trimStart()).join('\n');
|
|
27
|
+
if (!data)
|
|
28
|
+
return undefined;
|
|
29
|
+
let event;
|
|
30
|
+
try {
|
|
31
|
+
event = JSON.parse(data);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
throw new UhpError('malformed_sse', redactUhpText('Malformed JSON in UHP event stream', options.secrets), { remoteState: 'unknown' });
|
|
35
|
+
}
|
|
36
|
+
if (!Number.isSafeInteger(event.sequence_number) || event.sequence_number !== expectedSequence) {
|
|
37
|
+
throw new UhpError('event_sequence_gap', `Expected UHP event sequence ${expectedSequence}, received ${String(event.sequence_number)}`, { remoteState: 'unknown' });
|
|
38
|
+
}
|
|
39
|
+
if (first && event.type !== 'response.created')
|
|
40
|
+
throw new UhpError('invalid_first_event', `First UHP event must be response.created, received ${event.type}`, { remoteState: 'unknown' });
|
|
41
|
+
first = false;
|
|
42
|
+
expectedSequence += 1;
|
|
43
|
+
if (TERMINAL_EVENTS.has(event.type))
|
|
44
|
+
terminalCount += 1;
|
|
45
|
+
if (terminalCount > 1)
|
|
46
|
+
throw new UhpError('duplicate_terminal_event', 'UHP stream emitted more than one terminal event', { remoteState: 'unknown' });
|
|
47
|
+
return event;
|
|
48
|
+
};
|
|
49
|
+
try {
|
|
50
|
+
while (true) {
|
|
51
|
+
options.signal?.throwIfAborted();
|
|
52
|
+
const { done, value } = await read();
|
|
53
|
+
buffer += decoder.decode(value, { stream: !done });
|
|
54
|
+
const blocks = buffer.split(/\r?\n\r?\n/);
|
|
55
|
+
buffer = blocks.pop() ?? '';
|
|
56
|
+
for (const block of blocks) {
|
|
57
|
+
const event = decodeBlock(block);
|
|
58
|
+
if (event)
|
|
59
|
+
yield event;
|
|
60
|
+
}
|
|
61
|
+
if (done)
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
if (buffer.trim()) {
|
|
65
|
+
const event = decodeBlock(buffer);
|
|
66
|
+
if (event)
|
|
67
|
+
yield event;
|
|
68
|
+
}
|
|
69
|
+
if (terminalCount !== 1)
|
|
70
|
+
throw new UhpError('missing_terminal_event', 'UHP stream ended without exactly one terminal event; remote task state is unknown', { retryable: true, remoteState: 'unknown' });
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
reader.releaseLock();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=sse.js.map
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
* the calling handlers.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { execFileSync } from 'node:child_process';
|
|
10
9
|
import { existsSync, readFileSync } from 'node:fs';
|
|
11
10
|
import path from 'node:path';
|
|
12
11
|
import { getPackageRoot, loadConfig } from '../channel/manager.mjs';
|
|
@@ -16,7 +15,7 @@ import {
|
|
|
16
15
|
loadInstallationIdentity,
|
|
17
16
|
saveInstallationIdentity,
|
|
18
17
|
} from '../installation/manager.mjs';
|
|
19
|
-
import {
|
|
18
|
+
import { executeManagerCommand } from '../installation/manager-command.mjs';
|
|
20
19
|
|
|
21
20
|
const VALID_MODES = new Set(['npm', 'web', 'source']);
|
|
22
21
|
|
|
@@ -149,9 +148,7 @@ export async function updateInstallation(options = {}) {
|
|
|
149
148
|
throw new Error('Canonical npm installation has no package-manager executable. Run `aiwg installation adopt --manager <absolute-path-to-npm>`.');
|
|
150
149
|
}
|
|
151
150
|
if (!dryRun) {
|
|
152
|
-
|
|
153
|
-
const execute = options.execute ?? ((file, args) => execFileSync(file, args, { stdio: 'inherit' }));
|
|
154
|
-
execute(invocation.file, invocation.args);
|
|
151
|
+
executeManagerCommand(managerExecutable, command, options);
|
|
155
152
|
if (detected.identity && detected.identityPersistent && options.persistIdentity !== false) {
|
|
156
153
|
saveInstallationIdentity({ ...detected.identity, channel }, options);
|
|
157
154
|
}
|