@kanadego/dsh-heartbeat 1.9.2 → 2.0.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 +21 -21
- package/README.md +344 -396
- package/client.js +108 -20
- package/config/policy.json +74 -73
- package/config/profile-schema.json +306 -306
- package/dist/{bindings-225SI7KC.js → bindings-U2M3CO2D.js} +3 -3
- package/dist/{chunk-TY6UP74X.js → chunk-3DNGY4DS.js} +2 -2
- package/dist/{chunk-CUOSICYJ.js → chunk-544QOJN5.js} +397 -23
- package/dist/chunk-544QOJN5.js.map +1 -0
- package/dist/{chunk-AJ5HLAL7.js → chunk-6MVKWICX.js} +708 -154
- package/dist/chunk-6MVKWICX.js.map +1 -0
- package/dist/{chunk-IG6YMUHW.js → chunk-6XM6KY7M.js} +43 -12
- package/dist/chunk-6XM6KY7M.js.map +1 -0
- package/dist/chunk-AKIJ4LS2.js +680 -0
- package/dist/chunk-AKIJ4LS2.js.map +1 -0
- package/dist/{chunk-KB5SMG3F.js → chunk-DC5HMCJC.js} +3 -3
- package/dist/{chunk-3MDBU6WY.js → chunk-DZ7YCFGX.js} +37 -7
- package/dist/chunk-DZ7YCFGX.js.map +1 -0
- package/dist/{chunk-WRUTATW4.js → chunk-IBBAISSW.js} +13 -2
- package/dist/chunk-IBBAISSW.js.map +1 -0
- package/dist/{chunk-ZLV4NMFX.js → chunk-IFRMKVIC.js} +85 -21
- package/dist/chunk-IFRMKVIC.js.map +1 -0
- package/dist/{chunk-XFNCTOW7.js → chunk-NCPKOWS7.js} +52 -4
- package/dist/chunk-NCPKOWS7.js.map +1 -0
- package/dist/{chunk-JDH2LDFS.js → chunk-TVX4HV4Y.js} +4 -6
- package/dist/{chunk-JDH2LDFS.js.map → chunk-TVX4HV4Y.js.map} +1 -1
- package/dist/cli/index.js +149 -26
- package/dist/cli/index.js.map +1 -1
- package/dist/{inbox-P26DDMWC.js → inbox-OWBK6PE2.js} +8 -7
- package/dist/index.d.ts +50 -315
- package/dist/index.js +288 -920
- package/dist/index.js.map +1 -1
- package/dist/migrate-TQ5PB2DI.js +27 -0
- package/dist/{orchestrator-EUTZ3KG6.js → orchestrator-P7AEWVYR.js} +27 -12
- package/dist/{pool-UTXQJJ5C.js → pool-2T6TVS2L.js} +4 -5
- package/dist/{snapshot-K5VHETTK.js → snapshot-F5B2DD56.js} +5 -5
- package/package.json +84 -83
- package/dist/chunk-3MDBU6WY.js.map +0 -1
- package/dist/chunk-AJ5HLAL7.js.map +0 -1
- package/dist/chunk-CUOSICYJ.js.map +0 -1
- package/dist/chunk-IG6YMUHW.js.map +0 -1
- package/dist/chunk-IV2ZWQA3.js +0 -56
- package/dist/chunk-IV2ZWQA3.js.map +0 -1
- package/dist/chunk-K5Y6JP2B.js +0 -399
- package/dist/chunk-K5Y6JP2B.js.map +0 -1
- package/dist/chunk-WRUTATW4.js.map +0 -1
- package/dist/chunk-XFNCTOW7.js.map +0 -1
- package/dist/chunk-ZLV4NMFX.js.map +0 -1
- package/dist/migrate-D4VKAKYT.js +0 -21
- /package/dist/{bindings-225SI7KC.js.map → bindings-U2M3CO2D.js.map} +0 -0
- /package/dist/{chunk-TY6UP74X.js.map → chunk-3DNGY4DS.js.map} +0 -0
- /package/dist/{chunk-KB5SMG3F.js.map → chunk-DC5HMCJC.js.map} +0 -0
- /package/dist/{inbox-P26DDMWC.js.map → inbox-OWBK6PE2.js.map} +0 -0
- /package/dist/{migrate-D4VKAKYT.js.map → migrate-TQ5PB2DI.js.map} +0 -0
- /package/dist/{orchestrator-EUTZ3KG6.js.map → orchestrator-P7AEWVYR.js.map} +0 -0
- /package/dist/{pool-UTXQJJ5C.js.map → pool-2T6TVS2L.js.map} +0 -0
- /package/dist/{snapshot-K5VHETTK.js.map → snapshot-F5B2DD56.js.map} +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MIGRATE_FILES,
|
|
3
|
+
MIGRATE_MAGIC,
|
|
4
|
+
MIGRATE_MAX_BYTES,
|
|
5
|
+
MIGRATE_MAX_FILES,
|
|
6
|
+
MIGRATE_VERSION,
|
|
7
|
+
applyMigrationEntries,
|
|
8
|
+
collectMigrationEntries,
|
|
9
|
+
decryptContainer,
|
|
10
|
+
encryptContainer,
|
|
11
|
+
isMigratablePath
|
|
12
|
+
} from "./chunk-NCPKOWS7.js";
|
|
13
|
+
import "./chunk-AKIJ4LS2.js";
|
|
14
|
+
import "./chunk-IBBAISSW.js";
|
|
15
|
+
export {
|
|
16
|
+
MIGRATE_FILES,
|
|
17
|
+
MIGRATE_MAGIC,
|
|
18
|
+
MIGRATE_MAX_BYTES,
|
|
19
|
+
MIGRATE_MAX_FILES,
|
|
20
|
+
MIGRATE_VERSION,
|
|
21
|
+
applyMigrationEntries,
|
|
22
|
+
collectMigrationEntries,
|
|
23
|
+
decryptContainer,
|
|
24
|
+
encryptContainer,
|
|
25
|
+
isMigratablePath
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=migrate-TQ5PB2DI.js.map
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
|
+
BeatAbortedError,
|
|
2
3
|
ENGINE_ROOM_EXTRA_TOOLS,
|
|
3
4
|
HOME_ROTATE_EVENT_COUNT,
|
|
4
5
|
TOKEN_SAVER_IDLE_SECONDS,
|
|
6
|
+
TOKEN_SAVER_WAKE_MS,
|
|
5
7
|
agentLooksAlive,
|
|
8
|
+
agentTurn,
|
|
6
9
|
applyHeartbeatInterval,
|
|
7
10
|
beat,
|
|
8
11
|
buildEngineRoomAllowList,
|
|
@@ -15,29 +18,36 @@ import {
|
|
|
15
18
|
markHomeRotateIfOverflow,
|
|
16
19
|
parseJsonBlock,
|
|
17
20
|
pickSpokenLine,
|
|
21
|
+
pinEngineRoomTools,
|
|
18
22
|
resetHomeAgent,
|
|
19
23
|
resetHomeSession,
|
|
24
|
+
selectedPresetId,
|
|
20
25
|
sessionEventCount,
|
|
21
26
|
sessionEvents,
|
|
22
27
|
shouldArchiveRotatedHome,
|
|
23
28
|
shouldRotateHome,
|
|
24
29
|
spokeTextSince,
|
|
25
|
-
startOrchestrator
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
startOrchestrator,
|
|
31
|
+
throwIfAborted,
|
|
32
|
+
userActiveInBoundSessions,
|
|
33
|
+
withTimeout
|
|
34
|
+
} from "./chunk-6MVKWICX.js";
|
|
35
|
+
import "./chunk-6XM6KY7M.js";
|
|
28
36
|
import "./chunk-3QJJRXIR.js";
|
|
29
|
-
import "./chunk-
|
|
30
|
-
import "./chunk-
|
|
31
|
-
import "./chunk-
|
|
32
|
-
import "./chunk-
|
|
33
|
-
import "./chunk-
|
|
34
|
-
import "./chunk-
|
|
35
|
-
import "./chunk-WRUTATW4.js";
|
|
37
|
+
import "./chunk-TVX4HV4Y.js";
|
|
38
|
+
import "./chunk-DZ7YCFGX.js";
|
|
39
|
+
import "./chunk-DC5HMCJC.js";
|
|
40
|
+
import "./chunk-544QOJN5.js";
|
|
41
|
+
import "./chunk-AKIJ4LS2.js";
|
|
42
|
+
import "./chunk-IBBAISSW.js";
|
|
36
43
|
export {
|
|
44
|
+
BeatAbortedError,
|
|
37
45
|
ENGINE_ROOM_EXTRA_TOOLS,
|
|
38
46
|
HOME_ROTATE_EVENT_COUNT,
|
|
39
47
|
TOKEN_SAVER_IDLE_SECONDS,
|
|
48
|
+
TOKEN_SAVER_WAKE_MS,
|
|
40
49
|
agentLooksAlive,
|
|
50
|
+
agentTurn,
|
|
41
51
|
applyHeartbeatInterval,
|
|
42
52
|
beat,
|
|
43
53
|
buildEngineRoomAllowList,
|
|
@@ -50,13 +60,18 @@ export {
|
|
|
50
60
|
markHomeRotateIfOverflow,
|
|
51
61
|
parseJsonBlock,
|
|
52
62
|
pickSpokenLine,
|
|
63
|
+
pinEngineRoomTools,
|
|
53
64
|
resetHomeAgent,
|
|
54
65
|
resetHomeSession,
|
|
66
|
+
selectedPresetId,
|
|
55
67
|
sessionEventCount,
|
|
56
68
|
sessionEvents,
|
|
57
69
|
shouldArchiveRotatedHome,
|
|
58
70
|
shouldRotateHome,
|
|
59
71
|
spokeTextSince,
|
|
60
|
-
startOrchestrator
|
|
72
|
+
startOrchestrator,
|
|
73
|
+
throwIfAborted,
|
|
74
|
+
userActiveInBoundSessions,
|
|
75
|
+
withTimeout
|
|
61
76
|
};
|
|
62
|
-
//# sourceMappingURL=orchestrator-
|
|
77
|
+
//# sourceMappingURL=orchestrator-P7AEWVYR.js.map
|
|
@@ -16,10 +16,9 @@ import {
|
|
|
16
16
|
savePool,
|
|
17
17
|
seedsFilePath,
|
|
18
18
|
surfaceSeed
|
|
19
|
-
} from "./chunk-
|
|
20
|
-
import "./chunk-
|
|
21
|
-
import "./chunk-
|
|
22
|
-
import "./chunk-WRUTATW4.js";
|
|
19
|
+
} from "./chunk-TVX4HV4Y.js";
|
|
20
|
+
import "./chunk-AKIJ4LS2.js";
|
|
21
|
+
import "./chunk-IBBAISSW.js";
|
|
23
22
|
export {
|
|
24
23
|
SEED_CATEGORY_CAPS,
|
|
25
24
|
TTL_KEYS,
|
|
@@ -39,4 +38,4 @@ export {
|
|
|
39
38
|
seedsFilePath,
|
|
40
39
|
surfaceSeed
|
|
41
40
|
};
|
|
42
|
-
//# sourceMappingURL=pool-
|
|
41
|
+
//# sourceMappingURL=pool-2T6TVS2L.js.map
|
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
snapshotDue,
|
|
4
4
|
snapshotIfDue,
|
|
5
5
|
snapshotProfile
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-DC5HMCJC.js";
|
|
7
|
+
import "./chunk-544QOJN5.js";
|
|
8
|
+
import "./chunk-AKIJ4LS2.js";
|
|
9
|
+
import "./chunk-IBBAISSW.js";
|
|
10
10
|
export {
|
|
11
11
|
SNAPSHOT_THRESHOLD,
|
|
12
12
|
snapshotDue,
|
|
13
13
|
snapshotIfDue,
|
|
14
14
|
snapshotProfile
|
|
15
15
|
};
|
|
16
|
-
//# sourceMappingURL=snapshot-
|
|
16
|
+
//# sourceMappingURL=snapshot-F5B2DD56.js.map
|
package/package.json
CHANGED
|
@@ -1,83 +1,84 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@kanadego/dsh-heartbeat",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Heartbeat plugin for DeepSeek Harness: scheduled autonomous reflection loop with user profile, material pool, pace gate, and gated proactive expression.",
|
|
5
|
-
"repository": {
|
|
6
|
-
"type": "git",
|
|
7
|
-
"url": "git+https://github.com/Kanadego/dsh-heartbeat.git"
|
|
8
|
-
},
|
|
9
|
-
"homepage": "https://github.com/Kanadego/dsh-heartbeat",
|
|
10
|
-
"bugs": {
|
|
11
|
-
"url": "https://github.com/Kanadego/dsh-heartbeat/issues"
|
|
12
|
-
},
|
|
13
|
-
"keywords": [
|
|
14
|
-
"dsh",
|
|
15
|
-
"dsh-plugin",
|
|
16
|
-
"deepseek-harness",
|
|
17
|
-
"heartbeat",
|
|
18
|
-
"proactive",
|
|
19
|
-
"agent"
|
|
20
|
-
],
|
|
21
|
-
"publishConfig": {
|
|
22
|
-
"registry": "https://registry.npmjs.org"
|
|
23
|
-
},
|
|
24
|
-
"type": "module",
|
|
25
|
-
"main": "dist/index.js",
|
|
26
|
-
"types": "dist/index.d.ts",
|
|
27
|
-
"exports": {
|
|
28
|
-
".": {
|
|
29
|
-
"types": "./dist/index.d.ts",
|
|
30
|
-
"default": "./dist/index.js"
|
|
31
|
-
},
|
|
32
|
-
"./cli": {
|
|
33
|
-
"types": "./dist/cli/index.d.ts",
|
|
34
|
-
"default": "./dist/cli/index.js"
|
|
35
|
-
},
|
|
36
|
-
"./client": "./client.js",
|
|
37
|
-
"./package.json": "./package.json",
|
|
38
|
-
"./cordis.patch.yml": "./cordis.patch.yml"
|
|
39
|
-
},
|
|
40
|
-
"files": [
|
|
41
|
-
"dist",
|
|
42
|
-
"config",
|
|
43
|
-
"assets",
|
|
44
|
-
"client.js",
|
|
45
|
-
"cordis.patch.yml",
|
|
46
|
-
"README.md",
|
|
47
|
-
"LICENSE"
|
|
48
|
-
],
|
|
49
|
-
"engines": {
|
|
50
|
-
"node": ">=22.19.0"
|
|
51
|
-
},
|
|
52
|
-
"os": [
|
|
53
|
-
"win32"
|
|
54
|
-
],
|
|
55
|
-
"dependencies": {
|
|
56
|
-
"@deepseek-ai/dsh-settings": "^0.1.1-rc.2 || ^0.1.5-rc.2 || ^0.1.7-rc.1 || ^0.2.0-rc.1"
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
"@deepseek-ai/dsh-
|
|
64
|
-
"@deepseek-ai/
|
|
65
|
-
"@types/node": "^24.0.0",
|
|
66
|
-
"tsup": "^8.3.0",
|
|
67
|
-
"tsx": "^4.19.0",
|
|
68
|
-
"typescript": "^5.7.0"
|
|
69
|
-
},
|
|
70
|
-
"scripts": {
|
|
71
|
-
"build": "tsup",
|
|
72
|
-
"typecheck": "tsc --noEmit",
|
|
73
|
-
"
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@kanadego/dsh-heartbeat",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Heartbeat plugin for DeepSeek Harness: scheduled autonomous reflection loop with user profile, material pool, pace gate, and gated proactive expression.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/Kanadego/dsh-heartbeat.git"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/Kanadego/dsh-heartbeat",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/Kanadego/dsh-heartbeat/issues"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"dsh",
|
|
15
|
+
"dsh-plugin",
|
|
16
|
+
"deepseek-harness",
|
|
17
|
+
"heartbeat",
|
|
18
|
+
"proactive",
|
|
19
|
+
"agent"
|
|
20
|
+
],
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"registry": "https://registry.npmjs.org"
|
|
23
|
+
},
|
|
24
|
+
"type": "module",
|
|
25
|
+
"main": "dist/index.js",
|
|
26
|
+
"types": "dist/index.d.ts",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"default": "./dist/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./cli": {
|
|
33
|
+
"types": "./dist/cli/index.d.ts",
|
|
34
|
+
"default": "./dist/cli/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./client": "./client.js",
|
|
37
|
+
"./package.json": "./package.json",
|
|
38
|
+
"./cordis.patch.yml": "./cordis.patch.yml"
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist",
|
|
42
|
+
"config",
|
|
43
|
+
"assets",
|
|
44
|
+
"client.js",
|
|
45
|
+
"cordis.patch.yml",
|
|
46
|
+
"README.md",
|
|
47
|
+
"LICENSE"
|
|
48
|
+
],
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=22.19.0"
|
|
51
|
+
},
|
|
52
|
+
"os": [
|
|
53
|
+
"win32"
|
|
54
|
+
],
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@deepseek-ai/dsh-settings": "^0.1.1-rc.2 || ^0.1.5-rc.2 || ^0.1.7-rc.1 || ^0.2.0-rc.1 || ^0.2.1-rc.1 || ^0.2.1-rc.2",
|
|
57
|
+
"@deepseek-ai/schemastery": "^3.18.2"
|
|
58
|
+
},
|
|
59
|
+
"peerDependencies": {
|
|
60
|
+
"@deepseek-ai/dsh-llm": "^0.1.1-rc.2 || ^0.1.5-rc.2 || ^0.1.7-rc.1 || ^0.2.0-rc.1 || ^0.2.1-rc.1 || ^0.2.1-rc.2"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@deepseek-ai/dsh-llm": "^0.1.7-rc.1",
|
|
64
|
+
"@deepseek-ai/dsh-settings": "^0.1.1-rc.2",
|
|
65
|
+
"@types/node": "^24.0.0",
|
|
66
|
+
"tsup": "^8.3.0",
|
|
67
|
+
"tsx": "^4.19.0",
|
|
68
|
+
"typescript": "^5.7.0"
|
|
69
|
+
},
|
|
70
|
+
"scripts": {
|
|
71
|
+
"build": "tsup",
|
|
72
|
+
"typecheck": "tsc --noEmit",
|
|
73
|
+
"check:client": "node --check client.js",
|
|
74
|
+
"test": "node --import tsx --test \"tests/*.test.ts\""
|
|
75
|
+
},
|
|
76
|
+
"dsh": {
|
|
77
|
+
"bundle": {
|
|
78
|
+
"patch": "./cordis.patch.yml"
|
|
79
|
+
},
|
|
80
|
+
"client": {
|
|
81
|
+
"platform": "web"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/profile/inbox.ts"],"sourcesContent":["// Observation inbox (design doc §3.2): append-only queue of pending\n// observations; drained by the consolidation run. DPAPI-encrypted. Items hold\n// pointers + at most one short sentence - never raw conversation/screen text.\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport type { PathGuard } from '../core/path-guard.js';\nimport { loadEncryptedText, saveEncryptedText } from '../vault/vault.js';\nimport { withFileLock } from '../core/file-lock.js';\nimport type { InboxItem } from './types.js';\n\nconst MAX_NOTE_CHARS = 120;\n\nexport function inboxFilePath(dataDir: string): string {\n return path.join(dataDir, 'profile_inbox.jsonl');\n}\n\nfunction truncateNote(note: string): string {\n const oneLine = note.replace(/\\r?\\n/g, ' ').trim();\n return oneLine.length > MAX_NOTE_CHARS ? oneLine.slice(0, MAX_NOTE_CHARS) + '…' : oneLine;\n}\n\nexport function inboxAppend(\n guard: PathGuard,\n file: string,\n item: Omit<InboxItem, 'id'> & { id?: string },\n): InboxItem {\n // H-20 (minimal tier): the append is a whole-file encrypted rewrite, so it\n // needs the same cross-process lock the pool uses — the CLI can be draining\n // or writing the same file while a beat appends.\n return withFileLock(file, () => inboxAppendLocked(guard, file, item));\n}\n\nfunction inboxAppendLocked(\n guard: PathGuard,\n file: string,\n item: Omit<InboxItem, 'id'> & { id?: string },\n): InboxItem {\n const full: InboxItem = {\n id: item.id ?? randomUUID().slice(0, 8),\n kind: item.kind,\n at: item.at,\n ref: item.ref,\n note: truncateNote(item.note),\n };\n const prev = loadEncryptedText(guard, file) ?? '';\n // H-16 (minimal tier): this file is a whole-file encrypted rewrite, so a\n // repeated observation used to cost a full decrypt + encrypt + write for a\n // duplicate row. The §3.7 dedupe key is kind+ref — if that row is already\n // queued, hand it back instead of appending a second copy. (A stalled cursor\n // used to grow the queue here and rely on the consumer's dedupeItems.)\n for (const line of prev.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const existing = JSON.parse(trimmed) as InboxItem;\n if (existing.kind === full.kind && existing.ref === full.ref) return existing;\n } catch {\n // corrupt line: ignore (the queue is re-derivable from its sources)\n }\n }\n saveEncryptedText(guard, file, prev + JSON.stringify(full) + '\\n');\n return full;\n}\n\nexport function inboxCount(guard: PathGuard, file: string): number {\n const raw = loadEncryptedText(guard, file);\n if (!raw) return 0;\n return raw.split('\\n').filter((l) => l.trim()).length;\n}\n\n/**\n * Drain all items. `commit` controls crash semantics: on consolidation failure\n * the inbox must SURVIVE (§3.7), so the caller drains with commit=false first,\n * and only rewrites an empty inbox after the run succeeded.\n */\nexport function inboxDrain(guard: PathGuard, file: string): InboxItem[] {\n const raw = loadEncryptedText(guard, file);\n if (!raw) return [];\n const items: InboxItem[] = [];\n for (const line of raw.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n items.push(JSON.parse(trimmed) as InboxItem);\n } catch {\n // corrupt line: drop (queue is re-derivable from sources)\n }\n }\n return items;\n}\n\nexport function inboxClear(guard: PathGuard, file: string): void {\n saveEncryptedText(guard, file, '');\n}\n\n/** Dedupe key (§3.7): same source kind + same ref must not flood the queue. */\nexport function dedupeItems(items: InboxItem[]): InboxItem[] {\n const seen = new Set<string>();\n const out: InboxItem[] = [];\n for (const it of items) {\n const key = `${it.kind}#${it.ref}`;\n if (seen.has(key)) continue;\n seen.add(key);\n out.push(it);\n }\n return out;\n}\n\nexport function inboxHealthCheck(guard: PathGuard, file: string): { total: number; corrupt: number; duplicates: number } {\n const raw = loadEncryptedText(guard, file) ?? '';\n let total = 0;\n let corrupt = 0;\n const keys = new Set<string>();\n let duplicates = 0;\n for (const line of raw.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const it = JSON.parse(trimmed) as InboxItem;\n total += 1;\n const key = `${it.kind}#${it.ref}`;\n if (keys.has(key)) duplicates += 1;\n keys.add(key);\n } catch {\n corrupt += 1;\n }\n }\n return { total, corrupt, duplicates };\n}\n\nexport function inboxFileExists(guard: PathGuard, file: string): boolean {\n return fs.existsSync(guard.assert(file));\n}\n"],"mappings":"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","names":[]}
|