@deftai/directive-runtime 0.129.5 → 0.129.6
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/Taskfile.yml +235 -0
- package/UPGRADING.md +1 -0
- package/contracts/design-critique.md +1 -1
- package/contracts/path-write-fence.md +6 -0
- package/dist/applying-host-release.d.ts +16 -0
- package/dist/applying-host-release.js +98 -0
- package/dist/authz.d.ts +1 -1
- package/dist/authz.js +1 -1
- package/dist/check.d.ts +1 -0
- package/dist/check.js +27 -4
- package/dist/design-critique-ensure-arc-dest.d.ts +16 -0
- package/dist/design-critique-ensure-arc-dest.js +168 -0
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +8 -0
- package/dist/hook-dispatch.js +3 -2
- package/dist/human-presence-mint.d.ts +6 -1
- package/dist/human-presence-mint.js +20 -6
- package/dist/session-start.js +40 -6
- package/dist/setup-wiring.d.ts +36 -0
- package/dist/setup-wiring.js +169 -14
- package/dist/verify-source-cli/verify-deposit-closure.js +5 -5
- package/dist/windows-bin-ps1.d.ts +2 -2
- package/dist/windows-bin-ps1.js +5 -11
- package/docs/deft-directive-disable.md +3 -3
- package/package.json +2 -3
- package/packs/lessons/lessons-pack-0.1.json +15 -0
- package/packs/skills/skills-pack-0.1.json +2 -2
- package/skills/deft-directive-design-critique/SKILL.md +1 -1
- package/skills/deft-directive-release/SKILL.md +31 -1
- package/vendor/directive-content/Taskfile.yml +235 -0
- package/vendor/directive-content/UPGRADING.md +1 -0
- package/vendor/directive-content/contracts/design-critique.md +1 -1
- package/vendor/directive-content/contracts/path-write-fence.md +6 -0
- package/vendor/directive-content/docs/deft-directive-disable.md +3 -3
- package/vendor/directive-content/packs/lessons/lessons-pack-0.1.json +15 -0
- package/vendor/directive-content/packs/skills/skills-pack-0.1.json +2 -2
- package/vendor/directive-content/skills/deft-directive-design-critique/SKILL.md +1 -1
- package/vendor/directive-content/skills/deft-directive-release/SKILL.md +31 -1
- package/vendor/directive-core/dist/.tsbuildinfo +1 -1
- package/vendor/directive-core/dist/authz/classify.d.ts +12 -0
- package/vendor/directive-core/dist/authz/classify.d.ts.map +1 -1
- package/vendor/directive-core/dist/authz/classify.js +40 -12
- package/vendor/directive-core/dist/authz/classify.js.map +1 -1
- package/vendor/directive-core/dist/authz/templates.d.ts +2 -2
- package/vendor/directive-core/dist/authz/templates.d.ts.map +1 -1
- package/vendor/directive-core/dist/authz/templates.js +1 -0
- package/vendor/directive-core/dist/authz/templates.js.map +1 -1
- package/vendor/directive-core/dist/authz/types.d.ts +1 -1
- package/vendor/directive-core/dist/authz/types.d.ts.map +1 -1
- package/vendor/directive-core/dist/authz/types.js +2 -0
- package/vendor/directive-core/dist/authz/types.js.map +1 -1
- package/vendor/directive-core/dist/authz/verb-classification.d.ts.map +1 -1
- package/vendor/directive-core/dist/authz/verb-classification.js +30 -3
- package/vendor/directive-core/dist/authz/verb-classification.js.map +1 -1
- package/vendor/directive-core/dist/cache/fetch.d.ts.map +1 -1
- package/vendor/directive-core/dist/cache/fetch.js +50 -4
- package/vendor/directive-core/dist/cache/fetch.js.map +1 -1
- package/vendor/directive-core/dist/design-critique/arc-dest.d.ts +22 -5
- package/vendor/directive-core/dist/design-critique/arc-dest.d.ts.map +1 -1
- package/vendor/directive-core/dist/design-critique/arc-dest.js +61 -0
- package/vendor/directive-core/dist/design-critique/arc-dest.js.map +1 -1
- package/vendor/directive-core/dist/design-critique/run-posture.d.ts +7 -2
- package/vendor/directive-core/dist/design-critique/run-posture.d.ts.map +1 -1
- package/vendor/directive-core/dist/design-critique/run-posture.js +6 -1
- package/vendor/directive-core/dist/design-critique/run-posture.js.map +1 -1
- package/vendor/directive-core/dist/hooks/dispatcher.d.ts.map +1 -1
- package/vendor/directive-core/dist/hooks/dispatcher.js +174 -12
- package/vendor/directive-core/dist/hooks/dispatcher.js.map +1 -1
- package/vendor/directive-core/dist/hooks/shell-write-targets.d.ts +5 -0
- package/vendor/directive-core/dist/hooks/shell-write-targets.d.ts.map +1 -1
- package/vendor/directive-core/dist/hooks/shell-write-targets.js +18 -1
- package/vendor/directive-core/dist/hooks/shell-write-targets.js.map +1 -1
- package/vendor/directive-core/dist/init-deposit/host-hook-outer.d.ts +5 -0
- package/vendor/directive-core/dist/init-deposit/host-hook-outer.d.ts.map +1 -1
- package/vendor/directive-core/dist/init-deposit/host-hook-outer.js +22 -9
- package/vendor/directive-core/dist/init-deposit/host-hook-outer.js.map +1 -1
- package/vendor/directive-core/dist/init-deposit/scaffold.d.ts +8 -1
- package/vendor/directive-core/dist/init-deposit/scaffold.d.ts.map +1 -1
- package/vendor/directive-core/dist/init-deposit/scaffold.js +38 -4
- package/vendor/directive-core/dist/init-deposit/scaffold.js.map +1 -1
- package/vendor/directive-core/dist/install-health/cheap.d.ts +2 -1
- package/vendor/directive-core/dist/install-health/cheap.d.ts.map +1 -1
- package/vendor/directive-core/dist/install-health/cheap.js +4 -3
- package/vendor/directive-core/dist/install-health/cheap.js.map +1 -1
- package/vendor/directive-core/dist/install-health/constants.d.ts +18 -2
- package/vendor/directive-core/dist/install-health/constants.d.ts.map +1 -1
- package/vendor/directive-core/dist/install-health/constants.js +18 -2
- package/vendor/directive-core/dist/install-health/constants.js.map +1 -1
- package/vendor/directive-core/dist/policy/deft-directive-disable.d.ts +42 -5
- package/vendor/directive-core/dist/policy/deft-directive-disable.d.ts.map +1 -1
- package/vendor/directive-core/dist/policy/deft-directive-disable.js +71 -41
- package/vendor/directive-core/dist/policy/deft-directive-disable.js.map +1 -1
- package/vendor/directive-core/dist/pr-closeout-attestable/evaluate.d.ts +6 -1
- package/vendor/directive-core/dist/pr-closeout-attestable/evaluate.d.ts.map +1 -1
- package/vendor/directive-core/dist/pr-closeout-attestable/evaluate.js +24 -12
- package/vendor/directive-core/dist/pr-closeout-attestable/evaluate.js.map +1 -1
- package/vendor/directive-core/dist/pr-closeout-attestable/pr-head-assert.d.ts +68 -14
- package/vendor/directive-core/dist/pr-closeout-attestable/pr-head-assert.d.ts.map +1 -1
- package/vendor/directive-core/dist/pr-closeout-attestable/pr-head-assert.js +278 -47
- package/vendor/directive-core/dist/pr-closeout-attestable/pr-head-assert.js.map +1 -1
- package/vendor/directive-core/dist/release/gh.d.ts.map +1 -1
- package/vendor/directive-core/dist/release/gh.js +2 -1
- package/vendor/directive-core/dist/release/gh.js.map +1 -1
- package/vendor/directive-core/dist/release/version.d.ts +4 -2
- package/vendor/directive-core/dist/release/version.d.ts.map +1 -1
- package/vendor/directive-core/dist/release/version.js +4 -2
- package/vendor/directive-core/dist/release/version.js.map +1 -1
- package/vendor/directive-core/dist/release-publish/gh-api.d.ts.map +1 -1
- package/vendor/directive-core/dist/release-publish/gh-api.js +4 -2
- package/vendor/directive-core/dist/release-publish/gh-api.js.map +1 -1
- package/vendor/directive-core/dist/release-publish/main.d.ts.map +1 -1
- package/vendor/directive-core/dist/release-publish/main.js +15 -4
- package/vendor/directive-core/dist/release-publish/main.js.map +1 -1
- package/vendor/directive-core/dist/release-publish/pipeline.d.ts +11 -0
- package/vendor/directive-core/dist/release-publish/pipeline.d.ts.map +1 -1
- package/vendor/directive-core/dist/release-publish/pipeline.js +143 -2
- package/vendor/directive-core/dist/release-publish/pipeline.js.map +1 -1
- package/vendor/directive-core/dist/release-rollback/gh.d.ts.map +1 -1
- package/vendor/directive-core/dist/release-rollback/gh.js +2 -1
- package/vendor/directive-core/dist/release-rollback/gh.js.map +1 -1
- package/vendor/directive-core/dist/session/git.d.ts +21 -2
- package/vendor/directive-core/dist/session/git.d.ts.map +1 -1
- package/vendor/directive-core/dist/session/git.js +21 -4
- package/vendor/directive-core/dist/session/git.js.map +1 -1
- package/vendor/directive-core/dist/session/occupancy.d.ts +93 -6
- package/vendor/directive-core/dist/session/occupancy.d.ts.map +1 -1
- package/vendor/directive-core/dist/session/occupancy.js +215 -52
- package/vendor/directive-core/dist/session/occupancy.js.map +1 -1
- package/vendor/directive-core/dist/session/session-start.d.ts.map +1 -1
- package/vendor/directive-core/dist/session/session-start.js +5 -2
- package/vendor/directive-core/dist/session/session-start.js.map +1 -1
- package/vendor/directive-core/dist/swarm/dest-place.d.ts +1 -1
- package/vendor/directive-core/dist/swarm/dest-place.d.ts.map +1 -1
- package/vendor/directive-core/dist/swarm/dest-place.js +36 -41
- package/vendor/directive-core/dist/swarm/dest-place.js.map +1 -1
- package/vendor/directive-core/dist/swarm/finalize-owed.d.ts +14 -0
- package/vendor/directive-core/dist/swarm/finalize-owed.d.ts.map +1 -1
- package/vendor/directive-core/dist/swarm/finalize-owed.js +214 -48
- package/vendor/directive-core/dist/swarm/finalize-owed.js.map +1 -1
- package/vendor/directive-core/dist/swarm/launch.d.ts.map +1 -1
- package/vendor/directive-core/dist/swarm/launch.js +15 -4
- package/vendor/directive-core/dist/swarm/launch.js.map +1 -1
- package/vendor/directive-core/dist/swarm/worktree-pm-install.d.ts +49 -2
- package/vendor/directive-core/dist/swarm/worktree-pm-install.d.ts.map +1 -1
- package/vendor/directive-core/dist/swarm/worktree-pm-install.js +207 -12
- package/vendor/directive-core/dist/swarm/worktree-pm-install.js.map +1 -1
- package/vendor/directive-core/dist/swarm/worktrees-cli.d.ts +6 -0
- package/vendor/directive-core/dist/swarm/worktrees-cli.d.ts.map +1 -1
- package/vendor/directive-core/dist/swarm/worktrees-cli.js +79 -2
- package/vendor/directive-core/dist/swarm/worktrees-cli.js.map +1 -1
- package/vendor/directive-core/dist/swarm/worktrees.d.ts +12 -1
- package/vendor/directive-core/dist/swarm/worktrees.d.ts.map +1 -1
- package/vendor/directive-core/dist/swarm/worktrees.js +34 -26
- package/vendor/directive-core/dist/swarm/worktrees.js.map +1 -1
|
@@ -327,8 +327,11 @@ export function readApplyingHost(projectRoot, now = new Date()) {
|
|
|
327
327
|
* Supported repair when the applying-host record is missing, stale, or
|
|
328
328
|
* conflicting (#5676 Prefer-A Recut-5). Mutation session:start is reinforcement
|
|
329
329
|
* only — first publication is SessionStart or read-only session:start.
|
|
330
|
+
*
|
|
331
|
+
* When a live foreign occupant holds the lease (#6101), do not prescribe another
|
|
332
|
+
* owner's session-id republish recipe — name the incumbent and supported exits.
|
|
330
333
|
*/
|
|
331
|
-
export function formatApplyingHostRepairDiagnostic(reason = "missing") {
|
|
334
|
+
export function formatApplyingHostRepairDiagnostic(reason = "missing", opts = {}) {
|
|
332
335
|
const subject = reason === "missing"
|
|
333
336
|
? "Applying-host record is missing"
|
|
334
337
|
: reason === "stale"
|
|
@@ -336,11 +339,26 @@ export function formatApplyingHostRepairDiagnostic(reason = "missing") {
|
|
|
336
339
|
: reason === "conflicting"
|
|
337
340
|
? "Applying-host record conflicts with this host session"
|
|
338
341
|
: "Applying-host record is invalid";
|
|
342
|
+
const live = opts.liveSessionId?.trim() || null;
|
|
343
|
+
const caller = opts.callerSessionId?.trim() || null;
|
|
344
|
+
if (live !== null && live !== caller) {
|
|
345
|
+
return (`${subject}. Live occupant ${live} still holds this worktree. ` +
|
|
346
|
+
"Supported exits: that owner runs occupancy:release / session:end, or wait for lease TTL. " +
|
|
347
|
+
"Do not republish applying-host with another owner's session-id.");
|
|
348
|
+
}
|
|
339
349
|
return (`${subject}. Republish via host SessionStart reconnect and/or ` +
|
|
340
350
|
"`deft session:start --read-only --session-id=<applyingHostSessionId>` " +
|
|
341
351
|
"before retrying mutation lifecycle. UUID / Harbor residuals stay under #5544.");
|
|
342
352
|
}
|
|
343
|
-
/**
|
|
353
|
+
/**
|
|
354
|
+
* Write/replace the worktree applying-host record (#5676 / #6101 / #6143).
|
|
355
|
+
*
|
|
356
|
+
* Under the occupancy writer lock, skip when a live foreign occupant holds the
|
|
357
|
+
* lease — keyed to the canonical session id being written. Without
|
|
358
|
+
* `allowForeignTakeover`, also skip replacing a different provider's fresh
|
|
359
|
+
* no-lease claim (RO SessionStart must not displace). No unlocked write
|
|
360
|
+
* fallback. Deferred is distinct from non-canonical null on the FromCanonical path.
|
|
361
|
+
*/
|
|
344
362
|
export function publishApplyingHost(projectRoot, input) {
|
|
345
363
|
if (!isUsableHostSessionId(input.rawSessionId)) {
|
|
346
364
|
throw new Error("publishApplyingHost: rawSessionId is not a usable host session id");
|
|
@@ -355,39 +373,148 @@ export function publishApplyingHost(projectRoot, input) {
|
|
|
355
373
|
claimed_at: timestampIso(claimedAt),
|
|
356
374
|
transport: input.transport ?? "native",
|
|
357
375
|
};
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
376
|
+
return withOccupancyLock(root, (fence) => {
|
|
377
|
+
const live = liveOccupant(root, claimedAt);
|
|
378
|
+
if (live !== null && live.sessionId !== record.applyingHostSessionId) {
|
|
379
|
+
return {
|
|
380
|
+
status: "deferred",
|
|
381
|
+
reason: "live-foreign-occupant",
|
|
382
|
+
liveSessionId: live.sessionId,
|
|
383
|
+
attemptedSessionId: record.applyingHostSessionId,
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
const existing = readApplyingHost(root, claimedAt);
|
|
387
|
+
if (existing.status === "ok" &&
|
|
388
|
+
existing.record.provider !== record.provider &&
|
|
389
|
+
live?.sessionId !== record.applyingHostSessionId &&
|
|
390
|
+
input.allowForeignTakeover !== true) {
|
|
391
|
+
return {
|
|
392
|
+
status: "deferred",
|
|
393
|
+
reason: "foreign-fresh-claim",
|
|
394
|
+
liveSessionId: existing.record.applyingHostSessionId,
|
|
395
|
+
attemptedSessionId: record.applyingHostSessionId,
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
fence();
|
|
399
|
+
const target = applyingHostPath(root);
|
|
400
|
+
assertWriteTargetSafe(root, target);
|
|
401
|
+
const dir = dirname(target);
|
|
402
|
+
const tmpName = join(dir, `.applying-host.${process.pid}.json.tmp`);
|
|
403
|
+
const text = `${stableJson(record, 2)}\n`;
|
|
368
404
|
try {
|
|
369
|
-
|
|
405
|
+
containedWrite({ root, target: tmpName, data: text, mode: "create" });
|
|
406
|
+
renameSync(tmpName, target);
|
|
370
407
|
}
|
|
371
|
-
|
|
372
|
-
|
|
408
|
+
finally {
|
|
409
|
+
try {
|
|
410
|
+
rmSync(tmpName, { force: true });
|
|
411
|
+
}
|
|
412
|
+
catch {
|
|
413
|
+
/* best-effort cleanup of tmp only */
|
|
414
|
+
}
|
|
373
415
|
}
|
|
374
|
-
|
|
375
|
-
|
|
416
|
+
return { status: "published", record };
|
|
417
|
+
});
|
|
376
418
|
}
|
|
377
419
|
/**
|
|
378
|
-
* Publish from a canonical `host:<provider>:v1:<base64url>` owner (#5676).
|
|
420
|
+
* Publish from a canonical `host:<provider>:v1:<base64url>` owner (#5676 / #6101 / #6143).
|
|
379
421
|
* Returns null when the id is not canonical (opaque UUID leftovers stay #5544).
|
|
422
|
+
* Deferred live-foreign / foreign-fresh skip is a discriminated result, never collapsed into null.
|
|
380
423
|
*/
|
|
381
424
|
export function publishApplyingHostFromCanonicalSessionId(projectRoot, sessionId, opts = {}) {
|
|
382
425
|
const parsed = parseCanonicalHostSessionId(sessionId.trim());
|
|
383
426
|
if (parsed === null)
|
|
384
427
|
return null;
|
|
385
|
-
|
|
428
|
+
const result = publishApplyingHost(projectRoot, {
|
|
386
429
|
provider: parsed.provider,
|
|
387
430
|
rawSessionId: parsed.rawSessionId,
|
|
388
431
|
claimedAt: opts.claimedAt,
|
|
389
432
|
transport: opts.transport,
|
|
433
|
+
allowForeignTakeover: opts.allowForeignTakeover,
|
|
390
434
|
});
|
|
435
|
+
if (result.status === "published") {
|
|
436
|
+
return result;
|
|
437
|
+
}
|
|
438
|
+
// Collapse foreign-fresh-claim for session:start's narrower deferred report.
|
|
439
|
+
return {
|
|
440
|
+
status: "deferred",
|
|
441
|
+
reason: "live-foreign-occupant",
|
|
442
|
+
liveSessionId: result.liveSessionId,
|
|
443
|
+
attemptedSessionId: result.attemptedSessionId,
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Clear the worktree applying-host record (#6143).
|
|
448
|
+
*
|
|
449
|
+
* Owner match always clears. With no live foreign occupant, any presented caller
|
|
450
|
+
* may clear an abandoned no-lease soft claim. Live foreign lease keeps the
|
|
451
|
+
* record (#5913 / #6101 keep-outs).
|
|
452
|
+
*/
|
|
453
|
+
export function clearApplyingHost(projectRoot, input = {}) {
|
|
454
|
+
const root = resolve(projectRoot);
|
|
455
|
+
const now = input.now ?? new Date();
|
|
456
|
+
const caller = input.sessionId?.trim() || null;
|
|
457
|
+
return withOccupancyLock(root, (fence) => {
|
|
458
|
+
const read = readApplyingHost(root, now);
|
|
459
|
+
if (read.status === "missing") {
|
|
460
|
+
return { status: "missing" };
|
|
461
|
+
}
|
|
462
|
+
if (read.status === "invalid" || read.record === null) {
|
|
463
|
+
fence();
|
|
464
|
+
containedRemove({ root, target: applyingHostPath(root) });
|
|
465
|
+
return { status: "cleared", previousSessionId: "<invalid>" };
|
|
466
|
+
}
|
|
467
|
+
const record = read.record;
|
|
468
|
+
const live = liveOccupant(root, now);
|
|
469
|
+
const liveId = live?.sessionId ?? null;
|
|
470
|
+
const owns = caller !== null && caller === record.applyingHostSessionId;
|
|
471
|
+
if (!owns && liveId !== null && liveId !== caller) {
|
|
472
|
+
return {
|
|
473
|
+
status: "denied",
|
|
474
|
+
record,
|
|
475
|
+
message: `Directive refused applying-host:release for caller ${caller ?? "<missing>"}. ` +
|
|
476
|
+
`Live occupant ${liveId} still holds this worktree. Wait for that owner to ` +
|
|
477
|
+
"run occupancy:release / session:end, or occupancy:steal --confirm.",
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
if (!owns && liveId !== null && liveId === caller) {
|
|
481
|
+
// Live lease holder may clear a replaced applying-host soft claim.
|
|
482
|
+
}
|
|
483
|
+
else if (!owns && liveId === null) {
|
|
484
|
+
// Abandoned no-lease soft claim — clearable without impersonating owner.
|
|
485
|
+
}
|
|
486
|
+
else if (!owns) {
|
|
487
|
+
return {
|
|
488
|
+
status: "denied",
|
|
489
|
+
record,
|
|
490
|
+
message: `Directive refused applying-host:release for caller ${caller ?? "<missing>"}. ` +
|
|
491
|
+
`Recorded applying-host is ${record.applyingHostSessionId}. Re-run as that owner, ` +
|
|
492
|
+
"or clear after the lease is gone.",
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
fence();
|
|
496
|
+
containedRemove({ root, target: applyingHostPath(root) });
|
|
497
|
+
return {
|
|
498
|
+
status: "cleared",
|
|
499
|
+
previousSessionId: record.applyingHostSessionId,
|
|
500
|
+
};
|
|
501
|
+
}, input.lockDeps);
|
|
502
|
+
}
|
|
503
|
+
/** Foreign-owner deny names the caller and takeover/wait path — never the owner's id (#6143 P2). */
|
|
504
|
+
export function formatApplyingHostForeignOwnerDeny(input) {
|
|
505
|
+
const caller = input.callerSessionId?.trim() || null;
|
|
506
|
+
const live = input.liveSessionId?.trim() || null;
|
|
507
|
+
const callerLabel = caller ?? "<unresolved-caller>";
|
|
508
|
+
if (live !== null) {
|
|
509
|
+
return (`Directive refused foreign lifecycle for caller ${callerLabel}. ` +
|
|
510
|
+
`Live occupant ${live} still holds this worktree. Take over with ` +
|
|
511
|
+
"`occupancy:steal --confirm`, wait for occupancy:release / session:end, or " +
|
|
512
|
+
"`applying-host:release` from the owner. Do not re-run with another owner's --session-id.");
|
|
513
|
+
}
|
|
514
|
+
return (`Directive refused foreign lifecycle for caller ${callerLabel}. ` +
|
|
515
|
+
"Applying-host soft claim has no live lease for this caller path; use " +
|
|
516
|
+
"`applying-host:release`, wait for SessionStart soft-claim takeover, or " +
|
|
517
|
+
"retry bare lifecycle after the claim is cleared. Do not re-run with another owner's --session-id.");
|
|
391
518
|
}
|
|
392
519
|
/**
|
|
393
520
|
* Lifecycle admission against the applying-host record (#5676).
|
|
@@ -398,7 +525,10 @@ export function publishApplyingHostFromCanonicalSessionId(projectRoot, sessionId
|
|
|
398
525
|
* no flip-flop shape returns `absent` so single-host flows keep prior behavior.
|
|
399
526
|
*/
|
|
400
527
|
export function evaluateApplyingHostLifecycleAdmission(input) {
|
|
401
|
-
const
|
|
528
|
+
const now = input.now ?? new Date();
|
|
529
|
+
const deposit = input.depositSessionId?.trim() || null;
|
|
530
|
+
const named = input.namedSessionId?.trim() || null;
|
|
531
|
+
const read = readApplyingHost(input.projectRoot, now);
|
|
402
532
|
if (read.status === "invalid") {
|
|
403
533
|
return {
|
|
404
534
|
kind: "repair",
|
|
@@ -407,26 +537,28 @@ export function evaluateApplyingHostLifecycleAdmission(input) {
|
|
|
407
537
|
};
|
|
408
538
|
}
|
|
409
539
|
if (read.status === "stale") {
|
|
410
|
-
//
|
|
411
|
-
//
|
|
412
|
-
//
|
|
413
|
-
const staleLive = liveOccupant(input.projectRoot,
|
|
540
|
+
// Deposit-keyed live-owner cleanup (#6101 Prefer-A Recut-2): key solely on
|
|
541
|
+
// depositSessionId === liveId with no applyingHostSessionId relation conjunct.
|
|
542
|
+
// Maps onto dispatcher liveOwnerBypass so bare keeps rewrite injection.
|
|
543
|
+
const staleLive = liveOccupant(input.projectRoot, now);
|
|
414
544
|
const staleLiveId = staleLive?.sessionId ?? null;
|
|
415
|
-
|
|
416
|
-
if (staleLiveId !== null &&
|
|
417
|
-
read.record.applyingHostSessionId === staleLiveId &&
|
|
418
|
-
staleNamed === staleLiveId) {
|
|
545
|
+
if (staleLiveId !== null && deposit === staleLiveId) {
|
|
419
546
|
return {
|
|
420
|
-
kind: "
|
|
547
|
+
kind: "live-owner-cleanup",
|
|
421
548
|
record: read.record,
|
|
422
|
-
reason: "live-lease-owner-cleanup",
|
|
423
549
|
};
|
|
424
550
|
}
|
|
425
|
-
return {
|
|
551
|
+
return {
|
|
552
|
+
kind: "repair",
|
|
553
|
+
record: read.record,
|
|
554
|
+
message: formatApplyingHostRepairDiagnostic("stale", {
|
|
555
|
+
liveSessionId: staleLiveId,
|
|
556
|
+
callerSessionId: deposit ?? named,
|
|
557
|
+
}),
|
|
558
|
+
};
|
|
426
559
|
}
|
|
427
560
|
if (read.status === "missing" || read.record === null) {
|
|
428
|
-
const
|
|
429
|
-
const deposit = input.depositSessionId?.trim() || null;
|
|
561
|
+
const missingLive = liveOccupant(input.projectRoot, now);
|
|
430
562
|
if (named !== null && deposit !== null && named !== deposit) {
|
|
431
563
|
const namedParts = parseCanonicalHostSessionId(named);
|
|
432
564
|
const depositParts = parseCanonicalHostSessionId(deposit);
|
|
@@ -437,24 +569,25 @@ export function evaluateApplyingHostLifecycleAdmission(input) {
|
|
|
437
569
|
return {
|
|
438
570
|
kind: "repair",
|
|
439
571
|
record: null,
|
|
440
|
-
message: formatApplyingHostRepairDiagnostic("missing"
|
|
572
|
+
message: formatApplyingHostRepairDiagnostic("missing", {
|
|
573
|
+
liveSessionId: missingLive?.sessionId ?? null,
|
|
574
|
+
callerSessionId: deposit,
|
|
575
|
+
}),
|
|
441
576
|
};
|
|
442
577
|
}
|
|
443
578
|
}
|
|
444
579
|
return { kind: "absent", record: null };
|
|
445
580
|
}
|
|
446
581
|
const record = read.record;
|
|
447
|
-
//
|
|
448
|
-
//
|
|
582
|
+
// Deposit-keyed live-owner cleanup when applying-host was replaced (#6101).
|
|
583
|
+
// Delete dead ok-branch soft-pass; map onto liveOwnerBypass via new kind so
|
|
449
584
|
// bare commands still take the rewrite path (do not skip --session-id injection).
|
|
450
|
-
const live = liveOccupant(input.projectRoot,
|
|
585
|
+
const live = liveOccupant(input.projectRoot, now);
|
|
451
586
|
const liveId = live?.sessionId ?? null;
|
|
452
|
-
|
|
453
|
-
if (liveId !== null && record.applyingHostSessionId !== liveId && named === liveId) {
|
|
587
|
+
if (liveId !== null && deposit === liveId && record.applyingHostSessionId !== liveId) {
|
|
454
588
|
return {
|
|
455
|
-
kind: "
|
|
589
|
+
kind: "live-owner-cleanup",
|
|
456
590
|
record,
|
|
457
|
-
reason: "live-lease-owner-cleanup",
|
|
458
591
|
};
|
|
459
592
|
}
|
|
460
593
|
if (isHookHostIdentityProvider(input.depositHost) &&
|
|
@@ -466,7 +599,10 @@ export function evaluateApplyingHostLifecycleAdmission(input) {
|
|
|
466
599
|
return {
|
|
467
600
|
kind: "repair",
|
|
468
601
|
record,
|
|
469
|
-
message: formatApplyingHostRepairDiagnostic("conflicting"
|
|
602
|
+
message: formatApplyingHostRepairDiagnostic("conflicting", {
|
|
603
|
+
liveSessionId: liveId,
|
|
604
|
+
callerSessionId: deposit ?? named,
|
|
605
|
+
}),
|
|
470
606
|
};
|
|
471
607
|
}
|
|
472
608
|
}
|
|
@@ -481,27 +617,39 @@ export function evaluateApplyingHostLifecycleAdmission(input) {
|
|
|
481
617
|
reason: "non-matching-deposit-names-applying-host",
|
|
482
618
|
};
|
|
483
619
|
}
|
|
620
|
+
// #6143 P1: no-lease fresh claim is advisory — other-provider bare lifecycle
|
|
621
|
+
// may take over (republish). Keep-outs #5913/#6101 still bind when a live
|
|
622
|
+
// lease exists.
|
|
623
|
+
if (liveId === null) {
|
|
624
|
+
return {
|
|
625
|
+
kind: "advisory-takeover",
|
|
626
|
+
record,
|
|
627
|
+
callerSessionId: deposit,
|
|
628
|
+
};
|
|
629
|
+
}
|
|
484
630
|
return {
|
|
485
631
|
kind: "foreign-owner",
|
|
486
632
|
record,
|
|
487
633
|
namedSessionId: named,
|
|
488
|
-
message:
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
`${record.applyingHostSessionId}. Re-run with ` +
|
|
494
|
-
`--session-id=${record.applyingHostSessionId}.`,
|
|
634
|
+
message: formatApplyingHostForeignOwnerDeny({
|
|
635
|
+
callerSessionId: deposit,
|
|
636
|
+
liveSessionId: liveId,
|
|
637
|
+
namedSessionId: named,
|
|
638
|
+
}),
|
|
495
639
|
};
|
|
496
640
|
}
|
|
497
641
|
if (named !== null && named !== record.applyingHostSessionId) {
|
|
642
|
+
// Same-provider wrong named id: still foreign, but deny names the caller
|
|
643
|
+
// (#6143 P2) and never tells the caller to impersonate applying-host.
|
|
498
644
|
return {
|
|
499
645
|
kind: "foreign-owner",
|
|
500
646
|
record,
|
|
501
647
|
namedSessionId: named,
|
|
502
|
-
message:
|
|
503
|
-
|
|
504
|
-
|
|
648
|
+
message: formatApplyingHostForeignOwnerDeny({
|
|
649
|
+
callerSessionId: deposit,
|
|
650
|
+
liveSessionId: liveId,
|
|
651
|
+
namedSessionId: named,
|
|
652
|
+
}),
|
|
505
653
|
};
|
|
506
654
|
}
|
|
507
655
|
return {
|
|
@@ -1720,6 +1868,14 @@ export function releaseOccupancy(projectRoot, input = {}) {
|
|
|
1720
1868
|
return withOccupancyLock(root, (fence) => {
|
|
1721
1869
|
const existing = readOccupancy(root);
|
|
1722
1870
|
if (existing === null) {
|
|
1871
|
+
// #6143: release with no lease still clears an abandoned applying-host soft claim.
|
|
1872
|
+
try {
|
|
1873
|
+
fence();
|
|
1874
|
+
containedRemove({ root, target: applyingHostPath(root) });
|
|
1875
|
+
}
|
|
1876
|
+
catch {
|
|
1877
|
+
/* best-effort */
|
|
1878
|
+
}
|
|
1723
1879
|
return {
|
|
1724
1880
|
action: "released",
|
|
1725
1881
|
sessionId: caller,
|
|
@@ -1788,6 +1944,13 @@ export function releaseOccupancy(projectRoot, input = {}) {
|
|
|
1788
1944
|
};
|
|
1789
1945
|
}
|
|
1790
1946
|
removeOccupancyFile(root, fence);
|
|
1947
|
+
// #6143 P3: session:end / occupancy:release clear applying-host with the lease.
|
|
1948
|
+
try {
|
|
1949
|
+
containedRemove({ root, target: applyingHostPath(root) });
|
|
1950
|
+
}
|
|
1951
|
+
catch {
|
|
1952
|
+
/* best-effort; lease release already succeeded */
|
|
1953
|
+
}
|
|
1791
1954
|
return {
|
|
1792
1955
|
action: "released",
|
|
1793
1956
|
sessionId: still.sessionId,
|