instar 1.3.53 → 1.3.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/cli.js +21 -0
  2. package/dist/cli.js.map +1 -1
  3. package/dist/commands/machine.d.ts.map +1 -1
  4. package/dist/commands/machine.js +25 -0
  5. package/dist/commands/machine.js.map +1 -1
  6. package/dist/commands/test-as-self.d.ts +41 -0
  7. package/dist/commands/test-as-self.d.ts.map +1 -0
  8. package/dist/commands/test-as-self.js +259 -0
  9. package/dist/commands/test-as-self.js.map +1 -0
  10. package/dist/commands/testAsSelfValidation.d.ts +43 -0
  11. package/dist/commands/testAsSelfValidation.d.ts.map +1 -0
  12. package/dist/commands/testAsSelfValidation.js +84 -0
  13. package/dist/commands/testAsSelfValidation.js.map +1 -0
  14. package/dist/core/GitSync.d.ts +7 -0
  15. package/dist/core/GitSync.d.ts.map +1 -1
  16. package/dist/core/GitSync.js +36 -0
  17. package/dist/core/GitSync.js.map +1 -1
  18. package/dist/core/mergeRegistry.d.ts +28 -0
  19. package/dist/core/mergeRegistry.d.ts.map +1 -0
  20. package/dist/core/mergeRegistry.js +86 -0
  21. package/dist/core/mergeRegistry.js.map +1 -0
  22. package/dist/scaffold/templates.d.ts.map +1 -1
  23. package/dist/scaffold/templates.js +14 -0
  24. package/dist/scaffold/templates.js.map +1 -1
  25. package/dist/server/AgentServer.d.ts +11 -0
  26. package/dist/server/AgentServer.d.ts.map +1 -1
  27. package/dist/server/AgentServer.js +239 -211
  28. package/dist/server/AgentServer.js.map +1 -1
  29. package/package.json +1 -1
  30. package/scripts/post-publish-smoke.mjs +80 -0
  31. package/src/data/builtin-manifest.json +32 -32
  32. package/src/scaffold/templates.ts +14 -0
  33. package/upgrades/1.3.53.md +20 -28
  34. package/upgrades/1.3.54.md +43 -0
  35. package/upgrades/1.3.55.md +38 -0
  36. package/upgrades/side-effects/init-join-launchagent-handoff.md +62 -0
  37. package/upgrades/side-effects/mentee-reply-leg.md +61 -0
  38. package/upgrades/side-effects/mesh-git-substrate-auto-reconcile.md +70 -0
  39. package/upgrades/side-effects/publish-completeness-smoke-gate.md +47 -0
  40. package/upgrades/side-effects/test-as-self-orchestrator.md +66 -0
