@dsh-cc/subagent-resume-pins 0.5.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/LICENSE +201 -0
- package/README.md +48 -0
- package/lib/fingerprint.d.ts +25 -0
- package/lib/fingerprint.d.ts.map +1 -0
- package/lib/fingerprint.js +49 -0
- package/lib/fingerprint.js.map +1 -0
- package/lib/gate.d.ts +98 -0
- package/lib/gate.d.ts.map +1 -0
- package/lib/gate.js +218 -0
- package/lib/gate.js.map +1 -0
- package/lib/index.d.ts +22 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +22 -0
- package/lib/index.js.map +1 -0
- package/lib/overlay.d.ts +37 -0
- package/lib/overlay.d.ts.map +1 -0
- package/lib/overlay.js +80 -0
- package/lib/overlay.js.map +1 -0
- package/lib/pin.d.ts +129 -0
- package/lib/pin.d.ts.map +1 -0
- package/lib/pin.js +211 -0
- package/lib/pin.js.map +1 -0
- package/lib/plugin.d.ts +67 -0
- package/lib/plugin.d.ts.map +1 -0
- package/lib/plugin.js +354 -0
- package/lib/plugin.js.map +1 -0
- package/lib/policy.d.ts +41 -0
- package/lib/policy.d.ts.map +1 -0
- package/lib/policy.js +45 -0
- package/lib/policy.js.map +1 -0
- package/lib/serialize.d.ts +27 -0
- package/lib/serialize.d.ts.map +1 -0
- package/lib/serialize.js +38 -0
- package/lib/serialize.js.map +1 -0
- package/lib/store.d.ts +62 -0
- package/lib/store.d.ts.map +1 -0
- package/lib/store.js +133 -0
- package/lib/store.js.map +1 -0
- package/package.json +78 -0
package/lib/store.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-child pin store: one JSON file per child under `<pinsRoot>/<childId>.json`.
|
|
3
|
+
*
|
|
4
|
+
* Durability and coherence contract (plan §4.1/§4.6):
|
|
5
|
+
* - `write` creates a pin and fails if one already exists (preallocated ids).
|
|
6
|
+
* - `update` rewrites the file atomically (temp file + rename) AND publishes
|
|
7
|
+
* the mutated pin to the store's single synchronous in-memory cache, so no
|
|
8
|
+
* stale-cache read can serve the first request after a gate mutation.
|
|
9
|
+
* - `read` resolves `undefined` for an absent pin (legacy/foreign child,
|
|
10
|
+
* pass-through) and a `{kind:'corrupt'}` sentinel for a file that exists
|
|
11
|
+
* but is unparseable or unsupported-version — fail-closed callers
|
|
12
|
+
* distinguish those; it never throws.
|
|
13
|
+
* - `remove` tombstone-deletes the file and the cache entry.
|
|
14
|
+
* - childIds are UUID-ish; anything containing a path separator or `..` is
|
|
15
|
+
* rejected before it can traverse out of `pinsRoot`.
|
|
16
|
+
*
|
|
17
|
+
* @module @dsh-cc/subagent-resume-pins/store
|
|
18
|
+
*/
|
|
19
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
20
|
+
import { join } from 'node:path';
|
|
21
|
+
import { PinParseError, parsePin, writePin } from "./pin.js";
|
|
22
|
+
/** The childId shape the store accepts: no separators, no `..`. */
|
|
23
|
+
function assertSafeChildId(childId) {
|
|
24
|
+
if (childId.length === 0 || childId.includes('/') || childId.includes('\\') || childId.includes('..')) {
|
|
25
|
+
throw new Error(`unsafe resume-pin childId: ${JSON.stringify(childId)}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Owns the pin files under one root and the single shared in-memory cache the
|
|
30
|
+
* gate and overlay listeners consult.
|
|
31
|
+
*/
|
|
32
|
+
export class PinStore {
|
|
33
|
+
pinsRoot;
|
|
34
|
+
cache = new Map();
|
|
35
|
+
constructor(pinsRoot) {
|
|
36
|
+
this.pinsRoot = pinsRoot;
|
|
37
|
+
mkdirSync(this.pinsRoot, { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
/** The on-disk path for one child's pin (validates the childId first). */
|
|
40
|
+
pathFor(childId) {
|
|
41
|
+
assertSafeChildId(childId);
|
|
42
|
+
return join(this.pinsRoot, `${childId}.json`);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Read a pin by child id: `undefined` when absent, the corrupt sentinel when
|
|
46
|
+
* the file exists but cannot be parsed. Read-through: the disk is re-read on
|
|
47
|
+
* every call (files are tiny, one per model request), so a file deleted or
|
|
48
|
+
* corrupted out-of-band is never served stale from the cache; the cache only
|
|
49
|
+
* accelerates nothing — it exists to publish synchronous in-process updates
|
|
50
|
+
* and is invalidated by any failed disk read.
|
|
51
|
+
*/
|
|
52
|
+
read(childId) {
|
|
53
|
+
const path = this.pathFor(childId);
|
|
54
|
+
if (!existsSync(path)) {
|
|
55
|
+
this.cache.delete(childId);
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
let text;
|
|
59
|
+
try {
|
|
60
|
+
text = readFileSync(path, 'utf8');
|
|
61
|
+
}
|
|
62
|
+
catch (cause) {
|
|
63
|
+
this.cache.delete(childId);
|
|
64
|
+
return { kind: 'corrupt', reason: `unreadable: ${String(cause)}` };
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const pin = parsePin(text);
|
|
68
|
+
this.cache.set(childId, pin);
|
|
69
|
+
return pin;
|
|
70
|
+
}
|
|
71
|
+
catch (cause) {
|
|
72
|
+
this.cache.delete(childId);
|
|
73
|
+
const reason = cause instanceof PinParseError ? cause.message : String(cause);
|
|
74
|
+
return { kind: 'corrupt', reason };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** Read only the in-memory cache: `undefined` on miss (no disk access). */
|
|
78
|
+
getCached(childId) {
|
|
79
|
+
return this.cache.get(childId);
|
|
80
|
+
}
|
|
81
|
+
/** Create the pin file; fails when a pin for this child already exists. */
|
|
82
|
+
write(pin) {
|
|
83
|
+
const path = this.pathFor(pin.childId);
|
|
84
|
+
if (existsSync(path)) {
|
|
85
|
+
throw new Error(`resume pin already exists for child ${pin.childId}`);
|
|
86
|
+
}
|
|
87
|
+
this.atomicWrite(path, pin);
|
|
88
|
+
this.cache.set(pin.childId, pin);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Atomically rewrite a pin through `mutator` (a structural clone is handed
|
|
92
|
+
* to the mutator) and publish the result to the shared cache synchronously.
|
|
93
|
+
*/
|
|
94
|
+
update(childId, mutator) {
|
|
95
|
+
const current = this.read(childId);
|
|
96
|
+
if (current === undefined)
|
|
97
|
+
throw new Error(`no resume pin for child ${childId}`);
|
|
98
|
+
if ('kind' in current && current.kind === 'corrupt') {
|
|
99
|
+
throw new Error(`cannot update corrupt resume pin for child ${childId}`);
|
|
100
|
+
}
|
|
101
|
+
const draft = structuredClone(current);
|
|
102
|
+
mutator(draft);
|
|
103
|
+
const updated = parsePin(writePin(draft));
|
|
104
|
+
this.atomicWrite(this.pathFor(childId), updated);
|
|
105
|
+
this.cache.set(childId, updated);
|
|
106
|
+
return updated;
|
|
107
|
+
}
|
|
108
|
+
/** Tombstone-delete the pin file and its cache entry (idempotent). */
|
|
109
|
+
remove(childId) {
|
|
110
|
+
rmSync(this.pathFor(childId), { force: true });
|
|
111
|
+
this.cache.delete(childId);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The child ids with a pin file on disk (best-effort; used by the
|
|
115
|
+
* `list_agents` annotation). Not guaranteed cached or readable.
|
|
116
|
+
*/
|
|
117
|
+
ids() {
|
|
118
|
+
try {
|
|
119
|
+
return readdirSync(this.pinsRoot)
|
|
120
|
+
.filter(name => name.endsWith('.json'))
|
|
121
|
+
.map(name => name.slice(0, -'.json'.length));
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
atomicWrite(path, pin) {
|
|
128
|
+
const temp = `${path}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
129
|
+
writeFileSync(temp, writePin(pin), { flag: 'wx' });
|
|
130
|
+
renameSync(temp, path);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=store.js.map
|
package/lib/store.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dsh-cc/subagent-resume-pins",
|
|
3
|
+
"description": "Pinned resume descriptors for continuable background subagents",
|
|
4
|
+
"version": "0.5.0",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/dsh-cc/dsh-cc.git",
|
|
8
|
+
"directory": "packages/subagent/resume-pins"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./lib/index.d.ts",
|
|
14
|
+
"default": "./lib/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./pin": {
|
|
17
|
+
"types": "./lib/pin.d.ts",
|
|
18
|
+
"default": "./lib/pin.js"
|
|
19
|
+
},
|
|
20
|
+
"./store": {
|
|
21
|
+
"types": "./lib/store.d.ts",
|
|
22
|
+
"default": "./lib/store.js"
|
|
23
|
+
},
|
|
24
|
+
"./fingerprint": {
|
|
25
|
+
"types": "./lib/fingerprint.d.ts",
|
|
26
|
+
"default": "./lib/fingerprint.js"
|
|
27
|
+
},
|
|
28
|
+
"./gate": {
|
|
29
|
+
"types": "./lib/gate.d.ts",
|
|
30
|
+
"default": "./lib/gate.js"
|
|
31
|
+
},
|
|
32
|
+
"./overlay": {
|
|
33
|
+
"types": "./lib/overlay.d.ts",
|
|
34
|
+
"default": "./lib/overlay.js"
|
|
35
|
+
},
|
|
36
|
+
"./policy": {
|
|
37
|
+
"types": "./lib/policy.d.ts",
|
|
38
|
+
"default": "./lib/policy.js"
|
|
39
|
+
},
|
|
40
|
+
"./plugin": {
|
|
41
|
+
"types": "./lib/plugin.d.ts",
|
|
42
|
+
"default": "./lib/plugin.js"
|
|
43
|
+
},
|
|
44
|
+
"./src/*": "./src/*",
|
|
45
|
+
"./package.json": "./package.json"
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"lib"
|
|
49
|
+
],
|
|
50
|
+
"license": "Apache-2.0",
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"@deepseek-ai/cordis": ">=0.1.1-rc.2",
|
|
53
|
+
"@deepseek-ai/dsh-session": ">=0.1.1-rc.2",
|
|
54
|
+
"@deepseek-ai/dsh-settings": ">=0.1.1-rc.2",
|
|
55
|
+
"@deepseek-ai/schemastery": "^3.18.1",
|
|
56
|
+
"@dsh-cc/claude-code-agents": "^0.5.0",
|
|
57
|
+
"@dsh-cc/model-aliases": "^0.5.0"
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@dsh-cc/claude-code-agents": "^0.5.0",
|
|
61
|
+
"@dsh-cc/model-aliases": "^0.5.0"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@deepseek-ai/cordis": "link:../../../../deepseek-harness/vendor/cordis",
|
|
65
|
+
"@deepseek-ai/dsh-agent": "link:../../../../deepseek-harness/packages/core/agent",
|
|
66
|
+
"@deepseek-ai/dsh-llm": "link:../../../../deepseek-harness/packages/llm/llm",
|
|
67
|
+
"@deepseek-ai/dsh-session": "link:../../../../deepseek-harness/packages/core/session",
|
|
68
|
+
"@deepseek-ai/dsh-session-persistence": "link:../../../../deepseek-harness/packages/session/session-persistence",
|
|
69
|
+
"@deepseek-ai/dsh-settings": "link:../../../../deepseek-harness/packages/settings/settings",
|
|
70
|
+
"@deepseek-ai/dsh-tools": "link:../../../../deepseek-harness/packages/core/tools",
|
|
71
|
+
"@deepseek-ai/schemastery": "link:../../../../deepseek-harness/vendor/schemastery",
|
|
72
|
+
"@dsh-cc/claude-code-agents": "^0.5.0",
|
|
73
|
+
"@dsh-cc/model-aliases": "^0.5.0"
|
|
74
|
+
},
|
|
75
|
+
"publishConfig": {
|
|
76
|
+
"access": "public"
|
|
77
|
+
}
|
|
78
|
+
}
|