@quantiya/codevibe-codex-plugin 2.0.47 → 2.0.49
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/node_modules/@quantiya/codevibe-core/dist/index.js +453 -447
- package/node_modules/@quantiya/codevibe-core/dist/local-executor/shadow-recovery.d.ts +15 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/cli.js +137 -23
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/context-compaction.d.ts +7 -5
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/doctor-cli.d.ts +44 -0
- package/node_modules/@quantiya/codevibe-core/package.json +2 -2
- package/package.json +3 -3
|
@@ -250,6 +250,21 @@ interface RegisteredShadowRoot extends AnchoredFsIdentity {
|
|
|
250
250
|
canonicalPath?: string;
|
|
251
251
|
birthtimeNs?: string;
|
|
252
252
|
}
|
|
253
|
+
/**
|
|
254
|
+
* FU-1 — a registered physical-copy root whose pathname is gone and whose bytes could NOT be proven reclaimed.
|
|
255
|
+
*
|
|
256
|
+
* Carries the two paths the user needs to act, because the generic surfacing cannot: the implementor-round
|
|
257
|
+
* classifier returns a closed label and never the raw message, and the durable log projection strips message,
|
|
258
|
+
* name, code and path. Both are deliberate wire-safety controls (#SR-2), so the recovery instructions travel as
|
|
259
|
+
* STRUCTURED FIELDS on the error rather than as text the classifier would have to parse or leak. Rendering these
|
|
260
|
+
* two paths in full — desktop, hosted events and durable diagnostics — is FU1-D2, an owner decision made with the
|
|
261
|
+
* trade-off stated: they are CodeVibe-registered root paths, never raw error text and never user content.
|
|
262
|
+
*/
|
|
263
|
+
export declare class StaleShadowRootError extends Error {
|
|
264
|
+
readonly stalePath: string;
|
|
265
|
+
readonly registryPath: string;
|
|
266
|
+
constructor(stalePath: string, registryPath: string);
|
|
267
|
+
}
|
|
253
268
|
/**
|
|
254
269
|
* Durable quota-scope registry. Every process sharing `stateRoot` registers its
|
|
255
270
|
* physical shadow root before copying, so the aggregate scan cannot be split by
|
|
@@ -30495,13 +30495,18 @@ async function hasUnreclaimedExposureRetention(stateRoot) {
|
|
|
30495
30495
|
}
|
|
30496
30496
|
return !1;
|
|
30497
30497
|
}
|
|
30498
|
+
var StaleShadowRootError = class extends Error {
|
|
30499
|
+
constructor(stalePath, registryPath) {
|
|
30500
|
+
super("registered physical-copy root disappeared while quota authority is retained"), this.name = "StaleShadowRootError", this.stalePath = stalePath, this.registryPath = registryPath;
|
|
30501
|
+
}
|
|
30502
|
+
};
|
|
30498
30503
|
function isSameRegisteredRootAuthority(prior, current) {
|
|
30499
30504
|
return prior.dev === current.dev && prior.ino === current.ino && prior.version === current.version && prior.canonicalPath === current.canonicalPath && prior.birthtimeNs === current.birthtimeNs;
|
|
30500
30505
|
}
|
|
30501
30506
|
function isSameRootAfterDeviceReincarnation(prior, current) {
|
|
30502
30507
|
return prior.dev !== current.dev && prior.ino === current.ino && prior.version === current.version && prior.canonicalPath === current.canonicalPath && prior.birthtimeNs === current.birthtimeNs;
|
|
30503
30508
|
}
|
|
30504
|
-
async function collectDurablyReferencedShadowRoots(stateRoot, stateRootAuthority, maxStateMarkerBytes, registeredShadowRoots, afterTaskEntry, afterMarkerEntry, afterMarkerStat, allowUnrecognizedRegularFiles = !1, allowUnregisteredReferences = !1, allowConcurrentSiblingTeardown = !1) {
|
|
30509
|
+
async function collectDurablyReferencedShadowRoots(stateRoot, stateRootAuthority, maxStateMarkerBytes, registeredShadowRoots, afterTaskEntry, afterMarkerEntry, afterMarkerStat, allowUnrecognizedRegularFiles = !1, allowUnregisteredReferences = !1, allowConcurrentSiblingTeardown = !1, markerIndex) {
|
|
30505
30510
|
let retryConcurrentSiblingTeardown = (error, target) => {
|
|
30506
30511
|
let code = error?.code, message = error instanceof Error ? error.message : String(error), isSiblingChurn = code === "ENOENT" || message.includes("workspace root changed while opening") || message.includes("workspace root cwd identity mismatch") || message.includes("workspace root changed during authority capture") || message.includes("bounded-directory target identity mismatch") || message.includes("bounded-directory parent changed while opening") || message.includes("bounded-directory parent changed while descending") || message.includes("anchored read root authority unavailable") || message.includes("anchored read root identity mismatch") || message.includes("anchored read root incarnation mismatch") || message.includes("anchored read directory chain changed") || message.includes("anchored read directory changed while descending") || message.includes("anchored read cwd identity mismatch") || message.includes("anchored read file identity mismatch") || message.includes("anchored read file changed during read") || message.includes("anchored read file path changed") || message.includes("anchored read file changed after read");
|
|
30507
30512
|
throw allowConcurrentSiblingTeardown && isSiblingChurn ? new Error(
|
|
@@ -30591,7 +30596,7 @@ async function collectDurablyReferencedShadowRoots(stateRoot, stateRootAuthority
|
|
|
30591
30596
|
if (allowUnregisteredReferences) continue;
|
|
30592
30597
|
throw new Error("physical-copy root reference marker names an unregistered root");
|
|
30593
30598
|
}
|
|
30594
|
-
referenced.add(markerRoot2);
|
|
30599
|
+
referenced.add(markerRoot2), markerIndex && markerIndex.set(markerRoot2, [...markerIndex.get(markerRoot2) ?? [], stateFile]);
|
|
30595
30600
|
continue;
|
|
30596
30601
|
}
|
|
30597
30602
|
let preliminary = value;
|
|
@@ -30602,7 +30607,7 @@ async function collectDurablyReferencedShadowRoots(stateRoot, stateRootAuthority
|
|
|
30602
30607
|
if (allowUnregisteredReferences) continue;
|
|
30603
30608
|
throw new Error("physical-copy root exposure marker names an unregistered root");
|
|
30604
30609
|
}
|
|
30605
|
-
referenced.add(markerRoot);
|
|
30610
|
+
referenced.add(markerRoot), markerIndex && markerIndex.set(markerRoot, [...markerIndex.get(markerRoot) ?? [], stateFile]);
|
|
30606
30611
|
}
|
|
30607
30612
|
}
|
|
30608
30613
|
return referenced;
|
|
@@ -30640,7 +30645,7 @@ async function registerAndListQuotaShadowRoots(stateRoot, stateRootIdentity, cur
|
|
|
30640
30645
|
else
|
|
30641
30646
|
throw new Error("physical-copy root changed identity while quota authority is retained");
|
|
30642
30647
|
if (!priorCurrent && mode === "register-current" && consumeMetadataPath(registryBudget, currentShadowRoot, "physical-copy root registry"), mode === "register-current" && byPath.set(currentShadowRoot, { path: currentShadowRoot, ...currentShadowRootIdentity }), byPath.size > 256) throw new Error("physical-copy root registry exceeds 256 roots");
|
|
30643
|
-
let retained = [], scanBudget = createPathBudget(), referencedShadowRoots = null, hasPhysicalCopyEntry = async (candidate) => {
|
|
30648
|
+
let retained = [], scanBudget = createPathBudget(), referencedShadowRoots = null, vanishedMarkerIndex = null, hasPhysicalCopyEntry = async (candidate) => {
|
|
30644
30649
|
let liveRoot;
|
|
30645
30650
|
try {
|
|
30646
30651
|
liveRoot = await captureWorkspaceRootAuthority(candidate.path);
|
|
@@ -30668,7 +30673,79 @@ async function registerAndListQuotaShadowRoots(stateRoot, stateRootIdentity, cur
|
|
|
30668
30673
|
afterQuotaReferenceTaskEntry,
|
|
30669
30674
|
afterQuotaReferenceMarkerEntry,
|
|
30670
30675
|
afterQuotaReferenceMarkerStat
|
|
30671
|
-
), !referencedShadowRoots.has(candidate.path))
|
|
30676
|
+
), !referencedShadowRoots.has(candidate.path)), vanishedRootInodeSurvives = async (candidate) => {
|
|
30677
|
+
let parent = path26.dirname(candidate.path);
|
|
30678
|
+
if (parent === candidate.path) return !0;
|
|
30679
|
+
try {
|
|
30680
|
+
await fs19.lstat(parent);
|
|
30681
|
+
} catch (err) {
|
|
30682
|
+
return err.code !== "ENOENT";
|
|
30683
|
+
}
|
|
30684
|
+
let entries;
|
|
30685
|
+
try {
|
|
30686
|
+
entries = await readDirectoryBounded(
|
|
30687
|
+
parent,
|
|
30688
|
+
scanBudget,
|
|
30689
|
+
"physical-copy root reconcile parent scan",
|
|
30690
|
+
parent,
|
|
30691
|
+
{ includeStats: !0 }
|
|
30692
|
+
);
|
|
30693
|
+
} catch {
|
|
30694
|
+
return !0;
|
|
30695
|
+
}
|
|
30696
|
+
for (let entry of entries) {
|
|
30697
|
+
let stat13 = boundedDirectoryStat(entry);
|
|
30698
|
+
if (stat13 && stat13.ino === candidate.ino) return !0;
|
|
30699
|
+
}
|
|
30700
|
+
return !1;
|
|
30701
|
+
}, canRetireVanishedRoot = async (candidate) => {
|
|
30702
|
+
if (await vanishedRootInodeSurvives(candidate)) return !1;
|
|
30703
|
+
let referenced = referencedShadowRoots, markers = vanishedMarkerIndex;
|
|
30704
|
+
if ((referenced === null || markers === null) && (markers = /* @__PURE__ */ new Map(), referenced = await collectDurablyReferencedShadowRoots(
|
|
30705
|
+
stateRoot,
|
|
30706
|
+
stateRootIdentity,
|
|
30707
|
+
maxStateMarkerBytes,
|
|
30708
|
+
new Set(byPath.keys()),
|
|
30709
|
+
afterQuotaReferenceTaskEntry,
|
|
30710
|
+
afterQuotaReferenceMarkerEntry,
|
|
30711
|
+
afterQuotaReferenceMarkerStat,
|
|
30712
|
+
// TOLERANT on purpose. (Stage 1 F4: an earlier version of this comment said "unlike the
|
|
30713
|
+
// retirement-mode call above" — that was wrong, and had been wrong on main too: the retirement-mode
|
|
30714
|
+
// call already passes all three flags true. The scan that stays STRICT is the one behind
|
|
30715
|
+
// `canRetireReincarnatedRoot`.)
|
|
30716
|
+
//
|
|
30717
|
+
// This scan answers one narrow question — is the DEAD root still referenced? — and it runs on a state root
|
|
30718
|
+
// shared by every CodeVibe session and agent on the machine. Strict mode aborts the whole reconcile on
|
|
30719
|
+
// anything unexpected anywhere in that directory, which in practice means: a stray regular file (the
|
|
30720
|
+
// registry's own `.bak` copies — including the ones `codevibe doctor --repair` used to write there before
|
|
30721
|
+
// Stage 1 F5 moved every write it makes to `~/.codevibe/shadow-root-backups/`), a marker naming a
|
|
30722
|
+
// root some other agent never cleaned up (six such directories existed on the dogfood machine), or a
|
|
30723
|
+
// sibling session tearing down concurrently. Any of those would re-wedge the user with
|
|
30724
|
+
// `physical-copy root reference state entry changed type` and no way out — which is exactly what the
|
|
30725
|
+
// real-surface E2E hit.
|
|
30726
|
+
//
|
|
30727
|
+
// Tolerating them cannot lose quota authority: an entry this scan skips is simply not counted as a
|
|
30728
|
+
// reference, and the retirement still requires the root's inode to be proven freed first.
|
|
30729
|
+
!0,
|
|
30730
|
+
// allowUnrecognizedRegularFiles
|
|
30731
|
+
!0,
|
|
30732
|
+
// allowUnregisteredReferences
|
|
30733
|
+
!0,
|
|
30734
|
+
// allowConcurrentSiblingTeardown — surfaces as a retryable enumeration change
|
|
30735
|
+
markers
|
|
30736
|
+
), referencedShadowRoots = referenced, vanishedMarkerIndex = markers), !referenced.has(candidate.path)) return !0;
|
|
30737
|
+
for (let markerFile of markers.get(candidate.path) ?? []) {
|
|
30738
|
+
await anchoredRemoveFile(markerFile);
|
|
30739
|
+
let taskStateDir = path26.dirname(markerFile);
|
|
30740
|
+
try {
|
|
30741
|
+
await anchoredRemoveEmptyDirectory(taskStateDir, void 0, { expectedParent: stateRootIdentity });
|
|
30742
|
+
} catch (err) {
|
|
30743
|
+
let code = err.code;
|
|
30744
|
+
if (code !== "ENOTEMPTY" && code !== "ENOENT" && code !== "EEXIST") throw err;
|
|
30745
|
+
}
|
|
30746
|
+
}
|
|
30747
|
+
return !0;
|
|
30748
|
+
};
|
|
30672
30749
|
if (mode === "retire-current-if-unused") {
|
|
30673
30750
|
let candidate = priorCurrent;
|
|
30674
30751
|
if (await assertWorkspaceRootAuthority(
|
|
@@ -30731,8 +30808,8 @@ async function registerAndListQuotaShadowRoots(stateRoot, stateRootIdentity, cur
|
|
|
30731
30808
|
)).some((entry) => entry.isDirectory() && !entry.isSymbolicLink() && (SHADOW_DIR_RE.test(entry.name) || SHADOW_STAGING_DIR_RE.test(entry.name) || SHADOW_TREE_TOMBSTONE_RE.test(entry.name))) ? retained.push(candidate) : reincarnatedDevice !== null && (await canRetireReincarnatedRoot(candidate) || retained.push(candidate));
|
|
30732
30809
|
} catch (err) {
|
|
30733
30810
|
if (err.code === "ENOENT") {
|
|
30734
|
-
if (!await canRetireReincarnatedRoot(candidate))
|
|
30735
|
-
throw new
|
|
30811
|
+
if (!await canRetireReincarnatedRoot(candidate) && !await canRetireVanishedRoot(candidate))
|
|
30812
|
+
throw new StaleShadowRootError(candidate.path, registryPath);
|
|
30736
30813
|
byPath.delete(candidate.path);
|
|
30737
30814
|
continue;
|
|
30738
30815
|
}
|
|
@@ -48439,8 +48516,15 @@ function projectDistilledForRole(entry, role, clearance, scope, retiredIds) {
|
|
|
48439
48516
|
};
|
|
48440
48517
|
return projected.task_specs.length === 0 && projected.outcomes.length === 0 && projected.artifact_refs.length === 0 && projected.surviving_decisions.length === 0 && projected.surviving_open_questions.length === 0 ? null : projected;
|
|
48441
48518
|
}
|
|
48442
|
-
var compactionIntegrityWarned = /* @__PURE__ */ new Set(), compactionsInFlight = /* @__PURE__ */ new Set();
|
|
48519
|
+
var compactionIntegrityWarned = /* @__PURE__ */ new Set(), compactionsInFlight = /* @__PURE__ */ new Set(), compactionChains = /* @__PURE__ */ new Map();
|
|
48443
48520
|
async function compactSessionContext(deps) {
|
|
48521
|
+
let current = compactionChains.get(deps.sessionId) ?? Promise.resolve(), run2 = () => compactSessionContextLocked(deps), next = current.then(run2, run2), chain = next.catch(() => {
|
|
48522
|
+
});
|
|
48523
|
+
return compactionChains.set(deps.sessionId, chain), chain.finally(() => {
|
|
48524
|
+
compactionChains.get(deps.sessionId) === chain && compactionChains.delete(deps.sessionId);
|
|
48525
|
+
}), next;
|
|
48526
|
+
}
|
|
48527
|
+
async function compactSessionContextLocked(deps) {
|
|
48444
48528
|
try {
|
|
48445
48529
|
let verified = await readVerifiedContextItems(deps.sessionId);
|
|
48446
48530
|
if (!verified.ok)
|
|
@@ -48564,7 +48648,6 @@ async function renderRehydratedSessionContext(deps) {
|
|
|
48564
48648
|
for (let item of [...hot.slice(-RENDERED_HOT_ITEM_MAX)].reverse()) {
|
|
48565
48649
|
let who = item.author.role === "agent" && item.author.agent_id ? item.author.agent_id : item.author.role, fact = bodyToFactText(item.body), rendered = (classifying || isBrainstorm) && item.kind === "turn" ? fact : capForRender(fact), line = `- [${item.kind}] ${who}: ${rendered}`;
|
|
48566
48650
|
if (!take(hotLinesNewestFirst, line)) {
|
|
48567
|
-
if (!classifying && !isBrainstorm) break;
|
|
48568
48651
|
hotLinesNewestFirst.length === 0 && take(
|
|
48569
48652
|
hotLinesNewestFirst,
|
|
48570
48653
|
cutPreservingEnds(line, Math.min(sectionMax - used - 1, Math.floor(sectionMax * 2 / 3)))
|
|
@@ -48575,22 +48658,46 @@ async function renderRehydratedSessionContext(deps) {
|
|
|
48575
48658
|
let hotLines = [...hotLinesNewestFirst].reverse();
|
|
48576
48659
|
allocateMessages(USER_CONTEXT_MESSAGE_MAX_CHARS_PLANNER);
|
|
48577
48660
|
let distilledLineGroups = [];
|
|
48578
|
-
|
|
48579
|
-
let group = [];
|
|
48661
|
+
for (let d of [...rehydrated.distilled].reverse()) {
|
|
48662
|
+
let group = [], savedUsed = used, fits = !0;
|
|
48580
48663
|
for (let spec of d.task_specs)
|
|
48581
|
-
if (!take(group, `- Task: ${capForRender(bodyToFactText(spec.body))}`))
|
|
48582
|
-
|
|
48583
|
-
|
|
48584
|
-
|
|
48664
|
+
if (!take(group, `- Task: ${capForRender(bodyToFactText(spec.body))}`)) {
|
|
48665
|
+
fits = !1;
|
|
48666
|
+
break;
|
|
48667
|
+
}
|
|
48668
|
+
if (fits) {
|
|
48669
|
+
for (let out of d.outcomes)
|
|
48670
|
+
if (!take(group, ` Outcome: ${capForRender(bodyToFactText(out.body))}`)) {
|
|
48671
|
+
fits = !1;
|
|
48672
|
+
break;
|
|
48673
|
+
}
|
|
48674
|
+
}
|
|
48675
|
+
if (fits && deps.purpose !== "classification") {
|
|
48585
48676
|
for (let dec of d.surviving_decisions)
|
|
48586
|
-
if (!isUserRuleBody(dec.body) && !take(group, ` Decision: ${capForRender(bodyToFactText(dec.body))}`))
|
|
48587
|
-
|
|
48588
|
-
|
|
48589
|
-
|
|
48677
|
+
if (!isUserRuleBody(dec.body) && !take(group, ` Decision: ${capForRender(bodyToFactText(dec.body))}`)) {
|
|
48678
|
+
fits = !1;
|
|
48679
|
+
break;
|
|
48680
|
+
}
|
|
48681
|
+
if (fits) {
|
|
48682
|
+
for (let q of d.surviving_open_questions)
|
|
48683
|
+
if (!take(group, ` Open question: ${capForRender(bodyToFactText(q.body))}`)) {
|
|
48684
|
+
fits = !1;
|
|
48685
|
+
break;
|
|
48686
|
+
}
|
|
48687
|
+
}
|
|
48688
|
+
}
|
|
48689
|
+
if (fits) {
|
|
48690
|
+
for (let a of d.artifact_refs)
|
|
48691
|
+
if (!take(group, ` Artifact: ${capForRender(bodyToFactText(a.body))}`)) {
|
|
48692
|
+
fits = !1;
|
|
48693
|
+
break;
|
|
48694
|
+
}
|
|
48590
48695
|
}
|
|
48591
|
-
|
|
48592
|
-
|
|
48593
|
-
|
|
48696
|
+
if (!fits) {
|
|
48697
|
+
used = savedUsed;
|
|
48698
|
+
continue;
|
|
48699
|
+
}
|
|
48700
|
+
group.length > 0 && distilledLineGroups.push(group);
|
|
48594
48701
|
}
|
|
48595
48702
|
let distilledLines = distilledLineGroups.reverse().flat(), userLines = [];
|
|
48596
48703
|
if (carriesUserList && userCandidates) {
|
|
@@ -52127,6 +52234,8 @@ var AUTHORITY_REFUSAL_LABEL = {
|
|
|
52127
52234
|
function classifyImplementorRoundFailure(err) {
|
|
52128
52235
|
if (err instanceof AuthorityError)
|
|
52129
52236
|
return AUTHORITY_REFUSAL_LABEL[err.refusal.category] ?? "the implementor was refused authority";
|
|
52237
|
+
if (err instanceof StaleShadowRootError)
|
|
52238
|
+
return `the recorded workspace-copy folder ${err.stalePath} is missing and its contents could not be accounted for (they may have been moved). Run \`codevibe doctor\` to review and clear it`;
|
|
52130
52239
|
let msg = err instanceof Error ? err.message.toLowerCase() : "";
|
|
52131
52240
|
return msg.includes("enoent") || msg.includes("spawn") || msg.includes("command not found") || msg.includes("not installed") ? "the coding agent could not be started" : "an unexpected error occurred";
|
|
52132
52241
|
}
|
|
@@ -55206,7 +55315,12 @@ ${section}`);
|
|
|
55206
55315
|
}
|
|
55207
55316
|
logger.warn("[QuorumLoop] implementor round failed", {
|
|
55208
55317
|
gateId,
|
|
55209
|
-
...errorShapeOnly(err)
|
|
55318
|
+
...errorShapeOnly(err),
|
|
55319
|
+
// FU-1 — the ONE exception to the shape-only projection, decided as FU1-D2. These are CodeVibe-registered
|
|
55320
|
+
// root pathnames carried as structured fields, never raw error text and never user content; without them
|
|
55321
|
+
// the log records `messageBytes` and nothing else, and a machine-wide outage is undiagnosable after the
|
|
55322
|
+
// fact (it was, twice, on 2026-09-17).
|
|
55323
|
+
...err instanceof StaleShadowRootError ? { staleShadowRoot: err.stalePath, shadowRootRegistry: err.registryPath } : {}
|
|
55210
55324
|
});
|
|
55211
55325
|
let reason = classifyImplementorRoundFailure(err);
|
|
55212
55326
|
this.surfaceHalt(`The task could not proceed \u2014 ${reason}.`);
|
package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/context-compaction.d.ts
CHANGED
|
@@ -127,11 +127,9 @@ export interface SessionCompactionCache {
|
|
|
127
127
|
sessionId: string;
|
|
128
128
|
/**
|
|
129
129
|
* High-watermark `seq` — every item with `seq <= compactedThroughSeq` is
|
|
130
|
-
* covered by `distilled`. `null` = nothing compacted yet. This is
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
* hosted upload path, which does not exist yet; flagged in the A1f
|
|
134
|
-
* report).
|
|
130
|
+
* covered by `distilled`. `null` = nothing compacted yet. This is the LOCAL
|
|
131
|
+
* watermark; hosted blind-hold upload (shipped in A1e via `putContextItem`)
|
|
132
|
+
* tracks its own upload watermark in `hosted-sync.json`.
|
|
135
133
|
*/
|
|
136
134
|
compactedThroughSeq: string | null;
|
|
137
135
|
/**
|
|
@@ -238,6 +236,8 @@ export declare function projectDistilledForRole(entry: DistilledTaskSummary, rol
|
|
|
238
236
|
*
|
|
239
237
|
* LOSSLESS: the log is never touched — only the sidecar cache advances.
|
|
240
238
|
* Fail-closed: an unverifiable chain compacts nothing. Never throws.
|
|
239
|
+
* Mutex-held per session: `onTaskBoundary` and `maybeFireCompactionSafetyValve`
|
|
240
|
+
* serialize strictly so a valve run never overwrites a boundary distillation.
|
|
241
241
|
*/
|
|
242
242
|
export declare function compactSessionContext(deps: {
|
|
243
243
|
sessionId: string;
|
|
@@ -402,3 +402,5 @@ export declare function gcContextItemLogs(deps: {
|
|
|
402
402
|
export declare function onTaskBoundary(sessionId: string): Promise<void>;
|
|
403
403
|
/** Test seam — reset module state (vitest-gated, the established pattern). */
|
|
404
404
|
export declare function resetContextCompactionProcessStateForTests(): void;
|
|
405
|
+
/** Test seam — inspect compactionChains size to verify prompt cleanup upon settlement. */
|
|
406
|
+
export declare function getCompactionChainsSizeForTests(): number;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
interface RegisteredRoot {
|
|
2
|
+
path: string;
|
|
3
|
+
dev?: string;
|
|
4
|
+
ino?: string;
|
|
5
|
+
canonicalPath?: string;
|
|
6
|
+
birthtimeNs?: string;
|
|
7
|
+
version?: number;
|
|
8
|
+
}
|
|
9
|
+
/** What the registry says about one root, and what the filesystem says back. */
|
|
10
|
+
export interface RootDiagnosis {
|
|
11
|
+
root: RegisteredRoot;
|
|
12
|
+
/** The registered pathname resolves to a directory right now. */
|
|
13
|
+
present: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* The recorded inode was found among the root's siblings — the folder was renamed and its copies still exist,
|
|
16
|
+
* so the entry is still real quota authority. `undefined` when the parent EXISTS but could not be enumerated,
|
|
17
|
+
* which is a refusal to guess rather than an answer; a parent that is gone reads `false` (F1-10).
|
|
18
|
+
*/
|
|
19
|
+
inodeSurvives?: boolean;
|
|
20
|
+
/** Durable markers that name this root (`dirname(shadowDir)` / `dirname(finalShadowDir)`). */
|
|
21
|
+
markers: string[];
|
|
22
|
+
verdict: 'healthy' | 'reconcilable' | 'bytes-may-exist' | 'unknown';
|
|
23
|
+
}
|
|
24
|
+
/** The product's own state root — never a second spelling of it (Stage 1 F7). */
|
|
25
|
+
export declare function shadowStateRoot(): string;
|
|
26
|
+
/** Read the registry. A missing or unreadable registry is reported, never repaired. */
|
|
27
|
+
export declare function readRegistry(stateRoot: string): {
|
|
28
|
+
roots: RegisteredRoot[];
|
|
29
|
+
raw: string;
|
|
30
|
+
} | null;
|
|
31
|
+
/** Every durable marker under the state root, mapped to the root it names. */
|
|
32
|
+
export declare function collectMarkers(stateRoot: string): Map<string, string[]>;
|
|
33
|
+
/**
|
|
34
|
+
* Does the recorded inode still exist among the root's siblings?
|
|
35
|
+
*
|
|
36
|
+
* `false` — proven gone, so the entry is reconcilable. `true` — a sibling still holds it, so the bytes are real.
|
|
37
|
+
* `undefined` — the parent exists but could not be READ, which is a refusal to guess rather than an answer.
|
|
38
|
+
*/
|
|
39
|
+
export declare function inodeSurvivesInParent(root: RegisteredRoot): boolean | undefined;
|
|
40
|
+
export declare function diagnose(stateRoot: string, roots: RegisteredRoot[]): RootDiagnosis[];
|
|
41
|
+
export declare function runDoctorCli(argv: string[], opts?: {
|
|
42
|
+
stateRoot?: string;
|
|
43
|
+
}): Promise<number>;
|
|
44
|
+
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quantiya/codevibe-core",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.42",
|
|
4
4
|
"description": "Core library for CodeVibe plugins - shared keychain, crypto, AppSync, and auth functionality",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"typecheck": "tsc --noEmit",
|
|
19
19
|
"emit-types": "tsc -p tsconfig.types.json --emitDeclarationOnly",
|
|
20
20
|
"build": "rm -rf dist && npm run emit-types && esbuild src/index.ts --bundle --platform=node --target=node18 --minify --packages=external --define:__CODEVIBE_TEST_BUILD__=false --outfile=dist/index.js && esbuild src/orchestration-shell/cli.ts --bundle --platform=node --target=node18 --minify-syntax --packages=external --define:__CODEVIBE_TEST_BUILD__=false --outfile=dist/orchestration-shell/cli.js --banner:js=\"#!/usr/bin/env node\" && esbuild src/orchestration-shell/web/web-extract-worker.ts --bundle --platform=node --target=node18 --minify --packages=external --outfile=dist/orchestration-shell/web-extract-worker.js && npm run verify-no-test-hooks && npm run verify-no-test-types",
|
|
21
|
-
"verify-no-test-hooks": "if grep -ERl 'CODEVIBE_TEST_FORCE_QUOTA_FAIL|CODEVIBE_TEST_FORCE_IMPLEMENTOR_AGENT|CODEVIBE_ANCHORED_PUBLICATION_AUTHORITY_ROOT|codevibe-anchored-publications-|cv-publication-authority-vitest-|codevibe\\.test\\.publication-authority-|setPublicationAuthorityRootForTestBuild|__CODEVIBE_TEST_BUILD__|_onBeforeLinkForTesting|_onBeforeSummariesLockForTesting|__codevibe_test_on_before_link|__codevibe_test_on_before_summaries_lock' dist; then echo 'ERROR: a test-only hook leaked into a published artifact (prod-unreachability invariant)'; exit 1; fi; echo 'OK
|
|
21
|
+
"verify-no-test-hooks": "if grep -ERl 'CODEVIBE_TEST_FORCE_QUOTA_FAIL|CODEVIBE_TEST_FORCE_IMPLEMENTOR_AGENT|CODEVIBE_ANCHORED_PUBLICATION_AUTHORITY_ROOT|codevibe-anchored-publications-|cv-publication-authority-vitest-|codevibe\\.test\\.publication-authority-|setPublicationAuthorityRootForTestBuild|__CODEVIBE_TEST_BUILD__|_onBeforeLinkForTesting|_onBeforeSummariesLockForTesting|__codevibe_test_on_before_link|__codevibe_test_on_before_summaries_lock' dist; then echo 'ERROR: a test-only hook leaked into a published artifact (prod-unreachability invariant)'; exit 1; fi; echo 'OK \u2014 no test-only hooks in published artifacts'",
|
|
22
22
|
"verify-no-test-types": "if find dist -type f \\( -path '*/__tests__/*' -o -name '*.test.d.ts' -o -name 'test-publication-authority-setup.d.ts' \\) | grep -q .; then echo 'verify-no-test-types: test declarations present in dist (tsconfig.types.json must exclude test sources)' >&2; exit 1; fi",
|
|
23
23
|
"clean": "rm -rf dist",
|
|
24
24
|
"prepublishOnly": "npm run build",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quantiya/codevibe-codex-plugin",
|
|
3
|
-
"version": "2.0.
|
|
4
|
-
"description": "Control OpenAI Codex CLI from your iPhone and Android
|
|
3
|
+
"version": "2.0.49",
|
|
4
|
+
"description": "Control OpenAI Codex CLI from your iPhone and Android \u2014 real-time sync, approve file edits, send prompts by voice. Part of CodeVibe.",
|
|
5
5
|
"main": "dist/server.js",
|
|
6
6
|
"codevibe": {
|
|
7
7
|
"companionLauncher": "./libexec/companion-launcher"
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"node": ">=22.0.0"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@quantiya/codevibe-core": "^2.0.
|
|
50
|
+
"@quantiya/codevibe-core": "^2.0.42",
|
|
51
51
|
"@quantiya/quorum-core": "^1.0.1",
|
|
52
52
|
"chokidar": "^4.0.0",
|
|
53
53
|
"dotenv": "^16.6.1",
|