instar 0.28.52 → 0.28.53
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/dist/cli.js +40 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/gate.d.ts +33 -0
- package/dist/commands/gate.d.ts.map +1 -0
- package/dist/commands/gate.js +171 -0
- package/dist/commands/gate.js.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +29 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/core/MessageSentinel.d.ts +40 -0
- package/dist/core/MessageSentinel.d.ts.map +1 -1
- package/dist/core/MessageSentinel.js +80 -0
- package/dist/core/MessageSentinel.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts +7 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +114 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/SessionManager.d.ts +29 -0
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +104 -1
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/StopGateDb.d.ts +97 -0
- package/dist/core/StopGateDb.d.ts.map +1 -0
- package/dist/core/StopGateDb.js +282 -0
- package/dist/core/StopGateDb.js.map +1 -0
- package/dist/core/UnjustifiedStopGate.d.ts +145 -0
- package/dist/core/UnjustifiedStopGate.d.ts.map +1 -0
- package/dist/core/UnjustifiedStopGate.js +325 -0
- package/dist/core/UnjustifiedStopGate.js.map +1 -0
- package/dist/core/WorktreeKeyVault.d.ts +50 -0
- package/dist/core/WorktreeKeyVault.d.ts.map +1 -0
- package/dist/core/WorktreeKeyVault.js +242 -0
- package/dist/core/WorktreeKeyVault.js.map +1 -0
- package/dist/core/WorktreeManager.d.ts +250 -0
- package/dist/core/WorktreeManager.d.ts.map +1 -0
- package/dist/core/WorktreeManager.js +833 -0
- package/dist/core/WorktreeManager.js.map +1 -0
- package/dist/monitoring/DegradationReporter.d.ts +15 -0
- package/dist/monitoring/DegradationReporter.d.ts.map +1 -1
- package/dist/monitoring/DegradationReporter.js +27 -0
- package/dist/monitoring/DegradationReporter.js.map +1 -1
- package/dist/monitoring/WorktreeReaper.d.ts +52 -0
- package/dist/monitoring/WorktreeReaper.d.ts.map +1 -0
- package/dist/monitoring/WorktreeReaper.js +199 -0
- package/dist/monitoring/WorktreeReaper.js.map +1 -0
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +8 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts +18 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +24 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/middleware.d.ts.map +1 -1
- package/dist/server/middleware.js +20 -3
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/routes.d.ts +10 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +432 -0
- package/dist/server/routes.js.map +1 -1
- package/dist/server/stopGate.d.ts +77 -0
- package/dist/server/stopGate.d.ts.map +1 -0
- package/dist/server/stopGate.js +161 -0
- package/dist/server/stopGate.js.map +1 -0
- package/dist/server/worktreeRoutes.d.ts +48 -0
- package/dist/server/worktreeRoutes.d.ts.map +1 -0
- package/dist/server/worktreeRoutes.js +247 -0
- package/dist/server/worktreeRoutes.js.map +1 -0
- package/package.json +1 -1
- package/scripts/destructive-command-shim.js +218 -0
- package/scripts/gh-ruleset-install.mjs +143 -0
- package/scripts/migrate-incident-2026-04-17.mjs +138 -0
- package/scripts/worktree-commit-msg-hook.js +168 -0
- package/scripts/worktree-precommit-gate.js +144 -0
- package/src/data/builtin-manifest.json +93 -93
- package/upgrades/0.28.53.md +70 -0
- package/upgrades/side-effects/context-death-pr0a-server-infra.md +131 -0
- package/upgrades/side-effects/context-death-pr0b-sentinel-intent.md +130 -0
- package/upgrades/side-effects/context-death-pr0c-guardian-pulse-degradation-consumer.md +118 -0
- package/upgrades/side-effects/context-death-pr0d-e2e-compaction-harness.md +113 -0
- package/upgrades/side-effects/context-death-pr1-identity-text.md +110 -0
- package/upgrades/side-effects/context-death-pr2-e2e-compaction-recovery-test.md +82 -0
- package/upgrades/side-effects/context-death-pr3-gate-authority.md +193 -0
- package/upgrades/side-effects/context-death-pr4-gate-cli.md +91 -0
- package/upgrades/side-effects/parallel-dev-isolation.md +129 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorktreeKeyVault — Ed25519 + HMAC key storage for parallel-dev isolation.
|
|
3
|
+
*
|
|
4
|
+
* Per PARALLEL-DEV-ISOLATION-SPEC.md "Key management (iter 4)" + K1 (iter-4
|
|
5
|
+
* adversarial finding: Ed25519 private-key extraction via flat-file fallback).
|
|
6
|
+
*
|
|
7
|
+
* Storage strategy:
|
|
8
|
+
* 1. macOS — Keychain Services via `security` CLI.
|
|
9
|
+
* 2. Linux — libsecret via `secret-tool` CLI when available.
|
|
10
|
+
* 3. Windows — Credential Manager via `cmdkey`/`Get-Credential` (best-effort).
|
|
11
|
+
* 4. Headless fallback — flat file at `<stateDir>/local-state/keys.enc`,
|
|
12
|
+
* AES-GCM encrypted with key derived from user passphrase via Argon2id-style
|
|
13
|
+
* scrypt KDF (Node has scrypt built-in; Argon2id would require a dep).
|
|
14
|
+
* File is chmod 0600.
|
|
15
|
+
*
|
|
16
|
+
* K1: passphrase REQUIRED in headless mode. Caller can pass `headless.allowed=true`
|
|
17
|
+
* with a passphrase resolver (env var, prompt, etc.); otherwise headless = error.
|
|
18
|
+
*/
|
|
19
|
+
import crypto from 'node:crypto';
|
|
20
|
+
import { execFileSync } from 'node:child_process';
|
|
21
|
+
import fs from 'node:fs';
|
|
22
|
+
import path from 'node:path';
|
|
23
|
+
const SECURE_FILE_MODE = 0o600;
|
|
24
|
+
const SCRYPT_PARAMS = { N: 1 << 16, r: 8, p: 1 }; // ~64MB, ~250ms
|
|
25
|
+
const SCRYPT_KEY_LEN = 32;
|
|
26
|
+
const KEYCHAIN_SERVICE = 'instar.parallel-dev';
|
|
27
|
+
const KEYCHAIN_ITEM_HMAC = 'hmac-key';
|
|
28
|
+
const KEYCHAIN_ITEM_SIGNING_PRIV = 'signing-private';
|
|
29
|
+
const KEYCHAIN_ITEM_SIGNING_PUB = 'signing-public';
|
|
30
|
+
const KEYCHAIN_ITEM_MACHINE_ID = 'machine-id';
|
|
31
|
+
const KEYCHAIN_ITEM_KEY_VERSION = 'key-version';
|
|
32
|
+
// ── Backend probes ───────────────────────────────────────────────────
|
|
33
|
+
function macOsKeychainAvailable() {
|
|
34
|
+
if (process.platform !== 'darwin')
|
|
35
|
+
return false;
|
|
36
|
+
try {
|
|
37
|
+
execFileSync('security', ['list-keychains', '-d', 'user'], { stdio: 'pipe', timeout: 2000 });
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function linuxLibsecretAvailable() {
|
|
45
|
+
if (process.platform !== 'linux')
|
|
46
|
+
return false;
|
|
47
|
+
try {
|
|
48
|
+
execFileSync('secret-tool', ['--version'], { stdio: 'pipe', timeout: 2000 });
|
|
49
|
+
return !!process.env.DBUS_SESSION_BUS_ADDRESS;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// ── Backend impls ────────────────────────────────────────────────────
|
|
56
|
+
function macReadItem(account) {
|
|
57
|
+
try {
|
|
58
|
+
return execFileSync('security', [
|
|
59
|
+
'find-generic-password', '-s', KEYCHAIN_SERVICE, '-a', account, '-w',
|
|
60
|
+
], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 5000 }).trim();
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function macWriteItem(account, value) {
|
|
67
|
+
// Delete first if exists, then add (security tool doesn't have upsert)
|
|
68
|
+
try {
|
|
69
|
+
execFileSync('security', ['delete-generic-password', '-s', KEYCHAIN_SERVICE, '-a', account], {
|
|
70
|
+
stdio: 'pipe', timeout: 5000,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
catch { /* @silent-fallback-ok */ }
|
|
74
|
+
execFileSync('security', [
|
|
75
|
+
'add-generic-password', '-s', KEYCHAIN_SERVICE, '-a', account, '-w', value,
|
|
76
|
+
], { stdio: 'pipe', timeout: 5000 });
|
|
77
|
+
}
|
|
78
|
+
function linuxReadItem(account) {
|
|
79
|
+
try {
|
|
80
|
+
return execFileSync('secret-tool', ['lookup', 'service', KEYCHAIN_SERVICE, 'account', account], {
|
|
81
|
+
encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 5000,
|
|
82
|
+
}).trim();
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function linuxWriteItem(account, value) {
|
|
89
|
+
// secret-tool reads from stdin
|
|
90
|
+
execFileSync('secret-tool', ['store', '--label', `instar:${account}`,
|
|
91
|
+
'service', KEYCHAIN_SERVICE, 'account', account], {
|
|
92
|
+
input: value, timeout: 5000,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
async function deriveKeyFromPassphrase(passphrase, salt) {
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
// maxmem must be ≥ 128 * N * r (per Node docs); set generous headroom.
|
|
98
|
+
const maxmem = 128 * SCRYPT_PARAMS.N * SCRYPT_PARAMS.r * 2;
|
|
99
|
+
crypto.scrypt(passphrase, salt, SCRYPT_KEY_LEN, { ...SCRYPT_PARAMS, maxmem }, (err, derived) => {
|
|
100
|
+
if (err)
|
|
101
|
+
reject(err);
|
|
102
|
+
else
|
|
103
|
+
resolve(derived);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
async function flatFileWrite(filePath, plaintext, passphrase) {
|
|
108
|
+
const salt = crypto.randomBytes(16);
|
|
109
|
+
const key = await deriveKeyFromPassphrase(passphrase, salt);
|
|
110
|
+
const iv = crypto.randomBytes(12);
|
|
111
|
+
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
|
|
112
|
+
const ct = Buffer.concat([cipher.update(plaintext, 'utf-8'), cipher.final()]);
|
|
113
|
+
const authTag = cipher.getAuthTag();
|
|
114
|
+
const payload = {
|
|
115
|
+
version: 1,
|
|
116
|
+
kdf: 'scrypt',
|
|
117
|
+
scryptParams: SCRYPT_PARAMS,
|
|
118
|
+
salt: salt.toString('base64'),
|
|
119
|
+
iv: iv.toString('base64'),
|
|
120
|
+
ciphertext: ct.toString('base64'),
|
|
121
|
+
authTag: authTag.toString('base64'),
|
|
122
|
+
};
|
|
123
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
124
|
+
fs.writeFileSync(filePath, JSON.stringify(payload), { mode: SECURE_FILE_MODE });
|
|
125
|
+
}
|
|
126
|
+
async function flatFileRead(filePath, passphrase) {
|
|
127
|
+
const payload = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
128
|
+
if (payload.version !== 1 || payload.kdf !== 'scrypt') {
|
|
129
|
+
throw new Error(`unsupported keyvault version: ${payload.version}/${payload.kdf}`);
|
|
130
|
+
}
|
|
131
|
+
const salt = Buffer.from(payload.salt, 'base64');
|
|
132
|
+
const iv = Buffer.from(payload.iv, 'base64');
|
|
133
|
+
const ct = Buffer.from(payload.ciphertext, 'base64');
|
|
134
|
+
const authTag = Buffer.from(payload.authTag, 'base64');
|
|
135
|
+
const key = await deriveKeyFromPassphrase(passphrase, salt);
|
|
136
|
+
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
|
|
137
|
+
decipher.setAuthTag(authTag);
|
|
138
|
+
const pt = Buffer.concat([decipher.update(ct), decipher.final()]);
|
|
139
|
+
return pt.toString('utf-8');
|
|
140
|
+
}
|
|
141
|
+
// ── Public API ───────────────────────────────────────────────────────
|
|
142
|
+
export class WorktreeKeyVault {
|
|
143
|
+
stateDir;
|
|
144
|
+
opts;
|
|
145
|
+
flatFilePath;
|
|
146
|
+
constructor(opts) {
|
|
147
|
+
this.stateDir = opts.stateDir;
|
|
148
|
+
this.opts = {
|
|
149
|
+
stateDir: opts.stateDir,
|
|
150
|
+
headlessAllowed: opts.headlessAllowed ?? false,
|
|
151
|
+
forceBackend: opts.forceBackend ?? null,
|
|
152
|
+
passphraseResolver: opts.passphraseResolver ?? null,
|
|
153
|
+
};
|
|
154
|
+
this.flatFilePath = path.join(opts.stateDir, 'local-state', 'keys.enc');
|
|
155
|
+
}
|
|
156
|
+
async loadOrInit() {
|
|
157
|
+
const backend = this.detectBackend();
|
|
158
|
+
if (backend === 'keychain')
|
|
159
|
+
return this.loadOrInitKeychain();
|
|
160
|
+
if (backend === 'flatfile')
|
|
161
|
+
return this.loadOrInitFlatFile();
|
|
162
|
+
throw new Error('no keyvault backend available; set headlessAllowed=true with passphraseResolver to use flat-file fallback');
|
|
163
|
+
}
|
|
164
|
+
detectBackend() {
|
|
165
|
+
if (this.opts.forceBackend)
|
|
166
|
+
return this.opts.forceBackend;
|
|
167
|
+
if (macOsKeychainAvailable())
|
|
168
|
+
return 'keychain';
|
|
169
|
+
if (linuxLibsecretAvailable())
|
|
170
|
+
return 'keychain';
|
|
171
|
+
if (this.opts.headlessAllowed)
|
|
172
|
+
return 'flatfile';
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
async loadOrInitKeychain() {
|
|
176
|
+
const macOs = process.platform === 'darwin';
|
|
177
|
+
const read = macOs ? macReadItem : linuxReadItem;
|
|
178
|
+
const write = macOs ? macWriteItem : linuxWriteItem;
|
|
179
|
+
let hmacB64 = read(KEYCHAIN_ITEM_HMAC);
|
|
180
|
+
let signingPriv = read(KEYCHAIN_ITEM_SIGNING_PRIV);
|
|
181
|
+
let signingPub = read(KEYCHAIN_ITEM_SIGNING_PUB);
|
|
182
|
+
let machineId = read(KEYCHAIN_ITEM_MACHINE_ID);
|
|
183
|
+
let keyVersionStr = read(KEYCHAIN_ITEM_KEY_VERSION);
|
|
184
|
+
if (!hmacB64 || !signingPriv || !signingPub || !machineId) {
|
|
185
|
+
const fresh = generateFreshMaterial();
|
|
186
|
+
write(KEYCHAIN_ITEM_HMAC, fresh.hmacB64);
|
|
187
|
+
write(KEYCHAIN_ITEM_SIGNING_PRIV, fresh.signingPriv);
|
|
188
|
+
write(KEYCHAIN_ITEM_SIGNING_PUB, fresh.signingPub);
|
|
189
|
+
write(KEYCHAIN_ITEM_MACHINE_ID, fresh.machineId);
|
|
190
|
+
write(KEYCHAIN_ITEM_KEY_VERSION, '1');
|
|
191
|
+
return materialFromParts(fresh, 1);
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
hmacKey: Buffer.from(hmacB64, 'base64'),
|
|
195
|
+
signing: { privateKeyPem: signingPriv, publicKeyPem: signingPub, keyVersion: Number(keyVersionStr ?? 1) },
|
|
196
|
+
machineId,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
async loadOrInitFlatFile() {
|
|
200
|
+
if (!this.opts.passphraseResolver) {
|
|
201
|
+
throw new Error('K1: headless flat-file mode requires passphraseResolver');
|
|
202
|
+
}
|
|
203
|
+
const passphrase = await this.opts.passphraseResolver();
|
|
204
|
+
if (!passphrase || passphrase.length < 12) {
|
|
205
|
+
throw new Error('K1: passphrase must be ≥12 characters');
|
|
206
|
+
}
|
|
207
|
+
if (fs.existsSync(this.flatFilePath)) {
|
|
208
|
+
const decrypted = await flatFileRead(this.flatFilePath, passphrase);
|
|
209
|
+
const parsed = JSON.parse(decrypted);
|
|
210
|
+
return {
|
|
211
|
+
hmacKey: Buffer.from(parsed.hmacB64, 'base64'),
|
|
212
|
+
signing: { privateKeyPem: parsed.signingPriv, publicKeyPem: parsed.signingPub, keyVersion: parsed.keyVersion },
|
|
213
|
+
machineId: parsed.machineId,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
const fresh = generateFreshMaterial();
|
|
217
|
+
const payload = JSON.stringify({ ...fresh, keyVersion: 1 });
|
|
218
|
+
await flatFileWrite(this.flatFilePath, payload, passphrase);
|
|
219
|
+
return materialFromParts(fresh, 1);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
function generateFreshMaterial() {
|
|
223
|
+
const hmac = crypto.randomBytes(32);
|
|
224
|
+
const { publicKey, privateKey } = crypto.generateKeyPairSync('ed25519', {
|
|
225
|
+
publicKeyEncoding: { type: 'spki', format: 'pem' },
|
|
226
|
+
privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
|
|
227
|
+
});
|
|
228
|
+
return {
|
|
229
|
+
hmacB64: hmac.toString('base64'),
|
|
230
|
+
signingPriv: privateKey,
|
|
231
|
+
signingPub: publicKey,
|
|
232
|
+
machineId: crypto.randomUUID(),
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function materialFromParts(f, keyVersion) {
|
|
236
|
+
return {
|
|
237
|
+
hmacKey: Buffer.from(f.hmacB64, 'base64'),
|
|
238
|
+
signing: { privateKeyPem: f.signingPriv, publicKeyPem: f.signingPub, keyVersion },
|
|
239
|
+
machineId: f.machineId,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
//# sourceMappingURL=WorktreeKeyVault.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorktreeKeyVault.js","sourceRoot":"","sources":["../../src/core/WorktreeKeyVault.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorktreeManager — Topic-bound parallel-dev isolation (PARALLEL-DEV-ISOLATION-SPEC.md iter 4).
|
|
3
|
+
*
|
|
4
|
+
* Source of truth for: topic→worktree bindings, exclusive locks, fencing tokens,
|
|
5
|
+
* commit-trailer signing, force-take protocol, state reconciliation matrix.
|
|
6
|
+
*
|
|
7
|
+
* Two storage layers:
|
|
8
|
+
* - Machine-local (gitignored): bindings, locks, fencing, binding-history.db, snapshots/
|
|
9
|
+
* - Git-synced (signed): topic-branch-map (path-free), binding-history-log.jsonl
|
|
10
|
+
*
|
|
11
|
+
* Authority model:
|
|
12
|
+
* - Local advisory: pre-commit gate (cwd-vs-binding, lock-owner)
|
|
13
|
+
* - Local authoritative-on-trailer: commit-msg hook (Ed25519 sign tree+nonce+parent)
|
|
14
|
+
* - Origin authoritative: GitHub Repository Ruleset + workflow check (Ed25519 verify offline)
|
|
15
|
+
*
|
|
16
|
+
* Same-topic concurrency: EXCLUSIVE — one session per topic worktree.
|
|
17
|
+
*/
|
|
18
|
+
import { EventEmitter } from 'node:events';
|
|
19
|
+
export type WorktreeMode = 'dev' | 'read-only' | 'doc-fix' | 'platform';
|
|
20
|
+
export interface WorktreeBinding {
|
|
21
|
+
topicId: number | 'platform';
|
|
22
|
+
slug: string;
|
|
23
|
+
branch: string;
|
|
24
|
+
worktreePath: string;
|
|
25
|
+
mode: WorktreeMode;
|
|
26
|
+
status: 'active' | 'merged' | 'abandoned' | 'lost' | 'quarantined';
|
|
27
|
+
createdAt: string;
|
|
28
|
+
createdBy: string;
|
|
29
|
+
machineId: string;
|
|
30
|
+
fencingToken: string;
|
|
31
|
+
serverSignature: string;
|
|
32
|
+
}
|
|
33
|
+
export interface SessionLock {
|
|
34
|
+
schema: 'v2';
|
|
35
|
+
machineId: string;
|
|
36
|
+
bootId: string;
|
|
37
|
+
pid: number;
|
|
38
|
+
processStartTime: number;
|
|
39
|
+
sessionId: string;
|
|
40
|
+
fencingToken: string;
|
|
41
|
+
topicId: number | 'platform';
|
|
42
|
+
acquiredAt: string;
|
|
43
|
+
heartbeatAt: string;
|
|
44
|
+
serverSignature: string;
|
|
45
|
+
}
|
|
46
|
+
export interface ResolveResult {
|
|
47
|
+
cwd: string;
|
|
48
|
+
branch: string;
|
|
49
|
+
fencingToken: string;
|
|
50
|
+
sessionContextPath: string;
|
|
51
|
+
mode: WorktreeMode;
|
|
52
|
+
binding: WorktreeBinding;
|
|
53
|
+
}
|
|
54
|
+
export interface SignedTrailerResult {
|
|
55
|
+
trailers: string[];
|
|
56
|
+
nonce: string;
|
|
57
|
+
issued: number;
|
|
58
|
+
maxPushDelay: number;
|
|
59
|
+
keyVersion: number;
|
|
60
|
+
}
|
|
61
|
+
export interface WorktreeManagerOptions {
|
|
62
|
+
projectDir: string;
|
|
63
|
+
stateDir: string;
|
|
64
|
+
signingKey: {
|
|
65
|
+
privateKeyPem: string;
|
|
66
|
+
publicKeyPem: string;
|
|
67
|
+
keyVersion: number;
|
|
68
|
+
};
|
|
69
|
+
hmacKey: Buffer;
|
|
70
|
+
machineId: string;
|
|
71
|
+
bootId: string;
|
|
72
|
+
repoOriginUrl: string;
|
|
73
|
+
fsTypeProbe?: () => Promise<FsType>;
|
|
74
|
+
maxPushDelaySeconds?: number;
|
|
75
|
+
}
|
|
76
|
+
type FsType = 'apfs' | 'btrfs' | 'xfs' | 'ext4' | 'hfs+' | 'ntfs' | 'tmpfs' | 'unknown';
|
|
77
|
+
export declare class WorktreeManager extends EventEmitter {
|
|
78
|
+
private opts;
|
|
79
|
+
private bindings;
|
|
80
|
+
private locks;
|
|
81
|
+
private fencingCounter;
|
|
82
|
+
private bindingsFile;
|
|
83
|
+
private fencingFile;
|
|
84
|
+
private bindingHistoryLog;
|
|
85
|
+
private worktreesRoot;
|
|
86
|
+
private snapshotsDir;
|
|
87
|
+
private quarantineDir;
|
|
88
|
+
constructor(options: WorktreeManagerOptions);
|
|
89
|
+
/**
|
|
90
|
+
* Load persistent state from disk. Idempotent.
|
|
91
|
+
*/
|
|
92
|
+
initialize(): void;
|
|
93
|
+
private loadBindings;
|
|
94
|
+
private saveBindings;
|
|
95
|
+
private loadFencing;
|
|
96
|
+
private saveFencing;
|
|
97
|
+
private loadLocks;
|
|
98
|
+
private hmacHex;
|
|
99
|
+
private signBinding;
|
|
100
|
+
private verifySignature;
|
|
101
|
+
private signLock;
|
|
102
|
+
private verifyLockSignature;
|
|
103
|
+
private nextFencingToken;
|
|
104
|
+
/**
|
|
105
|
+
* Atomically: ensure binding for (topicId, mode) exists, ensure worktree exists,
|
|
106
|
+
* acquire exclusive lock, return the cwd to spawn into.
|
|
107
|
+
*
|
|
108
|
+
* Throws on lock contention with `code: 'LOCK_HELD'`.
|
|
109
|
+
*/
|
|
110
|
+
resolve(args: {
|
|
111
|
+
topicId: number | 'platform';
|
|
112
|
+
mode: WorktreeMode;
|
|
113
|
+
sessionId: string;
|
|
114
|
+
pid: number;
|
|
115
|
+
processStartTime: number;
|
|
116
|
+
slug?: string;
|
|
117
|
+
}): Promise<ResolveResult>;
|
|
118
|
+
/**
|
|
119
|
+
* Release the lock held by (sessionId, fencingToken). No-op if not the holder.
|
|
120
|
+
*/
|
|
121
|
+
release(args: {
|
|
122
|
+
sessionId: string;
|
|
123
|
+
fencingToken: string;
|
|
124
|
+
}): {
|
|
125
|
+
released: boolean;
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* Server-stamped heartbeat. Validates fencing token before accepting.
|
|
129
|
+
*/
|
|
130
|
+
heartbeat(args: {
|
|
131
|
+
sessionId: string;
|
|
132
|
+
fencingToken: string;
|
|
133
|
+
}): {
|
|
134
|
+
ok: boolean;
|
|
135
|
+
reason?: string;
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* Force-take an existing lock (per spec section "Force-take protocol iter 4").
|
|
139
|
+
* Performs FS snapshot + scoped stash (no --include-ignored), then bumps fencing token.
|
|
140
|
+
*/
|
|
141
|
+
forceTake(args: {
|
|
142
|
+
topicId: number | 'platform';
|
|
143
|
+
mode: WorktreeMode;
|
|
144
|
+
bySessionId: string;
|
|
145
|
+
pid: number;
|
|
146
|
+
processStartTime: number;
|
|
147
|
+
}): Promise<{
|
|
148
|
+
snapshotPath: string;
|
|
149
|
+
stashRef: string | null;
|
|
150
|
+
previousLock: SessionLock | null;
|
|
151
|
+
}>;
|
|
152
|
+
/**
|
|
153
|
+
* Issue a signed trailer set for a new commit.
|
|
154
|
+
* The hook calls this after computing treeHash + parents.
|
|
155
|
+
*/
|
|
156
|
+
signTrailer(args: {
|
|
157
|
+
sessionId: string;
|
|
158
|
+
fencingToken: string;
|
|
159
|
+
treeHash: string;
|
|
160
|
+
parents: string[];
|
|
161
|
+
}): SignedTrailerResult;
|
|
162
|
+
/**
|
|
163
|
+
* Verify a trailer set (used by GH check via /gh-check/verify-nonce).
|
|
164
|
+
* Returns ok plus a reason on failure (uniform error for oracle protection).
|
|
165
|
+
*/
|
|
166
|
+
verifyTrailer(args: {
|
|
167
|
+
trailers: Record<string, string>;
|
|
168
|
+
pushReceivedAt?: number;
|
|
169
|
+
}): {
|
|
170
|
+
ok: boolean;
|
|
171
|
+
reason?: string;
|
|
172
|
+
};
|
|
173
|
+
/**
|
|
174
|
+
* Append-only signed log with Merkle chain (K3 hardening).
|
|
175
|
+
*
|
|
176
|
+
* Each entry includes `prevEntrySha = sha256(previousLine)`, so a malicious
|
|
177
|
+
* `git rebase -i` that drops or reorders entries breaks the chain — detectable
|
|
178
|
+
* by `verifyHistoryChain()`. The chain head is periodically anchored to a
|
|
179
|
+
* GitHub Repo Variable for cross-machine tamper detection.
|
|
180
|
+
*/
|
|
181
|
+
private appendHistoryEvent;
|
|
182
|
+
/**
|
|
183
|
+
* Compute SHA-256 of the most recent log line (Merkle chain head).
|
|
184
|
+
* Returns null on empty log.
|
|
185
|
+
*/
|
|
186
|
+
computeChainHead(): string | null;
|
|
187
|
+
/**
|
|
188
|
+
* Walk the entire log and verify (a) HMAC of each line, and (b) prevEntrySha
|
|
189
|
+
* chain integrity. Returns null on success, or the first detected breach.
|
|
190
|
+
*/
|
|
191
|
+
verifyHistoryChain(): {
|
|
192
|
+
lineNumber: number;
|
|
193
|
+
reason: string;
|
|
194
|
+
} | null;
|
|
195
|
+
/**
|
|
196
|
+
* Check whether nonce was previously used for a different commit.
|
|
197
|
+
* Idempotent: returns 'unseen' or 'seen-for-same-commit' (allowed retry) or 'seen-for-different-commit'.
|
|
198
|
+
*/
|
|
199
|
+
checkNonceUnique(args: {
|
|
200
|
+
nonce: string;
|
|
201
|
+
commitSha: string;
|
|
202
|
+
}): 'unseen' | 'seen-for-same-commit' | 'seen-for-different-commit';
|
|
203
|
+
/**
|
|
204
|
+
* Bind a commit SHA to a previously-issued trailer (called post-push).
|
|
205
|
+
*/
|
|
206
|
+
recordCommitForNonce(args: {
|
|
207
|
+
nonce: string;
|
|
208
|
+
commitSha: string;
|
|
209
|
+
}): void;
|
|
210
|
+
private createBinding;
|
|
211
|
+
private fastCopyDeps;
|
|
212
|
+
private snapshotWorktree;
|
|
213
|
+
private writeLockAtomic;
|
|
214
|
+
private isLockLive;
|
|
215
|
+
/**
|
|
216
|
+
* Walk worktree state from three sources (bindings ∪ filesystem ∪ git worktree list)
|
|
217
|
+
* and return the rows that need action per the matrix.
|
|
218
|
+
*/
|
|
219
|
+
reconcile(): Array<{
|
|
220
|
+
row: string;
|
|
221
|
+
binding: WorktreeBinding | null;
|
|
222
|
+
gitWorktree: {
|
|
223
|
+
path: string;
|
|
224
|
+
} | null;
|
|
225
|
+
fsPath: string | null;
|
|
226
|
+
action: string;
|
|
227
|
+
}>;
|
|
228
|
+
private bindingKey;
|
|
229
|
+
getBinding(topicId: number | 'platform', mode: WorktreeMode): WorktreeBinding | undefined;
|
|
230
|
+
listBindings(): WorktreeBinding[];
|
|
231
|
+
getLock(worktreePath: string): SessionLock | undefined;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Build a WorktreeManager from an instar agent config + machine identity.
|
|
235
|
+
* Generates an HMAC key on first start; persists to keychain (or flat file fallback).
|
|
236
|
+
*/
|
|
237
|
+
export declare function createWorktreeManager(args: {
|
|
238
|
+
projectDir: string;
|
|
239
|
+
stateDir: string;
|
|
240
|
+
signingKey: {
|
|
241
|
+
privateKeyPem: string;
|
|
242
|
+
publicKeyPem: string;
|
|
243
|
+
keyVersion: number;
|
|
244
|
+
};
|
|
245
|
+
hmacKey: Buffer;
|
|
246
|
+
machineId: string;
|
|
247
|
+
repoOriginUrl: string;
|
|
248
|
+
}): WorktreeManager;
|
|
249
|
+
export {};
|
|
250
|
+
//# sourceMappingURL=WorktreeManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorktreeManager.d.ts","sourceRoot":"","sources":["../../src/core/WorktreeManager.ts"],"names":[],"mappings":"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"}
|