opencode-swarm 7.164.6 → 7.164.8
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/README.md +1 -1
- package/dist/background/pending-delegations.d.ts +3 -0
- package/dist/background/pr-subscriptions.d.ts +1 -8
- package/dist/cli/{coder-settlement-6qgvzx40.js → coder-settlement-qrtjv4jk.js} +14 -14
- package/dist/cli/{config-doctor-d1cbh67h.js → config-doctor-hp9dj0fg.js} +5 -3
- package/dist/cli/{core-g0cvvj3b.js → core-bmmrm36k.js} +2 -2
- package/dist/cli/{curation-policy-7f8x9yg6.js → curation-policy-de7emfqc.js} +7 -6
- package/dist/cli/{curator-drift-0r0scc8r.js → curator-drift-5sykmtf5.js} +8 -6
- package/dist/cli/{curator-q3qn89wn.js → curator-k8xdr1mn.js} +40 -38
- package/dist/cli/curator-llm-factory-pe61p0r6.js +68 -0
- package/dist/cli/{dispatch-q4v8x2pk.js → dispatch-dqybvj8v.js} +10 -6
- package/dist/cli/{evidence-summary-service-3meyb8rc.js → evidence-summary-service-qzpkdv7a.js} +20 -17
- package/dist/cli/{gate-evidence-mhc0w7vp.js → gate-evidence-jmns4e76.js} +14 -8
- package/dist/cli/guardrail-explain-vzwbmvyf.js +69 -0
- package/dist/cli/{guardrail-log-0nd1eqvz.js → guardrail-log-kckc7cg4.js} +9 -8
- package/dist/cli/{guardrail-reset-mzeyd6jh.js → guardrail-reset-acndbsv9.js} +40 -38
- package/dist/cli/hive-promoter-wvt5kk99.js +83 -0
- package/dist/cli/{index-x6zyc38w.js → index-0zjwnbze.js} +1 -1
- package/dist/cli/{index-x76mprg2.js → index-29w778rw.js} +185 -376
- package/dist/cli/{index-fxxja498.js → index-2czt53wz.js} +1 -1
- package/dist/cli/{index-pvp5tnn2.js → index-3sv8t7ca.js} +2 -2
- package/dist/cli/{index-kvb4dwgf.js → index-4pm3v7yc.js} +12 -6
- package/dist/cli/{index-jzvrvdmr.js → index-4v28t7jh.js} +4 -4
- package/dist/cli/{index-935ww10s.js → index-52m9kter.js} +1236 -1193
- package/dist/cli/index-7qefgq4j.js +71 -0
- package/dist/cli/{index-zfwd65c2.js → index-8ntf8jnj.js} +19 -18
- package/dist/cli/{index-m1nrd3yd.js → index-8psybzzf.js} +1 -1
- package/dist/cli/{index-2c3np82d.js → index-8tqqmsav.js} +1 -1
- package/dist/cli/{index-tegp2mny.js → index-93znbdam.js} +9 -5
- package/dist/cli/{index-hdapetg1.js → index-9ek9d96g.js} +3 -3
- package/dist/cli/{index-p56xc59p.js → index-9ydhzegh.js} +28 -17
- package/dist/cli/{index-ew99d4y6.js → index-apdp9bc1.js} +1 -1
- package/dist/cli/{index-12xzj0hm.js → index-b10yvv6h.js} +4 -4
- package/dist/cli/{index-zjg5ajf5.js → index-bv90qkyw.js} +72 -48
- package/dist/cli/{index-zypacgjc.js → index-bz8vsc8r.js} +5 -5
- package/dist/cli/{index-4k16cz8r.js → index-bzesypf5.js} +36 -27
- package/dist/cli/{index-ay9cr8tr.js → index-chcv8c7n.js} +1 -1
- package/dist/cli/index-cw912re7.js +200 -0
- package/dist/cli/{index-ty3vtqe2.js → index-espcjyrx.js} +4 -4
- package/dist/cli/{index-gwg7a00b.js → index-g2e8b3wm.js} +20 -15
- package/dist/cli/{index-rysxqae0.js → index-ghnbpez3.js} +7 -7
- package/dist/cli/{index-t1nkr7cz.js → index-gkqrk8dd.js} +2 -2
- package/dist/cli/{index-1dz8hv7p.js → index-kvq1e82k.js} +3 -3
- package/dist/cli/{index-ze5zyv28.js → index-mr3h3sm5.js} +2 -2
- package/dist/cli/{index-zaab1wz9.js → index-n4fzmqz8.js} +3 -1
- package/dist/cli/{index-g5714mpv.js → index-px4a2ve0.js} +17 -8
- package/dist/cli/index-ry16d01s.js +107 -0
- package/dist/cli/{index-j3hsjynw.js → index-s3z936wh.js} +100 -97
- package/dist/cli/{index-yh8wxegw.js → index-s6ejwhew.js} +21 -11
- package/dist/cli/{index-b0m3efpf.js → index-sxxh4ams.js} +2 -2
- package/dist/cli/{index-cyhw0der.js → index-t1qzjhnj.js} +13 -13
- package/dist/cli/{index-3f7hqtgg.js → index-w3gtqey0.js} +4 -1
- package/dist/cli/{index-9qvmsyab.js → index-wgqeqy68.js} +2 -2
- package/dist/cli/{index-y4z0rhsa.js → index-whz6am0v.js} +42 -40
- package/dist/cli/{index-g94qqwnz.js → index-wtnx33hz.js} +2 -2
- package/dist/cli/{index-j645xpsm.js → index-y6s0gpn3.js} +12 -5
- package/dist/cli/{index-6f9yvd67.js → index-ya4ta1pd.js} +2 -2
- package/dist/cli/{index-5p1tzpwh.js → index-ypjffdrg.js} +3 -2
- package/dist/cli/{index-59hvr3f4.js → index-yscwyq3t.js} +9 -6
- package/dist/cli/{index-7v3bb0h3.js → index-yzn1fm9a.js} +1 -1
- package/dist/cli/{index-qdbgc16x.js → index-z39vxvdx.js} +20 -12
- package/dist/cli/index.js +40 -38
- package/dist/cli/{knowledge-escalator-aca0nhqg.js → knowledge-escalator-h9834mrp.js} +15 -14
- package/dist/cli/{knowledge-events-n5t313ht.js → knowledge-events-e8hrmjf0.js} +13 -12
- package/dist/cli/{knowledge-link-8ea4ksda.js → knowledge-link-hhnmc4g1.js} +6 -5
- package/dist/cli/{knowledge-store-j97ejf6a.js → knowledge-store-w3w9gchr.js} +7 -6
- package/dist/cli/{knowledge-validator-01evhydg.js → knowledge-validator-exd900vc.js} +9 -8
- package/dist/cli/{model-preflight-pmnbfzjv.js → model-preflight-bq035tfh.js} +1 -1
- package/dist/cli/{pending-delegations-w73abdk3.js → pending-delegations-p4ak2e86.js} +7 -7
- package/dist/cli/{pr-subscriptions-05dzvavk.js → pr-subscriptions-73fs8y3n.js} +7 -6
- package/dist/cli/{pr-workflow-gate-t0tnkx5f.js → pr-workflow-gate-pvt2ra6e.js} +40 -38
- package/dist/cli/{runner-fh7t0mn9.js → runner-5qqh83e2.js} +6 -6
- package/dist/cli/{scan-cursor-63zx2qd8.js → scan-cursor-ysd8b563.js} +8 -7
- package/dist/cli/{schema-t1scx08g.js → schema-mbb9g4w4.js} +2 -2
- package/dist/cli/{scope-persistence-1a5qmchf.js → scope-persistence-jrbnhxvx.js} +12 -10
- package/dist/cli/{skill-generator-7werbwgv.js → skill-generator-b4ng5xky.js} +17 -16
- package/dist/cli/{sqlite-loader-8zefc142.js → sqlite-loader-xrnf6bq8.js} +1 -1
- package/dist/cli/{telemetry-j14cj552.js → telemetry-85gxedng.js} +1 -1
- package/dist/cli/{workspace-snapshot-yq0tc49d.js → workspace-snapshot-eh18vgkn.js} +2 -1
- package/dist/cli/{worktree-collision-ownership-wzdzky33.js → worktree-collision-ownership-ns8p2fks.js} +12 -15
- package/dist/cli/{worktree-isolation-m02ay3kg.js → worktree-isolation-j6zxhjab.js} +40 -38
- package/dist/db/canonical-project.d.ts +10 -3
- package/dist/db/driver-parity.d.ts +12 -0
- package/dist/db/project-db.d.ts +4 -0
- package/dist/evidence/task-gate-repair.d.ts +1 -1
- package/dist/gate-evidence.d.ts +19 -1
- package/dist/index.js +581 -581
- package/dist/plan/ledger.d.ts +2 -0
- package/dist/tools/pre-check-batch.d.ts +1 -1
- package/dist/utils/canonical-root.d.ts +21 -1
- package/dist/utils/filesystem-identity.d.ts +59 -0
- package/package.json +2 -1
- package/dist/cli/curator-llm-factory-dw7md4nr.js +0 -66
- package/dist/cli/guardrail-explain-6cbszhw1.js +0 -67
- package/dist/cli/hive-promoter-w7g879cm.js +0 -81
- package/dist/cli/index-ddszzne4.js +0 -42
|
@@ -2,23 +2,27 @@
|
|
|
2
2
|
import {
|
|
3
3
|
computePlanStructureHash,
|
|
4
4
|
derivePlanId
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-y6s0gpn3.js";
|
|
6
|
+
import {
|
|
7
|
+
canonicalExistingFilesystemPath,
|
|
8
|
+
legacyCanonicalExistingFilesystemPath
|
|
9
|
+
} from "./index-ry16d01s.js";
|
|
6
10
|
import {
|
|
7
11
|
appendCoreEventSync
|
|
8
|
-
} from "./index-
|
|
12
|
+
} from "./index-3sv8t7ca.js";
|
|
9
13
|
import {
|
|
10
14
|
unsafePathTextReason
|
|
11
15
|
} from "./index-556ja8an.js";
|
|
12
16
|
import {
|
|
13
17
|
PlanSchema
|
|
14
|
-
} from "./index-
|
|
18
|
+
} from "./index-apdp9bc1.js";
|
|
15
19
|
import {
|
|
16
20
|
assertProjectRoot
|
|
17
|
-
} from "./index-
|
|
21
|
+
} from "./index-2czt53wz.js";
|
|
18
22
|
import {
|
|
19
23
|
atomicWriteSwarmFile,
|
|
20
24
|
atomicWriteSwarmFileSync
|
|
21
|
-
} from "./index-
|
|
25
|
+
} from "./index-t1qzjhnj.js";
|
|
22
26
|
import {
|
|
23
27
|
require_proper_lockfile
|
|
24
28
|
} from "./index-7g4c7s5r.js";
|
|
@@ -29,12 +33,11 @@ import {
|
|
|
29
33
|
// src/scope/scope-persistence.ts
|
|
30
34
|
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
31
35
|
import { createHash } from "crypto";
|
|
32
|
-
import * as
|
|
36
|
+
import * as fs from "fs";
|
|
33
37
|
import * as path2 from "path";
|
|
34
38
|
|
|
35
39
|
// src/scope/scope-binding.ts
|
|
36
40
|
import { randomUUID } from "crypto";
|
|
37
|
-
import * as fs from "fs";
|
|
38
41
|
import * as path from "path";
|
|
39
42
|
var MAX_PENDING_SCOPE_BINDINGS = 256;
|
|
40
43
|
var DEFAULT_SCOPE_BINDING_TTL_MS = 60 * 60 * 1000;
|
|
@@ -50,12 +53,7 @@ function isScopeBindingIdentity(value) {
|
|
|
50
53
|
return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f-]{27}$/i.test(value);
|
|
51
54
|
}
|
|
52
55
|
function canonicalWorkspaceIdentity(directory) {
|
|
53
|
-
|
|
54
|
-
const real = fs.realpathSync(directory).replace(/\\/g, "/");
|
|
55
|
-
return process.platform === "win32" ? real.toLowerCase() : real;
|
|
56
|
-
} catch {
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
56
|
+
return canonicalExistingFilesystemPath(directory);
|
|
59
57
|
}
|
|
60
58
|
function normalizeScopePath(value) {
|
|
61
59
|
if (typeof value !== "string")
|
|
@@ -346,14 +344,14 @@ function isSafeTaskId(taskId) {
|
|
|
346
344
|
}
|
|
347
345
|
function isScopesDirSafe(directory, scopesDir) {
|
|
348
346
|
try {
|
|
349
|
-
const resolvedWorkspace =
|
|
347
|
+
const resolvedWorkspace = fs.realpathSync(directory);
|
|
350
348
|
const expectedSwarmDir = path2.join(resolvedWorkspace, ".swarm");
|
|
351
349
|
const expectedScopesDir = path2.join(expectedSwarmDir, "scopes");
|
|
352
|
-
const swarmStat =
|
|
353
|
-
const scopesStat =
|
|
350
|
+
const swarmStat = fs.lstatSync(expectedSwarmDir);
|
|
351
|
+
const scopesStat = fs.lstatSync(expectedScopesDir);
|
|
354
352
|
if (!swarmStat.isDirectory() || swarmStat.isSymbolicLink() || !scopesStat.isDirectory() || scopesStat.isSymbolicLink())
|
|
355
353
|
return false;
|
|
356
|
-
const resolvedScopes =
|
|
354
|
+
const resolvedScopes = fs.realpathSync(scopesDir);
|
|
357
355
|
if (normalizePathForComparison(resolvedScopes) !== normalizePathForComparison(expectedScopesDir))
|
|
358
356
|
return false;
|
|
359
357
|
const rel = path2.relative(resolvedWorkspace, resolvedScopes);
|
|
@@ -364,24 +362,24 @@ function isScopesDirSafe(directory, scopesDir) {
|
|
|
364
362
|
}
|
|
365
363
|
function resolveSafeScopeFileForUnlink(directory, targetPath) {
|
|
366
364
|
try {
|
|
367
|
-
const resolvedWorkspace =
|
|
365
|
+
const resolvedWorkspace = fs.realpathSync(directory);
|
|
368
366
|
const scopesDir = path2.join(resolvedWorkspace, SCOPES_DIR);
|
|
369
367
|
if (!isScopesDirSafe(resolvedWorkspace, scopesDir))
|
|
370
368
|
return null;
|
|
371
369
|
const candidate = path2.resolve(targetPath);
|
|
372
|
-
const resolvedCandidate =
|
|
370
|
+
const resolvedCandidate = fs.realpathSync(candidate);
|
|
373
371
|
if (normalizePathForComparison(path2.dirname(candidate)) !== normalizePathForComparison(scopesDir) || normalizePathForComparison(resolvedCandidate) !== normalizePathForComparison(candidate))
|
|
374
372
|
return null;
|
|
375
373
|
const relative2 = path2.relative(resolvedWorkspace, resolvedCandidate);
|
|
376
374
|
if (relative2.length === 0 || relative2 === ".." || relative2.startsWith(`..${path2.sep}`) || path2.isAbsolute(relative2))
|
|
377
375
|
return null;
|
|
378
|
-
const leafStat =
|
|
376
|
+
const leafStat = fs.lstatSync(candidate);
|
|
379
377
|
if (!leafStat.isFile() || leafStat.isSymbolicLink())
|
|
380
378
|
return null;
|
|
381
379
|
if (!isScopesDirSafe(resolvedWorkspace, scopesDir))
|
|
382
380
|
return null;
|
|
383
|
-
const finalResolvedCandidate =
|
|
384
|
-
const finalLeafStat =
|
|
381
|
+
const finalResolvedCandidate = fs.realpathSync(candidate);
|
|
382
|
+
const finalLeafStat = fs.lstatSync(candidate);
|
|
385
383
|
if (normalizePathForComparison(finalResolvedCandidate) !== normalizePathForComparison(candidate) || !finalLeafStat.isFile() || finalLeafStat.isSymbolicLink() || finalLeafStat.dev !== leafStat.dev || finalLeafStat.ino !== leafStat.ino)
|
|
386
384
|
return null;
|
|
387
385
|
return candidate;
|
|
@@ -431,10 +429,10 @@ function ensureLockTargetSync(targetPath) {
|
|
|
431
429
|
if (path2.basename(scopesDir) !== "scopes" || path2.basename(swarmDir) !== ".swarm")
|
|
432
430
|
return false;
|
|
433
431
|
assertProjectRoot(path2.dirname(swarmDir));
|
|
434
|
-
|
|
435
|
-
const nofollow =
|
|
436
|
-
const fd =
|
|
437
|
-
|
|
432
|
+
fs.mkdirSync(path2.dirname(targetPath), { recursive: true });
|
|
433
|
+
const nofollow = fs.constants.O_NOFOLLOW ?? 0;
|
|
434
|
+
const fd = fs.openSync(targetPath, fs.constants.O_WRONLY | fs.constants.O_CREAT | nofollow);
|
|
435
|
+
fs.closeSync(fd);
|
|
438
436
|
return true;
|
|
439
437
|
} catch {
|
|
440
438
|
return false;
|
|
@@ -444,25 +442,25 @@ function exactBindingPrefix(taskId) {
|
|
|
444
442
|
return `binding-${taskId}-`;
|
|
445
443
|
}
|
|
446
444
|
function readBoundedFile(filePath) {
|
|
447
|
-
const nofollow =
|
|
445
|
+
const nofollow = fs.constants.O_NOFOLLOW ?? 0;
|
|
448
446
|
let fd;
|
|
449
447
|
try {
|
|
450
|
-
fd =
|
|
448
|
+
fd = fs.openSync(filePath, fs.constants.O_RDONLY | nofollow);
|
|
451
449
|
} catch {
|
|
452
450
|
return null;
|
|
453
451
|
}
|
|
454
452
|
try {
|
|
455
|
-
const stat =
|
|
453
|
+
const stat = fs.fstatSync(fd);
|
|
456
454
|
if (!stat.isFile() || stat.size <= 0 || stat.size > MAX_SCOPE_BYTES)
|
|
457
455
|
return null;
|
|
458
456
|
const buffer = Buffer.alloc(stat.size);
|
|
459
|
-
|
|
457
|
+
fs.readSync(fd, buffer, 0, stat.size, 0);
|
|
460
458
|
return buffer.toString("utf8");
|
|
461
459
|
} catch {
|
|
462
460
|
return null;
|
|
463
461
|
} finally {
|
|
464
462
|
try {
|
|
465
|
-
|
|
463
|
+
fs.closeSync(fd);
|
|
466
464
|
} catch {}
|
|
467
465
|
}
|
|
468
466
|
}
|
|
@@ -472,8 +470,9 @@ function deterministicIdentity(value) {
|
|
|
472
470
|
}
|
|
473
471
|
function validateScopeBindingPayload(directory, parsed, options = {}) {
|
|
474
472
|
const workspaceIdentity = canonicalWorkspaceIdentity(directory);
|
|
473
|
+
const legacyWorkspaceIdentity = legacyCanonicalExistingFilesystemPath(directory);
|
|
475
474
|
const files = Array.isArray(parsed.files) ? normalizeScopeFiles(parsed.files.filter((file) => typeof file === "string")) : null;
|
|
476
|
-
if (parsed.version !== 2 || !workspaceIdentity || parsed.workspaceIdentity !== workspaceIdentity || !isSafeTaskId(parsed.taskId ?? "") || !files || typeof parsed.planId !== "string" || !parsed.planId || typeof parsed.planStructureHash !== "string" || !parsed.planStructureHash || typeof parsed.ownerSessionId !== "string" || !parsed.ownerSessionId.trim() || typeof parsed.ownerMessageId !== "string" || !parsed.ownerMessageId.trim() || !["declaration", "pending_child", "active"].includes(parsed.activation ?? "") || ![
|
|
475
|
+
if (parsed.version !== 2 || !workspaceIdentity || parsed.workspaceIdentity !== workspaceIdentity && parsed.workspaceIdentity !== legacyWorkspaceIdentity || !isSafeTaskId(parsed.taskId ?? "") || !files || typeof parsed.planId !== "string" || !parsed.planId || typeof parsed.planStructureHash !== "string" || !parsed.planStructureHash || typeof parsed.ownerSessionId !== "string" || !parsed.ownerSessionId.trim() || typeof parsed.ownerMessageId !== "string" || !parsed.ownerMessageId.trim() || !["declaration", "pending_child", "active"].includes(parsed.activation ?? "") || ![
|
|
477
476
|
"declare_scope",
|
|
478
477
|
"plan",
|
|
479
478
|
"file_directive",
|
|
@@ -523,8 +522,8 @@ function validateScopeBindingPayload(directory, parsed, options = {}) {
|
|
|
523
522
|
leaseStartedAt
|
|
524
523
|
};
|
|
525
524
|
}
|
|
526
|
-
function exactFilenameMatches(filePath, binding) {
|
|
527
|
-
return normalizePathForComparison(filePath) === normalizePathForComparison(getBindingFilePath(
|
|
525
|
+
function exactFilenameMatches(directory, filePath, binding) {
|
|
526
|
+
return normalizePathForComparison(filePath) === normalizePathForComparison(getBindingFilePath(directory, binding));
|
|
528
527
|
}
|
|
529
528
|
function migrateLegacyBindingsSync(directory, scanCapacity = bindingFileScanCapacity) {
|
|
530
529
|
try {
|
|
@@ -537,7 +536,7 @@ function migrateLegacyBindingsSync(directory, scanCapacity = bindingFileScanCapa
|
|
|
537
536
|
return false;
|
|
538
537
|
let names;
|
|
539
538
|
try {
|
|
540
|
-
names =
|
|
539
|
+
names = fs.readdirSync(scopesDir).sort();
|
|
541
540
|
} catch {
|
|
542
541
|
return true;
|
|
543
542
|
}
|
|
@@ -568,14 +567,14 @@ function migrateLegacyBindingsSync(directory, scanCapacity = bindingFileScanCapa
|
|
|
568
567
|
const ownerHash = binding ? createHash("sha256").update(binding.ownerSessionId).digest("hex").slice(0, 24) : "";
|
|
569
568
|
const valid = binding && binding.taskId === match[1] && ownerHash.toLowerCase() === match[2].toLowerCase() && normalizePathForComparison(getLegacyBindingFilePath(directory, binding.taskId, binding.ownerSessionId)) === normalizePathForComparison(legacyPath);
|
|
570
569
|
const archiveDir = path2.join(scopesDir, "archive");
|
|
571
|
-
|
|
572
|
-
const archiveStat =
|
|
570
|
+
fs.mkdirSync(archiveDir, { recursive: true });
|
|
571
|
+
const archiveStat = fs.lstatSync(archiveDir);
|
|
573
572
|
if (!archiveStat.isDirectory() || archiveStat.isSymbolicLink())
|
|
574
573
|
return false;
|
|
575
574
|
const archiveDigest = createHash("sha256").update(raw ?? name).digest("hex").slice(0, 32);
|
|
576
575
|
if (valid && binding) {
|
|
577
576
|
const exactPath = getBindingFilePath(directory, binding);
|
|
578
|
-
if (!
|
|
577
|
+
if (!fs.existsSync(exactPath)) {
|
|
579
578
|
atomicWriteSwarmFileSync(exactPath, JSON.stringify(binding, null, 2));
|
|
580
579
|
} else {
|
|
581
580
|
const existingRaw = readBoundedFile(exactPath);
|
|
@@ -585,24 +584,24 @@ function migrateLegacyBindingsSync(directory, scanCapacity = bindingFileScanCapa
|
|
|
585
584
|
}
|
|
586
585
|
}
|
|
587
586
|
const archivePath = path2.join(archiveDir, `${valid ? "migrated" : "quarantined"}-${archiveDigest}.json`);
|
|
588
|
-
if (!
|
|
589
|
-
|
|
587
|
+
if (!fs.existsSync(archivePath))
|
|
588
|
+
fs.renameSync(legacyPath, archivePath);
|
|
590
589
|
else
|
|
591
|
-
|
|
592
|
-
|
|
590
|
+
fs.unlinkSync(legacyPath);
|
|
591
|
+
fs.writeFileSync(`${archivePath}.receipt.json`, JSON.stringify({
|
|
593
592
|
version: 1,
|
|
594
593
|
legacyName: name,
|
|
595
594
|
result: valid ? "migrated" : "quarantined",
|
|
596
595
|
bindingId: binding?.bindingId,
|
|
597
596
|
generationId: binding?.generationId
|
|
598
597
|
}, null, 2));
|
|
599
|
-
const archiveEntries =
|
|
598
|
+
const archiveEntries = fs.readdirSync(archiveDir).sort();
|
|
600
599
|
for (const stale of archiveEntries.slice(0, Math.max(0, archiveEntries.length - 2 * MAX_DURABLE_TOMBSTONES))) {
|
|
601
600
|
const stalePath = path2.join(archiveDir, stale);
|
|
602
601
|
try {
|
|
603
|
-
const stat =
|
|
602
|
+
const stat = fs.lstatSync(stalePath);
|
|
604
603
|
if (stat.isFile() && !stat.isSymbolicLink())
|
|
605
|
-
|
|
604
|
+
fs.unlinkSync(stalePath);
|
|
606
605
|
} catch {}
|
|
607
606
|
}
|
|
608
607
|
} catch {
|
|
@@ -630,7 +629,7 @@ async function writeScopeToDisk(directory, taskId, files, ttlMs = DEFAULT_TTL_MS
|
|
|
630
629
|
const scopesDir = getScopesDir(directory);
|
|
631
630
|
const scopePath = getScopeFilePath(directory, taskId);
|
|
632
631
|
try {
|
|
633
|
-
|
|
632
|
+
fs.mkdirSync(scopesDir, { recursive: true });
|
|
634
633
|
} catch {
|
|
635
634
|
return;
|
|
636
635
|
}
|
|
@@ -646,10 +645,10 @@ async function writeScopeToDisk(directory, taskId, files, ttlMs = DEFAULT_TTL_MS
|
|
|
646
645
|
};
|
|
647
646
|
const content = JSON.stringify(payload, null, 2);
|
|
648
647
|
try {
|
|
649
|
-
const flags =
|
|
650
|
-
const nofollow =
|
|
651
|
-
const fd =
|
|
652
|
-
|
|
648
|
+
const flags = fs.constants.O_WRONLY | fs.constants.O_CREAT;
|
|
649
|
+
const nofollow = fs.constants.O_NOFOLLOW ?? 0;
|
|
650
|
+
const fd = fs.openSync(scopePath, flags | nofollow);
|
|
651
|
+
fs.closeSync(fd);
|
|
653
652
|
} catch {
|
|
654
653
|
return;
|
|
655
654
|
}
|
|
@@ -687,7 +686,7 @@ async function writeScopeBindingToDisk(directory, binding) {
|
|
|
687
686
|
const scopesDir = getScopesDir(directory);
|
|
688
687
|
const scopePath = getBindingFilePath(directory, binding);
|
|
689
688
|
try {
|
|
690
|
-
|
|
689
|
+
fs.mkdirSync(scopesDir, { recursive: true });
|
|
691
690
|
} catch {
|
|
692
691
|
return persistenceFailure("Could not create the durable scope store.");
|
|
693
692
|
}
|
|
@@ -695,10 +694,10 @@ async function writeScopeBindingToDisk(directory, binding) {
|
|
|
695
694
|
return persistenceFailure("The durable scope store failed containment checks.");
|
|
696
695
|
const content = JSON.stringify({ ...binding, files }, null, 2);
|
|
697
696
|
try {
|
|
698
|
-
const flags =
|
|
699
|
-
const nofollow =
|
|
700
|
-
const fd =
|
|
701
|
-
|
|
697
|
+
const flags = fs.constants.O_WRONLY | fs.constants.O_CREAT;
|
|
698
|
+
const nofollow = fs.constants.O_NOFOLLOW ?? 0;
|
|
699
|
+
const fd = fs.openSync(scopePath, flags | nofollow);
|
|
700
|
+
fs.closeSync(fd);
|
|
702
701
|
} catch {
|
|
703
702
|
return persistenceFailure("Could not create the exact generation record.");
|
|
704
703
|
}
|
|
@@ -791,7 +790,7 @@ function clearScopeBindingFromDisk(input) {
|
|
|
791
790
|
}
|
|
792
791
|
let release;
|
|
793
792
|
try {
|
|
794
|
-
const resolvedWorkspace =
|
|
793
|
+
const resolvedWorkspace = fs.realpathSync(input.directory);
|
|
795
794
|
const scopePath = getBindingFilePath(resolvedWorkspace, input.binding);
|
|
796
795
|
if (!isScopesDirSafe(resolvedWorkspace, getScopesDir(resolvedWorkspace)))
|
|
797
796
|
return persistenceFailure("The durable scope store failed containment checks.");
|
|
@@ -810,7 +809,7 @@ function clearScopeBindingFromDisk(input) {
|
|
|
810
809
|
const raw = readBoundedFile(scopePath);
|
|
811
810
|
if (!raw) {
|
|
812
811
|
try {
|
|
813
|
-
|
|
812
|
+
fs.unlinkSync(retirementIntentPath);
|
|
814
813
|
} catch {}
|
|
815
814
|
return localRetirement ? { ok: true, value: localRetirement } : persistenceFailure("Exact generation disappeared before serialized retirement.");
|
|
816
815
|
}
|
|
@@ -820,7 +819,7 @@ function clearScopeBindingFromDisk(input) {
|
|
|
820
819
|
if (current.lifecycleState !== "live") {
|
|
821
820
|
installScopeBindingTombstone(current);
|
|
822
821
|
try {
|
|
823
|
-
|
|
822
|
+
fs.unlinkSync(retirementIntentPath);
|
|
824
823
|
} catch {}
|
|
825
824
|
return { ok: true, value: current };
|
|
826
825
|
}
|
|
@@ -839,7 +838,7 @@ function clearScopeBindingFromDisk(input) {
|
|
|
839
838
|
return persistenceFailure("Serialized retirement verification failed.");
|
|
840
839
|
installScopeBindingTombstone(verified);
|
|
841
840
|
try {
|
|
842
|
-
|
|
841
|
+
fs.unlinkSync(retirementIntentPath);
|
|
843
842
|
} catch {}
|
|
844
843
|
scheduleScopeBindingMaintenance(resolvedWorkspace);
|
|
845
844
|
return { ok: true, value: verified };
|
|
@@ -924,7 +923,7 @@ async function refreshScopeBindingLease(input) {
|
|
|
924
923
|
return persistenceFailure("Invalid refresh identity.");
|
|
925
924
|
}
|
|
926
925
|
const generationLockPath = getGenerationLockPath(scopePath);
|
|
927
|
-
const createdGenerationLockTarget = !
|
|
926
|
+
const createdGenerationLockTarget = !fs.existsSync(generationLockPath);
|
|
928
927
|
if (!await ensureLockTarget(generationLockPath))
|
|
929
928
|
return persistenceFailure("Could not prepare refresh lock.");
|
|
930
929
|
let release;
|
|
@@ -976,9 +975,9 @@ async function refreshScopeBindingLease(input) {
|
|
|
976
975
|
try {
|
|
977
976
|
await release();
|
|
978
977
|
} catch {}
|
|
979
|
-
if (createdGenerationLockTarget && !
|
|
978
|
+
if (createdGenerationLockTarget && !fs.existsSync(scopePath)) {
|
|
980
979
|
try {
|
|
981
|
-
|
|
980
|
+
fs.unlinkSync(generationLockPath);
|
|
982
981
|
} catch {}
|
|
983
982
|
}
|
|
984
983
|
}
|
|
@@ -990,7 +989,7 @@ function claimBaseName(binding) {
|
|
|
990
989
|
function readAllExactBindings(directory, options = {}) {
|
|
991
990
|
const scopesDir = getScopesDir(directory);
|
|
992
991
|
try {
|
|
993
|
-
|
|
992
|
+
fs.lstatSync(scopesDir);
|
|
994
993
|
} catch (error) {
|
|
995
994
|
return error.code === "ENOENT" ? [] : null;
|
|
996
995
|
}
|
|
@@ -1001,7 +1000,7 @@ function readAllExactBindings(directory, options = {}) {
|
|
|
1001
1000
|
return null;
|
|
1002
1001
|
let names;
|
|
1003
1002
|
try {
|
|
1004
|
-
names =
|
|
1003
|
+
names = fs.readdirSync(scopesDir).sort();
|
|
1005
1004
|
} catch {
|
|
1006
1005
|
return [];
|
|
1007
1006
|
}
|
|
@@ -1017,7 +1016,7 @@ function readAllExactBindings(directory, options = {}) {
|
|
|
1017
1016
|
continue;
|
|
1018
1017
|
try {
|
|
1019
1018
|
const binding = validateScopeBindingPayload(directory, JSON.parse(raw));
|
|
1020
|
-
if (binding && exactFilenameMatches(filePath, binding)) {
|
|
1019
|
+
if (binding && exactFilenameMatches(directory, filePath, binding)) {
|
|
1021
1020
|
if (hasDurableRetirementIntent(filePath, binding)) {
|
|
1022
1021
|
let createdAt = Date.now();
|
|
1023
1022
|
try {
|
|
@@ -1134,7 +1133,7 @@ async function claimScopeBindingForChildDurably(input) {
|
|
|
1134
1133
|
if (!receiptWinner)
|
|
1135
1134
|
return persistenceFailure("Claim receipt has no verified successor; pending remains fail-closed for restart reconciliation.");
|
|
1136
1135
|
if (receiptWinner.lifecycleState !== "live" || receiptWinner.expiresAt <= Date.now()) {
|
|
1137
|
-
|
|
1136
|
+
fs.writeFileSync(claimPath, "");
|
|
1138
1137
|
receipt = null;
|
|
1139
1138
|
}
|
|
1140
1139
|
}
|
|
@@ -1287,7 +1286,9 @@ async function replaceExistingScopeDeclaration(input) {
|
|
|
1287
1286
|
}
|
|
1288
1287
|
}
|
|
1289
1288
|
function scheduleScopeBindingMaintenance(directory) {
|
|
1290
|
-
const key =
|
|
1289
|
+
const key = canonicalExistingFilesystemPath(directory);
|
|
1290
|
+
if (key === null)
|
|
1291
|
+
return;
|
|
1291
1292
|
if (maintenanceJobs.has(key))
|
|
1292
1293
|
return;
|
|
1293
1294
|
while (maintenanceJobs.size >= MAX_MAINTENANCE_JOBS) {
|
|
@@ -1304,7 +1305,9 @@ function scheduleScopeBindingMaintenance(directory) {
|
|
|
1304
1305
|
maintenanceJobs.set(key, job);
|
|
1305
1306
|
}
|
|
1306
1307
|
async function flushScopeBindingMaintenance(directory) {
|
|
1307
|
-
const key = directory ?
|
|
1308
|
+
const key = directory ? canonicalExistingFilesystemPath(directory) : undefined;
|
|
1309
|
+
if (directory && key === null)
|
|
1310
|
+
return;
|
|
1308
1311
|
const job = key ? maintenanceJobs.get(key) : undefined;
|
|
1309
1312
|
await Promise.all(job ? [job] : [...maintenanceJobs.values()]);
|
|
1310
1313
|
}
|
|
@@ -1336,7 +1339,7 @@ async function pruneScopeBindingTombstones(directory) {
|
|
|
1336
1339
|
const finalized = await tombstoneScopeBinding(directory, binding, "revoked");
|
|
1337
1340
|
if (finalized.ok)
|
|
1338
1341
|
try {
|
|
1339
|
-
|
|
1342
|
+
fs.unlinkSync(getRetirementIntentPath(filePath));
|
|
1340
1343
|
} catch {}
|
|
1341
1344
|
}
|
|
1342
1345
|
all = readAllExactBindings(directory, {
|
|
@@ -1368,7 +1371,7 @@ async function pruneScopeBindingTombstones(directory) {
|
|
|
1368
1371
|
const latest = latestRaw ? validateScopeBindingPayload(directory, JSON.parse(latestRaw)) : null;
|
|
1369
1372
|
if (!latest || latest.generationId !== binding.generationId || latest.revision !== binding.revision || latest.lifecycleState === "live" && !hasDurableRetirementIntent(filePath, latest))
|
|
1370
1373
|
continue;
|
|
1371
|
-
|
|
1374
|
+
fs.unlinkSync(filePath);
|
|
1372
1375
|
removedExact = true;
|
|
1373
1376
|
removed++;
|
|
1374
1377
|
} catch {} finally {
|
|
@@ -1377,18 +1380,18 @@ async function pruneScopeBindingTombstones(directory) {
|
|
|
1377
1380
|
await releaseExact();
|
|
1378
1381
|
} catch {}
|
|
1379
1382
|
}
|
|
1380
|
-
if (removedExact && !
|
|
1383
|
+
if (removedExact && !fs.existsSync(filePath)) {
|
|
1381
1384
|
try {
|
|
1382
|
-
|
|
1385
|
+
fs.unlinkSync(exactLockPath);
|
|
1383
1386
|
} catch {}
|
|
1384
1387
|
try {
|
|
1385
|
-
|
|
1388
|
+
fs.unlinkSync(getRetirementIntentPath(filePath));
|
|
1386
1389
|
} catch {}
|
|
1387
1390
|
}
|
|
1388
1391
|
}
|
|
1389
1392
|
let receiptNames = [];
|
|
1390
1393
|
try {
|
|
1391
|
-
receiptNames =
|
|
1394
|
+
receiptNames = fs.readdirSync(getScopesDir(directory)).filter((name) => /^claim-[a-f0-9]{40}\.json$/i.test(name)).slice(0, MAX_BINDING_FILES_TO_SCAN);
|
|
1392
1395
|
} catch {}
|
|
1393
1396
|
for (const name of receiptNames) {
|
|
1394
1397
|
const receiptPath = path2.join(getScopesDir(directory), name);
|
|
@@ -1407,9 +1410,9 @@ async function pruneScopeBindingTombstones(directory) {
|
|
|
1407
1410
|
receipt = JSON.parse(raw);
|
|
1408
1411
|
} catch {}
|
|
1409
1412
|
const winner = receipt ? all.find((binding) => binding.generationId === receipt?.winnerGenerationId) : undefined;
|
|
1410
|
-
const old = Date.now() -
|
|
1413
|
+
const old = Date.now() - fs.statSync(receiptPath).mtimeMs > MAX_TOMBSTONE_AGE_MS;
|
|
1411
1414
|
if (old || Boolean(winner && (winner.lifecycleState !== "live" || winner.expiresAt <= Date.now()))) {
|
|
1412
|
-
|
|
1415
|
+
fs.unlinkSync(receiptPath);
|
|
1413
1416
|
removed++;
|
|
1414
1417
|
}
|
|
1415
1418
|
} catch {} finally {
|
|
@@ -1432,10 +1435,10 @@ async function pruneScopeBindingTombstones(directory) {
|
|
|
1432
1435
|
function readCurrentPlan(directory) {
|
|
1433
1436
|
try {
|
|
1434
1437
|
const planPath = path2.join(directory, ".swarm", "plan.json");
|
|
1435
|
-
const stat =
|
|
1438
|
+
const stat = fs.statSync(planPath);
|
|
1436
1439
|
if (!stat.isFile() || stat.size > MAX_PLAN_BYTES)
|
|
1437
1440
|
return null;
|
|
1438
|
-
const parsed = PlanSchema.safeParse(JSON.parse(
|
|
1441
|
+
const parsed = PlanSchema.safeParse(JSON.parse(fs.readFileSync(planPath, "utf8")));
|
|
1439
1442
|
return parsed.success ? parsed.data : null;
|
|
1440
1443
|
} catch {
|
|
1441
1444
|
return null;
|
|
@@ -1474,7 +1477,7 @@ function attemptIdleScopeBindingRevival(directory, resolution) {
|
|
|
1474
1477
|
return null;
|
|
1475
1478
|
let release;
|
|
1476
1479
|
try {
|
|
1477
|
-
const resolvedWorkspace =
|
|
1480
|
+
const resolvedWorkspace = fs.realpathSync(directory);
|
|
1478
1481
|
assertProjectRoot(resolvedWorkspace);
|
|
1479
1482
|
const scopePath = getBindingFilePath(resolvedWorkspace, candidate);
|
|
1480
1483
|
if (!isScopesDirSafe(resolvedWorkspace, getScopesDir(resolvedWorkspace)))
|
|
@@ -1602,34 +1605,34 @@ function resolveAuthorizedScopeBindingForSessionDetailed(input) {
|
|
|
1602
1605
|
}
|
|
1603
1606
|
function readPrFeedbackBindingFile(directory, filePath, activeSessionId, taskId) {
|
|
1604
1607
|
try {
|
|
1605
|
-
const leaf =
|
|
1608
|
+
const leaf = fs.lstatSync(filePath);
|
|
1606
1609
|
if (!leaf.isFile() || leaf.isSymbolicLink())
|
|
1607
1610
|
return null;
|
|
1608
|
-
if (normalizePathForComparison(
|
|
1611
|
+
if (normalizePathForComparison(fs.realpathSync(filePath)) !== normalizePathForComparison(filePath))
|
|
1609
1612
|
return null;
|
|
1610
1613
|
} catch {
|
|
1611
1614
|
return null;
|
|
1612
1615
|
}
|
|
1613
|
-
const nofollow =
|
|
1616
|
+
const nofollow = fs.constants.O_NOFOLLOW ?? 0;
|
|
1614
1617
|
let fd;
|
|
1615
1618
|
try {
|
|
1616
|
-
fd =
|
|
1619
|
+
fd = fs.openSync(filePath, fs.constants.O_RDONLY | nofollow);
|
|
1617
1620
|
} catch {
|
|
1618
1621
|
return null;
|
|
1619
1622
|
}
|
|
1620
1623
|
let raw = "";
|
|
1621
1624
|
try {
|
|
1622
|
-
const stat =
|
|
1625
|
+
const stat = fs.fstatSync(fd);
|
|
1623
1626
|
if (!stat.isFile() || stat.size > MAX_SCOPE_BYTES)
|
|
1624
1627
|
return null;
|
|
1625
1628
|
const buffer = Buffer.alloc(stat.size);
|
|
1626
|
-
|
|
1629
|
+
fs.readSync(fd, buffer, 0, stat.size, 0);
|
|
1627
1630
|
raw = buffer.toString("utf8");
|
|
1628
1631
|
} catch {
|
|
1629
1632
|
return null;
|
|
1630
1633
|
} finally {
|
|
1631
1634
|
try {
|
|
1632
|
-
|
|
1635
|
+
fs.closeSync(fd);
|
|
1633
1636
|
} catch {}
|
|
1634
1637
|
}
|
|
1635
1638
|
let parsed;
|
|
@@ -1663,7 +1666,7 @@ function resolveAuthorizedPrFeedbackScopeBindingFromDisk(input) {
|
|
|
1663
1666
|
if (!isSafeTaskId(input.taskId))
|
|
1664
1667
|
return null;
|
|
1665
1668
|
try {
|
|
1666
|
-
const names =
|
|
1669
|
+
const names = fs.readdirSync(scopesDir);
|
|
1667
1670
|
if (names.length > MAX_BINDING_FILES_TO_SCAN)
|
|
1668
1671
|
return null;
|
|
1669
1672
|
candidates = names.filter((name) => name.startsWith(exactBindingPrefix(input.taskId)) && name.endsWith(".json")).map((name) => path2.join(scopesDir, name));
|
|
@@ -1672,7 +1675,7 @@ function resolveAuthorizedPrFeedbackScopeBindingFromDisk(input) {
|
|
|
1672
1675
|
}
|
|
1673
1676
|
} else {
|
|
1674
1677
|
try {
|
|
1675
|
-
const names =
|
|
1678
|
+
const names = fs.readdirSync(scopesDir);
|
|
1676
1679
|
if (names.length > MAX_BINDING_FILES_TO_SCAN)
|
|
1677
1680
|
return null;
|
|
1678
1681
|
candidates = names.filter((name) => name.startsWith("binding-") && name.endsWith(".json")).map((name) => path2.join(scopesDir, name));
|
|
@@ -1719,28 +1722,28 @@ function readScopeFromDisk(directory, taskId) {
|
|
|
1719
1722
|
if (!isScopesDirSafe(directory, scopesDir))
|
|
1720
1723
|
return null;
|
|
1721
1724
|
const scopePath = getScopeFilePath(directory, taskId);
|
|
1722
|
-
const nofollow =
|
|
1725
|
+
const nofollow = fs.constants.O_NOFOLLOW ?? 0;
|
|
1723
1726
|
let fd;
|
|
1724
1727
|
try {
|
|
1725
|
-
fd =
|
|
1728
|
+
fd = fs.openSync(scopePath, fs.constants.O_RDONLY | nofollow);
|
|
1726
1729
|
} catch {
|
|
1727
1730
|
return null;
|
|
1728
1731
|
}
|
|
1729
1732
|
let raw;
|
|
1730
1733
|
try {
|
|
1731
|
-
const stat =
|
|
1734
|
+
const stat = fs.fstatSync(fd);
|
|
1732
1735
|
if (!stat.isFile())
|
|
1733
1736
|
return null;
|
|
1734
1737
|
if (stat.size > MAX_SCOPE_BYTES)
|
|
1735
1738
|
return null;
|
|
1736
1739
|
const buf = Buffer.alloc(stat.size);
|
|
1737
|
-
|
|
1740
|
+
fs.readSync(fd, buf, 0, stat.size, 0);
|
|
1738
1741
|
raw = buf.toString("utf-8");
|
|
1739
1742
|
} catch {
|
|
1740
1743
|
return null;
|
|
1741
1744
|
} finally {
|
|
1742
1745
|
try {
|
|
1743
|
-
|
|
1746
|
+
fs.closeSync(fd);
|
|
1744
1747
|
} catch {}
|
|
1745
1748
|
}
|
|
1746
1749
|
if (!raw.trim())
|
|
@@ -1774,12 +1777,12 @@ function readPlanScope(directory, taskId) {
|
|
|
1774
1777
|
return null;
|
|
1775
1778
|
try {
|
|
1776
1779
|
const planPath = path2.join(directory, ".swarm", "plan.json");
|
|
1777
|
-
const stat =
|
|
1780
|
+
const stat = fs.statSync(planPath);
|
|
1778
1781
|
if (!stat.isFile())
|
|
1779
1782
|
return null;
|
|
1780
1783
|
if (stat.size > MAX_PLAN_BYTES)
|
|
1781
1784
|
return null;
|
|
1782
|
-
const raw =
|
|
1785
|
+
const raw = fs.readFileSync(planPath, "utf-8");
|
|
1783
1786
|
const plan = JSON.parse(raw);
|
|
1784
1787
|
for (const phase of plan.phases ?? []) {
|
|
1785
1788
|
for (const task of phase.tasks ?? []) {
|
|
@@ -1806,13 +1809,13 @@ function clearScopeForTask(directory, taskId) {
|
|
|
1806
1809
|
return;
|
|
1807
1810
|
try {
|
|
1808
1811
|
assertProjectRoot(directory);
|
|
1809
|
-
|
|
1812
|
+
fs.unlinkSync(getScopeFilePath(directory, taskId));
|
|
1810
1813
|
} catch {}
|
|
1811
1814
|
}
|
|
1812
1815
|
function clearAllScopes(directory) {
|
|
1813
1816
|
try {
|
|
1814
1817
|
assertProjectRoot(directory);
|
|
1815
|
-
|
|
1818
|
+
fs.rmSync(getScopesDir(directory), { recursive: true, force: true });
|
|
1816
1819
|
} catch {}
|
|
1817
1820
|
}
|
|
1818
1821
|
function resolveScopeWithFallbacks(input) {
|