grounder 0.5.0 → 0.6.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 +21 -20
- package/dist/agents/claude.d.ts +4 -4
- package/dist/agents/claude.d.ts.map +1 -1
- package/dist/agents/claude.js +158 -179
- package/dist/agents/claude.js.map +1 -1
- package/dist/agents/cursor.d.ts +3 -3
- package/dist/agents/cursor.d.ts.map +1 -1
- package/dist/agents/cursor.js +97 -144
- package/dist/agents/cursor.js.map +1 -1
- package/dist/agents/home-skills.d.ts +46 -0
- package/dist/agents/home-skills.d.ts.map +1 -0
- package/dist/agents/home-skills.js +83 -0
- package/dist/agents/home-skills.js.map +1 -0
- package/dist/agents/hook-fragment.d.ts +52 -0
- package/dist/agents/hook-fragment.d.ts.map +1 -0
- package/dist/agents/hook-fragment.js +76 -0
- package/dist/agents/hook-fragment.js.map +1 -0
- package/dist/agents/hook-install.d.ts +62 -0
- package/dist/agents/hook-install.d.ts.map +1 -0
- package/dist/agents/hook-install.js +74 -0
- package/dist/agents/hook-install.js.map +1 -0
- package/dist/agents/hook-runtime.d.ts +77 -10
- package/dist/agents/hook-runtime.d.ts.map +1 -1
- package/dist/agents/hook-runtime.js +274 -70
- package/dist/agents/hook-runtime.js.map +1 -1
- package/dist/agents/index.d.ts +8 -14
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +13 -19
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/types.d.ts +56 -16
- package/dist/agents/types.d.ts.map +1 -1
- package/dist/cli.js +4 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/apply.d.ts +69 -0
- package/dist/commands/apply.d.ts.map +1 -0
- package/dist/commands/apply.js +238 -0
- package/dist/commands/apply.js.map +1 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +190 -97
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/handoff/peek.d.ts +1 -1
- package/dist/commands/handoff/peek.d.ts.map +1 -1
- package/dist/commands/handoff/peek.js +28 -12
- package/dist/commands/handoff/peek.js.map +1 -1
- package/dist/commands/install-drift.d.ts +34 -0
- package/dist/commands/install-drift.d.ts.map +1 -0
- package/dist/commands/install-drift.js +72 -0
- package/dist/commands/install-drift.js.map +1 -0
- package/dist/commands/migrate.d.ts +11 -3
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +67 -33
- package/dist/commands/migrate.js.map +1 -1
- package/dist/commands/overview.d.ts +33 -0
- package/dist/commands/overview.d.ts.map +1 -0
- package/dist/commands/overview.js +150 -0
- package/dist/commands/overview.js.map +1 -0
- package/dist/commands/render-artifact-table.d.ts +85 -0
- package/dist/commands/render-artifact-table.d.ts.map +1 -0
- package/dist/commands/render-artifact-table.js +232 -0
- package/dist/commands/render-artifact-table.js.map +1 -0
- package/dist/commands/search.d.ts.map +1 -1
- package/dist/commands/search.js +15 -4
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +86 -13
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/status.d.ts +7 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +269 -88
- package/dist/commands/status.js.map +1 -1
- package/dist/connector/ledger-migrations.d.ts +55 -0
- package/dist/connector/ledger-migrations.d.ts.map +1 -0
- package/dist/connector/ledger-migrations.js +94 -0
- package/dist/connector/ledger-migrations.js.map +1 -0
- package/dist/connector/state.d.ts +96 -59
- package/dist/connector/state.d.ts.map +1 -1
- package/dist/connector/state.js +165 -107
- package/dist/connector/state.js.map +1 -1
- package/dist/help.d.ts +1 -1
- package/dist/help.d.ts.map +1 -1
- package/dist/help.js +27 -5
- package/dist/help.js.map +1 -1
- package/dist/reconcile/apply.d.ts +31 -0
- package/dist/reconcile/apply.d.ts.map +1 -0
- package/dist/reconcile/apply.js +97 -0
- package/dist/reconcile/apply.js.map +1 -0
- package/dist/reconcile/core.d.ts +82 -0
- package/dist/reconcile/core.d.ts.map +1 -0
- package/dist/reconcile/core.js +163 -0
- package/dist/reconcile/core.js.map +1 -0
- package/dist/reconcile/disk.d.ts +13 -0
- package/dist/reconcile/disk.d.ts.map +1 -0
- package/dist/reconcile/disk.js +28 -0
- package/dist/reconcile/disk.js.map +1 -0
- package/dist/util/fs.d.ts +14 -0
- package/dist/util/fs.d.ts.map +1 -1
- package/dist/util/fs.js +27 -1
- package/dist/util/fs.js.map +1 -1
- package/dist/util/merge-json.d.ts +13 -2
- package/dist/util/merge-json.d.ts.map +1 -1
- package/dist/util/merge-json.js +24 -10
- package/dist/util/merge-json.js.map +1 -1
- package/dist/vault/list-handoffs.d.ts +13 -3
- package/dist/vault/list-handoffs.d.ts.map +1 -1
- package/dist/vault/list-handoffs.js +28 -13
- package/dist/vault/list-handoffs.js.map +1 -1
- package/dist/vault/list-notes.d.ts +12 -3
- package/dist/vault/list-notes.d.ts.map +1 -1
- package/dist/vault/list-notes.js +13 -7
- package/dist/vault/list-notes.js.map +1 -1
- package/dist/vault/list-plans.d.ts +12 -3
- package/dist/vault/list-plans.d.ts.map +1 -1
- package/dist/vault/list-plans.js +13 -7
- package/dist/vault/list-plans.js.map +1 -1
- package/dist/vault/search.d.ts.map +1 -1
- package/dist/vault/search.js +128 -24
- package/dist/vault/search.js.map +1 -1
- package/package.json +2 -2
- package/templates/agents/claude/skills/grounder-handoff/SKILL.md +73 -0
- package/templates/agents/claude/{commands/grounder-note.md → skills/grounder-note/SKILL.md} +6 -0
- package/templates/agents/claude/skills/grounder-overview/SKILL.md +21 -0
- package/templates/agents/claude/{commands/grounder-plan.md → skills/grounder-plan/SKILL.md} +6 -0
- package/templates/agents/claude/skills/grounder-recall/SKILL.md +34 -0
- package/templates/agents/claude/{commands/grounder-search.md → skills/grounder-search/SKILL.md} +16 -8
- package/templates/agents/cursor/skills/grounder-handoff/SKILL.md +73 -0
- package/templates/agents/cursor/{commands/grounder-note.md → skills/grounder-note/SKILL.md} +6 -0
- package/templates/agents/cursor/skills/grounder-overview/SKILL.md +21 -0
- package/templates/agents/cursor/{commands/grounder-plan.md → skills/grounder-plan/SKILL.md} +6 -0
- package/templates/agents/cursor/skills/grounder-recall/SKILL.md +34 -0
- package/templates/agents/cursor/{commands/grounder-search.md → skills/grounder-search/SKILL.md} +16 -8
- package/templates/vault/plan.md +1 -1
- package/templates/vault/session-handoff.md +2 -1
- package/dist/agents/install-command.d.ts +0 -35
- package/dist/agents/install-command.d.ts.map +0 -1
- package/dist/agents/install-command.js +0 -65
- package/dist/agents/install-command.js.map +0 -1
- package/dist/commands/apply-agent-installs.d.ts +0 -34
- package/dist/commands/apply-agent-installs.d.ts.map +0 -1
- package/dist/commands/apply-agent-installs.js +0 -137
- package/dist/commands/apply-agent-installs.js.map +0 -1
- package/templates/agents/claude/commands/grounder-task-handoff.md +0 -58
- package/templates/agents/claude/commands/grounder-task.md +0 -22
- package/templates/agents/cursor/commands/grounder-task-handoff.md +0 -58
- package/templates/agents/cursor/commands/grounder-task.md +0 -22
package/dist/help.js
CHANGED
|
@@ -136,6 +136,18 @@ Subcommands:
|
|
|
136
136
|
--markdown Agent relay: file:// links + fenced snippets
|
|
137
137
|
--json Structured output (relativePath, fileUri, alsoMatchedHint per hit)`,
|
|
138
138
|
},
|
|
139
|
+
{
|
|
140
|
+
id: "overview",
|
|
141
|
+
group: "Retrieve",
|
|
142
|
+
summary: "Bird's-eye view: counts + recent titles across notes/handoffs/plans",
|
|
143
|
+
listUsage: "overview",
|
|
144
|
+
usage: "grounder overview [--limit <n>] [--markdown] [--json]",
|
|
145
|
+
flags: `Flags:
|
|
146
|
+
--limit <n> Max recent titles to print per bucket (default: 3)
|
|
147
|
+
--markdown Agent relay: [bucketRelativePath](fileUri) title lines
|
|
148
|
+
--json Structured output (total, count, truncated, items per bucket;
|
|
149
|
+
each item includes mtimeMs)`,
|
|
150
|
+
},
|
|
139
151
|
{
|
|
140
152
|
id: "path notes",
|
|
141
153
|
group: "Paths",
|
|
@@ -174,7 +186,9 @@ Subcommands:
|
|
|
174
186
|
group: "Maintain",
|
|
175
187
|
summary: "Snapshot of machine + project link + resolved paths",
|
|
176
188
|
listUsage: "status",
|
|
177
|
-
usage: "grounder status",
|
|
189
|
+
usage: "grounder status [--json]",
|
|
190
|
+
flags: `Flags:
|
|
191
|
+
--json Print a single-line JSON payload instead of formatted text`,
|
|
178
192
|
},
|
|
179
193
|
{
|
|
180
194
|
id: "doctor",
|
|
@@ -190,13 +204,20 @@ Subcommands:
|
|
|
190
204
|
group: "Maintain",
|
|
191
205
|
summary: "Refresh agent install after upgrading grounder",
|
|
192
206
|
listUsage: "migrate",
|
|
193
|
-
usage: "grounder migrate [--force] [--dry-run] [--agent <id>] [--hooks]",
|
|
207
|
+
usage: "grounder migrate [--force] [--dry-run] [--agent <id>] [--hooks | --no-hooks]",
|
|
194
208
|
flags: `Flags:
|
|
195
|
-
--force Overwrite
|
|
196
|
-
once when upgrading from Grounder before 0.3
|
|
209
|
+
--force Overwrite skill files you edited locally; also needed
|
|
210
|
+
once when upgrading from Grounder before 0.3. Also
|
|
211
|
+
deletes locally-edited pre-skill grounder-*.md command
|
|
212
|
+
files left over from before 0.6 (edits are not ported)
|
|
197
213
|
--dry-run Preview without writing
|
|
198
214
|
--agent <id> Limit to a specific agent (repeatable)
|
|
199
|
-
--hooks Also install hooks if not previously installed
|
|
215
|
+
--hooks Also install hooks if not previously installed
|
|
216
|
+
--no-hooks Turn hooks off and remove the installed hook entry
|
|
217
|
+
(sticky — a later plain migrate will not re-enable it)
|
|
218
|
+
|
|
219
|
+
Also retires pre-skill grounder-*.md command files superseded by
|
|
220
|
+
SKILL.md packaging (safe ones automatically; edited ones need --force).`,
|
|
200
221
|
},
|
|
201
222
|
{
|
|
202
223
|
id: "handoff peek",
|
|
@@ -240,6 +261,7 @@ export const DISPATCHED_COMMAND_IDS = [
|
|
|
240
261
|
"plan",
|
|
241
262
|
"plan list",
|
|
242
263
|
"search",
|
|
264
|
+
"overview",
|
|
243
265
|
"path",
|
|
244
266
|
"path notes",
|
|
245
267
|
"path logs",
|
package/dist/help.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help.js","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"help.js","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type PlanEntry } from "./core.js";
|
|
2
|
+
export interface ApplyPlanOptions {
|
|
3
|
+
agentId: string;
|
|
4
|
+
plan: readonly PlanEntry[];
|
|
5
|
+
/** Desired content for `create`/`update`/`noop` entries — path → rendered bytes. */
|
|
6
|
+
content: Record<string, string>;
|
|
7
|
+
grounderVersion: string;
|
|
8
|
+
homeDir?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Directories this agent is allowed to write into / delete from (its own
|
|
11
|
+
* `AgentAdapter#ownedPrefixes`) — re-checked here via
|
|
12
|
+
* {@link isUnderOwnedPrefix}, not trusted solely from the caller, so a plan
|
|
13
|
+
* built from a stray/corrupted ledger entry can never be applied as a
|
|
14
|
+
* filesystem write outside the agent's own tree.
|
|
15
|
+
*/
|
|
16
|
+
ownedPrefixes: readonly string[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Execute a whole-file plan: write/delete each path, and persist that path's
|
|
20
|
+
* ledger hash right after its own file write succeeds (per-artifact, not
|
|
21
|
+
* batched) — a mid-run crash leaves the ledger consistent with whatever
|
|
22
|
+
* actually completed.
|
|
23
|
+
*
|
|
24
|
+
* Returns nothing: callers render their tables from the `PlanEntry[]` they
|
|
25
|
+
* passed in (see `commands/render-artifact-table.ts`'s
|
|
26
|
+
* `rowStatusFromPlanAction`), so a second per-path outcome vocabulary here
|
|
27
|
+
* would only be a chance for the two to disagree. Failure is a throw, not a
|
|
28
|
+
* status — every entry that doesn't throw did exactly what its action says.
|
|
29
|
+
*/
|
|
30
|
+
export declare function applyPlan(opts: ApplyPlanOptions): Promise<void>;
|
|
31
|
+
//# sourceMappingURL=apply.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/reconcile/apply.ts"],"names":[],"mappings":"AAIA,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAE/D,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,SAAS,SAAS,EAAE,CAAC;IAC3B,oFAAoF;IACpF,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkFrE"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { unlink } from "node:fs/promises";
|
|
2
|
+
import { forgetLedgerFile, setLedgerFileHash } from "../connector/state.js";
|
|
3
|
+
import { writeFileAtomic } from "../util/fs.js";
|
|
4
|
+
import { hashContent } from "../util/hash.js";
|
|
5
|
+
import { isUnderOwnedPrefix } from "./core.js";
|
|
6
|
+
/**
|
|
7
|
+
* Execute a whole-file plan: write/delete each path, and persist that path's
|
|
8
|
+
* ledger hash right after its own file write succeeds (per-artifact, not
|
|
9
|
+
* batched) — a mid-run crash leaves the ledger consistent with whatever
|
|
10
|
+
* actually completed.
|
|
11
|
+
*
|
|
12
|
+
* Returns nothing: callers render their tables from the `PlanEntry[]` they
|
|
13
|
+
* passed in (see `commands/render-artifact-table.ts`'s
|
|
14
|
+
* `rowStatusFromPlanAction`), so a second per-path outcome vocabulary here
|
|
15
|
+
* would only be a chance for the two to disagree. Failure is a throw, not a
|
|
16
|
+
* status — every entry that doesn't throw did exactly what its action says.
|
|
17
|
+
*/
|
|
18
|
+
export async function applyPlan(opts) {
|
|
19
|
+
for (const entry of opts.plan) {
|
|
20
|
+
if ((entry.action === "create" || entry.action === "update" || entry.action === "delete") &&
|
|
21
|
+
!isUnderOwnedPrefix(entry.path, opts.ownedPrefixes)) {
|
|
22
|
+
throw new Error(`Refusing to ${entry.action} ${entry.path}: outside ${opts.agentId}'s owned prefixes`);
|
|
23
|
+
}
|
|
24
|
+
switch (entry.action) {
|
|
25
|
+
case "create":
|
|
26
|
+
case "update": {
|
|
27
|
+
const content = opts.content[entry.path];
|
|
28
|
+
if (content === undefined) {
|
|
29
|
+
throw new Error(`No desired content for ${entry.path} (action: ${entry.action})`);
|
|
30
|
+
}
|
|
31
|
+
await writeFileAtomic(entry.path, content);
|
|
32
|
+
await setLedgerFileHash({
|
|
33
|
+
agentId: opts.agentId,
|
|
34
|
+
filePath: entry.path,
|
|
35
|
+
hash: hashContent(content),
|
|
36
|
+
grounderVersion: opts.grounderVersion,
|
|
37
|
+
homeDir: opts.homeDir,
|
|
38
|
+
});
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
case "noop": {
|
|
42
|
+
// A desired path already matching on disk — hydrate the ledger hash
|
|
43
|
+
// when it wasn't recorded yet (or recorded stale), so a manually
|
|
44
|
+
// correct file becomes safely Grounder-managed going forward.
|
|
45
|
+
const content = opts.content[entry.path];
|
|
46
|
+
if (content !== undefined) {
|
|
47
|
+
await setLedgerFileHash({
|
|
48
|
+
agentId: opts.agentId,
|
|
49
|
+
filePath: entry.path,
|
|
50
|
+
hash: hashContent(content),
|
|
51
|
+
grounderVersion: opts.grounderVersion,
|
|
52
|
+
homeDir: opts.homeDir,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
case "delete": {
|
|
58
|
+
try {
|
|
59
|
+
await unlink(entry.path);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
if (error.code !== "ENOENT") {
|
|
63
|
+
// A real failure (EACCES, EISDIR, …) — propagate rather than
|
|
64
|
+
// forgetting the ledger hash for a file that's still on disk;
|
|
65
|
+
// swallowing it here would leave the ledger and disk permanently
|
|
66
|
+
// disagreeing, with no way for a future run to notice and retry.
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
await forgetLedgerFile({
|
|
71
|
+
agentId: opts.agentId,
|
|
72
|
+
filePath: entry.path,
|
|
73
|
+
grounderVersion: opts.grounderVersion,
|
|
74
|
+
homeDir: opts.homeDir,
|
|
75
|
+
});
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
case "forget": {
|
|
79
|
+
// Already gone from disk, but the ledger still holds a stale hash
|
|
80
|
+
// (removed outside `migrate`) — drop it so it doesn't linger forever.
|
|
81
|
+
await forgetLedgerFile({
|
|
82
|
+
agentId: opts.agentId,
|
|
83
|
+
filePath: entry.path,
|
|
84
|
+
grounderVersion: opts.grounderVersion,
|
|
85
|
+
homeDir: opts.homeDir,
|
|
86
|
+
});
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
case "conflict":
|
|
90
|
+
// Left alone on purpose — on-disk content Grounder can't confirm it
|
|
91
|
+
// wrote. `--force` is what turns this into an `update`/`delete`
|
|
92
|
+
// upstream in `reconcile()`, so there is nothing to do here.
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=apply.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/reconcile/apply.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure reconciliation core — no I/O anywhere in this file.
|
|
3
|
+
*
|
|
4
|
+
* Two shapes, per the design: {@link desiredDrift} answers "would migrate
|
|
5
|
+
* change something" cheaply (ledger vs. rendered template hashes only, no
|
|
6
|
+
* disk read) for `peek`/`status`; {@link reconcile} is the full three-way
|
|
7
|
+
* (desired vs. ledger vs. on-disk) plan `setup`/`migrate`/`doctor` execute or
|
|
8
|
+
* preview. Modeled on chezmoi's source/destination/target state and dpkg's
|
|
9
|
+
* old-pristine/new-pristine/on-disk compare.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* True when `filePath` sits under one of `prefixes` (a directory, matched
|
|
13
|
+
* exactly or via a `prefix + separator` boundary — never a bare substring
|
|
14
|
+
* match, and never a `..`-segment escape). Callers use this to keep a
|
|
15
|
+
* ledger's extra/stray entries — a hand-edited or corrupted `state.json`,
|
|
16
|
+
* say — from ever being treated as delete candidates for paths outside the
|
|
17
|
+
* directories an adapter actually manages. Comparison is lexical
|
|
18
|
+
* (`path.resolve` + `path.relative`, no symlink following): both sides are
|
|
19
|
+
* resolved to absolute form first, so a `../` segment in `filePath` cannot
|
|
20
|
+
* walk back out of a prefix it superficially starts with.
|
|
21
|
+
* `reconcile()` itself stays agnostic to this (see its own docs); callers
|
|
22
|
+
* filter `ledger` before passing it in.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isUnderOwnedPrefix(filePath: string, prefixes: readonly string[]): boolean;
|
|
25
|
+
export type DriftKind = "create" | "update";
|
|
26
|
+
export interface DriftEntry {
|
|
27
|
+
path: string;
|
|
28
|
+
kind: DriftKind;
|
|
29
|
+
}
|
|
30
|
+
/** One agent's last-applied manifest — path → hash of the bytes Grounder wrote. */
|
|
31
|
+
export type LedgerManifest = Record<string, {
|
|
32
|
+
hash?: string;
|
|
33
|
+
}>;
|
|
34
|
+
/**
|
|
35
|
+
* Compare desired (rendered template) hashes against one agent's last-applied
|
|
36
|
+
* ledger manifest. No disk I/O — the caller renders + hashes templates, and
|
|
37
|
+
* passes in the ledger's `files` map already read from `state.json`.
|
|
38
|
+
*
|
|
39
|
+
* `ledger === undefined` means this agent has no ledger entry at all (never
|
|
40
|
+
* installed) — returns no drift. Scoping to ledger-recorded agents lives
|
|
41
|
+
* here, not in every caller: otherwise a detected-but-never-installed agent
|
|
42
|
+
* would tease `migrate` forever with no command able to silence it.
|
|
43
|
+
*
|
|
44
|
+
* Within a ledger-recorded agent, a desired path missing from its `files` map
|
|
45
|
+
* IS drift (`"create"`) — that's how a newly added skill file surfaces here.
|
|
46
|
+
*/
|
|
47
|
+
export declare function desiredDrift(desired: Record<string, string>, ledger: LedgerManifest | undefined): DriftEntry[];
|
|
48
|
+
export type PlanAction = "create" | "update" | "delete" | "conflict" | "noop" | "forget";
|
|
49
|
+
export interface PlanEntry {
|
|
50
|
+
path: string;
|
|
51
|
+
action: PlanAction;
|
|
52
|
+
/** Only set when `action === "conflict"` — which action `--force` would take. */
|
|
53
|
+
blockedAction?: "overwrite" | "delete";
|
|
54
|
+
}
|
|
55
|
+
/** path → on-disk content hash, `undefined` when the path does not exist. */
|
|
56
|
+
export type DiskHashes = Record<string, string | undefined>;
|
|
57
|
+
/**
|
|
58
|
+
* Full three-way reconcile for one agent's whole-file artifacts: desired
|
|
59
|
+
* (current templates) vs. ledger (last-applied) vs. disk (actual). Pure —
|
|
60
|
+
* `disk`/`ledger` are already-read snapshots, not live filesystem access.
|
|
61
|
+
*
|
|
62
|
+
* `tombstones` are extra "previously desired, no longer desired" paths
|
|
63
|
+
* (pre-skill command files, etc.) unioned into the retirement side of the
|
|
64
|
+
* diff even when the ledger never recorded them — the case a pure
|
|
65
|
+
* ledger-manifest diff is blind to (pre-hash-tracking installs).
|
|
66
|
+
*
|
|
67
|
+
* Safety: only ever call this for a known agent id whose `desired` this
|
|
68
|
+
* binary can actually compute — never for an unrecognized ledger entry,
|
|
69
|
+
* which would treat its entire recorded file set as delete candidates.
|
|
70
|
+
*/
|
|
71
|
+
export declare function reconcile(desired: Record<string, string>, tombstones: readonly string[], ledger: LedgerManifest | undefined, disk: DiskHashes, force: boolean): PlanEntry[];
|
|
72
|
+
/**
|
|
73
|
+
* Would applying `plan` actually change the ledger? Pure — mirrors exactly
|
|
74
|
+
* what `applyPlan()`'s per-artifact writes do (each has its own no-op guard):
|
|
75
|
+
* `create`/`update`/`noop` only write when the recorded hash would actually
|
|
76
|
+
* change; `delete` only forgets an entry that exists; `forget` always writes
|
|
77
|
+
* (by construction it only exists when there's something to forget);
|
|
78
|
+
* `conflict` never touches the ledger. Used so `--dry-run` and a real run
|
|
79
|
+
* predict/report the exact same thing for the exact same reason.
|
|
80
|
+
*/
|
|
81
|
+
export declare function planChangesLedger(plan: readonly PlanEntry[], ledger: LedgerManifest | undefined, desired: Record<string, string>): boolean;
|
|
82
|
+
//# sourceMappingURL=core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/reconcile/core.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAezF;AAED,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE5C,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;CACjB;AAED,mFAAmF;AACnF,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE/D;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,MAAM,EAAE,cAAc,GAAG,SAAS,GACjC,UAAU,EAAE,CAcd;AAED,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEzF,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;IACnB,iFAAiF;IACjF,aAAa,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAC;CACxC;AAED,6EAA6E;AAC7E,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE5D;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,MAAM,EAAE,cAAc,GAAG,SAAS,EAClC,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,OAAO,GACb,SAAS,EAAE,CA4Cb;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,SAAS,SAAS,EAAE,EAC1B,MAAM,EAAE,cAAc,GAAG,SAAS,EAClC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,OAAO,CAyBT"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
/**
|
|
3
|
+
* Pure reconciliation core — no I/O anywhere in this file.
|
|
4
|
+
*
|
|
5
|
+
* Two shapes, per the design: {@link desiredDrift} answers "would migrate
|
|
6
|
+
* change something" cheaply (ledger vs. rendered template hashes only, no
|
|
7
|
+
* disk read) for `peek`/`status`; {@link reconcile} is the full three-way
|
|
8
|
+
* (desired vs. ledger vs. on-disk) plan `setup`/`migrate`/`doctor` execute or
|
|
9
|
+
* preview. Modeled on chezmoi's source/destination/target state and dpkg's
|
|
10
|
+
* old-pristine/new-pristine/on-disk compare.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* True when `filePath` sits under one of `prefixes` (a directory, matched
|
|
14
|
+
* exactly or via a `prefix + separator` boundary — never a bare substring
|
|
15
|
+
* match, and never a `..`-segment escape). Callers use this to keep a
|
|
16
|
+
* ledger's extra/stray entries — a hand-edited or corrupted `state.json`,
|
|
17
|
+
* say — from ever being treated as delete candidates for paths outside the
|
|
18
|
+
* directories an adapter actually manages. Comparison is lexical
|
|
19
|
+
* (`path.resolve` + `path.relative`, no symlink following): both sides are
|
|
20
|
+
* resolved to absolute form first, so a `../` segment in `filePath` cannot
|
|
21
|
+
* walk back out of a prefix it superficially starts with.
|
|
22
|
+
* `reconcile()` itself stays agnostic to this (see its own docs); callers
|
|
23
|
+
* filter `ledger` before passing it in.
|
|
24
|
+
*/
|
|
25
|
+
export function isUnderOwnedPrefix(filePath, prefixes) {
|
|
26
|
+
const target = path.resolve(filePath);
|
|
27
|
+
return prefixes.some((prefix) => {
|
|
28
|
+
const root = path.resolve(prefix);
|
|
29
|
+
if (root === target) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
const relative = path.relative(root, target);
|
|
33
|
+
return (relative !== "" &&
|
|
34
|
+
relative !== ".." &&
|
|
35
|
+
!relative.startsWith(`..${path.sep}`) &&
|
|
36
|
+
!path.isAbsolute(relative));
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Compare desired (rendered template) hashes against one agent's last-applied
|
|
41
|
+
* ledger manifest. No disk I/O — the caller renders + hashes templates, and
|
|
42
|
+
* passes in the ledger's `files` map already read from `state.json`.
|
|
43
|
+
*
|
|
44
|
+
* `ledger === undefined` means this agent has no ledger entry at all (never
|
|
45
|
+
* installed) — returns no drift. Scoping to ledger-recorded agents lives
|
|
46
|
+
* here, not in every caller: otherwise a detected-but-never-installed agent
|
|
47
|
+
* would tease `migrate` forever with no command able to silence it.
|
|
48
|
+
*
|
|
49
|
+
* Within a ledger-recorded agent, a desired path missing from its `files` map
|
|
50
|
+
* IS drift (`"create"`) — that's how a newly added skill file surfaces here.
|
|
51
|
+
*/
|
|
52
|
+
export function desiredDrift(desired, ledger) {
|
|
53
|
+
if (!ledger) {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
const out = [];
|
|
57
|
+
for (const [path, hash] of Object.entries(desired)) {
|
|
58
|
+
const recorded = ledger[path]?.hash;
|
|
59
|
+
if (recorded === undefined) {
|
|
60
|
+
out.push({ path, kind: "create" });
|
|
61
|
+
}
|
|
62
|
+
else if (recorded !== hash) {
|
|
63
|
+
out.push({ path, kind: "update" });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Full three-way reconcile for one agent's whole-file artifacts: desired
|
|
70
|
+
* (current templates) vs. ledger (last-applied) vs. disk (actual). Pure —
|
|
71
|
+
* `disk`/`ledger` are already-read snapshots, not live filesystem access.
|
|
72
|
+
*
|
|
73
|
+
* `tombstones` are extra "previously desired, no longer desired" paths
|
|
74
|
+
* (pre-skill command files, etc.) unioned into the retirement side of the
|
|
75
|
+
* diff even when the ledger never recorded them — the case a pure
|
|
76
|
+
* ledger-manifest diff is blind to (pre-hash-tracking installs).
|
|
77
|
+
*
|
|
78
|
+
* Safety: only ever call this for a known agent id whose `desired` this
|
|
79
|
+
* binary can actually compute — never for an unrecognized ledger entry,
|
|
80
|
+
* which would treat its entire recorded file set as delete candidates.
|
|
81
|
+
*/
|
|
82
|
+
export function reconcile(desired, tombstones, ledger, disk, force) {
|
|
83
|
+
const ledgerFiles = ledger ?? {};
|
|
84
|
+
const allPaths = new Set([
|
|
85
|
+
...Object.keys(desired),
|
|
86
|
+
...Object.keys(ledgerFiles),
|
|
87
|
+
...tombstones,
|
|
88
|
+
]);
|
|
89
|
+
const entries = [];
|
|
90
|
+
for (const path of allPaths) {
|
|
91
|
+
const desiredHash = desired[path];
|
|
92
|
+
const ledgerHash = ledgerFiles[path]?.hash;
|
|
93
|
+
const onDisk = disk[path];
|
|
94
|
+
if (desiredHash !== undefined) {
|
|
95
|
+
// Whole-file artifact currently wanted.
|
|
96
|
+
if (onDisk === undefined) {
|
|
97
|
+
entries.push({ path, action: "create" });
|
|
98
|
+
}
|
|
99
|
+
else if (onDisk === desiredHash) {
|
|
100
|
+
entries.push({ path, action: "noop" });
|
|
101
|
+
}
|
|
102
|
+
else if (force || (ledgerHash !== undefined && ledgerHash === onDisk)) {
|
|
103
|
+
entries.push({ path, action: "update" });
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
entries.push({ path, action: "conflict", blockedAction: "overwrite" });
|
|
107
|
+
}
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
// Not in the current desired set — retirement candidate (tombstone, or a
|
|
111
|
+
// path dropped from the manifest by a schema change).
|
|
112
|
+
if (onDisk === undefined) {
|
|
113
|
+
// Already gone — noop, not a recurring delete (doctor would otherwise
|
|
114
|
+
// warn about an already-cleaned-up legacy path forever). If the ledger
|
|
115
|
+
// still holds a stale hash for it (removed outside `migrate`), that's
|
|
116
|
+
// a ledger-only cleanup ("forget"), not a file action.
|
|
117
|
+
entries.push({ path, action: ledgerHash !== undefined ? "forget" : "noop" });
|
|
118
|
+
}
|
|
119
|
+
else if (force || (ledgerHash !== undefined && ledgerHash === onDisk)) {
|
|
120
|
+
entries.push({ path, action: "delete" });
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
entries.push({ path, action: "conflict", blockedAction: "delete" });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return entries;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Would applying `plan` actually change the ledger? Pure — mirrors exactly
|
|
130
|
+
* what `applyPlan()`'s per-artifact writes do (each has its own no-op guard):
|
|
131
|
+
* `create`/`update`/`noop` only write when the recorded hash would actually
|
|
132
|
+
* change; `delete` only forgets an entry that exists; `forget` always writes
|
|
133
|
+
* (by construction it only exists when there's something to forget);
|
|
134
|
+
* `conflict` never touches the ledger. Used so `--dry-run` and a real run
|
|
135
|
+
* predict/report the exact same thing for the exact same reason.
|
|
136
|
+
*/
|
|
137
|
+
export function planChangesLedger(plan, ledger, desired) {
|
|
138
|
+
const ledgerFiles = ledger ?? {};
|
|
139
|
+
for (const entry of plan) {
|
|
140
|
+
switch (entry.action) {
|
|
141
|
+
case "create":
|
|
142
|
+
case "update":
|
|
143
|
+
case "noop": {
|
|
144
|
+
const desiredHash = desired[entry.path];
|
|
145
|
+
if (desiredHash !== undefined && ledgerFiles[entry.path]?.hash !== desiredHash) {
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
case "delete":
|
|
151
|
+
if (ledgerFiles[entry.path]?.hash !== undefined) {
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
break;
|
|
155
|
+
case "forget":
|
|
156
|
+
return true;
|
|
157
|
+
case "conflict":
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../../src/reconcile/core.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DiskHashes } from "./core.js";
|
|
2
|
+
/**
|
|
3
|
+
* Read + hash each path; a missing file maps to `undefined`. Any other read
|
|
4
|
+
* failure (EACCES, EISDIR, …) propagates instead of being folded into
|
|
5
|
+
* "missing" — an unreadable-but-present file must never be silently planned
|
|
6
|
+
* as a `create`, writing blind over content this binary never actually saw.
|
|
7
|
+
* Both callers already have somewhere for that to land gracefully: doctor's
|
|
8
|
+
* `computeAgentPlansSafe` catches per-agent and turns it into a "could not
|
|
9
|
+
* verify skill drift" warning; `setup`/`migrate` catch it around
|
|
10
|
+
* `applyAgentInstalls` and report it on stderr.
|
|
11
|
+
*/
|
|
12
|
+
export declare function readDiskHashes(paths: Iterable<string>): Promise<DiskHashes>;
|
|
13
|
+
//# sourceMappingURL=disk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disk.d.ts","sourceRoot":"","sources":["../../src/reconcile/disk.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAajF"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { hashContent } from "../util/hash.js";
|
|
3
|
+
/**
|
|
4
|
+
* Read + hash each path; a missing file maps to `undefined`. Any other read
|
|
5
|
+
* failure (EACCES, EISDIR, …) propagates instead of being folded into
|
|
6
|
+
* "missing" — an unreadable-but-present file must never be silently planned
|
|
7
|
+
* as a `create`, writing blind over content this binary never actually saw.
|
|
8
|
+
* Both callers already have somewhere for that to land gracefully: doctor's
|
|
9
|
+
* `computeAgentPlansSafe` catches per-agent and turns it into a "could not
|
|
10
|
+
* verify skill drift" warning; `setup`/`migrate` catch it around
|
|
11
|
+
* `applyAgentInstalls` and report it on stderr.
|
|
12
|
+
*/
|
|
13
|
+
export async function readDiskHashes(paths) {
|
|
14
|
+
const out = {};
|
|
15
|
+
for (const p of paths) {
|
|
16
|
+
try {
|
|
17
|
+
out[p] = hashContent(await readFile(p, "utf8"));
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
if (error.code !== "ENOENT") {
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
out[p] = undefined;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=disk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disk.js","sourceRoot":"","sources":["../../src/reconcile/disk.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9C;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAAuB;IAC1D,MAAM,GAAG,GAAe,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC;YACH,GAAG,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,MAAM,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACvD,MAAM,KAAK,CAAC;YACd,CAAC;YACD,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;QACrB,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/util/fs.d.ts
CHANGED
|
@@ -5,6 +5,20 @@ export declare function fileExists(filePath: string): Promise<boolean>;
|
|
|
5
5
|
* not oversell POSIX execute-bit semantics there.
|
|
6
6
|
*/
|
|
7
7
|
export declare function isExecutable(filePath: string): Promise<boolean>;
|
|
8
|
+
/**
|
|
9
|
+
* Write `content` to `filePath` via tmp file + rename, so a crash mid-write
|
|
10
|
+
* never leaves a truncated file at the real path. Creates the destination
|
|
11
|
+
* directory if needed; best-effort removes the tmp file if `rename` itself
|
|
12
|
+
* throws, so a failed write doesn't leave an orphaned `.tmp-*` sibling behind.
|
|
13
|
+
* `mode` (e.g. the pre-existing file's permission bits), when given, is
|
|
14
|
+
* applied to the tmp file before the rename — otherwise the replaced file
|
|
15
|
+
* would pick up the tmp file's default umask permissions instead of keeping
|
|
16
|
+
* whatever the file already had, which matters for host-owned config files
|
|
17
|
+
* edited by other tools.
|
|
18
|
+
*/
|
|
19
|
+
export declare function writeFileAtomic(filePath: string, content: string, options?: {
|
|
20
|
+
mode?: number;
|
|
21
|
+
}): Promise<void>;
|
|
8
22
|
/**
|
|
9
23
|
* Creates a new markdown file under `dir`; never overwrites.
|
|
10
24
|
* Tries `basename.md`, then `basename_02.md`, `_03`, … with `wx` (O_EXCL)
|
package/dist/util/fs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/util/fs.ts"],"names":[],"mappings":"AAIA,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOnE;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOrE;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CAgBjB"}
|
|
1
|
+
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/util/fs.ts"],"names":[],"mappings":"AAIA,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOnE;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOrE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAC9B,OAAO,CAAC,IAAI,CAAC,CAaf;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CAgBjB"}
|
package/dist/util/fs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { access, constants, writeFile } from "node:fs/promises";
|
|
1
|
+
import { access, chmod, constants, mkdir, rename, unlink, writeFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { collisionSuffix } from "./timestamp-slug.js";
|
|
4
4
|
export async function fileExists(filePath) {
|
|
@@ -24,6 +24,32 @@ export async function isExecutable(filePath) {
|
|
|
24
24
|
return false;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Write `content` to `filePath` via tmp file + rename, so a crash mid-write
|
|
29
|
+
* never leaves a truncated file at the real path. Creates the destination
|
|
30
|
+
* directory if needed; best-effort removes the tmp file if `rename` itself
|
|
31
|
+
* throws, so a failed write doesn't leave an orphaned `.tmp-*` sibling behind.
|
|
32
|
+
* `mode` (e.g. the pre-existing file's permission bits), when given, is
|
|
33
|
+
* applied to the tmp file before the rename — otherwise the replaced file
|
|
34
|
+
* would pick up the tmp file's default umask permissions instead of keeping
|
|
35
|
+
* whatever the file already had, which matters for host-owned config files
|
|
36
|
+
* edited by other tools.
|
|
37
|
+
*/
|
|
38
|
+
export async function writeFileAtomic(filePath, content, options = {}) {
|
|
39
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
40
|
+
const tmpPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
41
|
+
await writeFile(tmpPath, content, "utf8");
|
|
42
|
+
if (options.mode !== undefined) {
|
|
43
|
+
await chmod(tmpPath, options.mode);
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
await rename(tmpPath, filePath);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
await unlink(tmpPath).catch(() => { });
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
27
53
|
/**
|
|
28
54
|
* Creates a new markdown file under `dir`; never overwrites.
|
|
29
55
|
* Tries `basename.md`, then `basename_02.md`, `_03`, … with `wx` (O_EXCL)
|
package/dist/util/fs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/util/fs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/util/fs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9F,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,QAAgB;IAC/C,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QACvC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAgB,EAChB,OAAe,EACf,UAA6B,EAAE;IAE/B,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,MAAM,OAAO,GAAG,GAAG,QAAQ,QAAQ,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IAC/D,MAAM,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1C,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IACD,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACtC,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,GAAW,EACX,QAAgB,EAChB,OAAe;IAEf,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,SAAS,CAAC;QACR,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,GAAG,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;QACrE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC;QAC9C,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACrE,OAAO,QAAQ,CAAC;QAClB,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACvD,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;gBACxB,SAAS;YACX,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;AACH,CAAC"}
|