@sentropic/h2a 0.98.5 → 0.98.7-rc.1
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/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/dist/cli-command-map.d.ts.map +1 -1
- package/dist/cli-command-map.js +1 -0
- package/dist/cli-command-map.js.map +1 -1
- package/dist/cli-contract.js +2 -2
- package/dist/cli-contract.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +224 -16
- package/dist/cli.js.map +1 -1
- package/dist/hosts/agy.js +1 -1
- package/dist/hosts/agy.js.map +1 -1
- package/dist/hosts/installation-doctor.d.ts +1 -0
- package/dist/hosts/installation-doctor.d.ts.map +1 -1
- package/dist/hosts/installation-doctor.js +1 -1
- package/dist/hosts/installation-doctor.js.map +1 -1
- package/dist/hosts/muse.d.ts.map +1 -1
- package/dist/hosts/muse.js +2 -4
- package/dist/hosts/muse.js.map +1 -1
- package/dist/hosts/native-artifacts.d.ts +33 -0
- package/dist/hosts/native-artifacts.d.ts.map +1 -0
- package/dist/hosts/native-artifacts.js +104 -0
- package/dist/hosts/native-artifacts.js.map +1 -0
- package/dist/hosts/native-catalog.d.ts +19 -0
- package/dist/hosts/native-catalog.d.ts.map +1 -0
- package/dist/hosts/native-catalog.js +14 -0
- package/dist/hosts/native-catalog.js.map +1 -0
- package/dist/hosts/native-convergence.d.ts +132 -0
- package/dist/hosts/native-convergence.d.ts.map +1 -0
- package/dist/hosts/native-convergence.js +86 -0
- package/dist/hosts/native-convergence.js.map +1 -0
- package/dist/hosts/native-files.d.ts +40 -0
- package/dist/hosts/native-files.d.ts.map +1 -0
- package/dist/hosts/native-files.js +131 -0
- package/dist/hosts/native-files.js.map +1 -0
- package/dist/hosts/native-inspection.d.ts +31 -0
- package/dist/hosts/native-inspection.d.ts.map +1 -0
- package/dist/hosts/native-inspection.js +79 -0
- package/dist/hosts/native-inspection.js.map +1 -0
- package/dist/hosts/native-paths.d.ts +11 -0
- package/dist/hosts/native-paths.d.ts.map +1 -0
- package/dist/hosts/native-paths.js +21 -0
- package/dist/hosts/native-paths.js.map +1 -0
- package/dist/hosts/native-proof.d.ts +32 -0
- package/dist/hosts/native-proof.d.ts.map +1 -0
- package/dist/hosts/native-proof.js +31 -0
- package/dist/hosts/native-proof.js.map +1 -0
- package/dist/hosts/native-runtime-record.d.ts +3 -0
- package/dist/hosts/native-runtime-record.d.ts.map +1 -0
- package/dist/hosts/native-runtime-record.js +60 -0
- package/dist/hosts/native-runtime-record.js.map +1 -0
- package/dist/hosts/native-skills.d.ts +24 -0
- package/dist/hosts/native-skills.d.ts.map +1 -0
- package/dist/hosts/native-skills.js +56 -0
- package/dist/hosts/native-skills.js.map +1 -0
- package/dist/hosts/native-toml.d.ts +18 -0
- package/dist/hosts/native-toml.d.ts.map +1 -0
- package/dist/hosts/native-toml.js +91 -0
- package/dist/hosts/native-toml.js.map +1 -0
- package/dist/hosts/operator-notices.d.ts +3 -0
- package/dist/hosts/operator-notices.d.ts.map +1 -0
- package/dist/hosts/operator-notices.js +31 -0
- package/dist/hosts/operator-notices.js.map +1 -0
- package/dist/hosts/plugin.d.ts.map +1 -1
- package/dist/hosts/plugin.js +3 -2
- package/dist/hosts/plugin.js.map +1 -1
- package/dist/hosts/upgrade-equipment.d.ts +42 -0
- package/dist/hosts/upgrade-equipment.d.ts.map +1 -0
- package/dist/hosts/upgrade-equipment.js +26 -0
- package/dist/hosts/upgrade-equipment.js.map +1 -0
- package/dist/hosts/vibe-discovery.d.ts +12 -0
- package/dist/hosts/vibe-discovery.d.ts.map +1 -0
- package/dist/hosts/vibe-discovery.js +33 -0
- package/dist/hosts/vibe-discovery.js.map +1 -0
- package/dist/hosts/vibe-equipment.d.ts +71 -0
- package/dist/hosts/vibe-equipment.d.ts.map +1 -0
- package/dist/hosts/vibe-equipment.js +162 -0
- package/dist/hosts/vibe-equipment.js.map +1 -0
- package/dist/hosts/vibe-mcp.d.ts +32 -0
- package/dist/hosts/vibe-mcp.d.ts.map +1 -0
- package/dist/hosts/vibe-mcp.js +210 -0
- package/dist/hosts/vibe-mcp.js.map +1 -0
- package/dist/hosts/vibe.d.ts +12 -3
- package/dist/hosts/vibe.d.ts.map +1 -1
- package/dist/hosts/vibe.js +15 -7
- package/dist/hosts/vibe.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime/drive/consent.d.ts +1 -1
- package/dist/runtime/drive/consent.d.ts.map +1 -1
- package/dist/runtime/drive/consent.js +2 -2
- package/dist/runtime/drive/consent.js.map +1 -1
- package/dist/runtime/drive/index.d.ts +1 -1
- package/dist/runtime/drive/index.d.ts.map +1 -1
- package/dist/runtime/drive/index.js +3 -1
- package/dist/runtime/drive/index.js.map +1 -1
- package/dist/runtime/drumbeat/relaunchers.d.ts +1 -1
- package/dist/runtime/drumbeat/relaunchers.d.ts.map +1 -1
- package/dist/runtime/drumbeat/relaunchers.js +2 -1
- package/dist/runtime/drumbeat/relaunchers.js.map +1 -1
- package/dist/runtime/identity/binding-commit.d.ts +31 -0
- package/dist/runtime/identity/binding-commit.d.ts.map +1 -0
- package/dist/runtime/identity/binding-commit.js +211 -0
- package/dist/runtime/identity/binding-commit.js.map +1 -0
- package/dist/runtime/identity/bindings.d.ts +6 -30
- package/dist/runtime/identity/bindings.d.ts.map +1 -1
- package/dist/runtime/identity/bindings.js +85 -96
- package/dist/runtime/identity/bindings.js.map +1 -1
- package/dist/runtime/identity/durable.d.ts +7 -0
- package/dist/runtime/identity/durable.d.ts.map +1 -0
- package/dist/runtime/identity/durable.js +68 -0
- package/dist/runtime/identity/durable.js.map +1 -0
- package/dist/runtime/identity/live.d.ts +4 -1
- package/dist/runtime/identity/live.d.ts.map +1 -1
- package/dist/runtime/identity/live.js +59 -6
- package/dist/runtime/identity/live.js.map +1 -1
- package/dist/runtime/identity/possession.d.ts +34 -0
- package/dist/runtime/identity/possession.d.ts.map +1 -0
- package/dist/runtime/identity/possession.js +162 -0
- package/dist/runtime/identity/possession.js.map +1 -0
- package/dist/runtime/identity/worker.js +16 -5
- package/dist/runtime/identity/worker.js.map +1 -1
- package/dist/runtime/live/contracts.d.ts +55 -0
- package/dist/runtime/live/contracts.d.ts.map +1 -0
- package/dist/runtime/live/contracts.js +59 -0
- package/dist/runtime/live/contracts.js.map +1 -0
- package/dist/runtime/local-files/identity-fence.d.ts +164 -0
- package/dist/runtime/local-files/identity-fence.d.ts.map +1 -0
- package/dist/runtime/local-files/identity-fence.js +1338 -0
- package/dist/runtime/local-files/identity-fence.js.map +1 -0
- package/dist/runtime/local-files/index.d.ts +1 -0
- package/dist/runtime/local-files/index.d.ts.map +1 -1
- package/dist/runtime/local-files/index.js +1 -0
- package/dist/runtime/local-files/index.js.map +1 -1
- package/dist/runtime/local-files/legacy-identity-evidence.d.ts +26 -0
- package/dist/runtime/local-files/legacy-identity-evidence.d.ts.map +1 -0
- package/dist/runtime/local-files/legacy-identity-evidence.js +234 -0
- package/dist/runtime/local-files/legacy-identity-evidence.js.map +1 -0
- package/dist/runtime/local-files/locks.d.ts +3 -0
- package/dist/runtime/local-files/locks.d.ts.map +1 -1
- package/dist/runtime/local-files/locks.js +6 -5
- package/dist/runtime/local-files/locks.js.map +1 -1
- package/dist/runtime/local-files/orphan-gc.d.ts +3 -0
- package/dist/runtime/local-files/orphan-gc.d.ts.map +1 -0
- package/dist/runtime/local-files/orphan-gc.js +69 -0
- package/dist/runtime/local-files/orphan-gc.js.map +1 -0
- package/dist/runtime/local-files/presence.d.ts +5 -2
- package/dist/runtime/local-files/presence.d.ts.map +1 -1
- package/dist/runtime/local-files/presence.js +32 -29
- package/dist/runtime/local-files/presence.js.map +1 -1
- package/dist/runtime/local-files/recipient-hints.d.ts +10 -0
- package/dist/runtime/local-files/recipient-hints.d.ts.map +1 -0
- package/dist/runtime/local-files/recipient-hints.js +156 -0
- package/dist/runtime/local-files/recipient-hints.js.map +1 -0
- package/dist/runtime/local-files/store.d.ts +1 -1
- package/dist/runtime/local-files/store.d.ts.map +1 -1
- package/dist/runtime/local-files/store.js +12 -1
- package/dist/runtime/local-files/store.js.map +1 -1
- package/dist/runtime/local-files/succession-lock.d.ts +71 -6
- package/dist/runtime/local-files/succession-lock.d.ts.map +1 -1
- package/dist/runtime/local-files/succession-lock.js +226 -31
- package/dist/runtime/local-files/succession-lock.js.map +1 -1
- package/dist/runtime/mcp/handlers.d.ts +1 -0
- package/dist/runtime/mcp/handlers.d.ts.map +1 -1
- package/dist/runtime/mcp/handlers.js +7 -4
- package/dist/runtime/mcp/handlers.js.map +1 -1
- package/dist/runtime/mcp/identity-blocker-snapshot.d.ts +2 -0
- package/dist/runtime/mcp/identity-blocker-snapshot.d.ts.map +1 -0
- package/dist/runtime/mcp/identity-blocker-snapshot.js +98 -0
- package/dist/runtime/mcp/identity-blocker-snapshot.js.map +1 -0
- package/dist/runtime/mcp/identity-state.d.ts +20 -3
- package/dist/runtime/mcp/identity-state.d.ts.map +1 -1
- package/dist/runtime/mcp/identity-state.js +98 -13
- package/dist/runtime/mcp/identity-state.js.map +1 -1
- package/dist/runtime/mcp/notifications.d.ts +2 -1
- package/dist/runtime/mcp/notifications.d.ts.map +1 -1
- package/dist/runtime/mcp/notifications.js +16 -2
- package/dist/runtime/mcp/notifications.js.map +1 -1
- package/dist/runtime/mcp/server.d.ts +3 -0
- package/dist/runtime/mcp/server.d.ts.map +1 -1
- package/dist/runtime/mcp/server.js +31 -15
- package/dist/runtime/mcp/server.js.map +1 -1
- package/dist/runtime/mcp/sessions.d.ts +6 -6
- package/dist/runtime/mcp/sessions.d.ts.map +1 -1
- package/dist/runtime/mcp/sessions.js +18 -6
- package/dist/runtime/mcp/sessions.js.map +1 -1
- package/dist/runtime/mcp/stdio.d.ts.map +1 -1
- package/dist/runtime/mcp/stdio.js +11 -0
- package/dist/runtime/mcp/stdio.js.map +1 -1
- package/dist/runtime/mcp/tools.js +1 -1
- package/dist/runtime/mcp/tools.js.map +1 -1
- package/dist/runtime/remote/client.d.ts +1 -1
- package/dist/runtime/remote/client.d.ts.map +1 -1
- package/dist/runtime/remote/client.js +1 -1
- package/dist/runtime/remote/client.js.map +1 -1
- package/dist/runtime/send.d.ts +10 -0
- package/dist/runtime/send.d.ts.map +1 -1
- package/dist/runtime/send.js +80 -5
- package/dist/runtime/send.js.map +1 -1
- package/dist/runtime/upgrade/index.d.ts +1 -0
- package/dist/runtime/upgrade/index.d.ts.map +1 -1
- package/dist/runtime/upgrade/index.js +1 -0
- package/dist/runtime/upgrade/index.js.map +1 -1
- package/dist/vendor/engram-live/contracts.d.ts +208 -0
- package/dist/vendor/engram-live/contracts.js +558 -0
- package/fixtures/native-host-catalog.json +1 -0
- package/fixtures/native-host-history.json +1261 -0
- package/fixtures/native-host-renderers.json +1 -0
- package/hooks/deny-manual-h2a-cli.mjs +38 -0
- package/hooks/hooks.json +17 -0
- package/hooks/vibe-post-agent.mjs +29 -0
- package/hooks/vibe-pre-tool.mjs +40 -0
- package/package.json +9 -6
- package/scripts/qualification-budget.mjs +56 -0
- package/scripts/qualification-cleanup.mjs +15 -0
- package/scripts/qualification-oracles.mjs +44 -0
- package/scripts/qualification-patch.mjs +21 -0
- package/scripts/qualification-poll-hosts.mjs +19 -0
- package/scripts/qualification-probe.mjs +63 -0
- package/scripts/qualification-rpc.mjs +59 -0
- package/scripts/qualification-vibe.mjs +159 -0
- package/scripts/qualify-host.mjs +143 -0
- package/skills/h2a/SKILL.md +6 -2
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Opt-in native recipe. No native process is launched by doctor or upgrade.
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { isAbsolute, join, resolve } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { randomUUID } from 'node:crypto';
|
|
8
|
+
import { runCli as runTrackCli } from '@sentropic/track';
|
|
9
|
+
import { QualificationBudget, VIBE_QUALIFICATION_PLAN, PHASE2_RECIPE } from './qualification-budget.mjs';
|
|
10
|
+
import { qualifyVibe } from './qualification-vibe.mjs';
|
|
11
|
+
import { qualifyVibeProbe } from './qualification-probe.mjs';
|
|
12
|
+
import { qualifyPollHost } from './qualification-poll-hosts.mjs';
|
|
13
|
+
import { clearQualificationRecords, ownedRecordSnapshot } from './qualification-cleanup.mjs';
|
|
14
|
+
import { atomicNativeWrite, digest, jsonBytes, snapshot } from '../dist/hosts/native-files.js';
|
|
15
|
+
import { planVibeEquipment } from '../dist/hosts/vibe-equipment.js';
|
|
16
|
+
import { captureRuntimeGeneratedFiles, verifyRuntimeRecord } from '../dist/hosts/native-runtime-record.js';
|
|
17
|
+
import { parseNativeToml } from '../dist/hosts/native-toml.js';
|
|
18
|
+
const flags = {};
|
|
19
|
+
for (let i = 2; i < process.argv.length; i++) {
|
|
20
|
+
const key = process.argv[i]; if (!key.startsWith('--')) throw new Error('named flags required');
|
|
21
|
+
flags[key.slice(2)] = process.argv[i + 1]?.startsWith('--') || i + 1 === process.argv.length ? true : process.argv[++i];
|
|
22
|
+
}
|
|
23
|
+
if (!['vibe', 'muse', 'agy'].includes(flags.host)) throw new Error('--host vibe|muse|agy required');
|
|
24
|
+
const components = String(flags.components ?? 'skills,MCP,context,guard,lifecycle').split(',');
|
|
25
|
+
if (components.some(c => !['skills', 'MCP', 'context', 'guard', 'lifecycle'].includes(c))) throw new Error('unknown component');
|
|
26
|
+
const plan = { host: flags.host, components, status: 'not executed', execution: 'one app-server session (fork included), or the CLI probe',
|
|
27
|
+
iteration: 'one model call, including every delegated child call', budget: VIBE_QUALIFICATION_PLAN, phase2: PHASE2_RECIPE,
|
|
28
|
+
migration: 'bootstrap B and R5/R7 receipts remain external', notice: 'After every update run h2a doctor --repair; immediate visible relay is not guaranteed.' };
|
|
29
|
+
if (!flags.execute) { process.stdout.write(JSON.stringify(plan, null, 2) + '\n'); process.exit(0); }
|
|
30
|
+
if (!flags.home || !flags.output || !isAbsolute(flags.home) || !isAbsolute(flags.output)) throw new Error('--execute requires explicit absolute --home and --output paths');
|
|
31
|
+
const phase = Number(flags.phase ?? 1); if (![1, 2].includes(phase)) throw new Error('--phase 1|2 required');
|
|
32
|
+
const lane = fs.mkdtempSync(join(tmpdir(), 'h2a-qualification-'));
|
|
33
|
+
const output = resolve(flags.output); fs.mkdirSync(output, { recursive: true, mode: 0o700 });
|
|
34
|
+
for (const name of ['workspace-a', 'workspace-b', 'runtime', 'config', 'state']) fs.mkdirSync(join(lane, name), { mode: 0o700 });
|
|
35
|
+
const env = { ...process.env, HOME: flags.home, VIBE_HOME: join(flags.home, '.vibe'), XDG_RUNTIME_DIR: join(lane, 'runtime'), XDG_CONFIG_HOME: join(flags.home, '.config'), XDG_STATE_HOME: join(flags.home, '.local/state') };
|
|
36
|
+
const busRoot = flags.root ? resolve(flags.root) : join(lane, 'bus');
|
|
37
|
+
const instance = `h2a-qualification-${randomUUID()}`;
|
|
38
|
+
const entrypoint = fileURLToPath(new URL('../dist/bin.js', import.meta.url));
|
|
39
|
+
const evidence = [], cleanup = { sessions: [], deleted: [], incomplete: false, instances: [] };
|
|
40
|
+
const budget = new QualificationBudget();
|
|
41
|
+
let previousAttempt;
|
|
42
|
+
if (phase === 2) {
|
|
43
|
+
if (!flags.previous) throw new Error('phase 2 requires --previous <phase-1 attempt.json>');
|
|
44
|
+
const previous = JSON.parse(fs.readFileSync(flags.previous, 'utf8'));
|
|
45
|
+
if (previous.host !== flags.host || previous.busRoot !== busRoot || previous.profileHome !== flags.home || previous.phase !== 1) throw new Error('phase-1 profile/bus mismatch');
|
|
46
|
+
budget.restorePhase1(previous.accounting, previous.elapsedMilliseconds);
|
|
47
|
+
previousAttempt = previous;
|
|
48
|
+
}
|
|
49
|
+
const controller = new AbortController(), interrupt = () => controller.abort();
|
|
50
|
+
process.once('SIGINT', interrupt); process.once('SIGTERM', interrupt);
|
|
51
|
+
const watchdog = setTimeout(interrupt, budget.remaining());
|
|
52
|
+
let receiptPublication;
|
|
53
|
+
const evidencePath = join(output, 'qualification-' + instance + '.json');
|
|
54
|
+
const report = { ...plan, status: 'partial', fixture: flags.fixture === true, phase, instance, busRoot, profileHome: flags.home, cleanup, evidence, results: {} };
|
|
55
|
+
try {
|
|
56
|
+
if (flags.host !== 'vibe') {
|
|
57
|
+
report.results = qualifyPollHost({ host: flags.host, env, cwd: join(lane, 'workspace-a'), evidence });
|
|
58
|
+
if (flags.host === 'agy') {
|
|
59
|
+
const root = join(flags.home, '.gemini'), state = join(root, '.h2a-install-agy');
|
|
60
|
+
const shared = snapshot(join(root, '.h2a-install-agy/shared-owner.json'));
|
|
61
|
+
if (shared) {
|
|
62
|
+
const path = join(state, 'import-observation.json');
|
|
63
|
+
atomicNativeWrite(path, jsonBytes({ schema: 1, root, status: report.results.import, sharedManifestHash: digest(shared.bytes) }), { state, expected: snapshot(path) });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
report.limit = 'The native Muse/agy model accounting and session trace contracts are unverified. No unbounded model invocation is launched; M-B remains required.';
|
|
67
|
+
} else {
|
|
68
|
+
// Track must resolve a real, private store in each disposable workspace;
|
|
69
|
+
// an empty-view hint from an unadopted directory is not context evidence.
|
|
70
|
+
for (const name of ['workspace-a', 'workspace-b']) {
|
|
71
|
+
const workspace = join(lane, name);
|
|
72
|
+
const code = await runTrackCli(['--track-dir', join(workspace, '.track'), 'init'], { cwd: workspace, out: () => {}, err: () => {} });
|
|
73
|
+
if (code !== 0) throw new Error('private qualification Track initialization failed');
|
|
74
|
+
}
|
|
75
|
+
if (phase === 2) {
|
|
76
|
+
const root = env.VIBE_HOME || join(flags.home, '.vibe');
|
|
77
|
+
const manifest = JSON.parse(fs.readFileSync(join(root, '.h2a-install/manifest.json'), 'utf8'));
|
|
78
|
+
// Never exercise a lifecycle that can mutate somebody else's instance.
|
|
79
|
+
if (!manifest.lifecycle?.enabled || manifest.lifecycle.root !== busRoot || !flags['owned-instance'] || manifest.lifecycle.instance !== flags['owned-instance'])
|
|
80
|
+
throw new Error('Phase 2 requires a dedicated lifecycle instance and exact private bus root explicitly declared with --owned-instance.');
|
|
81
|
+
if (ownedRecordSnapshot(busRoot, flags['owned-instance']).own) throw new Error('qualification instance already has a record');
|
|
82
|
+
cleanup.instances.push(flags['owned-instance']);
|
|
83
|
+
}
|
|
84
|
+
const profileRoot = env.VIBE_HOME || join(flags.home, '.vibe');
|
|
85
|
+
const manifest = JSON.parse(fs.readFileSync(join(profileRoot, '.h2a-install/manifest.json'), 'utf8'));
|
|
86
|
+
const requiredResources = Object.entries(manifest.files).filter(([path, entry]) => path.includes('/assets/') && entry.selected).map(([path]) => ({ path: resolve(profileRoot, path), bytes: fs.readFileSync(resolve(profileRoot, path), 'utf8') }));
|
|
87
|
+
report.results = await qualifyVibe({ command: flags['app-server'] ?? 'vibe-app-server', args: [], env,
|
|
88
|
+
workspaces: [join(lane, 'workspace-a'), join(lane, 'workspace-b')], busRoot, phase, budget, signal: controller.signal, evidence, cleanup, components, requiredResources,
|
|
89
|
+
clearRecords: () => clearQualificationRecords({ root: busRoot, instances: cleanup.instances, entrypoint, env }),
|
|
90
|
+
recordSnapshot: () => ownedRecordSnapshot(busRoot, flags['owned-instance']) });
|
|
91
|
+
if (phase === 1) report.probe = await qualifyVibeProbe({ command: flags.vibe ?? 'vibe', appServer: flags['app-server'] ?? 'vibe-app-server', cwd: join(lane, 'workspace-a'), env,
|
|
92
|
+
tools: report.results.probeTools ?? [], requiredResources, busRoot, components, budget, signal: controller.signal, evidence, cleanup, directory: lane });
|
|
93
|
+
if (flags.record && flags.metadata && !cleanup.incomplete) {
|
|
94
|
+
const metadata = fs.readFileSync(flags.metadata, 'utf8'), version = /^Version: (.+)$/m.exec(metadata)?.[1];
|
|
95
|
+
if (!/Name: mistral[-_]vibe/i.test(metadata) || version !== report.results.runtimeVersion) throw new Error('mistral-vibe wheel metadata does not match the native runtime');
|
|
96
|
+
const state = join(profileRoot, '.h2a-install'), config = parseNativeToml(fs.readFileSync(join(profileRoot, 'config.toml'), 'utf8'));
|
|
97
|
+
const installed = planVibeEquipment({ root: profileRoot, state, version: manifest.version, config, mcpAvailable: (config.mcp_servers ?? []).length > 0, repair: false });
|
|
98
|
+
const previous = snapshot(join(state, 'qualification.json'));
|
|
99
|
+
const receipt = previous ? JSON.parse(previous.bytes.toString()) : { schema: 1, host: 'vibe', root: profileRoot, components: {} };
|
|
100
|
+
if (previous && receipt.fixture !== report.fixture) receipt.components = {};
|
|
101
|
+
receipt.fixture = report.fixture; receipt.recordedAt = new Date().toISOString();
|
|
102
|
+
const generatedFiles = captureRuntimeGeneratedFiles(resolve(flags.record));
|
|
103
|
+
if (!verifyRuntimeRecord(resolve(flags.record), generatedFiles)) throw new Error('native runtime RECORD verification failed');
|
|
104
|
+
receipt.runtime = { generatedFiles, distribution: 'mistral-vibe', version, recordPath: resolve(flags.record), metadataPath: resolve(flags.metadata), recordSha256: digest(fs.readFileSync(flags.record)) };
|
|
105
|
+
const dependencies = { MCP: ['MCP', 'profile', 'node', 'entrypoint'], context: ['MCP', 'profile', 'node', 'entrypoint'],
|
|
106
|
+
skills: ['skills', 'filters', 'profile'], guard: ['guard', 'node', 'entrypoint', 'masking', 'guardBlock', 'MCP'], lifecycle: ['lifecycle', 'node', 'entrypoint', 'lifecycleSelection', 'lifecycleBlock'] };
|
|
107
|
+
const exercised = phase === 1 ? ['skills', 'MCP', 'context'] : ['guard', 'lifecycle'];
|
|
108
|
+
for (const component of components.filter(c => exercised.includes(c))) receipt.components[component] = { status: report.results[component] === 'observed' && (phase !== 1 || report.probe?.status === 'observed') ? 'qualified' : 'partial', dependencies: Object.fromEntries(dependencies[component].map(key => [key, installed.observed[key]])),
|
|
109
|
+
evidence: [evidencePath], evidenceHashes: {}, scope: phase === 2 ? 'explicit lifecycle; parent non-forked only' : 'two isolated native sessions; observed direct MCP is non migrated' };
|
|
110
|
+
receiptPublication = { state, previous, receipt, exercised };
|
|
111
|
+
}
|
|
112
|
+
report.limit = 'Native observations are partial until resource resolution, CLI probe, context and per-component oracles all agree; no fixture qualifies the target host.';
|
|
113
|
+
}
|
|
114
|
+
} catch (error) { report.error = String(error.message).replace(/[\r\n]/g, ' ').slice(0, 500); }
|
|
115
|
+
finally {
|
|
116
|
+
clearTimeout(watchdog); process.removeListener('SIGINT', interrupt); process.removeListener('SIGTERM', interrupt);
|
|
117
|
+
report.accounting = [...budget.executions.values()];
|
|
118
|
+
report.elapsedMilliseconds = Date.now() - budget.start;
|
|
119
|
+
const currentPhase = phase === 1 ? ['skills', 'MCP', 'context'] : ['guard', 'lifecycle'];
|
|
120
|
+
report.componentStatus = Object.fromEntries(components.map(component => {
|
|
121
|
+
const current = currentPhase.includes(component);
|
|
122
|
+
const attempt = current ? report : previousAttempt;
|
|
123
|
+
const observed = attempt?.results?.[component] === 'observed' &&
|
|
124
|
+
(!['skills', 'MCP', 'context'].includes(component) || attempt?.probe?.status === 'observed') &&
|
|
125
|
+
!attempt?.error && !attempt?.cleanup?.incomplete && attempt?.fixture === report.fixture;
|
|
126
|
+
return [component, observed ? 'qualified' : 'partial'];
|
|
127
|
+
}));
|
|
128
|
+
if (!report.error && !cleanup.incomplete && Object.values(report.componentStatus).every(status => status === 'qualified'))
|
|
129
|
+
report.status = report.fixture ? 'fixture-only' : 'qualified';
|
|
130
|
+
// Persist only bounded metadata/hashes, never prompts, model output, stderr or credentials.
|
|
131
|
+
const path = evidencePath;
|
|
132
|
+
if (!cleanup.incomplete) fs.rmSync(lane, { recursive: true, force: true });
|
|
133
|
+
else { report.cleanupResume = { sessions: cleanup.sessions.filter(id => !cleanup.deleted.includes(id)), lane, busRoot, instances: cleanup.instances }; }
|
|
134
|
+
const bytes = JSON.stringify(report, null, 2) + '\n';
|
|
135
|
+
fs.writeFileSync(path, bytes, { mode: 0o600, flag: 'wx' });
|
|
136
|
+
if (receiptPublication && !report.error && !cleanup.incomplete) {
|
|
137
|
+
const { state, previous, receipt, exercised } = receiptPublication;
|
|
138
|
+
for (const c of components.filter(c => exercised.includes(c))) receipt.components[c].evidenceHashes[path] = digest(bytes);
|
|
139
|
+
atomicNativeWrite(join(state, 'qualification.json'), jsonBytes(receipt), { state, expected: previous });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
process.stdout.write(JSON.stringify({ status: report.status, evidence: evidencePath, cleanupComplete: !cleanup.incomplete }) + '\n');
|
|
143
|
+
process.exitCode = report.status === 'qualified' ? 0 : 2;
|
package/skills/h2a/SKILL.md
CHANGED
|
@@ -356,7 +356,7 @@ These can be invoked directly from the shell at any time, outside the slash-comm
|
|
|
356
356
|
- `h2a sessions [--root <path>]` — same listing as `/h2a discover` but from the shell.
|
|
357
357
|
- `h2a status [--root <path>] [--scope <s>] [--instance <i>]` — inventory of connected sessions split **direct** (local mcp-serve heartbeat) vs **indirect** (mirrored in from a remote/sidecar), with counts.
|
|
358
358
|
- `h2a keys generate --instance <id>` — produce an ed25519 PEM keypair.
|
|
359
|
-
- `h2a install-skills --host <claude|codex|gemini|agy|hermes|opencode|muse>` —
|
|
359
|
+
- `h2a install-skills --host <claude|codex|gemini|agy|hermes|opencode|muse|vibe>` — install skills and their referenced resources. Vibe uses nonempty `VIBE_HOME` (default `~/.vibe`); Muse uses `~/.config/muse/skills`. agy shares Gemini commands and their ownership; run `agy plugin import gemini`, then `agy plugin enable h2a`. Native discovery/import is distinct from qualification; Gemini never qualifies agy. Unknown/custom native files survive `--force`.
|
|
360
360
|
|
|
361
361
|
**Operational surfaces** (also shell-invocable; matching `h2a_*` MCP tools where noted):
|
|
362
362
|
|
|
@@ -364,4 +364,8 @@ These can be invoked directly from the shell at any time, outside the slash-comm
|
|
|
364
364
|
- `h2a blockage raise|list|resolve` — the peer blockage feedback loop, distinct from the drumbeat and from escalation (`h2a_blockage_*`, DEC-092). Subscribed sessions get `peer.blocked`/`peer.unblocked` pushes.
|
|
365
365
|
- `h2a drumbeat record|scan|clear|escalations|watch` — anti-stall relance daemon + escalation-to-PRINCIPAL (DEC-086/091/095). Gov D2/D4 (0.64.0): a claimed conductor owns its workspace's relances — peers defer on fresh stalls (relanceCount=0); a failsafe lets a peer step in if the conductor leaves an agent stuck (relanceCount>=1, preventing workspace freeze). Cross-workspace relances emit a CoI advisory (warn, not blocked). Both behaviors are opt-in and default-allow: pass `--instance <self>` to `h2a drumbeat watch` to activate them.
|
|
366
366
|
- `h2a sysml verify --json <env> --public-key <pem>` — verify a SysML-v2 ref embedded in a signed envelope (commit-trust + content-integrity, DEC-099).
|
|
367
|
-
- `h2a host setup|status|plugin --host <codex|claude|gemini|agy|hermes|opencode|muse>` — render the
|
|
367
|
+
- `h2a host setup|status|plugin --host <codex|claude|gemini|agy|hermes|opencode|muse|vibe>` — inspect installation/qualification/migration separately. Muse/agy setup and connect render only a nonrecommended historical endpoint: **non migré — bootstrap registre attendu**. Do not ask the operator to paste, translate or merge those snippets. Vibe ships the interim direct entry (owner 16/10, derogation O7.2): `h2a host setup --host vibe --write` installs `[[mcp_servers]] h2a` into `<VIBE_HOME>/config.toml`; `h2a host setup --host vibe --remove` clears it for the R5/R7 registry migration. The registry integrator owns bootstrap/activation and R5/R7 receipts. Existing explicit Muse/agy JSON writers remain available until their migration. Vibe JSON targets stay refused. Muse stdio remains unconfirmed; polling does not qualify hooks.
|
|
368
|
+
- `h2a doctor --repair --host vibe|muse|agy` converges managed native components; `--dry-run` is nonmutating and launches no runtime. Vibe repair installs the interim direct MCP entry when absent (additive; `setup --write` owns argument changes). A Vibe with no MCP entry at inspect time still means **Skills installées, outils MCP absents — bootstrap registre attendu**; repair success never closes native equipment or registry migration. `--skip-hosts` skips this extension.
|
|
369
|
+
- Vibe lifecycle is explicit: `host plugin --host vibe --instance <id> --write <VIBE_HOME>/hooks.toml`. One dedicated non-forked parent session only; no automatic instance isolation is demonstrated. `--instance auto` is unavailable until B. Child/fork payloads produce no record. `/branch` and ACP copies are inactive on resume; `session/fork` attaches its copy by default immediately, while the origin stays active. `vibe -c` can resume the latest copy: use `vibe --resume <original-id>` or a fresh non-forked session. After repair use a new session or clean idle resume with an empty journal; an interrupted-turn resume retains old bindings. `drive receive` is N-A for Vibe.
|
|
370
|
+
- First Vibe guard activation needs a current native MCP component receipt; configuration, fixture and manual observation are insufficient. Native recipes are opt-in and never automatic. Preserve ordinary stale hooks; observable MCP loss suspends an intact managed guard. Muse/agy M-B stays required until the owner accepts M-A.
|
|
371
|
+
- Relay any `operator_notices` returned by `h2a_session_open` or `h2a_identity_status` visibly to the operator. If these tools are not called or the host hides their results, immediate notification is not guaranteed. **After every update run `h2a doctor --repair`** using the verified new entrypoint. Starting from 0.98.6: `h2a upgrade`, `h2a --version`, then `h2a doctor --repair`; the old upgrade alone does not equip hosts.
|