harnery 0.31.6 → 0.33.0
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 +2 -0
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +5 -1
- package/dist/commands/agents.d.ts +0 -9
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +280 -94
- package/dist/commands/browse-session.d.ts +21 -0
- package/dist/commands/browse-session.d.ts.map +1 -0
- package/dist/commands/browse-session.js +157 -0
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +205 -37
- package/dist/commands/checkpoint.js +1 -1
- package/dist/commands/claude-desktop.d.ts +2 -2
- package/dist/commands/claude-desktop.d.ts.map +1 -1
- package/dist/commands/claude-desktop.js +74 -3
- package/dist/commands/deinit.d.ts.map +1 -1
- package/dist/commands/deinit.js +4 -0
- package/dist/commands/docs.d.ts.map +1 -1
- package/dist/commands/docs.js +40 -0
- package/dist/commands/doctor.d.ts +4 -2
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +141 -19
- package/dist/commands/init.d.ts +2 -2
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +26 -5
- package/dist/commands/instructions.d.ts +4 -0
- package/dist/commands/instructions.d.ts.map +1 -0
- package/dist/commands/instructions.js +100 -0
- package/dist/commands/presence.d.ts.map +1 -1
- package/dist/commands/presence.js +4 -1
- package/dist/commands/tunnel.d.ts.map +1 -1
- package/dist/commands/tunnel.js +2 -3
- package/dist/core/agents/canonical-emit.d.ts +2 -3
- package/dist/core/agents/canonical-emit.d.ts.map +1 -1
- package/dist/core/agents/canonical-emit.js +6 -5
- package/dist/core/agents/cli.js +128 -89
- package/dist/core/agents/coord-client.d.ts +18 -3
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +5 -4
- package/dist/core/agents/finalization.d.ts +68 -0
- package/dist/core/agents/finalization.d.ts.map +1 -0
- package/dist/core/agents/finalization.js +443 -0
- package/dist/core/agents/git-hook.d.ts +51 -0
- package/dist/core/agents/git-hook.d.ts.map +1 -0
- package/dist/core/agents/git-hook.js +118 -0
- package/dist/core/agents/index.d.ts +1 -0
- package/dist/core/agents/index.d.ts.map +1 -1
- package/dist/core/agents/index.js +1 -0
- package/dist/core/agents/render/prompt-context.d.ts +12 -5
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +70 -16
- package/dist/core/agents/render/session-context.d.ts.map +1 -1
- package/dist/core/agents/render/session-context.js +23 -4
- package/dist/core/agents/rules/claim-conflict.js +3 -3
- package/dist/core/agents/rules/commit-conflict.d.ts +15 -6
- package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
- package/dist/core/agents/rules/commit-conflict.js +21 -5
- package/dist/core/agents/rules/stop-hook.d.ts +3 -0
- package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
- package/dist/core/agents/rules/stop-hook.js +59 -23
- package/dist/core/agents/session-events.d.ts +8 -16
- package/dist/core/agents/session-events.d.ts.map +1 -1
- package/dist/core/agents/session-events.js +12 -26
- package/dist/core/agents/state/heartbeat-projector.d.ts +14 -0
- package/dist/core/agents/state/heartbeat-projector.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-projector.js +98 -1
- package/dist/core/agents/state/heartbeat-writer.d.ts +47 -5
- package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +86 -17
- package/dist/core/agents/state/names.d.ts +22 -1
- package/dist/core/agents/state/names.d.ts.map +1 -1
- package/dist/core/agents/state/names.js +40 -2
- package/dist/core/agents/state/session-state.d.ts +44 -0
- package/dist/core/agents/state/session-state.d.ts.map +1 -0
- package/dist/core/agents/state/session-state.js +81 -0
- package/dist/core/config.d.ts +30 -2
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +74 -11
- package/dist/core/governor/planning.d.ts.map +1 -1
- package/dist/core/governor/planning.js +12 -13
- package/dist/core/hooks/adapter/detect.d.ts +2 -4
- package/dist/core/hooks/adapter/detect.d.ts.map +1 -1
- package/dist/core/hooks/adapter/detect.js +4 -14
- package/dist/core/hooks/adapter/events.d.ts.map +1 -1
- package/dist/core/hooks/adapter/events.js +1 -0
- package/dist/core/hooks/adapter/output.d.ts +1 -1
- package/dist/core/hooks/adapter/output.d.ts.map +1 -1
- package/dist/core/hooks/adapter/output.js +5 -4
- package/dist/core/hooks/adapter/parse.d.ts +1 -1
- package/dist/core/hooks/adapter/parse.d.ts.map +1 -1
- package/dist/core/hooks/adapter/parse.js +2 -0
- package/dist/core/hooks/adapter/wiring.d.ts +23 -0
- package/dist/core/hooks/adapter/wiring.d.ts.map +1 -1
- package/dist/core/hooks/adapter/wiring.js +32 -0
- package/dist/core/hooks/cli.d.ts +1 -2
- package/dist/core/hooks/cli.d.ts.map +1 -1
- package/dist/core/hooks/cli.js +258 -32
- package/dist/core/hooks/codex-authorization.d.ts +30 -0
- package/dist/core/hooks/codex-authorization.d.ts.map +1 -0
- package/dist/core/hooks/codex-authorization.js +199 -0
- package/dist/core/hooks/codex-wsl-bridge.d.ts +46 -0
- package/dist/core/hooks/codex-wsl-bridge.d.ts.map +1 -0
- package/dist/core/hooks/codex-wsl-bridge.js +137 -0
- package/dist/core/hooks/effects/index.d.ts +1 -1
- package/dist/core/hooks/effects/index.js +3 -3
- package/dist/core/hooks/events/schema.d.ts +57 -1
- package/dist/core/hooks/events/schema.d.ts.map +1 -1
- package/dist/core/hooks/resolve/owner.d.ts +7 -1
- package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
- package/dist/core/hooks/resolve/owner.js +15 -0
- package/dist/core/hooks/resolve/transcript.d.ts +44 -0
- package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
- package/dist/core/hooks/resolve/transcript.js +176 -1
- package/dist/core/hooks/session-name-presence.d.ts +30 -0
- package/dist/core/hooks/session-name-presence.d.ts.map +1 -0
- package/dist/core/hooks/session-name-presence.js +43 -0
- package/dist/core/hooks/unsafe-cross-shell.d.ts +13 -0
- package/dist/core/hooks/unsafe-cross-shell.d.ts.map +1 -0
- package/dist/core/hooks/unsafe-cross-shell.js +151 -0
- package/dist/core/presence/blob.d.ts +4 -0
- package/dist/core/presence/blob.d.ts.map +1 -1
- package/dist/core/presence/blob.js +12 -0
- package/dist/core/presence/index.js +15 -1
- package/dist/core/work/state.d.ts +4 -5
- package/dist/core/work/state.d.ts.map +1 -1
- package/dist/core/work/state.js +5 -8
- package/dist/core/workflow/index.d.ts +1 -1
- package/dist/core/workflow/index.d.ts.map +1 -1
- package/dist/core/workflow/proof.d.ts +2 -2
- package/dist/core/workflow/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +2 -2
- package/dist/core/workflow/run-state.d.ts +2 -2
- package/dist/core/workflow/run-state.d.ts.map +1 -1
- package/dist/core/workflow/run-state.js +2 -2
- package/dist/core/workflow/types.d.ts +3 -3
- package/dist/core/workflow/types.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/execution.d.ts +2 -2
- package/dist/core/workflow/workspaces/execution.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/execution.js +5 -0
- package/dist/core/workflow/workspaces/index.d.ts +1 -1
- package/dist/core/workflow/workspaces/index.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/local-git.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/local-git.js +1 -2
- package/dist/core/workflow/workspaces/paths.d.ts +2 -2
- package/dist/core/workflow/workspaces/types.d.ts +0 -6
- package/dist/core/workflow/workspaces/types.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/validate.d.ts +0 -2
- package/dist/core/workflow/workspaces/validate.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/validate.js +0 -2
- package/dist/lib/browser/client.d.ts +118 -1
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +435 -6
- package/dist/lib/browser/geometry.d.ts.map +1 -1
- package/dist/lib/browser/geometry.js +180 -37
- package/dist/lib/browser/index.d.ts +5 -1
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/index.js +5 -1
- package/dist/lib/browser/netscape-cookies.d.ts +6 -0
- package/dist/lib/browser/netscape-cookies.d.ts.map +1 -0
- package/dist/lib/browser/netscape-cookies.js +31 -0
- package/dist/lib/browser/proxy.d.ts +24 -0
- package/dist/lib/browser/proxy.d.ts.map +1 -0
- package/dist/lib/browser/proxy.js +84 -0
- package/dist/lib/browser/runts.d.ts +6 -0
- package/dist/lib/browser/runts.d.ts.map +1 -1
- package/dist/lib/browser/runts.js +21 -4
- package/dist/lib/browser/session-control.d.ts +112 -0
- package/dist/lib/browser/session-control.d.ts.map +1 -0
- package/dist/lib/browser/session-control.js +670 -0
- package/dist/lib/claude-desktop.d.ts +47 -0
- package/dist/lib/claude-desktop.d.ts.map +1 -1
- package/dist/lib/claude-desktop.js +169 -1
- package/dist/lib/docs-links.d.ts +108 -0
- package/dist/lib/docs-links.d.ts.map +1 -0
- package/dist/lib/docs-links.js +555 -0
- package/dist/lib/exec.d.ts +1 -1
- package/dist/lib/exec.js +1 -1
- package/dist/lib/identities/assume.d.ts +4 -2
- package/dist/lib/identities/assume.d.ts.map +1 -1
- package/dist/lib/identities/assume.js +15 -2
- package/dist/lib/instructions/bundle.d.ts +33 -0
- package/dist/lib/instructions/bundle.d.ts.map +1 -0
- package/dist/lib/instructions/bundle.js +149 -0
- package/dist/lib/instructions/git-hooks.d.ts +75 -0
- package/dist/lib/instructions/git-hooks.d.ts.map +1 -0
- package/dist/lib/instructions/git-hooks.js +238 -0
- package/dist/lib/instructions/splice.d.ts +10 -4
- package/dist/lib/instructions/splice.d.ts.map +1 -1
- package/dist/lib/instructions/splice.js +19 -11
- package/package.json +2 -2
- package/schemas/config.schema.json +32 -0
- package/src/commander.ts +5 -1
- package/src/commands/agents.ts +341 -113
- package/src/commands/browse-session.ts +245 -0
- package/src/commands/browse.ts +287 -44
- package/src/commands/checkpoint.ts +1 -1
- package/src/commands/claude-desktop.ts +106 -5
- package/src/commands/deinit.ts +7 -1
- package/src/commands/docs.ts +56 -0
- package/src/commands/doctor.ts +155 -21
- package/src/commands/init.ts +28 -9
- package/src/commands/instructions.ts +129 -0
- package/src/commands/presence.ts +7 -1
- package/src/commands/tunnel.ts +2 -5
- package/src/core/agents/canonical-emit.ts +7 -6
- package/src/core/agents/cli.ts +143 -89
- package/src/core/agents/coord-client.ts +21 -5
- package/src/core/agents/finalization.ts +595 -0
- package/src/core/agents/git-hook.ts +126 -0
- package/src/core/agents/index.ts +1 -0
- package/src/core/agents/render/prompt-context.ts +96 -16
- package/src/core/agents/render/session-context.ts +29 -4
- package/src/core/agents/rules/claim-conflict.ts +3 -3
- package/src/core/agents/rules/commit-conflict.ts +35 -8
- package/src/core/agents/rules/stop-hook.ts +71 -23
- package/src/core/agents/session-events.ts +14 -41
- package/src/core/agents/state/heartbeat-projector.ts +108 -1
- package/src/core/agents/state/heartbeat-writer.ts +129 -16
- package/src/core/agents/state/names.ts +54 -2
- package/src/core/agents/state/session-state.ts +131 -0
- package/src/core/config.ts +92 -12
- package/src/core/governor/planning.ts +17 -12
- package/src/core/hooks/adapter/detect.ts +4 -13
- package/src/core/hooks/adapter/events.ts +1 -0
- package/src/core/hooks/adapter/output.ts +9 -4
- package/src/core/hooks/adapter/parse.ts +3 -0
- package/src/core/hooks/adapter/wiring.ts +43 -0
- package/src/core/hooks/cli.ts +296 -27
- package/src/core/hooks/codex-authorization.ts +253 -0
- package/src/core/hooks/codex-wsl-bridge.ts +188 -0
- package/src/core/hooks/effects/index.ts +5 -5
- package/src/core/hooks/events/schema.ts +71 -0
- package/src/core/hooks/resolve/owner.ts +22 -1
- package/src/core/hooks/resolve/transcript.ts +164 -1
- package/src/core/hooks/session-name-presence.ts +52 -0
- package/src/core/hooks/unsafe-cross-shell.ts +160 -0
- package/src/core/presence/blob.ts +18 -0
- package/src/core/presence/index.ts +18 -1
- package/src/core/work/state.ts +8 -12
- package/src/core/workflow/engine.ts +2 -2
- package/src/core/workflow/index.ts +0 -1
- package/src/core/workflow/proof.ts +4 -4
- package/src/core/workflow/run-state.ts +5 -5
- package/src/core/workflow/types.ts +3 -3
- package/src/core/workflow/workspaces/execution.ts +11 -4
- package/src/core/workflow/workspaces/index.ts +0 -3
- package/src/core/workflow/workspaces/local-git.ts +1 -2
- package/src/core/workflow/workspaces/paths.ts +2 -2
- package/src/core/workflow/workspaces/types.ts +0 -9
- package/src/core/workflow/workspaces/validate.ts +1 -5
- package/src/lib/browser/client.ts +528 -6
- package/src/lib/browser/geometry.ts +197 -37
- package/src/lib/browser/index.ts +39 -0
- package/src/lib/browser/netscape-cookies.ts +39 -0
- package/src/lib/browser/proxy.ts +105 -0
- package/src/lib/browser/runts.ts +27 -3
- package/src/lib/browser/session-control.ts +892 -0
- package/src/lib/claude-desktop.ts +232 -1
- package/src/lib/docs-links.ts +674 -0
- package/src/lib/exec.ts +1 -1
- package/src/lib/identities/assume.ts +22 -1
- package/src/lib/instructions/bundle.ts +199 -0
- package/src/lib/instructions/git-hooks.ts +259 -0
- package/src/lib/instructions/splice.ts +41 -11
|
@@ -58,6 +58,36 @@ export interface MirrorPlan {
|
|
|
58
58
|
/** Entries skipped because they are archived (opt in via includeArchived). */
|
|
59
59
|
skippedArchived: number;
|
|
60
60
|
}
|
|
61
|
+
export type DesktopLifecycleState = "active" | "blocked" | "done";
|
|
62
|
+
export interface DesktopLifecycleRecord {
|
|
63
|
+
state: DesktopLifecycleState;
|
|
64
|
+
updatedAt: string;
|
|
65
|
+
instanceId: string | null;
|
|
66
|
+
sessionId: string | null;
|
|
67
|
+
reason: string | null;
|
|
68
|
+
}
|
|
69
|
+
export type DesktopTidySource = "lifecycle" | "legacy-prefix";
|
|
70
|
+
export interface DesktopTidyAction {
|
|
71
|
+
entry: DesktopSessionEntry;
|
|
72
|
+
source: DesktopTidySource;
|
|
73
|
+
lifecycle: DesktopLifecycleRecord | null;
|
|
74
|
+
}
|
|
75
|
+
export type DesktopTidySkipReason = "already_archived" | "blocked_title" | "lifecycle_active" | "lifecycle_blocked" | "unmatched";
|
|
76
|
+
export interface DesktopTidySkip {
|
|
77
|
+
entry: DesktopSessionEntry;
|
|
78
|
+
reason: DesktopTidySkipReason;
|
|
79
|
+
lifecycle: DesktopLifecycleRecord | null;
|
|
80
|
+
}
|
|
81
|
+
export interface DesktopTidyPlan {
|
|
82
|
+
actions: DesktopTidyAction[];
|
|
83
|
+
skipped: DesktopTidySkip[];
|
|
84
|
+
}
|
|
85
|
+
export interface DesktopTidyOptions {
|
|
86
|
+
/** Restrict entries to accounts whose UUID starts with one of these prefixes. */
|
|
87
|
+
accounts?: string[];
|
|
88
|
+
/** Accept an unmatched historical `[DONE]` title as a compatibility fallback. */
|
|
89
|
+
includeLegacyPrefix?: boolean;
|
|
90
|
+
}
|
|
61
91
|
/**
|
|
62
92
|
* Candidate desktop-app data directories for this machine, most specific
|
|
63
93
|
* first. Only directories that exist AND contain a claude-code-sessions/
|
|
@@ -102,4 +132,21 @@ export declare function planMirror(accounts: DesktopAccount[], opts?: MirrorOpti
|
|
|
102
132
|
export declare function applyMirror(plan: MirrorPlan): {
|
|
103
133
|
copied: number;
|
|
104
134
|
};
|
|
135
|
+
/**
|
|
136
|
+
* Read the latest durable lifecycle declaration for every Harnery session.
|
|
137
|
+
*
|
|
138
|
+
* The canonical ledger rotates into `events-*.ndjson` archives. Stream each
|
|
139
|
+
* file rather than loading the whole history into one string, then compare
|
|
140
|
+
* event timestamps because adapter replay may append an older event later.
|
|
141
|
+
* Records are indexed by both session_id and instance_id so a desktop
|
|
142
|
+
* cliSessionId can match either identity shape used by older adapters.
|
|
143
|
+
*/
|
|
144
|
+
export declare function readDesktopLifecycleIndex(coordRoot: string): Promise<Map<string, DesktopLifecycleRecord>>;
|
|
145
|
+
/** Select desktop entries whose durable lifecycle is done. */
|
|
146
|
+
export declare function planTidy(accounts: DesktopAccount[], lifecycleBySession: ReadonlyMap<string, DesktopLifecycleRecord>, opts?: DesktopTidyOptions): DesktopTidyPlan;
|
|
147
|
+
/** Apply a tidy plan with same-directory temp files and atomic renames. */
|
|
148
|
+
export declare function applyTidy(plan: DesktopTidyPlan): {
|
|
149
|
+
archived: number;
|
|
150
|
+
alreadyArchived: number;
|
|
151
|
+
};
|
|
105
152
|
//# sourceMappingURL=claude-desktop.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-desktop.d.ts","sourceRoot":"","sources":["../../src/lib/claude-desktop.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"claude-desktop.d.ts","sourceRoot":"","sources":["../../src/lib/claude-desktop.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { copyFileSync, createReadStream, existsSync, mkdirSync, readdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
2
3
|
import { homedir } from "node:os";
|
|
3
4
|
import { basename, dirname, join } from "node:path";
|
|
5
|
+
import { createInterface } from "node:readline";
|
|
4
6
|
const SESSIONS_DIRNAME = "claude-code-sessions";
|
|
5
7
|
function isWsl() {
|
|
6
8
|
if (process.env.WSL_DISTRO_NAME)
|
|
@@ -218,3 +220,169 @@ export function applyMirror(plan) {
|
|
|
218
220
|
}
|
|
219
221
|
return { copied };
|
|
220
222
|
}
|
|
223
|
+
/**
|
|
224
|
+
* Read the latest durable lifecycle declaration for every Harnery session.
|
|
225
|
+
*
|
|
226
|
+
* The canonical ledger rotates into `events-*.ndjson` archives. Stream each
|
|
227
|
+
* file rather than loading the whole history into one string, then compare
|
|
228
|
+
* event timestamps because adapter replay may append an older event later.
|
|
229
|
+
* Records are indexed by both session_id and instance_id so a desktop
|
|
230
|
+
* cliSessionId can match either identity shape used by older adapters.
|
|
231
|
+
*/
|
|
232
|
+
export async function readDesktopLifecycleIndex(coordRoot) {
|
|
233
|
+
const coordDir = join(coordRoot, ".harnery");
|
|
234
|
+
const archives = safeReaddir(coordDir)
|
|
235
|
+
.filter((name) => name.startsWith("events-") && name.endsWith(".ndjson"))
|
|
236
|
+
.sort();
|
|
237
|
+
const files = [...archives, "events.ndjson"]
|
|
238
|
+
.map((name) => join(coordDir, name))
|
|
239
|
+
.filter((path) => existsSync(path));
|
|
240
|
+
const records = new Map();
|
|
241
|
+
const timestamps = new Map();
|
|
242
|
+
for (const file of files) {
|
|
243
|
+
let lines = null;
|
|
244
|
+
try {
|
|
245
|
+
lines = createInterface({
|
|
246
|
+
input: createReadStream(file, { encoding: "utf8" }),
|
|
247
|
+
crlfDelay: Infinity,
|
|
248
|
+
});
|
|
249
|
+
for await (const line of lines) {
|
|
250
|
+
if (!line.trim())
|
|
251
|
+
continue;
|
|
252
|
+
let raw;
|
|
253
|
+
try {
|
|
254
|
+
raw = JSON.parse(line);
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
if (!raw || typeof raw !== "object")
|
|
260
|
+
continue;
|
|
261
|
+
const event = raw;
|
|
262
|
+
if (event.event_type !== "state.task_state" || typeof event.ts !== "string")
|
|
263
|
+
continue;
|
|
264
|
+
const data = event.data;
|
|
265
|
+
if (!data || typeof data !== "object")
|
|
266
|
+
continue;
|
|
267
|
+
const state = data.state;
|
|
268
|
+
if (state !== "active" && state !== "blocked" && state !== "done")
|
|
269
|
+
continue;
|
|
270
|
+
const instanceId = typeof event.instance_id === "string" ? event.instance_id : null;
|
|
271
|
+
const sessionId = typeof event.session_id === "string" ? event.session_id : null;
|
|
272
|
+
const reasonValue = data.reason;
|
|
273
|
+
const record = {
|
|
274
|
+
state,
|
|
275
|
+
updatedAt: event.ts,
|
|
276
|
+
instanceId,
|
|
277
|
+
sessionId,
|
|
278
|
+
reason: typeof reasonValue === "string" && reasonValue.length > 0 ? reasonValue : null,
|
|
279
|
+
};
|
|
280
|
+
const timestamp = Number.isFinite(Date.parse(event.ts)) ? Date.parse(event.ts) : 0;
|
|
281
|
+
for (const key of new Set([sessionId, instanceId].filter((value) => !!value))) {
|
|
282
|
+
const priorTimestamp = timestamps.get(key);
|
|
283
|
+
if (priorTimestamp !== undefined && priorTimestamp > timestamp)
|
|
284
|
+
continue;
|
|
285
|
+
timestamps.set(key, timestamp);
|
|
286
|
+
records.set(key, record);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
catch {
|
|
291
|
+
// A missing or concurrently rotated event file cannot make tidy unsafe:
|
|
292
|
+
// absent lifecycle evidence leaves entries unmatched and therefore skipped.
|
|
293
|
+
}
|
|
294
|
+
finally {
|
|
295
|
+
lines?.close();
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return records;
|
|
299
|
+
}
|
|
300
|
+
/** Select desktop entries whose durable lifecycle is done. */
|
|
301
|
+
export function planTidy(accounts, lifecycleBySession, opts = {}) {
|
|
302
|
+
const selectedAccounts = accounts.filter((account) => !opts.accounts?.length ||
|
|
303
|
+
opts.accounts.some((prefix) => account.accountUuid.startsWith(prefix)));
|
|
304
|
+
const actions = [];
|
|
305
|
+
const skipped = [];
|
|
306
|
+
for (const account of selectedAccounts) {
|
|
307
|
+
for (const entry of account.entries) {
|
|
308
|
+
const lifecycle = lifecycleForEntry(entry, lifecycleBySession);
|
|
309
|
+
if (entry.isArchived) {
|
|
310
|
+
skipped.push({ entry, reason: "already_archived", lifecycle });
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
if (hasLifecyclePrefix(entry.title, "BLOCKED")) {
|
|
314
|
+
skipped.push({ entry, reason: "blocked_title", lifecycle });
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
if (lifecycle) {
|
|
318
|
+
if (lifecycle.state === "done") {
|
|
319
|
+
actions.push({ entry, source: "lifecycle", lifecycle });
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
skipped.push({ entry, reason: `lifecycle_${lifecycle.state}`, lifecycle });
|
|
323
|
+
}
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
if (opts.includeLegacyPrefix && hasLifecyclePrefix(entry.title, "DONE")) {
|
|
327
|
+
actions.push({ entry, source: "legacy-prefix", lifecycle: null });
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
skipped.push({ entry, reason: "unmatched", lifecycle: null });
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return { actions, skipped };
|
|
335
|
+
}
|
|
336
|
+
/** Apply a tidy plan with same-directory temp files and atomic renames. */
|
|
337
|
+
export function applyTidy(plan) {
|
|
338
|
+
let archived = 0;
|
|
339
|
+
let alreadyArchived = 0;
|
|
340
|
+
for (const action of plan.actions) {
|
|
341
|
+
if (archiveEntry(action.entry.file))
|
|
342
|
+
archived++;
|
|
343
|
+
else
|
|
344
|
+
alreadyArchived++;
|
|
345
|
+
}
|
|
346
|
+
return { archived, alreadyArchived };
|
|
347
|
+
}
|
|
348
|
+
function lifecycleForEntry(entry, lifecycleBySession) {
|
|
349
|
+
if (entry.cliSessionId) {
|
|
350
|
+
const lifecycle = lifecycleBySession.get(entry.cliSessionId);
|
|
351
|
+
if (lifecycle)
|
|
352
|
+
return lifecycle;
|
|
353
|
+
}
|
|
354
|
+
return entry.sessionId ? (lifecycleBySession.get(entry.sessionId) ?? null) : null;
|
|
355
|
+
}
|
|
356
|
+
function hasLifecyclePrefix(title, state) {
|
|
357
|
+
if (!title)
|
|
358
|
+
return false;
|
|
359
|
+
return new RegExp(`^\\s*\\[${state}\\](?:\\s*-|\\s|$)`, "i").test(title);
|
|
360
|
+
}
|
|
361
|
+
function archiveEntry(file) {
|
|
362
|
+
const text = readFileSync(file, "utf8");
|
|
363
|
+
const raw = JSON.parse(text);
|
|
364
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
365
|
+
throw new Error(`desktop entry is not a JSON object: ${file}`);
|
|
366
|
+
}
|
|
367
|
+
const entry = raw;
|
|
368
|
+
if (entry.isArchived === true)
|
|
369
|
+
return false;
|
|
370
|
+
entry.isArchived = true;
|
|
371
|
+
const pretty = text.includes("\n");
|
|
372
|
+
const trailingNewline = text.endsWith("\n") ? "\n" : "";
|
|
373
|
+
const next = `${JSON.stringify(entry, null, pretty ? 2 : undefined)}${trailingNewline}`;
|
|
374
|
+
const temp = join(dirname(file), `.${basename(file)}.${process.pid}.${randomUUID()}.tmp`);
|
|
375
|
+
try {
|
|
376
|
+
writeFileSync(temp, next, { encoding: "utf8", mode: statSync(file).mode });
|
|
377
|
+
renameSync(temp, file);
|
|
378
|
+
}
|
|
379
|
+
finally {
|
|
380
|
+
try {
|
|
381
|
+
unlinkSync(temp);
|
|
382
|
+
}
|
|
383
|
+
catch {
|
|
384
|
+
// rename already consumed the temp file, or creation failed before it existed
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
return true;
|
|
388
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
export declare function initDocsContext(opts: {
|
|
2
|
+
repoRoot: string;
|
|
3
|
+
submodules: readonly string[];
|
|
4
|
+
extraExcludedPrefixes?: readonly string[];
|
|
5
|
+
}): void;
|
|
6
|
+
export type LinkSeverity = "error" | "warning";
|
|
7
|
+
export type LinkRule = "missing-target" | "missing-fragment" | "case-mismatch" | "escapes-repo";
|
|
8
|
+
export interface LinkFinding {
|
|
9
|
+
severity: LinkSeverity;
|
|
10
|
+
repo: string;
|
|
11
|
+
/** Source file, relative to its repo root. */
|
|
12
|
+
path: string;
|
|
13
|
+
line: number;
|
|
14
|
+
rule: LinkRule;
|
|
15
|
+
/** The raw link target as written, fragment included. */
|
|
16
|
+
target: string;
|
|
17
|
+
message: string;
|
|
18
|
+
/** Populated for case-mismatch: the path that does exist on disk. */
|
|
19
|
+
suggestion?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface LinkOpts {
|
|
22
|
+
/** Limit to one submodule, or "." for the parent repo. */
|
|
23
|
+
repo?: string;
|
|
24
|
+
/** Skip heading-fragment validation; check target existence only. */
|
|
25
|
+
noFragments?: boolean;
|
|
26
|
+
/** Report findings in immutable-history docs at error severity too. */
|
|
27
|
+
strict?: boolean;
|
|
28
|
+
/** Also flag links that resolve outside their own repo root. */
|
|
29
|
+
checkEscapes?: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface LinkReport {
|
|
32
|
+
repo: string | null;
|
|
33
|
+
files_scanned: number;
|
|
34
|
+
links_checked: number;
|
|
35
|
+
links_skipped: number;
|
|
36
|
+
error_count: number;
|
|
37
|
+
warning_count: number;
|
|
38
|
+
findings: LinkFinding[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Blank out fenced code blocks, preserving line count so reported line numbers
|
|
42
|
+
* stay accurate. Replacing rather than deleting keeps the line index trivially
|
|
43
|
+
* correct.
|
|
44
|
+
*/
|
|
45
|
+
export declare function maskFences(content: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* Blank fenced blocks and inline code spans, preserving line count and column
|
|
48
|
+
* positions. This is the input for link extraction only.
|
|
49
|
+
*
|
|
50
|
+
* Anchor collection deliberately uses {@link maskFences} instead: a heading is
|
|
51
|
+
* very often entirely inline code (`### \`some command\``), and masking the span
|
|
52
|
+
* would erase the heading text and with it the anchor the document really has.
|
|
53
|
+
*/
|
|
54
|
+
export declare function maskCode(content: string): string;
|
|
55
|
+
export interface ExtractedLink {
|
|
56
|
+
target: string;
|
|
57
|
+
line: number;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Pull every link target out of masked Markdown: inline links, images, and
|
|
61
|
+
* reference definitions.
|
|
62
|
+
*
|
|
63
|
+
* The scan keys off each `](` rather than trying to match the link text, which
|
|
64
|
+
* is what makes nested constructs work: in `[](page.md)` both
|
|
65
|
+
* destinations are found, where a text-matching regex sees only one. Angle-
|
|
66
|
+
* bracket-wrapped destinations are unwrapped here so a legitimately spaced
|
|
67
|
+
* filename is not later mistaken for placeholder syntax.
|
|
68
|
+
*/
|
|
69
|
+
export declare function extractLinks(masked: string): ExtractedLink[];
|
|
70
|
+
/**
|
|
71
|
+
* GitHub's heading-anchor slug: lowercase, drop punctuation other than hyphen
|
|
72
|
+
* and underscore, then map each remaining space to one hyphen. Duplicate slugs
|
|
73
|
+
* in one document get -1, -2, ... suffixes in document order.
|
|
74
|
+
*
|
|
75
|
+
* Runs of whitespace are deliberately NOT collapsed. Dropping a punctuation
|
|
76
|
+
* mark leaves the spaces that surrounded it, so "Intent — capture" becomes
|
|
77
|
+
* "intent--capture" with a double hyphen, and that is the anchor GitHub renders
|
|
78
|
+
* and the one real links in the wild are written against.
|
|
79
|
+
*/
|
|
80
|
+
export declare function slugify(heading: string): string;
|
|
81
|
+
/**
|
|
82
|
+
* Every fragment a reader can legitimately target in one document: Markdown
|
|
83
|
+
* heading slugs (ATX and Setext), explicit `{#custom-id}` suffixes, and HTML
|
|
84
|
+
* `id=` / `name=` attributes, which docs use for stable anchors that survive a
|
|
85
|
+
* heading rename.
|
|
86
|
+
*/
|
|
87
|
+
export declare function collectAnchors(content: string): Set<string>;
|
|
88
|
+
interface CheckFileOpts {
|
|
89
|
+
repoName: string;
|
|
90
|
+
repoPath: string;
|
|
91
|
+
/** Source file path relative to repoPath. */
|
|
92
|
+
rel: string;
|
|
93
|
+
content: string;
|
|
94
|
+
noFragments: boolean;
|
|
95
|
+
strict: boolean;
|
|
96
|
+
checkEscapes: boolean;
|
|
97
|
+
/** Cache of absolute file path -> anchor set, shared across the run. */
|
|
98
|
+
anchorCache: Map<string, Set<string>>;
|
|
99
|
+
}
|
|
100
|
+
interface FileResult {
|
|
101
|
+
findings: LinkFinding[];
|
|
102
|
+
checked: number;
|
|
103
|
+
skipped: number;
|
|
104
|
+
}
|
|
105
|
+
export declare function checkFile(opts: CheckFileOpts): FileResult;
|
|
106
|
+
export declare function runLinks(opts: LinkOpts): Promise<LinkReport>;
|
|
107
|
+
export {};
|
|
108
|
+
//# sourceMappingURL=docs-links.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs-links.d.ts","sourceRoot":"","sources":["../../src/lib/docs-links.ts"],"names":[],"mappings":"AAsCA,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,qBAAqB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3C,GAAG,IAAI,CAIP;AAED,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,CAAC;AAE/C,MAAM,MAAM,QAAQ,GAAG,gBAAgB,GAAG,kBAAkB,GAAG,eAAe,GAAG,cAAc,CAAC;AAEhG,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,YAAY,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,CAAC;IACf,yDAAyD;IACzD,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,0DAA0D;IAC1D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uEAAuE;IACvE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gEAAgE;IAChE,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,WAAW,EAAE,CAAC;CACzB;AAgGD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA2BlD;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAQhD;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAoED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,EAAE,CA+B5D;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAM/C;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAuD3D;AA2CD,UAAU,aAAa;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,OAAO,CAAC;IACtB,wEAAwE;IACxE,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;CACvC;AAED,UAAU,UAAU;IAClB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,UAAU,CA+HzD;AAiBD,wBAAsB,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CAyClE"}
|