@volter/supercode-interchange 0.1.22 → 0.1.24
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/LICENSE-diffy-MIT +23 -0
- package/README.md +422 -2
- package/channel-records.mjs +71 -0
- package/channel-session-counts.mjs +81 -0
- package/channels-read.mjs +90 -0
- package/corpus-audit-records.mjs +192 -0
- package/corpus-audit-render.mjs +47 -0
- package/corpus-audit-schema.mjs +89 -0
- package/corpus-audit.d.ts +16 -0
- package/corpus-audit.mjs +132 -0
- package/file-io.mjs +21 -2
- package/harness-settings.mjs +19 -0
- package/hermes-fire-links.mjs +135 -0
- package/hermes-fires.mjs +106 -0
- package/hermes-read-home.d.ts +3 -0
- package/hermes-read-home.mjs +235 -0
- package/hermes-read-store.mjs +49 -0
- package/hermes-read-validation.mjs +170 -0
- package/hermes-read-workflow.mjs +164 -0
- package/hermes-read-yaml.mjs +68 -0
- package/hermes-store.mjs +1 -1
- package/homes.mjs +2 -2
- package/index.d.ts +14 -1
- package/index.mjs +1 -1
- package/inspection-builtin-tools.json +261 -0
- package/inspection-config-fields.json +765 -0
- package/inspection-schemas.d.ts +4 -0
- package/inspection-schemas.mjs +117 -0
- package/job-notepad-read.mjs +97 -0
- package/jobs-control.mjs +250 -0
- package/jobs-read.mjs +198 -0
- package/jsonl.mjs +4 -3
- package/memory-show.mjs +187 -0
- package/metadata.mjs +45 -3
- package/native-json.mjs +46 -3
- package/ontology-contracts.d.ts +5 -0
- package/ontology-contracts.mjs +29 -0
- package/ontology-operations.json +198 -0
- package/ontology-schemas.json +7946 -0
- package/openclaw-jobs-read.mjs +117 -0
- package/openclaw-profile-home.mjs +142 -0
- package/orchestrator-read-records.mjs +112 -0
- package/orchestrator-store.mjs +21 -9
- package/package.json +59 -4
- package/parity-ledger.json +6984 -0
- package/parity-orchestration.json +5538 -0
- package/parity-report.d.ts +7 -0
- package/parity-report.mjs +46 -0
- package/preset-profiles.mjs +27 -0
- package/profile-command.mjs +32 -0
- package/profile-orchestrator-door.mjs +104 -0
- package/profile-paths.mjs +25 -0
- package/profiles-control.mjs +98 -0
- package/profiles-read.mjs +119 -0
- package/reduction-attribution.mjs +54 -0
- package/reduction-diff.mjs +165 -0
- package/reduction-log.mjs +177 -0
- package/reduction-view.mjs +145 -0
- package/retained-projection.mjs +9 -0
- package/routes-read.mjs +103 -0
- package/runs-read.mjs +224 -0
- package/session-activity.d.ts +23 -0
- package/session-activity.mjs +124 -0
- package/session-append-scan.mjs +27 -17
- package/session-branch-handoff.mjs +115 -0
- package/session-claude-graph.mjs +29 -7
- package/session-claude-index.mjs +732 -114
- package/session-claude-runtime.d.ts +28 -0
- package/session-claude-runtime.mjs +171 -6
- package/session-claude-scan-store.mjs +164 -0
- package/session-claude.mjs +9 -0
- package/session-codex-activity.d.ts +6 -0
- package/session-codex-activity.mjs +120 -0
- package/session-codex-window.mjs +24 -4
- package/session-config-scan.mjs +141 -0
- package/session-convert.d.ts +33 -0
- package/session-convert.mjs +179 -0
- package/session-emission-version.json +1 -0
- package/session-file.mjs +11 -1
- package/session-follower.mjs +17 -5
- package/session-fresh-id.mjs +15 -0
- package/session-hermes-import.mjs +61 -0
- package/session-hermes.mjs +1 -1
- package/session-import.mjs +37 -0
- package/session-inspect.d.ts +18 -0
- package/session-inspect.mjs +122 -0
- package/session-machine-tree.d.ts +33 -0
- package/session-machine-tree.mjs +274 -0
- package/session-materialize-files.mjs +78 -0
- package/session-materialize-opencode.mjs +137 -0
- package/session-materialize.mjs +186 -0
- package/session-message.mjs +85 -0
- package/session-model.d.ts +9 -0
- package/session-model.mjs +1 -0
- package/session-opencode-store.mjs +39 -3
- package/session-path.mjs +6 -3
- package/session-pi-content.mjs +7 -2
- package/session-read.d.ts +134 -2
- package/session-read.mjs +86 -9
- package/session-recorded-config.mjs +3 -2
- package/session-records.mjs +12 -6
- package/session-residue-store.mjs +90 -0
- package/session-residue.mjs +150 -0
- package/session-resume-instructions.mjs +1 -1
- package/session-saved-read.mjs +105 -0
- package/session-transfer.mjs +141 -0
- package/session-views.mjs +1 -0
- package/session-write-claude.mjs +135 -0
- package/session-write-codex.mjs +146 -0
- package/session-write-gemini.mjs +77 -0
- package/session-write-goose.mjs +99 -0
- package/session-write-grok.mjs +70 -0
- package/session-write-native.mjs +41 -0
- package/session-write-opencode.mjs +197 -0
- package/session-write-pi.mjs +130 -0
- package/session-write-residue.mjs +19 -0
- package/session-write-utils.mjs +77 -0
- package/session-write.d.ts +10 -0
- package/session-write.mjs +37 -0
- package/skill-toml.mjs +80 -0
- package/skills-control.mjs +193 -0
- package/skills-list.mjs +237 -0
- package/source-files.mjs +12 -2
- package/sqlite-reader.mjs +134 -18
- package/support-registry.json +402 -0
- package/support-report.mjs +69 -0
- package/trigger-records.mjs +77 -0
- package/triggers-read.mjs +67 -0
- package/workflow-read.mjs +165 -0
package/sqlite-reader.mjs
CHANGED
|
@@ -1,49 +1,165 @@
|
|
|
1
1
|
import { DatabaseSync } from 'node:sqlite';
|
|
2
|
-
import {
|
|
2
|
+
import { mkdtemp, open, realpath, rm } from 'node:fs/promises';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join, resolve } from 'node:path';
|
|
5
|
+
import { fileFingerprint, sameFingerprint, withSessionFile } from './file-io.mjs';
|
|
3
6
|
import { sourceStat } from './store-registry.mjs';
|
|
4
7
|
import { verifySources } from './source-files.mjs';
|
|
5
8
|
import { parseNativeJson } from './native-json.mjs';
|
|
9
|
+
import { SESSION_UNREADABLE } from './session-file.mjs';
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
const SNAPSHOT_ROW_BYTES = 256 * 1024 * 1024;
|
|
12
|
+
const snapshots = new WeakMap();
|
|
13
|
+
function chargeRow(snapshot, row) {
|
|
14
|
+
if (row == null) return row;
|
|
15
|
+
let bytes = 64;
|
|
16
|
+
for (const [name, value] of Object.entries(row)) {
|
|
17
|
+
bytes += 32 + name.length * 2;
|
|
18
|
+
if (typeof value === 'string') bytes += value.length * 2;
|
|
19
|
+
else if (ArrayBuffer.isView(value)) bytes += value.byteLength;
|
|
20
|
+
else if (value instanceof ArrayBuffer) bytes += value.byteLength;
|
|
21
|
+
else bytes += 8;
|
|
22
|
+
}
|
|
23
|
+
if (bytes > SNAPSHOT_ROW_BYTES - snapshot.bytes) throw Object.assign(new Error(`${snapshot.path} exceeds the foreign-store snapshot row budget (${SNAPSHOT_ROW_BYTES} charged bytes); no partial session is returned`), { code: 'EFBIG', rpcCode: SESSION_UNREADABLE });
|
|
24
|
+
snapshot.bytes += bytes;
|
|
25
|
+
return row;
|
|
26
|
+
}
|
|
27
|
+
function admittedStatement(prepared, snapshot) {
|
|
28
|
+
const iterate = function* (...args) { for (const row of prepared.iterate(...args)) yield chargeRow(snapshot, row); };
|
|
29
|
+
return new Proxy(prepared, { get(target, name) {
|
|
30
|
+
if (name === 'iterate') return iterate;
|
|
31
|
+
if (name === 'all') return (...args) => Array.from(iterate(...args));
|
|
32
|
+
if (name === 'get') return (...args) => chargeRow(snapshot, target.get(...args));
|
|
33
|
+
const value = Reflect.get(target, name, target);
|
|
34
|
+
return typeof value === 'function' ? value.bind(target) : value;
|
|
35
|
+
} });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const missing = (error) => error.code === 'ENOENT' || error.code === 'ENOTDIR';
|
|
39
|
+
const changed = (path) => Object.assign(new Error(`${path} changed during its foreign-store snapshot; previous index rows are retained`), { code: 'ESTALE' });
|
|
40
|
+
|
|
41
|
+
/** Native aliases follow their database target, including its adjacent WAL
|
|
42
|
+
* and rollback journal. SHM is coordination, not transcript source content. */
|
|
43
|
+
async function storeSources(path) {
|
|
44
|
+
let target;
|
|
45
|
+
try { target = await realpath(path); }
|
|
46
|
+
catch (error) { if (!missing(error)) throw error; target = resolve(path); }
|
|
10
47
|
const sources = [];
|
|
11
|
-
for (const file of [path, `${
|
|
48
|
+
for (const file of [path, `${target}-wal`, `${target}-journal`]) {
|
|
12
49
|
const info = await sourceStat(file);
|
|
50
|
+
if (info && !info.isFile()) throw Object.assign(new Error(`${file} is not a regular foreign-store file`), { code: 'EINVAL' });
|
|
13
51
|
sources.push(info ? { path: file, fingerprint: fileFingerprint(info) } : { path: file, missing: true });
|
|
14
52
|
}
|
|
15
|
-
return sources;
|
|
53
|
+
return { target, sources };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function storeFingerprints(path) {
|
|
57
|
+
return (await storeSources(path)).sources;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function verifyStoreSources(path, target, sources) {
|
|
61
|
+
await verifySources(sources);
|
|
62
|
+
let current;
|
|
63
|
+
try { current = await realpath(path); } catch (error) { if (!missing(error)) throw error; }
|
|
64
|
+
if (current !== target) throw changed(path);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function copySource(source, destination, metrics, snapshot) {
|
|
68
|
+
await withSessionFile(source.path, async (reader) => {
|
|
69
|
+
if (!sameFingerprint(source.fingerprint, reader.fingerprint)) throw changed(source.path);
|
|
70
|
+
const output = await open(destination, 'wx', 0o600);
|
|
71
|
+
snapshot.outputs.add(output);
|
|
72
|
+
let copyError;
|
|
73
|
+
try {
|
|
74
|
+
for (let offset = 0; offset < reader.size; offset += 64 * 1024)
|
|
75
|
+
await output.writeFile(await reader.read(offset, Math.min(64 * 1024, reader.size - offset)));
|
|
76
|
+
} catch (error) { copyError = error; throw error; }
|
|
77
|
+
finally {
|
|
78
|
+
try { await output.close(); snapshot.outputs.delete(output); }
|
|
79
|
+
catch (error) {
|
|
80
|
+
if (copyError) throw new AggregateError([copyError, error], `${source.path} snapshot copy and close failed`);
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}, metrics);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// A failed close/removal keeps its exact owner and private path. A later read
|
|
88
|
+
// settles retained cleanup before admitting another snapshot, rather than
|
|
89
|
+
// forgetting a connection or treating uncertain cleanup as successful.
|
|
90
|
+
const retainedCleanup = new Map();
|
|
91
|
+
let cleanupDrain;
|
|
92
|
+
async function cleanupSnapshot(snapshot) {
|
|
93
|
+
for (const output of snapshot.outputs) {
|
|
94
|
+
if (output.fd !== -1) await output.close();
|
|
95
|
+
snapshot.outputs.delete(output);
|
|
96
|
+
}
|
|
97
|
+
if (snapshot.db) {
|
|
98
|
+
if (snapshot.db.isOpen !== false) snapshot.db.close();
|
|
99
|
+
snapshots.delete(snapshot.db);
|
|
100
|
+
snapshot.db = null;
|
|
101
|
+
}
|
|
102
|
+
await rm(snapshot.directory, { recursive: true, force: true });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function settleCleanup() {
|
|
106
|
+
if (!retainedCleanup.size) return;
|
|
107
|
+
cleanupDrain ??= (async () => {
|
|
108
|
+
for (const [directory, snapshot] of retainedCleanup) {
|
|
109
|
+
try { await cleanupSnapshot(snapshot); retainedCleanup.delete(directory); }
|
|
110
|
+
catch (error) { throw Object.assign(new Error(`foreign-store snapshot cleanup remains incomplete at ${directory}`, { cause: error }), { code: 'FOREIGN_STORE_CLEANUP' }); }
|
|
111
|
+
}
|
|
112
|
+
})().finally(() => { cleanupDrain = null; });
|
|
113
|
+
await cleanupDrain;
|
|
16
114
|
}
|
|
17
115
|
|
|
18
|
-
/**
|
|
19
|
-
*
|
|
116
|
+
/** SQLite opens only owned private copies, never a mutable foreign pathname.
|
|
117
|
+
* Source descriptors use nonblocking admission and exact initial/final stamps;
|
|
118
|
+
* copies stream in 64 KiB ranges. A changed DB/WAL/journal refuses the whole
|
|
119
|
+
* unit. Private SHM/locks belong to this snapshot, with no foreign writes.
|
|
20
120
|
* No foreign writer, journal-mode setter or extension loading is permitted. */
|
|
21
121
|
export async function readStore(path, work, metrics = {}) {
|
|
22
|
-
|
|
122
|
+
await settleCleanup();
|
|
123
|
+
const { target, sources } = await storeSources(path);
|
|
23
124
|
if (sources[0].missing) throw Object.assign(new Error(`${path} is not present`), { code: 'ENOENT' });
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
let result;
|
|
125
|
+
const snapshot = { directory: await mkdtemp(join(tmpdir(), 'supercode-store-')), db: null, outputs: new Set() };
|
|
126
|
+
let readError;
|
|
27
127
|
try {
|
|
128
|
+
const privatePath = join(snapshot.directory, 'source.db');
|
|
129
|
+
for (const [index, suffix] of ['', '-wal', '-journal'].entries())
|
|
130
|
+
if (!sources[index].missing) await copySource(sources[index], `${privatePath}${suffix}`, metrics, snapshot);
|
|
131
|
+
await verifyStoreSources(path, target, sources);
|
|
132
|
+
const db = snapshot.db = new DatabaseSync(privatePath, { readOnly: true, allowExtension: false });
|
|
133
|
+
snapshots.set(db, { path, bytes: 0 });
|
|
134
|
+
metrics.stores_read = (metrics.stores_read ?? 0) + 1;
|
|
28
135
|
db.exec('PRAGMA busy_timeout=0; BEGIN');
|
|
29
|
-
result = work(db);
|
|
136
|
+
const result = work(db);
|
|
30
137
|
if (result != null && typeof result.then === 'function') throw new Error('a foreign-store snapshot must be synchronous');
|
|
31
138
|
db.exec('COMMIT');
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
139
|
+
await verifyStoreSources(path, target, sources);
|
|
140
|
+
return { result, sources };
|
|
141
|
+
} catch (error) { readError = error; throw error; }
|
|
142
|
+
finally {
|
|
143
|
+
try { await cleanupSnapshot(snapshot); }
|
|
144
|
+
catch (error) {
|
|
145
|
+
retainedCleanup.set(snapshot.directory, snapshot);
|
|
146
|
+
const failures = readError ? [readError, error] : [error];
|
|
147
|
+
throw Object.assign(new AggregateError(failures, `foreign-store snapshot cleanup incomplete at ${snapshot.directory}`), { code: 'FOREIGN_STORE_CLEANUP' });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
35
150
|
}
|
|
36
151
|
|
|
37
152
|
export function statement(db, sql) {
|
|
38
153
|
const prepared = db.prepare(sql);
|
|
39
154
|
prepared.setReadBigInts(true);
|
|
40
|
-
|
|
155
|
+
const snapshot = snapshots.get(db);
|
|
156
|
+
return snapshot ? admittedStatement(prepared, snapshot) : prepared;
|
|
41
157
|
}
|
|
42
158
|
|
|
43
159
|
export function tableColumns(db, table) {
|
|
44
160
|
// Callers provide only these fixed native schema identifiers.
|
|
45
161
|
if (!['session', 'sessions', 'messages'].includes(table)) throw new Error('unknown catalog schema table');
|
|
46
|
-
return new Set(db
|
|
162
|
+
return new Set(statement(db, `PRAGMA table_info(${table})`).all().map((row) => row.name));
|
|
47
163
|
}
|
|
48
164
|
|
|
49
165
|
export function text(value, nullable = false) {
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "supercode.support-registry.v1",
|
|
3
|
+
"harnesses": [
|
|
4
|
+
{
|
|
5
|
+
"id": "claude-code",
|
|
6
|
+
"display_name": "Claude Code",
|
|
7
|
+
"native": {
|
|
8
|
+
"discover": "built_in",
|
|
9
|
+
"load": "built_in",
|
|
10
|
+
"follow": "built_in",
|
|
11
|
+
"import": "built_in",
|
|
12
|
+
"export": "built_in"
|
|
13
|
+
},
|
|
14
|
+
"runtime": {
|
|
15
|
+
"implementation": "built_in",
|
|
16
|
+
"protocol": "claude-stream-json",
|
|
17
|
+
"default_launch": {
|
|
18
|
+
"program": "claude",
|
|
19
|
+
"arguments": [
|
|
20
|
+
"--print",
|
|
21
|
+
"--input-format",
|
|
22
|
+
"stream-json",
|
|
23
|
+
"--output-format",
|
|
24
|
+
"stream-json",
|
|
25
|
+
"--verbose",
|
|
26
|
+
"--permission-prompt-tool",
|
|
27
|
+
"stdio"
|
|
28
|
+
],
|
|
29
|
+
"env": {}
|
|
30
|
+
},
|
|
31
|
+
"capabilities": {
|
|
32
|
+
"start_session": true,
|
|
33
|
+
"resume_session": true,
|
|
34
|
+
"attach_existing_process": false,
|
|
35
|
+
"send_input": true,
|
|
36
|
+
"stream_events": true,
|
|
37
|
+
"interrupt": true,
|
|
38
|
+
"steer": true,
|
|
39
|
+
"respond_to_requests": true
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": "codex",
|
|
45
|
+
"display_name": "Codex",
|
|
46
|
+
"native": {
|
|
47
|
+
"discover": "built_in",
|
|
48
|
+
"load": "built_in",
|
|
49
|
+
"follow": "built_in",
|
|
50
|
+
"import": "built_in",
|
|
51
|
+
"export": "built_in"
|
|
52
|
+
},
|
|
53
|
+
"runtime": {
|
|
54
|
+
"implementation": "built_in",
|
|
55
|
+
"protocol": "codex-app-server-jsonl",
|
|
56
|
+
"default_launch": {
|
|
57
|
+
"program": "codex",
|
|
58
|
+
"arguments": [
|
|
59
|
+
"app-server"
|
|
60
|
+
],
|
|
61
|
+
"env": {}
|
|
62
|
+
},
|
|
63
|
+
"capabilities": {
|
|
64
|
+
"start_session": true,
|
|
65
|
+
"resume_session": true,
|
|
66
|
+
"attach_existing_process": false,
|
|
67
|
+
"send_input": true,
|
|
68
|
+
"stream_events": true,
|
|
69
|
+
"interrupt": true,
|
|
70
|
+
"steer": true,
|
|
71
|
+
"respond_to_requests": true
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": "opencode",
|
|
77
|
+
"display_name": "OpenCode",
|
|
78
|
+
"native": {
|
|
79
|
+
"discover": "built_in",
|
|
80
|
+
"load": "built_in",
|
|
81
|
+
"follow": "built_in",
|
|
82
|
+
"import": "built_in",
|
|
83
|
+
"export": "built_in"
|
|
84
|
+
},
|
|
85
|
+
"runtime": {
|
|
86
|
+
"implementation": "built_in",
|
|
87
|
+
"protocol": "opencode-http-sse",
|
|
88
|
+
"default_launch": {
|
|
89
|
+
"program": "opencode",
|
|
90
|
+
"arguments": [
|
|
91
|
+
"serve"
|
|
92
|
+
],
|
|
93
|
+
"env": {}
|
|
94
|
+
},
|
|
95
|
+
"capabilities": {
|
|
96
|
+
"start_session": true,
|
|
97
|
+
"resume_session": true,
|
|
98
|
+
"attach_existing_process": false,
|
|
99
|
+
"send_input": true,
|
|
100
|
+
"stream_events": true,
|
|
101
|
+
"interrupt": true,
|
|
102
|
+
"steer": false,
|
|
103
|
+
"respond_to_requests": true
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"id": "pi",
|
|
109
|
+
"display_name": "Pi",
|
|
110
|
+
"native": {
|
|
111
|
+
"discover": "built_in",
|
|
112
|
+
"load": "built_in",
|
|
113
|
+
"follow": "built_in",
|
|
114
|
+
"import": "built_in",
|
|
115
|
+
"export": "built_in"
|
|
116
|
+
},
|
|
117
|
+
"runtime": {
|
|
118
|
+
"implementation": "built_in",
|
|
119
|
+
"protocol": "pi-rpc-jsonl",
|
|
120
|
+
"default_launch": {
|
|
121
|
+
"program": "pi",
|
|
122
|
+
"arguments": [
|
|
123
|
+
"--mode",
|
|
124
|
+
"rpc"
|
|
125
|
+
],
|
|
126
|
+
"env": {}
|
|
127
|
+
},
|
|
128
|
+
"capabilities": {
|
|
129
|
+
"start_session": true,
|
|
130
|
+
"resume_session": true,
|
|
131
|
+
"attach_existing_process": false,
|
|
132
|
+
"send_input": true,
|
|
133
|
+
"stream_events": true,
|
|
134
|
+
"interrupt": true,
|
|
135
|
+
"steer": false,
|
|
136
|
+
"respond_to_requests": true
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"id": "runhuman",
|
|
142
|
+
"display_name": "Runhuman",
|
|
143
|
+
"native": {
|
|
144
|
+
"discover": "absent",
|
|
145
|
+
"load": "absent",
|
|
146
|
+
"follow": "absent",
|
|
147
|
+
"import": "absent",
|
|
148
|
+
"export": "absent"
|
|
149
|
+
},
|
|
150
|
+
"runtime": {
|
|
151
|
+
"implementation": "built_in",
|
|
152
|
+
"protocol": "rhh-rpc-jsonl",
|
|
153
|
+
"default_launch": {
|
|
154
|
+
"program": "rhh",
|
|
155
|
+
"arguments": [
|
|
156
|
+
"--mode",
|
|
157
|
+
"rpc"
|
|
158
|
+
],
|
|
159
|
+
"env": {}
|
|
160
|
+
},
|
|
161
|
+
"capabilities": {
|
|
162
|
+
"start_session": true,
|
|
163
|
+
"resume_session": true,
|
|
164
|
+
"attach_existing_process": false,
|
|
165
|
+
"send_input": true,
|
|
166
|
+
"stream_events": true,
|
|
167
|
+
"interrupt": true,
|
|
168
|
+
"steer": false,
|
|
169
|
+
"respond_to_requests": true
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"id": "grok",
|
|
175
|
+
"display_name": "Grok",
|
|
176
|
+
"native": {
|
|
177
|
+
"discover": "built_in",
|
|
178
|
+
"load": "built_in",
|
|
179
|
+
"follow": "built_in",
|
|
180
|
+
"import": "built_in",
|
|
181
|
+
"export": "built_in"
|
|
182
|
+
},
|
|
183
|
+
"runtime": {
|
|
184
|
+
"implementation": "generic_protocol",
|
|
185
|
+
"protocol": "acp-v1-jsonrpc",
|
|
186
|
+
"default_launch": {
|
|
187
|
+
"program": "grok",
|
|
188
|
+
"arguments": [
|
|
189
|
+
"--sandbox",
|
|
190
|
+
"workspace",
|
|
191
|
+
"agent",
|
|
192
|
+
"--no-leader",
|
|
193
|
+
"stdio"
|
|
194
|
+
],
|
|
195
|
+
"env": {}
|
|
196
|
+
},
|
|
197
|
+
"capabilities": {
|
|
198
|
+
"start_session": true,
|
|
199
|
+
"resume_session": true,
|
|
200
|
+
"attach_existing_process": false,
|
|
201
|
+
"send_input": true,
|
|
202
|
+
"stream_events": true,
|
|
203
|
+
"interrupt": true,
|
|
204
|
+
"steer": false,
|
|
205
|
+
"respond_to_requests": true
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"id": "gemini",
|
|
211
|
+
"display_name": "Gemini CLI",
|
|
212
|
+
"native": {
|
|
213
|
+
"discover": "built_in",
|
|
214
|
+
"load": "built_in",
|
|
215
|
+
"follow": "built_in",
|
|
216
|
+
"import": "built_in",
|
|
217
|
+
"export": "built_in"
|
|
218
|
+
},
|
|
219
|
+
"runtime": {
|
|
220
|
+
"implementation": "generic_protocol",
|
|
221
|
+
"protocol": "acp-v1-jsonrpc",
|
|
222
|
+
"default_launch": {
|
|
223
|
+
"program": "gemini",
|
|
224
|
+
"arguments": [
|
|
225
|
+
"--experimental-acp"
|
|
226
|
+
],
|
|
227
|
+
"env": {}
|
|
228
|
+
},
|
|
229
|
+
"capabilities": {
|
|
230
|
+
"start_session": true,
|
|
231
|
+
"resume_session": true,
|
|
232
|
+
"attach_existing_process": false,
|
|
233
|
+
"send_input": true,
|
|
234
|
+
"stream_events": true,
|
|
235
|
+
"interrupt": true,
|
|
236
|
+
"steer": false,
|
|
237
|
+
"respond_to_requests": true
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"id": "goose",
|
|
243
|
+
"display_name": "Goose",
|
|
244
|
+
"native": {
|
|
245
|
+
"discover": "built_in",
|
|
246
|
+
"load": "built_in",
|
|
247
|
+
"follow": "built_in",
|
|
248
|
+
"import": "built_in",
|
|
249
|
+
"export": "built_in"
|
|
250
|
+
},
|
|
251
|
+
"runtime": {
|
|
252
|
+
"implementation": "generic_protocol",
|
|
253
|
+
"protocol": "acp-v1-jsonrpc",
|
|
254
|
+
"default_launch": {
|
|
255
|
+
"program": "goose",
|
|
256
|
+
"arguments": [
|
|
257
|
+
"acp"
|
|
258
|
+
],
|
|
259
|
+
"env": {}
|
|
260
|
+
},
|
|
261
|
+
"capabilities": {
|
|
262
|
+
"start_session": true,
|
|
263
|
+
"resume_session": true,
|
|
264
|
+
"attach_existing_process": false,
|
|
265
|
+
"send_input": true,
|
|
266
|
+
"stream_events": true,
|
|
267
|
+
"interrupt": true,
|
|
268
|
+
"steer": false,
|
|
269
|
+
"respond_to_requests": true
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
"id": "hermes",
|
|
275
|
+
"display_name": "Hermes Agent",
|
|
276
|
+
"native": {
|
|
277
|
+
"discover": "built_in",
|
|
278
|
+
"load": "built_in",
|
|
279
|
+
"follow": "absent",
|
|
280
|
+
"import": "absent",
|
|
281
|
+
"export": "generic_protocol"
|
|
282
|
+
},
|
|
283
|
+
"runtime": {
|
|
284
|
+
"implementation": "generic_protocol",
|
|
285
|
+
"protocol": "acp-v1-jsonrpc",
|
|
286
|
+
"default_launch": {
|
|
287
|
+
"program": "hermes-acp",
|
|
288
|
+
"arguments": [],
|
|
289
|
+
"env": {}
|
|
290
|
+
},
|
|
291
|
+
"capabilities": {
|
|
292
|
+
"start_session": true,
|
|
293
|
+
"resume_session": true,
|
|
294
|
+
"attach_existing_process": false,
|
|
295
|
+
"send_input": true,
|
|
296
|
+
"stream_events": true,
|
|
297
|
+
"interrupt": true,
|
|
298
|
+
"steer": false,
|
|
299
|
+
"respond_to_requests": true
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
"id": "openclaw",
|
|
305
|
+
"display_name": "OpenClaw",
|
|
306
|
+
"native": {
|
|
307
|
+
"discover": "built_in",
|
|
308
|
+
"load": "built_in",
|
|
309
|
+
"follow": "absent",
|
|
310
|
+
"import": "absent",
|
|
311
|
+
"export": "absent"
|
|
312
|
+
},
|
|
313
|
+
"runtime": {
|
|
314
|
+
"implementation": "generic_protocol",
|
|
315
|
+
"protocol": "acp-v1-jsonrpc",
|
|
316
|
+
"default_launch": {
|
|
317
|
+
"program": "openclaw",
|
|
318
|
+
"arguments": [
|
|
319
|
+
"acp"
|
|
320
|
+
],
|
|
321
|
+
"env": {}
|
|
322
|
+
},
|
|
323
|
+
"connect_launch": {
|
|
324
|
+
"config_path": "~/.openclaw/openclaw.json",
|
|
325
|
+
"address_pointer": "/gateway/remote/url",
|
|
326
|
+
"port_pointer": "/gateway/port",
|
|
327
|
+
"default_address": "ws://127.0.0.1:18789",
|
|
328
|
+
"auth_pointer": "/gateway/auth/token",
|
|
329
|
+
"protocol": "acp-v1-jsonrpc"
|
|
330
|
+
},
|
|
331
|
+
"capabilities": {
|
|
332
|
+
"start_session": true,
|
|
333
|
+
"resume_session": true,
|
|
334
|
+
"attach_existing_process": false,
|
|
335
|
+
"send_input": true,
|
|
336
|
+
"stream_events": true,
|
|
337
|
+
"interrupt": true,
|
|
338
|
+
"steer": false,
|
|
339
|
+
"respond_to_requests": true
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
"id": "orchestrator",
|
|
345
|
+
"display_name": "Orchestrator",
|
|
346
|
+
"native": {
|
|
347
|
+
"discover": "absent",
|
|
348
|
+
"load": "absent",
|
|
349
|
+
"follow": "absent",
|
|
350
|
+
"import": "absent",
|
|
351
|
+
"export": "absent"
|
|
352
|
+
},
|
|
353
|
+
"runtime": {
|
|
354
|
+
"implementation": "absent",
|
|
355
|
+
"protocol": "none",
|
|
356
|
+
"default_launch": null,
|
|
357
|
+
"capabilities": {
|
|
358
|
+
"start_session": false,
|
|
359
|
+
"resume_session": false,
|
|
360
|
+
"attach_existing_process": false,
|
|
361
|
+
"send_input": false,
|
|
362
|
+
"stream_events": false,
|
|
363
|
+
"interrupt": false,
|
|
364
|
+
"steer": false,
|
|
365
|
+
"respond_to_requests": false
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
"id": "supercode",
|
|
371
|
+
"display_name": "Volter Harness",
|
|
372
|
+
"native": {
|
|
373
|
+
"discover": "built_in",
|
|
374
|
+
"load": "built_in",
|
|
375
|
+
"follow": "built_in",
|
|
376
|
+
"import": "built_in",
|
|
377
|
+
"export": "built_in"
|
|
378
|
+
},
|
|
379
|
+
"runtime": {
|
|
380
|
+
"implementation": "generic_protocol",
|
|
381
|
+
"protocol": "acp-v1-jsonrpc",
|
|
382
|
+
"default_launch": {
|
|
383
|
+
"program": "supercode",
|
|
384
|
+
"arguments": [
|
|
385
|
+
"acp"
|
|
386
|
+
],
|
|
387
|
+
"env": {}
|
|
388
|
+
},
|
|
389
|
+
"capabilities": {
|
|
390
|
+
"start_session": true,
|
|
391
|
+
"resume_session": true,
|
|
392
|
+
"attach_existing_process": false,
|
|
393
|
+
"send_input": true,
|
|
394
|
+
"stream_events": true,
|
|
395
|
+
"interrupt": true,
|
|
396
|
+
"steer": false,
|
|
397
|
+
"respond_to_requests": true
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
]
|
|
402
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Implementation facts, not a verdict that a vendor works or is installed.
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { isAbsolute, toNamespacedPath } from 'node:path';
|
|
4
|
+
import { grokHomeEnvironment } from './session-resume-instructions.mjs';
|
|
5
|
+
|
|
6
|
+
const table = JSON.parse(readFileSync(new URL('./support-registry.json', import.meta.url), 'utf8'));
|
|
7
|
+
const concepts = ['scheduled_job', 'run', 'conversation', 'pending_request', 'profile', 'skills', 'memory', 'delivery_target', 'channel', 'routing', 'inbound_trigger', 'gateway_health'];
|
|
8
|
+
const gateways = ['hermes', 'openclaw', 'orchestrator'];
|
|
9
|
+
const lifecycle = { codex: ['archive', 'delete'], opencode: ['archive', 'delete'], hermes: ['reset', 'delete'], openclaw: ['new', 'reset'], orchestrator: ['new', 'reset'], supercode: ['archive', 'delete'] };
|
|
10
|
+
const methods = (noun, verbs) => verbs.map(verb => `harness.v1.${noun}.${verb}`);
|
|
11
|
+
|
|
12
|
+
export function supportOrchestration(descriptor) {
|
|
13
|
+
const id = descriptor.id, gateway = gateways.includes(id), jobs = gateway || id === 'claude-code';
|
|
14
|
+
return { concepts: concepts.map(concept => {
|
|
15
|
+
let observed = 'absent', controlled = 'absent', backing = [];
|
|
16
|
+
const read = list => { observed = 'built_in'; backing = list; };
|
|
17
|
+
const control = list => { read(list); controlled = 'built_in'; };
|
|
18
|
+
switch (concept) {
|
|
19
|
+
case 'scheduled_job':
|
|
20
|
+
if (gateway) control(methods('jobs', ['list', 'get', 'create', 'update', 'pause', 'resume', 'run', 'delete']));
|
|
21
|
+
else if (jobs) read(methods('jobs', ['list', 'get']));
|
|
22
|
+
break;
|
|
23
|
+
case 'run': if (gateway) read(methods('runs', ['list', 'get'])); break;
|
|
24
|
+
case 'conversation':
|
|
25
|
+
if (descriptor.native.load === 'built_in') {
|
|
26
|
+
const verbs = lifecycle[id] ?? [];
|
|
27
|
+
read(methods('sessions', ['discover', 'load', ...verbs]));
|
|
28
|
+
if (verbs.length) controlled = 'built_in';
|
|
29
|
+
} else if (id === 'orchestrator') control(methods('sessions', ['discover', ...lifecycle[id]]));
|
|
30
|
+
break;
|
|
31
|
+
case 'pending_request': if (descriptor.runtime.capabilities.respond_to_requests) control(['harness.v1.approvals.list', 'harness.v1.approvals.resolve', 'harness.v1.runtimes.respond']); break;
|
|
32
|
+
case 'profile':
|
|
33
|
+
if (gateway) control(methods('profiles', ['list', 'get', 'create', 'delete']));
|
|
34
|
+
else if (['codex', 'supercode'].includes(id)) read(methods('profiles', ['list', 'get']));
|
|
35
|
+
break;
|
|
36
|
+
case 'skills': if (['claude-code', 'codex', 'opencode', 'pi', 'hermes', 'openclaw'].includes(id)) control(methods('skills', ['list', 'install', 'remove'])); break;
|
|
37
|
+
case 'memory': if (['claude-code', 'hermes', 'openclaw'].includes(id)) read(methods('memory', ['show', 'search'])); break;
|
|
38
|
+
case 'delivery_target': if (jobs) read([...methods('jobs', ['list', 'get']), ...(gateway ? methods('runs', ['list', 'get']) : [])]); break;
|
|
39
|
+
case 'channel': if (gateway) read(methods('channels', ['list', 'status'])); break;
|
|
40
|
+
case 'routing': if (gateway) read(methods('routes', ['list'])); break;
|
|
41
|
+
case 'inbound_trigger': if (gateway) read(methods('triggers', ['list'])); break;
|
|
42
|
+
case 'gateway_health': if (gateway) read(['harness.v1.harnesses.list']); break;
|
|
43
|
+
}
|
|
44
|
+
return { concept, observed, controlled, ...(backing.length ? { methods: backing } : {}) };
|
|
45
|
+
}) };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function supportRegistryReport({ env = process.env, cwd = process.cwd() } = {}) {
|
|
49
|
+
const report = structuredClone(table);
|
|
50
|
+
for (const descriptor of report.harnesses) {
|
|
51
|
+
if (descriptor.id === 'codex') {
|
|
52
|
+
const program = env.SUPERCODE_CODEX_BIN;
|
|
53
|
+
// The native registry does not trim, stat or substitute a configured
|
|
54
|
+
// executable. An invalid relative override means no default launch.
|
|
55
|
+
const absolute = typeof program === 'string' && isAbsolute(program)
|
|
56
|
+
&& (process.platform !== 'win32' || /^(?:[A-Za-z]:[\\/]|[\\/]{2})/.test(program));
|
|
57
|
+
descriptor.runtime.default_launch = program ? absolute ? { program, arguments: ['app-server'], env: {} } : null
|
|
58
|
+
: { program: 'codex', arguments: ['app-server'], env: {} };
|
|
59
|
+
} else if (descriptor.id === 'grok') {
|
|
60
|
+
const home = grokHomeEnvironment(env, cwd);
|
|
61
|
+
// Rust canonicalize keeps the Windows extended path prefix in this
|
|
62
|
+
// inventory's environment value, including an owned junction target.
|
|
63
|
+
if (process.platform === 'win32' && home.GROK_HOME != null) home.GROK_HOME = toNamespacedPath(home.GROK_HOME);
|
|
64
|
+
descriptor.runtime.default_launch.env = { GROK_AGENT_DASHBOARD: '0', ...home };
|
|
65
|
+
}
|
|
66
|
+
descriptor.orchestration = supportOrchestration(descriptor);
|
|
67
|
+
}
|
|
68
|
+
return report;
|
|
69
|
+
}
|