@gajae-code/coding-agent 0.12.11 → 0.12.13
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/CHANGELOG.md +68 -0
- package/dist/types/cli/marketplace-hint.d.ts +28 -0
- package/dist/types/cli/notify-cli.d.ts +42 -1
- package/dist/types/cli/update-cli.d.ts +9 -3
- package/dist/types/cli.d.ts +10 -0
- package/dist/types/commands/notify.d.ts +6 -0
- package/dist/types/config/file-lock-gc.d.ts +13 -1
- package/dist/types/config/file-lock.d.ts +3 -0
- package/dist/types/config/model-registry.d.ts +6 -0
- package/dist/types/config/models-config-schema.d.ts +99 -0
- package/dist/types/coordinator/contract.d.ts +1 -1
- package/dist/types/coordinator-mcp/question-state.d.ts +3 -1
- package/dist/types/extensibility/extensions/index.d.ts +1 -0
- package/dist/types/extensibility/extensions/ouroboros-ooo-bridge.d.ts +13 -0
- package/dist/types/extensibility/extensions/prefix-command-bridge.d.ts +0 -1
- package/dist/types/extensibility/extensions/types.d.ts +2 -0
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +14 -0
- package/dist/types/gjc-runtime/gc-runtime.d.ts +11 -0
- package/dist/types/main.d.ts +6 -2
- package/dist/types/modes/acp/acp-agent.d.ts +24 -1
- package/dist/types/modes/components/session-selector.d.ts +1 -1
- package/dist/types/modes/utils/host-status.d.ts +23 -0
- package/dist/types/runtime-mcp/types.d.ts +2 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +12 -0
- package/dist/types/sdk/bus/chat-daemon-cli.d.ts +3 -0
- package/dist/types/sdk/bus/chat-daemon-command-channel.d.ts +244 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +11 -1
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +7 -0
- package/dist/types/sdk/bus/control-plane-frames.d.ts +43 -0
- package/dist/types/sdk/bus/conversation-store.d.ts +18 -0
- package/dist/types/sdk/bus/existing-thread-readiness.d.ts +71 -0
- package/dist/types/sdk/bus/html-format.d.ts +10 -0
- package/dist/types/sdk/bus/notification-service.d.ts +10 -0
- package/dist/types/sdk/bus/slack-daemon.d.ts +27 -0
- package/dist/types/sdk/bus/slack-live-provider.d.ts +11 -0
- package/dist/types/sdk/bus/slack-provider.d.ts +14 -0
- package/dist/types/sdk/bus/slack-thread-binding.d.ts +140 -0
- package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +2 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +28 -7
- package/dist/types/sdk/bus/telegram-daemon.d.ts +119 -17
- package/dist/types/sdk/bus/telegram-reference.d.ts +20 -1
- package/dist/types/sdk/bus/topic-registry.d.ts +130 -85
- package/dist/types/sdk/host/host.d.ts +52 -0
- package/dist/types/sdk/lifecycle-session.d.ts +6 -0
- package/dist/types/sdk/session-activation.d.ts +41 -0
- package/dist/types/sdk/session.d.ts +18 -0
- package/dist/types/sdk/startup-capability.d.ts +8 -1
- package/dist/types/session/agent-session.d.ts +7 -2
- package/dist/types/session/artifacts.d.ts +2 -2
- package/dist/types/session/session-manager.d.ts +40 -6
- package/dist/types/tools/index.d.ts +15 -0
- package/dist/types/utils/npm-registry.d.ts +71 -0
- package/examples/extensions/README.md +38 -4
- package/examples/extensions/ooo-bridge.ts +15 -0
- package/package.json +8 -8
- package/scripts/generate-sdk-operation-inventory.ts +4 -0
- package/src/async/job-manager.ts +9 -2
- package/src/cli/fast-help.ts +1 -0
- package/src/cli/marketplace-hint.ts +39 -0
- package/src/cli/notify-cli.ts +226 -2
- package/src/cli/plugin-cli.ts +10 -0
- package/src/cli/update-cli.ts +90 -23
- package/src/cli.ts +23 -0
- package/src/commands/notify.ts +27 -3
- package/src/commands/sdk.ts +1 -0
- package/src/config/file-lock-gc.ts +65 -26
- package/src/config/file-lock.ts +61 -16
- package/src/config/model-profiles.ts +46 -30
- package/src/config/model-registry.ts +17 -5
- package/src/config/models-config-schema.ts +9 -4
- package/src/coordinator/contract.ts +1 -0
- package/src/coordinator-mcp/question-state.ts +2 -0
- package/src/coordinator-mcp/server.ts +358 -7
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -1
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +2 -0
- package/src/extensibility/extensions/index.ts +1 -0
- package/src/extensibility/extensions/ouroboros-ooo-bridge.ts +235 -0
- package/src/extensibility/extensions/prefix-command-bridge.ts +4 -9
- package/src/extensibility/extensions/runner.ts +15 -2
- package/src/extensibility/extensions/types.ts +2 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +9 -5
- package/src/gjc-runtime/deep-interview-state.ts +27 -3
- package/src/gjc-runtime/gc-render.ts +8 -1
- package/src/gjc-runtime/gc-runtime.ts +15 -1
- package/src/gjc-runtime/launch-tmux.ts +53 -1
- package/src/internal-urls/docs-index.generated.ts +14 -13
- package/src/main.ts +214 -70
- package/src/modes/DESIGN.md +8 -5
- package/src/modes/acp/acp-agent.ts +123 -7
- package/src/modes/components/footer.ts +10 -18
- package/src/modes/components/model-selector.ts +52 -5
- package/src/modes/components/session-selector.ts +26 -3
- package/src/modes/components/status-line/gh.ts +23 -2
- package/src/modes/controllers/event-controller.ts +3 -0
- package/src/modes/controllers/extension-ui-controller.ts +2 -0
- package/src/modes/controllers/input-controller.ts +11 -0
- package/src/modes/controllers/selector-controller.ts +8 -2
- package/src/modes/interactive-mode.ts +7 -1
- package/src/modes/print-mode.ts +10 -0
- package/src/modes/utils/host-status.ts +38 -0
- package/src/prompts/system/project-prompt.md +19 -0
- package/src/runtime-mcp/types.ts +2 -0
- package/src/sdk/broker/lifecycle.ts +60 -3
- package/src/sdk/bus/chat-daemon-cli.ts +42 -0
- package/src/sdk/bus/chat-daemon-command-channel.ts +921 -0
- package/src/sdk/bus/chat-daemon-control.ts +16 -3
- package/src/sdk/bus/chat-daemon-runtime.ts +257 -21
- package/src/sdk/bus/control-plane-frames.ts +51 -0
- package/src/sdk/bus/conversation-store.ts +29 -1
- package/src/sdk/bus/existing-thread-readiness.ts +155 -0
- package/src/sdk/bus/html-format.ts +19 -3
- package/src/sdk/bus/index.ts +91 -12
- package/src/sdk/bus/notification-service.ts +28 -1
- package/src/sdk/bus/rich-render.ts +3 -2
- package/src/sdk/bus/slack-daemon.ts +99 -4
- package/src/sdk/bus/slack-live-provider.ts +32 -2
- package/src/sdk/bus/slack-provider.ts +11 -0
- package/src/sdk/bus/slack-thread-binding.ts +641 -0
- package/src/sdk/bus/telegram-daemon-cli.ts +11 -0
- package/src/sdk/bus/telegram-daemon-contract.ts +28 -7
- package/src/sdk/bus/telegram-daemon.ts +2007 -509
- package/src/sdk/bus/telegram-reference.ts +114 -15
- package/src/sdk/bus/topic-registry.ts +674 -181
- package/src/sdk/host/host.ts +180 -1
- package/src/sdk/lifecycle-session.ts +8 -2
- package/src/sdk/protocol/operation-inventory.generated.json +22 -0
- package/src/sdk/session-activation.ts +127 -0
- package/src/sdk/session.ts +144 -29
- package/src/sdk/startup-capability.ts +10 -1
- package/src/session/agent-session.ts +220 -13
- package/src/session/artifacts.ts +56 -13
- package/src/session/internal/managed-session-storage.ts +228 -7
- package/src/session/session-manager.ts +225 -60
- package/src/setup/provider-presets.json +3 -3
- package/src/task/index.ts +92 -44
- package/src/thinking-metadata.ts +2 -1
- package/src/tools/ask.ts +10 -0
- package/src/tools/index.ts +15 -0
- package/src/tools/todo-write.ts +4 -4
- package/src/utils/npm-registry.ts +660 -0
|
@@ -217,8 +217,84 @@ type ReplacementCleanupReceipt = {
|
|
|
217
217
|
predecessor: SerializedReplacementIdentity;
|
|
218
218
|
};
|
|
219
219
|
|
|
220
|
+
type LegacyReplacementCleanupIdentity = {
|
|
221
|
+
dev: bigint;
|
|
222
|
+
ino: bigint;
|
|
223
|
+
nlink: bigint;
|
|
224
|
+
size: bigint;
|
|
225
|
+
mtimeNs: bigint;
|
|
226
|
+
ctimeNs: bigint;
|
|
227
|
+
sha256: string;
|
|
228
|
+
};
|
|
229
|
+
|
|
220
230
|
const U64_MAX = 18_446_744_073_709_551_615n;
|
|
221
231
|
|
|
232
|
+
function parseCanonicalU64(value: unknown): bigint | undefined {
|
|
233
|
+
if (typeof value !== "string" || !/^(0|[1-9][0-9]*)$/.test(value) || value.length > 20) return undefined;
|
|
234
|
+
const parsed = BigInt(value);
|
|
235
|
+
return parsed <= U64_MAX ? parsed : undefined;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function parseLegacyHexU64(value: string): bigint | undefined {
|
|
239
|
+
if (!/^[0-9a-f]+$/.test(value) || value.length > 16) return undefined;
|
|
240
|
+
const parsed = BigInt(`0x${value}`);
|
|
241
|
+
return parsed <= U64_MAX ? parsed : undefined;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function asRecord(value: unknown): Record<string, unknown> | undefined {
|
|
245
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
246
|
+
? (value as Record<string, unknown>)
|
|
247
|
+
: undefined;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function legacyReplacementCleanupReceiptBinding(name: string): { dev: bigint; ino: bigint } | undefined {
|
|
251
|
+
const match = /^\.gjc-replace-cleanup-([0-9a-f]+)-([0-9a-f]+)\.json$/.exec(name);
|
|
252
|
+
if (!match?.[1] || !match[2]) return undefined;
|
|
253
|
+
const dev = parseLegacyHexU64(match[1]);
|
|
254
|
+
const ino = parseLegacyHexU64(match[2]);
|
|
255
|
+
return dev !== undefined && ino !== undefined ? { dev, ino } : undefined;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function parseLegacyReplacementCleanupIdentity(value: unknown): LegacyReplacementCleanupIdentity | undefined {
|
|
259
|
+
const identity = asRecord(value);
|
|
260
|
+
if (!identity) return undefined;
|
|
261
|
+
const dev = parseCanonicalU64(identity.dev);
|
|
262
|
+
const ino = parseCanonicalU64(identity.ino);
|
|
263
|
+
const nlink = parseCanonicalU64(identity.nlink);
|
|
264
|
+
const size = parseCanonicalU64(identity.size);
|
|
265
|
+
const mtimeNs = parseCanonicalU64(identity.mtimeNs);
|
|
266
|
+
const ctimeNs = parseCanonicalU64(identity.ctimeNs);
|
|
267
|
+
const sha256 = identity.sha256;
|
|
268
|
+
if (
|
|
269
|
+
dev === undefined ||
|
|
270
|
+
ino === undefined ||
|
|
271
|
+
nlink === undefined ||
|
|
272
|
+
size === undefined ||
|
|
273
|
+
mtimeNs === undefined ||
|
|
274
|
+
ctimeNs === undefined ||
|
|
275
|
+
typeof sha256 !== "string" ||
|
|
276
|
+
!/^[0-9a-f]{64}$/.test(sha256)
|
|
277
|
+
)
|
|
278
|
+
return undefined;
|
|
279
|
+
return { dev, ino, nlink, size, mtimeNs, ctimeNs, sha256 };
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function parseLegacyReplacementCleanupReceipt(
|
|
283
|
+
bytes: Uint8Array,
|
|
284
|
+
): { predecessor: string; successor: string; identity: LegacyReplacementCleanupIdentity } | undefined {
|
|
285
|
+
let value: unknown;
|
|
286
|
+
try {
|
|
287
|
+
value = JSON.parse(Buffer.from(bytes).toString("utf8")) as unknown;
|
|
288
|
+
} catch {
|
|
289
|
+
return undefined;
|
|
290
|
+
}
|
|
291
|
+
const receipt = asRecord(value);
|
|
292
|
+
if (receipt?.version !== 1 || typeof receipt.predecessor !== "string" || typeof receipt.successor !== "string")
|
|
293
|
+
return undefined;
|
|
294
|
+
const identity = parseLegacyReplacementCleanupIdentity(receipt.identity);
|
|
295
|
+
return identity ? { predecessor: receipt.predecessor, successor: receipt.successor, identity } : undefined;
|
|
296
|
+
}
|
|
297
|
+
|
|
222
298
|
function replacementCleanupReceiptBinding(
|
|
223
299
|
name: string,
|
|
224
300
|
): { predecessor: { dev: bigint; ino: bigint }; receipt: { dev: bigint; ino: bigint } } | undefined {
|
|
@@ -258,12 +334,20 @@ function replacementReceiptPath(
|
|
|
258
334
|
}
|
|
259
335
|
|
|
260
336
|
function replacementReceiptRetirementName(
|
|
261
|
-
receipt:
|
|
262
|
-
predecessor:
|
|
337
|
+
receipt: { dev: bigint; ino: bigint },
|
|
338
|
+
predecessor: { dev: bigint; ino: bigint },
|
|
263
339
|
): string {
|
|
264
340
|
return `.gjc-receipt-remove-${receipt.dev.toString(16)}-${receipt.ino.toString(16)}-${predecessor.dev.toString(16)}-${predecessor.ino.toString(16)}`;
|
|
265
341
|
}
|
|
266
342
|
|
|
343
|
+
function replacementReceiptPlaceholderRetirementName(
|
|
344
|
+
placeholder: { dev: bigint; ino: bigint },
|
|
345
|
+
predecessor: { dev: bigint; ino: bigint },
|
|
346
|
+
receipt: { dev: bigint; ino: bigint },
|
|
347
|
+
): string {
|
|
348
|
+
return `.gjc-receipt-placeholder-remove-${placeholder.dev.toString(16)}-${placeholder.ino.toString(16)}-${predecessor.dev.toString(16)}-${predecessor.ino.toString(16)}-${receipt.dev.toString(16)}-${receipt.ino.toString(16)}`;
|
|
349
|
+
}
|
|
350
|
+
|
|
267
351
|
const ACL_FAILURE_CODES = new Set(["acl_denied", "acl_io_error", "acl_present", "acl_malformed", "acl_unknown"]);
|
|
268
352
|
const ACL_CLEAR_EVIDENCE = new Set(["cleared", "already_absent", "unsupported", "not_run"]);
|
|
269
353
|
const GENERAL_FAILURE_CODES = new Set([
|
|
@@ -785,14 +869,68 @@ export class ManagedSessionDescendantStore {
|
|
|
785
869
|
}
|
|
786
870
|
}
|
|
787
871
|
|
|
872
|
+
#recoverReplacementCleanupPlaceholder(
|
|
873
|
+
receiptPath: string,
|
|
874
|
+
binding: { predecessor: { dev: bigint; ino: bigint }; receipt: { dev: bigint; ino: bigint } },
|
|
875
|
+
placeholder: ManagedFileSnapshot,
|
|
876
|
+
): boolean {
|
|
877
|
+
if (placeholder.bytes.byteLength !== 0) return false;
|
|
878
|
+
const detachedReceiptPath = path.join(
|
|
879
|
+
this.#baseDir,
|
|
880
|
+
replacementReceiptRetirementName(binding.receipt, binding.predecessor),
|
|
881
|
+
);
|
|
882
|
+
let detachedReceipt: ManagedFileSnapshot;
|
|
883
|
+
try {
|
|
884
|
+
detachedReceipt = captureManagedFileNoFollow(detachedReceiptPath);
|
|
885
|
+
} catch (error) {
|
|
886
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return false;
|
|
887
|
+
throw error;
|
|
888
|
+
}
|
|
889
|
+
if (detachedReceipt.identity.dev !== binding.receipt.dev || detachedReceipt.identity.ino !== binding.receipt.ino)
|
|
890
|
+
return false;
|
|
891
|
+
|
|
892
|
+
const quarantineName = replacementReceiptPlaceholderRetirementName(
|
|
893
|
+
placeholder.identity,
|
|
894
|
+
binding.predecessor,
|
|
895
|
+
binding.receipt,
|
|
896
|
+
);
|
|
897
|
+
const removed = exactUnlink(receiptPath, {
|
|
898
|
+
dev: placeholder.identity.dev,
|
|
899
|
+
ino: placeholder.identity.ino,
|
|
900
|
+
nlink: placeholder.identity.nlink,
|
|
901
|
+
parentDev: this.#subtreeRoot.dev,
|
|
902
|
+
parentIno: this.#subtreeRoot.ino,
|
|
903
|
+
size: BigInt(placeholder.identity.size),
|
|
904
|
+
mtimeNs: placeholder.identity.mtimeNs,
|
|
905
|
+
sha256: placeholder.identity.sha256,
|
|
906
|
+
quarantineName,
|
|
907
|
+
});
|
|
908
|
+
if (
|
|
909
|
+
(!exactUnlinkCompleted(removed) && removed.code !== "not_found") ||
|
|
910
|
+
removed.retainedSuccessorPath !== undefined ||
|
|
911
|
+
removed.retainedUnknownPath !== undefined
|
|
912
|
+
)
|
|
913
|
+
throw new Error(`managed_replace_receipt_cleanup_pending:${removed.code ?? "unknown"}`);
|
|
914
|
+
fsyncDirectory(this.#baseDir);
|
|
915
|
+
return true;
|
|
916
|
+
}
|
|
917
|
+
|
|
788
918
|
#detachReplacementCleanupReceipt(receiptPath: string): void {
|
|
789
919
|
const binding = replacementCleanupReceiptBinding(path.basename(receiptPath));
|
|
790
920
|
if (!binding) throw new Error("managed_replace_cleanup_receipt_invalid");
|
|
791
|
-
|
|
792
|
-
|
|
921
|
+
let receipt: ManagedFileSnapshot;
|
|
922
|
+
try {
|
|
923
|
+
receipt = captureManagedFileNoFollow(receiptPath);
|
|
924
|
+
} catch (error) {
|
|
925
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return;
|
|
926
|
+
throw error;
|
|
927
|
+
}
|
|
928
|
+
if (receipt.identity.dev !== binding.receipt.dev || receipt.identity.ino !== binding.receipt.ino) {
|
|
929
|
+
if (this.#recoverReplacementCleanupPlaceholder(receiptPath, binding, receipt)) return;
|
|
793
930
|
throw new Error("managed_replace_cleanup_receipt_invalid");
|
|
931
|
+
}
|
|
794
932
|
const predecessor = binding.predecessor;
|
|
795
|
-
const quarantineName =
|
|
933
|
+
const quarantineName = replacementReceiptRetirementName(receipt.identity, predecessor);
|
|
796
934
|
const detached = exactUnlink(receiptPath, {
|
|
797
935
|
dev: receipt.identity.dev,
|
|
798
936
|
ino: receipt.identity.ino,
|
|
@@ -805,6 +943,13 @@ export class ManagedSessionDescendantStore {
|
|
|
805
943
|
detachOnly: true,
|
|
806
944
|
quarantineName,
|
|
807
945
|
});
|
|
946
|
+
if (
|
|
947
|
+
!detached.ok &&
|
|
948
|
+
detached.code === "not_found" &&
|
|
949
|
+
detached.retainedSuccessorPath === undefined &&
|
|
950
|
+
detached.retainedUnknownPath === undefined
|
|
951
|
+
)
|
|
952
|
+
return;
|
|
808
953
|
if (
|
|
809
954
|
(!detached.ok && detached.code !== "cleanup_pending") ||
|
|
810
955
|
detached.detachedPath !== path.join(this.#baseDir, quarantineName) ||
|
|
@@ -815,14 +960,90 @@ export class ManagedSessionDescendantStore {
|
|
|
815
960
|
fsyncDirectory(this.#baseDir);
|
|
816
961
|
}
|
|
817
962
|
|
|
963
|
+
#reconcileLegacyReplacementCleanupReceipt(receiptPath: string, name: string): void {
|
|
964
|
+
const binding = legacyReplacementCleanupReceiptBinding(name);
|
|
965
|
+
if (!binding) throw new Error("managed_replace_cleanup_receipt_invalid");
|
|
966
|
+
let receipt: ManagedFileSnapshot;
|
|
967
|
+
try {
|
|
968
|
+
receipt = captureManagedFileNoFollow(receiptPath);
|
|
969
|
+
} catch (error) {
|
|
970
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return;
|
|
971
|
+
throw error;
|
|
972
|
+
}
|
|
973
|
+
const parsed = parseLegacyReplacementCleanupReceipt(receipt.bytes);
|
|
974
|
+
const expectedPredecessor = path.join(
|
|
975
|
+
this.#baseDir,
|
|
976
|
+
`.gjc-exact-replace-destination-${binding.dev.toString(16)}-${binding.ino.toString(16)}`,
|
|
977
|
+
);
|
|
978
|
+
if (
|
|
979
|
+
!parsed ||
|
|
980
|
+
parsed.identity.dev !== binding.dev ||
|
|
981
|
+
parsed.identity.ino !== binding.ino ||
|
|
982
|
+
path.resolve(parsed.predecessor) !== expectedPredecessor ||
|
|
983
|
+
path.dirname(path.resolve(parsed.successor)) !== this.#baseDir
|
|
984
|
+
)
|
|
985
|
+
throw new Error("managed_replace_cleanup_receipt_invalid");
|
|
986
|
+
|
|
987
|
+
const retired = exactUnlink(expectedPredecessor, {
|
|
988
|
+
dev: parsed.identity.dev,
|
|
989
|
+
ino: parsed.identity.ino,
|
|
990
|
+
nlink: parsed.identity.nlink,
|
|
991
|
+
parentDev: this.#subtreeRoot.dev,
|
|
992
|
+
parentIno: this.#subtreeRoot.ino,
|
|
993
|
+
size: parsed.identity.size,
|
|
994
|
+
mtimeNs: parsed.identity.mtimeNs,
|
|
995
|
+
sha256: parsed.identity.sha256,
|
|
996
|
+
quarantineName: `.gjc-replace-retry-${parsed.identity.dev.toString(16)}-${parsed.identity.ino.toString(16)}`,
|
|
997
|
+
});
|
|
998
|
+
if (!exactUnlinkCompleted(retired) && retired.code !== "not_found")
|
|
999
|
+
throw new Error(`managed_replace_cleanup_pending:${retired.code ?? "unknown"}`);
|
|
1000
|
+
|
|
1001
|
+
let currentReceipt: ManagedFileSnapshot;
|
|
1002
|
+
try {
|
|
1003
|
+
currentReceipt = captureManagedFileNoFollow(receiptPath);
|
|
1004
|
+
} catch (error) {
|
|
1005
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
|
|
1006
|
+
fsyncDirectory(this.#baseDir);
|
|
1007
|
+
return;
|
|
1008
|
+
}
|
|
1009
|
+
throw error;
|
|
1010
|
+
}
|
|
1011
|
+
if (
|
|
1012
|
+
!sameIdentity(currentReceipt.identity, receipt.identity) ||
|
|
1013
|
+
currentReceipt.identity.sha256 !== receipt.identity.sha256
|
|
1014
|
+
)
|
|
1015
|
+
throw new Error("managed_replace_cleanup_receipt_invalid");
|
|
1016
|
+
const removed = exactUnlink(receiptPath, {
|
|
1017
|
+
dev: currentReceipt.identity.dev,
|
|
1018
|
+
ino: currentReceipt.identity.ino,
|
|
1019
|
+
nlink: currentReceipt.identity.nlink,
|
|
1020
|
+
parentDev: this.#subtreeRoot.dev,
|
|
1021
|
+
parentIno: this.#subtreeRoot.ino,
|
|
1022
|
+
size: BigInt(currentReceipt.identity.size),
|
|
1023
|
+
mtimeNs: currentReceipt.identity.mtimeNs,
|
|
1024
|
+
sha256: currentReceipt.identity.sha256,
|
|
1025
|
+
quarantineName: `.gjc-receipt-remove-${currentReceipt.identity.dev.toString(16)}-${currentReceipt.identity.ino.toString(16)}`,
|
|
1026
|
+
});
|
|
1027
|
+
if (!exactUnlinkCompleted(removed) && removed.code !== "not_found")
|
|
1028
|
+
throw new Error(`managed_replace_receipt_cleanup_pending:${removed.code ?? "unknown"}`);
|
|
1029
|
+
fsyncDirectory(this.#baseDir);
|
|
1030
|
+
}
|
|
1031
|
+
|
|
818
1032
|
#reconcileReplacementCleanupReceipts(): void {
|
|
819
1033
|
if (this.#reconcilingReplacementCleanup) return;
|
|
820
1034
|
this.#reconcilingReplacementCleanup = true;
|
|
821
1035
|
try {
|
|
822
1036
|
for (const name of fs.readdirSync(this.#baseDir)) {
|
|
823
1037
|
if (!name.startsWith(".gjc-replace-cleanup-")) continue;
|
|
824
|
-
if (
|
|
825
|
-
|
|
1038
|
+
if (replacementCleanupReceiptBinding(name)) {
|
|
1039
|
+
this.#detachReplacementCleanupReceipt(path.join(this.#baseDir, name));
|
|
1040
|
+
continue;
|
|
1041
|
+
}
|
|
1042
|
+
if (legacyReplacementCleanupReceiptBinding(name)) {
|
|
1043
|
+
this.#reconcileLegacyReplacementCleanupReceipt(path.join(this.#baseDir, name), name);
|
|
1044
|
+
continue;
|
|
1045
|
+
}
|
|
1046
|
+
throw new Error("managed_replace_cleanup_receipt_invalid");
|
|
826
1047
|
}
|
|
827
1048
|
} finally {
|
|
828
1049
|
this.#reconcilingReplacementCleanup = false;
|