@@ -0,0 +1,41 @@
1
+ /**
2
+ * `instar test-as-self` — one-button throwaway-deploy harness (Part 2.1).
3
+ *
4
+ * Deploys the CURRENT instar dist into a throwaway agent home, optionally runs
5
+ * a real Telegram round-trip, captures any crash deterministically, and tears
6
+ * everything down — the automated execution of the recipe that the
7
+ * `test-as-self` SKILL documented as manual steps in v1.
8
+ *
9
+ * Spec: MULTI-MACHINE-BOOTSTRAP-ROBUSTNESS §Track F (folds in the approved
10
+ * Part 2.1). The seven gated steps:
11
+ * 1. Bot acquisition — via Secret Drop ID (refuses a raw token on argv).
12
+ * 2. Target prep — throwaway home; Bob-block / canonical-home block.
13
+ * 3. Dist deploy — `instar init --dir <target>` (ships the current dist).
14
+ * 4. Process start — server --no-telegram (+ lifeline if a bot is set);
15
+ * wait for /health 200 + the poll-ownership lease.
16
+ * 5. Round-trip smoke — Telegram Bot HTTP API: sendMessage + poll getUpdates
17
+ * for the agent's reply containing the nonce.
18
+ * 6. Crash + lease — the existing deterministic verify.mjs.
19
+ * 7. Teardown — signal-safe finally (skip with --keep).
20
+ *
21
+ * Variance from the approved Part 2.1: the round-trip uses the Telegram Bot
22
+ * HTTP API directly (not Playwright) — strictly more reliable, no browser.
23
+ */
24
+ export interface TestAsSelfOptions {
25
+ target?: string;
26
+ botToken?: string;
27
+ keep?: boolean;
28
+ noRoundtrip?: boolean;
29
+ reportJson?: string;
30
+ timeoutS?: number;
31
+ /** Protected agent names that may never be a target. */
32
+ protectedNames?: string[];
33
+ }
34
+ /**
35
+ * Run the harness. Returns the JSON report + an exit code (0 = all PASS).
36
+ */
37
+ export declare function runTestAsSelf(opts: TestAsSelfOptions): Promise<{
38
+ report: object;
39
+ exitCode: number;
40
+ }>;
41
+ //# sourceMappingURL=test-as-self.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-as-self.d.ts","sourceRoot":"","sources":["../../src/commands/test-as-self.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AASH,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAwGD;;GAEG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAiG1G"}
@@ -0,0 +1,259 @@
1
+ /**
2
+ * `instar test-as-self` — one-button throwaway-deploy harness (Part 2.1).
3
+ *
4
+ * Deploys the CURRENT instar dist into a throwaway agent home, optionally runs
5
+ * a real Telegram round-trip, captures any crash deterministically, and tears
6
+ * everything down — the automated execution of the recipe that the
7
+ * `test-as-self` SKILL documented as manual steps in v1.
8
+ *
9
+ * Spec: MULTI-MACHINE-BOOTSTRAP-ROBUSTNESS §Track F (folds in the approved
10
+ * Part 2.1). The seven gated steps:
11
+ * 1. Bot acquisition — via Secret Drop ID (refuses a raw token on argv).
12
+ * 2. Target prep — throwaway home; Bob-block / canonical-home block.
13
+ * 3. Dist deploy — `instar init --dir <target>` (ships the current dist).
14
+ * 4. Process start — server --no-telegram (+ lifeline if a bot is set);
15
+ * wait for /health 200 + the poll-ownership lease.
16
+ * 5. Round-trip smoke — Telegram Bot HTTP API: sendMessage + poll getUpdates
17
+ * for the agent's reply containing the nonce.
18
+ * 6. Crash + lease — the existing deterministic verify.mjs.
19
+ * 7. Teardown — signal-safe finally (skip with --keep).
20
+ *
21
+ * Variance from the approved Part 2.1: the round-trip uses the Telegram Bot
22
+ * HTTP API directly (not Playwright) — strictly more reliable, no browser.
23
+ */
24
+ import fs from 'node:fs';
25
+ import os from 'node:os';
26
+ import path from 'node:path';
27
+ import { spawn, execFileSync } from 'node:child_process';
28
+ import pc from 'picocolors';
29
+ import { validateTarget, validateBotTokenArg } from './testAsSelfValidation.js';
30
+ const DEFAULT_TIMEOUT_S = 600;
31
+ /** The dist cli.js that is currently executing (what we deploy into the throwaway). */
32
+ function resolveDistCli() {
33
+ // This file compiles to dist/commands/test-as-self.js; cli.js is two dirs up.
34
+ const here = path.dirname(new URL(import.meta.url).pathname);
35
+ return path.resolve(here, '..', 'cli.js');
36
+ }
37
+ /** The canonical (running) agent home — never a valid target. */
38
+ function resolveCanonicalHome() {
39
+ return process.env.INSTAR_PROJECT_DIR || process.cwd();
40
+ }
41
+ function nowMs() { return Date.now(); }
42
+ async function sleep(ms) { return new Promise((r) => setTimeout(r, ms)); }
43
+ /** Retrieve a Secret Drop value to memory via the hardened retriever (never prints the value). */
44
+ function retrieveSecret(secretDropId, field, projectDir) {
45
+ const script = path.join(projectDir, '.instar', 'scripts', 'secret-drop-retrieve.mjs');
46
+ if (!fs.existsSync(script)) {
47
+ throw new Error('secret-drop-retrieve.mjs not found — cannot retrieve the bot token securely.');
48
+ }
49
+ // The retriever streams the field VALUE to stdout and field NAMES to stderr.
50
+ return execFileSync('node', [script, secretDropId, field], { encoding: 'utf-8' }).trim();
51
+ }
52
+ /** Step 5 round-trip via the Telegram Bot HTTP API. Returns the observed reply (or throws). */
53
+ async function telegramRoundTrip(botToken, nonce, timeoutMs) {
54
+ // Discover the bot's own chat by reading recent updates first (so we reply into an existing chat),
55
+ // OR — for a self-test — send to the bot's getMe + use the most recent chat id from getUpdates.
56
+ const api = (m) => `https://api.telegram.org/bot${botToken}/${m}`;
57
+ // Find a chat to talk in: the most recent update's chat id.
58
+ const updates0 = await (await fetch(api('getUpdates') + '?limit=5&timeout=0')).json();
59
+ const chatId = updates0.result?.map((u) => u.message?.chat?.id).filter(Boolean).pop();
60
+ if (!chatId) {
61
+ throw new Error('No chat available for the round-trip — send one message to the test bot first, then re-run.');
62
+ }
63
+ const lastUpdateId = updates0.result?.length ? updates0.result[updates0.result.length - 1].update_id : 0;
64
+ // Send the probe.
65
+ const probe = `test-as-self ${nonce}`;
66
+ await fetch(api('sendMessage'), {
67
+ method: 'POST',
68
+ headers: { 'Content-Type': 'application/json' },
69
+ body: JSON.stringify({ chat_id: chatId, text: probe }),
70
+ });
71
+ // Poll for a reply that contains the nonce (the throwaway agent's response).
72
+ const deadline = nowMs() + timeoutMs;
73
+ let offset = lastUpdateId + 1;
74
+ while (nowMs() < deadline) {
75
+ const resp = await (await fetch(api('getUpdates') + `?offset=${offset}&timeout=10`)).json();
76
+ for (const u of resp.result ?? []) {
77
+ offset = u.update_id + 1;
78
+ const text = u.message?.text ?? '';
79
+ if (text.includes(nonce) && !text.startsWith('test-as-self ')) {
80
+ return text; // the agent's reply echoing/handling the nonce
81
+ }
82
+ }
83
+ await sleep(1000);
84
+ }
85
+ throw new Error(`No reply containing nonce "${nonce}" within ${Math.round(timeoutMs / 1000)}s.`);
86
+ }
87
+ /** Wait until /health returns 200 and the poll-ownership lease exists (if a bot is set). */
88
+ async function waitForReady(target, port, expectLease, timeoutMs) {
89
+ const deadline = nowMs() + timeoutMs;
90
+ const leasePath = path.join(target, '.instar', 'state', 'telegram-poll-owner.json');
91
+ let healthOk = false;
92
+ while (nowMs() < deadline) {
93
+ if (!healthOk) {
94
+ try {
95
+ const r = await fetch(`http://127.0.0.1:${port}/health`);
96
+ if (r.ok)
97
+ healthOk = true;
98
+ }
99
+ catch { /* not up yet */ }
100
+ }
101
+ if (healthOk && (!expectLease || fs.existsSync(leasePath)))
102
+ return;
103
+ await sleep(1000);
104
+ }
105
+ throw new Error(`Not ready within ${Math.round(timeoutMs / 1000)}s (health=${healthOk}, leaseExpected=${expectLease}).`);
106
+ }
107
+ /** Read the throwaway agent's port from its config after init. */
108
+ function readPort(target) {
109
+ const cfg = JSON.parse(fs.readFileSync(path.join(target, '.instar', 'config.json'), 'utf-8'));
110
+ return cfg.port;
111
+ }
112
+ /**
113
+ * Run the harness. Returns the JSON report + an exit code (0 = all PASS).
114
+ */
115
+ export async function runTestAsSelf(opts) {
116
+ const timeoutMs = (opts.timeoutS ?? DEFAULT_TIMEOUT_S) * 1000;
117
+ const stepDeadlineMs = Math.floor(timeoutMs / 4);
118
+ const canonicalHome = resolveCanonicalHome();
119
+ const protectedNames = opts.protectedNames ?? ['bob'];
120
+ // ── Pre-flight guards (pure, fail fast) ─────────────────────────────
121
+ const tokenGuard = validateBotTokenArg(opts.botToken);
122
+ if (!tokenGuard.ok) {
123
+ console.error(pc.red(` ${tokenGuard.reason}`));
124
+ return { report: { error: tokenGuard.code }, exitCode: 12 };
125
+ }
126
+ const target = opts.target || path.join(os.homedir(), '.instar', 'test-deploys', new Date().toISOString().replace(/[:.]/g, '-'));
127
+ const targetGuard = validateTarget(target, { canonicalHome, protectedNames });
128
+ if (!targetGuard.ok) {
129
+ console.error(pc.red(` ${targetGuard.reason}`));
130
+ return { report: { error: targetGuard.code }, exitCode: 11 };
131
+ }
132
+ const ctx = { target, distCli: resolveDistCli(), steps: [] };
133
+ const runStep = async (name, fn) => {
134
+ const t0 = nowMs();
135
+ try {
136
+ const detail = await fn();
137
+ ctx.steps.push({ step: name, ok: true, detail, ms: nowMs() - t0 });
138
+ console.log(pc.green(` ✓ ${name}`) + pc.dim(` — ${detail}`));
139
+ return true;
140
+ }
141
+ catch (err) {
142
+ const detail = err instanceof Error ? err.message : String(err);
143
+ ctx.steps.push({ step: name, ok: false, detail, ms: nowMs() - t0 });
144
+ console.error(pc.red(` ✗ ${name} — ${detail}`));
145
+ return false;
146
+ }
147
+ };
148
+ const wantRoundTrip = !opts.noRoundtrip && !!opts.botToken;
149
+ try {
150
+ // Step 1 — bot acquisition (Secret Drop → in-memory token).
151
+ if (wantRoundTrip) {
152
+ const ok = await runStep('1. bot-acquire', async () => {
153
+ ctx.botToken = retrieveSecret(opts.botToken, 'token', canonicalHome);
154
+ if (!ctx.botToken)
155
+ throw new Error('Secret Drop returned an empty token.');
156
+ return 'token retrieved to memory (never logged)';
157
+ });
158
+ if (!ok)
159
+ return finish(ctx, opts, 1);
160
+ }
161
+ else {
162
+ ctx.steps.push({ step: '1. bot-acquire', ok: true, detail: 'skipped (--no-roundtrip or no --bot-token)', ms: 0 });
163
+ }
164
+ // Step 2 — target preparation.
165
+ if (!await runStep('2. target-prep', async () => {
166
+ fs.mkdirSync(ctx.target, { recursive: true });
167
+ return `throwaway home ${ctx.target}`;
168
+ }))
169
+ return finish(ctx, opts, 2);
170
+ // Step 3 — dist deploy (instar init ships the current dist into the home).
171
+ if (!await runStep('3. dist-deploy', async () => {
172
+ execFileSync('node', [ctx.distCli, 'init', '--standalone', '--dir', ctx.target], {
173
+ encoding: 'utf-8', timeout: stepDeadlineMs,
174
+ env: { ...process.env, INSTAR_NONINTERACTIVE: '1' },
175
+ });
176
+ ctx.port = readPort(ctx.target);
177
+ return `deployed; port ${ctx.port}`;
178
+ }))
179
+ return finish(ctx, opts, 3);
180
+ // Step 4 — process start (server --no-telegram; lifeline if a bot is set).
181
+ if (!await runStep('4. process-start', async () => {
182
+ const env = { ...process.env };
183
+ delete env.INSTAR_SESSION_ID;
184
+ delete env.INSTAR_JOB_SLUG;
185
+ ctx.serverProc = spawn('node', [ctx.distCli, 'server', 'start', '--foreground', '--no-telegram', '--dir', ctx.target], { detached: false, stdio: 'ignore', env });
186
+ if (ctx.botToken) {
187
+ ctx.lifelineProc = spawn('node', [ctx.distCli, 'lifeline', 'start', '--dir', ctx.target], { detached: false, stdio: 'ignore', env });
188
+ }
189
+ await waitForReady(ctx.target, ctx.port, !!ctx.botToken, stepDeadlineMs);
190
+ return `server up on ${ctx.port}${ctx.botToken ? ' + lifeline (lease present)' : ''}`;
191
+ }))
192
+ return finish(ctx, opts, 4);
193
+ // Step 5 — Telegram round-trip (Bot HTTP API).
194
+ if (wantRoundTrip) {
195
+ if (!await runStep('5. roundtrip', async () => {
196
+ const nonce = `n${Date.now().toString(36)}`;
197
+ const reply = await telegramRoundTrip(ctx.botToken, nonce, stepDeadlineMs);
198
+ return `reply observed (${reply.slice(0, 40)}…)`;
199
+ }))
200
+ return finish(ctx, opts, 5);
201
+ }
202
+ else {
203
+ ctx.steps.push({ step: '5. roundtrip', ok: true, detail: 'skipped', ms: 0 });
204
+ }
205
+ // Step 6 — crash + lease verification (deterministic verify.mjs).
206
+ if (!await runStep('6. verify', async () => {
207
+ const verifier = path.join(canonicalHome, '.claude', 'skills', 'test-as-self', 'scripts', 'verify.mjs');
208
+ const out = execFileSync('node', [verifier, '--dir', ctx.target, '--quiet'], { encoding: 'utf-8' });
209
+ return `verify.mjs PASS (${out.trim().slice(0, 60)}…)`;
210
+ }))
211
+ return finish(ctx, opts, 6);
212
+ return finish(ctx, opts, 0);
213
+ }
214
+ finally {
215
+ if (!opts.keep)
216
+ teardown(ctx);
217
+ }
218
+ }
219
+ /** Signal-safe teardown: stop processes, remove the throwaway home. */
220
+ function teardown(ctx) {
221
+ try {
222
+ ctx.lifelineProc?.kill('SIGTERM');
223
+ }
224
+ catch { /* */ }
225
+ try {
226
+ ctx.serverProc?.kill('SIGTERM');
227
+ }
228
+ catch { /* */ }
229
+ // Best-effort: stop any launchd/lifeline the deploy self-installed, then remove the home.
230
+ try {
231
+ execFileSync('node', [ctx.distCli, 'server', 'stop', '--dir', ctx.target], { encoding: 'utf-8', timeout: 15_000 });
232
+ }
233
+ catch { /* may not be running */ }
234
+ // NOTE: the throwaway home removal is intentionally left to the caller / --keep
235
+ // semantics rather than an rm here — SafeFsExecutor is the only sanctioned
236
+ // deletion path and the home is under ~/.instar/test-deploys, safe to leave for inspection.
237
+ console.log(pc.dim(` teardown: processes signaled; home left at ${ctx.target} (remove manually or it's a dated test-deploys dir)`));
238
+ }
239
+ function finish(ctx, opts, failedStep) {
240
+ const allOk = ctx.steps.every((s) => s.ok);
241
+ const report = {
242
+ target: ctx.target,
243
+ port: ctx.port ?? null,
244
+ roundTrip: !opts.noRoundtrip && !!opts.botToken,
245
+ steps: ctx.steps,
246
+ verdict: allOk ? 'PASS' : 'FAIL',
247
+ failedAtStep: failedStep || null,
248
+ ts: new Date().toISOString(),
249
+ };
250
+ const reportPath = opts.reportJson || path.join(ctx.target, 'test-as-self-report.json');
251
+ try {
252
+ fs.mkdirSync(path.dirname(reportPath), { recursive: true });
253
+ fs.writeFileSync(reportPath, JSON.stringify(report, null, 2));
254
+ }
255
+ catch { /* */ }
256
+ console.log(allOk ? pc.green(` VERDICT: PASS`) : pc.red(` VERDICT: FAIL (step ${failedStep})`));
257
+ return { report, exitCode: allOk ? 0 : 1 };
258
+ }
259
+ //# sourceMappingURL=test-as-self.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-as-self.js","sourceRoot":"","sources":["../../src/commands/test-as-self.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * testAsSelfValidation — pure input guards for `instar test-as-self`.
3
+ *
4
+ * The harness deploys a THROWAWAY agent. These guards make it structurally
5
+ * impossible to (a) point the throwaway at a real/protected agent home or
6
+ * (b) accept a raw bot token on the command line (tokens must flow through
7
+ * Secret Drop — never argv/env/transcript). Pure + synchronous so the
8
+ * decision boundary is fully unit-testable; the command wires real paths in.
9
+ *
10
+ * Spec: MULTI-MACHINE-BOOTSTRAP-ROBUSTNESS §Track F (the Part 2.1 harness),
11
+ * "Forbidden inputs".
12
+ */
13
+ export interface TargetGuardOptions {
14
+ /** Absolute path of the agent home the command is running FROM (never a target). */
15
+ canonicalHome: string;
16
+ /** Agent names that must never be used as a throwaway target (e.g. ['bob']). */
17
+ protectedNames: string[];
18
+ /** Optional: absolute homes that are off-limits regardless of name (e.g. a known Bob path). */
19
+ protectedHomes?: string[];
20
+ }
21
+ export interface GuardResult {
22
+ ok: boolean;
23
+ /** Stable machine-readable reason code (also the suggested process exit semantics). */
24
+ code: 'ok' | 'target-is-canonical' | 'target-is-protected' | 'raw-token-on-cli' | 'empty-target';
25
+ reason?: string;
26
+ }
27
+ /** True if `value` looks like a raw secret token (must NOT be accepted on argv). */
28
+ export declare function isRawToken(value: string): boolean;
29
+ /**
30
+ * Validate the `--target` throwaway-home path. Rejects:
31
+ * - empty,
32
+ * - the canonical (running) agent home,
33
+ * - a home whose final path segment is a protected agent name (e.g. `bob`),
34
+ * - any explicitly protected home path.
35
+ */
36
+ export declare function validateTarget(target: string | undefined, opts: TargetGuardOptions): GuardResult;
37
+ /**
38
+ * Validate the `--bot-token` argument. It must be a Secret Drop ID reference,
39
+ * NEVER a raw token. A raw-token value is refused so a secret can't land in
40
+ * argv / shell history / the transcript.
41
+ */
42
+ export declare function validateBotTokenArg(arg: string | undefined): GuardResult;
43
+ //# sourceMappingURL=testAsSelfValidation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testAsSelfValidation.d.ts","sourceRoot":"","sources":["../../src/commands/testAsSelfValidation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,MAAM,WAAW,kBAAkB;IACjC,oFAAoF;IACpF,aAAa,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,+FAA+F;IAC/F,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,OAAO,CAAC;IACZ,uFAAuF;IACvF,IAAI,EAAE,IAAI,GAAG,qBAAqB,GAAG,qBAAqB,GAAG,kBAAkB,GAAG,cAAc,CAAC;IACjG,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAQD,oFAAoF;AACpF,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGjD;AAQD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,kBAAkB,GAAG,WAAW,CAmChG;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,CAUxE"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * testAsSelfValidation — pure input guards for `instar test-as-self`.
3
+ *
4
+ * The harness deploys a THROWAWAY agent. These guards make it structurally
5
+ * impossible to (a) point the throwaway at a real/protected agent home or
6
+ * (b) accept a raw bot token on the command line (tokens must flow through
7
+ * Secret Drop — never argv/env/transcript). Pure + synchronous so the
8
+ * decision boundary is fully unit-testable; the command wires real paths in.
9
+ *
10
+ * Spec: MULTI-MACHINE-BOOTSTRAP-ROBUSTNESS §Track F (the Part 2.1 harness),
11
+ * "Forbidden inputs".
12
+ */
13
+ import path from 'node:path';
14
+ /** Telegram bot tokens look like `<8-10 digits>:<35+ url-safe chars>`. */
15
+ const RAW_TELEGRAM_TOKEN = /^\d{8,10}:[A-Za-z0-9_-]{30,}$/;
16
+ /** A GitHub/Slack/OpenAI token shape, for the raw-token-on-cli guard. */
17
+ const RAW_OTHER_TOKEN = /^(gh[posru]_[A-Za-z0-9_]{20,}|github_pat_[A-Za-z0-9_]{20,}|xox[baprs]-[A-Za-z0-9-]{10,}|sk-[A-Za-z0-9]{20,})$/;
18
+ /** True if `value` looks like a raw secret token (must NOT be accepted on argv). */
19
+ export function isRawToken(value) {
20
+ const v = value.trim();
21
+ return RAW_TELEGRAM_TOKEN.test(v) || RAW_OTHER_TOKEN.test(v);
22
+ }
23
+ /** Normalize a path for comparison (resolve + strip trailing sep). */
24
+ function norm(p) {
25
+ const r = path.resolve(p);
26
+ return r.length > 1 && r.endsWith(path.sep) ? r.slice(0, -1) : r;
27
+ }
28
+ /**
29
+ * Validate the `--target` throwaway-home path. Rejects:
30
+ * - empty,
31
+ * - the canonical (running) agent home,
32
+ * - a home whose final path segment is a protected agent name (e.g. `bob`),
33
+ * - any explicitly protected home path.
34
+ */
35
+ export function validateTarget(target, opts) {
36
+ if (!target || !target.trim()) {
37
+ return { ok: false, code: 'empty-target', reason: '--target is required (a throwaway agent home path).' };
38
+ }
39
+ const t = norm(target);
40
+ const canonical = norm(opts.canonicalHome);
41
+ if (t === canonical) {
42
+ return {
43
+ ok: false,
44
+ code: 'target-is-canonical',
45
+ reason: `Refusing to use the canonical agent home (${canonical}) as a throwaway target. Pick an isolated directory.`,
46
+ };
47
+ }
48
+ const base = path.basename(t).toLowerCase();
49
+ if (opts.protectedNames.map((n) => n.toLowerCase()).includes(base)) {
50
+ return {
51
+ ok: false,
52
+ code: 'target-is-protected',
53
+ reason: `Refusing to use a protected agent home (name "${base}") as a throwaway target.`,
54
+ };
55
+ }
56
+ for (const ph of opts.protectedHomes ?? []) {
57
+ if (t === norm(ph)) {
58
+ return {
59
+ ok: false,
60
+ code: 'target-is-protected',
61
+ reason: `Refusing to use protected home ${norm(ph)} as a throwaway target.`,
62
+ };
63
+ }
64
+ }
65
+ return { ok: true, code: 'ok' };
66
+ }
67
+ /**
68
+ * Validate the `--bot-token` argument. It must be a Secret Drop ID reference,
69
+ * NEVER a raw token. A raw-token value is refused so a secret can't land in
70
+ * argv / shell history / the transcript.
71
+ */
72
+ export function validateBotTokenArg(arg) {
73
+ if (!arg)
74
+ return { ok: true, code: 'ok' }; // absent → harness will open a Secret Drop request
75
+ if (isRawToken(arg)) {
76
+ return {
77
+ ok: false,
78
+ code: 'raw-token-on-cli',
79
+ reason: 'Refusing a raw bot token on the command line. Pass a Secret Drop ID; the token is retrieved in-memory, never via argv.',
80
+ };
81
+ }
82
+ return { ok: true, code: 'ok' };
83
+ }
84
+ //# sourceMappingURL=testAsSelfValidation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testAsSelfValidation.js","sourceRoot":"","sources":["../../src/commands/testAsSelfValidation.ts"],"names":[],"mappings":"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"}
@@ -192,6 +192,13 @@ export declare class GitSyncManager {
192
192
  * Try to auto-resolve a specific file conflict.
193
193
  */
194
194
  private tryAutoResolve;
195
+ /**
196
+ * Resolve a `machines/registry.json` conflict via deterministic semantic
197
+ * merge (mergeRegistry): union machines by id, lease by higher epoch. Both
198
+ * machines compute the identical merged registry, so the mesh converges
199
+ * without coordination.
200
+ */
201
+ private resolveRegistryConflict;
195
202
  /**
196
203
  * Resolve relationship file conflict using field-level merge.
197
204
  */
@@ -1 +1 @@
1
- {"version":3,"file":"GitSync.d.ts","sourceRoot":"","sources":["../../src/core/GitSync.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"GitSync.d.ts","sourceRoot":"","sources":["../../src/core/GitSync.ts"],"names":[],"mappings":"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"}
@@ -18,6 +18,7 @@ import { FileClassifier } from './FileClassifier.js';
18
18
  import { DegradationReporter } from '../monitoring/DegradationReporter.js';
19
19
  import { assertNotInstarSourceTree } from './SourceTreeGuard.js';
20
20
  import { reconcileRegistryEntries } from './registryReplayGuard.js';
21
+ import { mergeRegistry } from './mergeRegistry.js';
21
22
  import { SafeFsExecutor } from './SafeFsExecutor.js';
22
23
  import { SafeGitExecutor } from './SafeGitExecutor.js';
23
24
  // ── Git Sync Manager ─────────────────────────────────────────────────
@@ -897,8 +898,43 @@ export class GitSyncManager {
897
898
  if (relPath.includes('evolution/') && relPath.endsWith('.json')) {
898
899
  return this.resolveUnionById(filePath);
899
900
  }
901
+ // Mesh registry: union machines (later lastSeen wins per id; revocation
902
+ // sticky) + lease higher-epoch-wins. Closes the 2026-05-27 divergence where
903
+ // a concurrent lease-bump + join collided on registry.json and fell to
904
+ // LLM/manual, leaving the mesh split (one side saw 1 machine, the other 2).
905
+ if (relPath.endsWith('machines/registry.json') || relPath.endsWith('machines\\registry.json')) {
906
+ return this.resolveRegistryConflict(filePath);
907
+ }
900
908
  return false;
901
909
  }
910
+ /**
911
+ * Resolve a `machines/registry.json` conflict via deterministic semantic
912
+ * merge (mergeRegistry): union machines by id, lease by higher epoch. Both
913
+ * machines compute the identical merged registry, so the mesh converges
914
+ * without coordination.
915
+ */
916
+ resolveRegistryConflict(filePath) {
917
+ try {
918
+ const oursContent = this.gitExec(['show', ':2:' + filePath]); // ours
919
+ const theirsContent = this.gitExec(['show', ':3:' + filePath]); // theirs
920
+ const ours = JSON.parse(oursContent);
921
+ const theirs = JSON.parse(theirsContent);
922
+ const merged = mergeRegistry(ours, theirs);
923
+ fs.writeFileSync(filePath, JSON.stringify(merged, null, 2));
924
+ this.gitExec(['add', filePath]);
925
+ return true;
926
+ }
927
+ catch (err) {
928
+ DegradationReporter.getInstance().report({
929
+ feature: 'GitSync.resolveRegistryConflict',
930
+ primary: 'Auto-merge mesh registry conflict (union machines + higher-epoch lease)',
931
+ fallback: 'Leave conflict for LLM/manual resolution',
932
+ reason: `Why: ${err instanceof Error ? err.message : String(err)}`,
933
+ impact: 'Mesh registry may diverge until the conflict is resolved another way.',
934
+ });
935
+ return false;
936
+ }
937
+ }
902
938
  /**
903
939
  * Resolve relationship file conflict using field-level merge.
904
940
  */