@theseus-whale/dsh-continuity 0.0.0-stage → 4.12.2
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/INSTALL.md +25 -0
- package/PANEL.md +92 -0
- package/README.md +286 -2
- package/RELEASE-NOTES.md +732 -0
- package/bin/bc-acceptance-full.mjs +91 -0
- package/bin/bc-acceptance-tight.mjs +66 -0
- package/bin/bc-acceptance.mjs +22 -0
- package/bin/bc-add-keywords.mjs +21 -0
- package/bin/bc-demo.mjs +47 -0
- package/bin/bc-expand-hint.mjs +179 -0
- package/bin/bc-ingest-index.mjs +35 -0
- package/bin/bc-ingest.mjs +31 -0
- package/bin/bc-label-demo.mjs +18 -0
- package/bin/bc-relabel.mjs +150 -0
- package/bin/bc-sessionize.mjs +59 -0
- package/bin/coref_pipeline.py +47 -0
- package/bin/coref_service.py +57 -0
- package/bin/debug_ckip.py +16 -0
- package/bin/debug_ner_zh.py +18 -0
- package/bin/doctor.mjs +275 -0
- package/bin/en_ner_error_audit.py +33 -0
- package/bin/eval-label-rules.mjs +342 -0
- package/bin/export-turns.py +68 -0
- package/bin/extract-user-paragraph.mjs +14 -0
- package/bin/extraction-composite-smoke.mjs +28 -0
- package/bin/extraction-latency.mjs +58 -0
- package/bin/extraction-user-smoke.mjs +28 -0
- package/bin/extraction_service.py +164 -0
- package/bin/facet-active-experiment.mjs +110 -0
- package/bin/facet-covid.mjs +8 -0
- package/bin/facet-curve.mjs +27 -0
- package/bin/facet-embedding-train.mjs +20 -0
- package/bin/facet-embedding-validate.mjs +83 -0
- package/bin/facet-eval-roleplay.mjs +42 -0
- package/bin/facet-eval.mjs +38 -0
- package/bin/facet-fold.mjs +31 -0
- package/bin/facet-load.mjs +16 -0
- package/bin/facet-mlp-scan.mjs +45 -0
- package/bin/facet-mvp.mjs +34 -0
- package/bin/facet-online-experiments.mjs +78 -0
- package/bin/facet-online-race.mjs +99 -0
- package/bin/facet-online-validate.mjs +51 -0
- package/bin/facet-panel.mjs +22 -0
- package/bin/facet-passage.mjs +41 -0
- package/bin/facet-random-validate.mjs +48 -0
- package/bin/facet-roleplay.mjs +33 -0
- package/bin/facet-scan.mjs +56 -0
- package/bin/facet-segment.mjs +34 -0
- package/bin/facet-train.mjs +19 -0
- package/bin/facet-validate.mjs +103 -0
- package/bin/facet-zeroshot.mjs +14 -0
- package/bin/install-templates.mjs +72 -0
- package/bin/memory-bench.mjs +53 -0
- package/bin/memory-build-summary.mjs +43 -0
- package/bin/memory-build-vector.mjs +31 -0
- package/bin/memory-build.mjs +41 -0
- package/bin/memory-calibration.mjs +70 -0
- package/bin/memory-closed-loop.mjs +119 -0
- package/bin/memory-dry-run.mjs +70 -0
- package/bin/memory-eval.mjs +104 -0
- package/bin/memory-event-alias-test.mjs +89 -0
- package/bin/memory-extraction-bench.mjs +58 -0
- package/bin/memory-load-gate-replay.mjs +137 -0
- package/bin/memory-loop-test.mjs +90 -0
- package/bin/memory-pre-turn-harness.mjs +63 -0
- package/bin/memory-query.mjs +39 -0
- package/bin/memory-replay-hints.mjs +84 -0
- package/bin/memory-scale.mjs +58 -0
- package/bin/memory-scenario-test.mjs +146 -0
- package/bin/memory-user-loop.mjs +95 -0
- package/bin/ner_bench_tiny_zh.py +59 -0
- package/bin/ner_bench_zh.py +60 -0
- package/bin/ner_conll_en.py +139 -0
- package/bin/ner_direct_en.py +123 -0
- package/bin/ner_direct_zh.py +100 -0
- package/bin/ner_pipeline.py +208 -0
- package/bin/noise-selfcheck.mjs +50 -0
- package/bin/pack-integrity.mjs +47 -0
- package/bin/panel-check.mjs +57 -0
- package/bin/plugin-integrity.mjs +74 -0
- package/bin/preview-live.mjs +13 -0
- package/bin/public-install-check.mjs +222 -0
- package/bin/relabel-apply.mjs +272 -0
- package/bin/relabel-dry-run.mjs +381 -0
- package/bin/relik_pipeline.py +39 -0
- package/bin/relik_service.py +52 -0
- package/bin/srl_pipeline.py +55 -0
- package/bin/srl_service.py +68 -0
- package/bin/summary-index.mjs +151 -0
- package/bin/summary-query.mjs +79 -0
- package/bin/vec-check.mjs +27 -0
- package/bin/zh_ner_error_audit.py +36 -0
- package/bin/zh_ner_slot_eval.py +38 -0
- package/client.js +760 -0
- package/cordis.patch.yml +378 -0
- package/docs/API-NOTES.md +1743 -0
- package/docs/ARCHITECTURE.md +355 -0
- package/docs/CACHE.md +253 -0
- package/docs/CONDUCT.md +30 -0
- package/docs/CREATOR-HANDOFF.md +102 -0
- package/docs/EXPERIMENT.md +136 -0
- package/docs/FACET-MVP-REPORT.md +473 -0
- package/docs/GUIDE-0.4.66.md +195 -0
- package/docs/GUIDE.md +127 -0
- package/docs/MECHANISM.md +243 -0
- package/docs/NEW-INSTANCE-HANDOFF.md +219 -0
- package/docs/README.md +37 -0
- package/docs/SESSION-LAYOUT.md +151 -0
- package/docs/history-map.md +249 -0
- package/docs/relabel-migration-wiring.md +366 -0
- package/guides/00-READ-FIRST.md +206 -0
- package/guides/01-INSTALL.md +207 -0
- package/guides/02-TABLES.md +225 -0
- package/guides/03-AUDIT.md +201 -0
- package/guides/04-REBUILD.md +306 -0
- package/guides/05-FIRST-RUN.md +191 -0
- package/guides/06-EMBEDDING.md +146 -0
- package/guides/07-PTC-AND-ASSETS.md +221 -0
- package/icon.svg +7 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/models/README.md +13 -0
- package/models/Xenova/bge-small-zh-v1.5/config.json +31 -0
- package/models/Xenova/bge-small-zh-v1.5/onnx/model_quantized.onnx +0 -0
- package/models/Xenova/bge-small-zh-v1.5/tokenizer.json +21278 -0
- package/models/Xenova/bge-small-zh-v1.5/tokenizer_config.json +15 -0
- package/package.json +139 -4
- package/src/asset-tool.mjs +237 -0
- package/src/assets.mjs +244 -0
- package/src/backfill.mjs +74 -0
- package/src/backup.mjs +80 -0
- package/src/deadend.mjs +95 -0
- package/src/deleted-store.mjs +35 -0
- package/src/engine.mjs +3831 -0
- package/src/facets/classifier.mjs +146 -0
- package/src/facets/embedding-service.mjs +53 -0
- package/src/facets/embedding-worker.mjs +27 -0
- package/src/facets/embedding.mjs +163 -0
- package/src/facets/extract.mjs +80 -0
- package/src/facets/fold-plan.mjs +84 -0
- package/src/facets/hybrid.mjs +29 -0
- package/src/facets/index.mjs +113 -0
- package/src/facets/linear-probe.mjs +43 -0
- package/src/facets/load.mjs +37 -0
- package/src/facets/mlp-probe.mjs +54 -0
- package/src/facets/mlp-service.mjs +53 -0
- package/src/facets/mlp-worker.mjs +26 -0
- package/src/facets/online-knn.mjs +58 -0
- package/src/facets/online-models.mjs +227 -0
- package/src/facets/panel-state.mjs +23 -0
- package/src/facets/panel.mjs +73 -0
- package/src/facets/random.mjs +26 -0
- package/src/facets/scanner.mjs +35 -0
- package/src/facets/schema.mjs +75 -0
- package/src/facets/seed-examples.mjs +58 -0
- package/src/facets/sensitivity.mjs +98 -0
- package/src/facets/service.mjs +53 -0
- package/src/facets/store.mjs +39 -0
- package/src/facets/worker.mjs +23 -0
- package/src/folds-store.mjs +109 -0
- package/src/groups.mjs +167 -0
- package/src/handoff-tool.mjs +51 -0
- package/src/handoff.mjs +127 -0
- package/src/index.mjs +649 -0
- package/src/inject-policy.mjs +17 -0
- package/src/learning.mjs +88 -0
- package/src/memory/alias-proposal.mjs +40 -0
- package/src/memory/bc-audit.mjs +245 -0
- package/src/memory/bc-index-updater.mjs +404 -0
- package/src/memory/bc-index.mjs +48 -0
- package/src/memory/bc-label.mjs +220 -0
- package/src/memory/bc-panel-state.mjs +107 -0
- package/src/memory/bc-pre-step.mjs +463 -0
- package/src/memory/bc-recall.mjs +470 -0
- package/src/memory/bc-shift.mjs +123 -0
- package/src/memory/bc-store.mjs +41 -0
- package/src/memory/bm25.mjs +112 -0
- package/src/memory/calibration.mjs +54 -0
- package/src/memory/chatter.mjs +29 -0
- package/src/memory/cmap-file.mjs +107 -0
- package/src/memory/concepts-file.mjs +41 -0
- package/src/memory/coref-slots.mjs +40 -0
- package/src/memory/event-alias-ledger.mjs +87 -0
- package/src/memory/event-log.mjs +95 -0
- package/src/memory/event-model.mjs +132 -0
- package/src/memory/event-segmenter.mjs +36 -0
- package/src/memory/event-summary-tree.mjs +122 -0
- package/src/memory/extraction-adapter.mjs +76 -0
- package/src/memory/extraction-composite.mjs +75 -0
- package/src/memory/extraction-core.mjs +76 -0
- package/src/memory/extraction-pre-step.mjs +161 -0
- package/src/memory/extraction-provider.mjs +300 -0
- package/src/memory/extraction-score.mjs +36 -0
- package/src/memory/facet-stabilizer.mjs +59 -0
- package/src/memory/history-map.mjs +139 -0
- package/src/memory/language-router.mjs +30 -0
- package/src/memory/load-gate.mjs +161 -0
- package/src/memory/mechanical-note.mjs +104 -0
- package/src/memory/onboarding.mjs +163 -0
- package/src/memory/persona.mjs +78 -0
- package/src/memory/planner.mjs +249 -0
- package/src/memory/pre-turn.mjs +80 -0
- package/src/memory/query-aliases.mjs +39 -0
- package/src/memory/recall-cue.mjs +43 -0
- package/src/memory/recall.mjs +65 -0
- package/src/memory/referent-candidates.mjs +55 -0
- package/src/memory/referent-ledger.mjs +86 -0
- package/src/memory/relabel-migrate.mjs +376 -0
- package/src/memory/relik-adapter.mjs +25 -0
- package/src/memory/special-keywords.mjs +60 -0
- package/src/memory/structured-adapters.mjs +75 -0
- package/src/memory/summary-index.mjs +335 -0
- package/src/memory/summary-tree.mjs +110 -0
- package/src/memory/term-extractor.mjs +44 -0
- package/src/memory/tokenize.mjs +9 -0
- package/src/memory/vector-index.mjs +54 -0
- package/src/memory/window-summary.mjs +133 -0
- package/src/mood.mjs +133 -0
- package/src/peer-tool.mjs +63 -0
- package/src/peer.mjs +144 -0
- package/src/policy.mjs +170 -0
- package/src/preflight.mjs +113 -0
- package/src/provenance.mjs +94 -0
- package/src/range.mjs +75 -0
- package/src/recall-exact-tool.mjs +267 -0
- package/src/recall-tool.mjs +521 -0
- package/src/recheck.mjs +99 -0
- package/src/save-start.mjs +29 -0
- package/src/session-guard.mjs +140 -0
- package/src/session-log-tool.mjs +322 -0
- package/src/session-log.mjs +606 -0
- package/src/skills.mjs +111 -0
- package/src/split-range.mjs +115 -0
- package/src/state.mjs +198 -0
- package/src/t0.mjs +149 -0
- package/src/tag-confirm.mjs +78 -0
- package/src/tag-detect.mjs +42 -0
- package/src/tag-maintenance.mjs +285 -0
- package/src/tag-reject.mjs +73 -0
- package/src/tags-store.mjs +94 -0
- package/src/tags.mjs +692 -0
- package/src/threads-backend.mjs +26 -0
- package/src/threads-core.mjs +1887 -0
- package/src/threads-store.mjs +207 -0
- package/src/threads-tool.mjs +522 -0
- package/src/threads.mjs +929 -0
- package/src/tool-preview.mjs +427 -0
- package/src/topic.mjs +63 -0
- package/src/training.mjs +75 -0
- package/src/turn-tag.mjs +62 -0
- package/src/user-turn.mjs +39 -0
- package/templates/cmap.md +11 -0
- package/templates/concepts.md +12 -0
- package/templates/habits.md +40 -0
- package/templates/keywords.md +6 -0
- package/templates/rebuild.md +134 -0
- package/templates/rules-safe.md +184 -0
- package/templates/rules.md +177 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"clean_up_tokenization_spaces": true,
|
|
3
|
+
"cls_token": "[CLS]",
|
|
4
|
+
"do_basic_tokenize": true,
|
|
5
|
+
"do_lower_case": false,
|
|
6
|
+
"mask_token": "[MASK]",
|
|
7
|
+
"model_max_length": 512,
|
|
8
|
+
"never_split": null,
|
|
9
|
+
"pad_token": "[PAD]",
|
|
10
|
+
"sep_token": "[SEP]",
|
|
11
|
+
"strip_accents": null,
|
|
12
|
+
"tokenize_chinese_chars": true,
|
|
13
|
+
"tokenizer_class": "BertTokenizer",
|
|
14
|
+
"unk_token": "[UNK]"
|
|
15
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,141 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theseus-whale/dsh-continuity",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "4.12.2",
|
|
4
|
+
"description": "Band-controlled compaction with session-scoped pointer indexes, persona-scoped A/B/C/K memory, verifiable pass receipts, and read-only retrieval for DeepSeek Harness",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "./src/index.mjs",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./src/index.mjs",
|
|
10
|
+
"./engine": "./src/engine.mjs",
|
|
11
|
+
"./policy": "./src/policy.mjs",
|
|
12
|
+
"./provenance": "./src/provenance.mjs",
|
|
13
|
+
"./range": "./src/range.mjs",
|
|
14
|
+
"./session-log": "./src/session-log.mjs",
|
|
15
|
+
"./session-log-tool": "./src/session-log-tool.mjs",
|
|
16
|
+
"./threads": "./src/threads.mjs",
|
|
17
|
+
"./threads-tool": "./src/threads-tool.mjs",
|
|
18
|
+
"./threads-core": "./src/threads-core.mjs",
|
|
19
|
+
"./threads-store": "./src/threads-store.mjs",
|
|
20
|
+
"./threads-backend": "./src/threads-backend.mjs",
|
|
21
|
+
"./tags": "./src/tags.mjs",
|
|
22
|
+
"./tags-store": "./src/tags-store.mjs",
|
|
23
|
+
"./folds-store": "./src/folds-store.mjs",
|
|
24
|
+
"./deleted-store": "./src/deleted-store.mjs",
|
|
25
|
+
"./tag-reject": "./src/tag-reject.mjs",
|
|
26
|
+
"./tool-preview": "./src/tool-preview.mjs",
|
|
27
|
+
"./client": "./client.js",
|
|
28
|
+
"./locale/*.json": "./locale/*.json",
|
|
29
|
+
"./icon": "./icon.svg",
|
|
30
|
+
"./package.json": "./package.json",
|
|
31
|
+
"./facets/schema": "./src/facets/schema.mjs",
|
|
32
|
+
"./facets/extract": "./src/facets/extract.mjs",
|
|
33
|
+
"./facets/index": "./src/facets/index.mjs",
|
|
34
|
+
"./facets/scanner": "./src/facets/scanner.mjs",
|
|
35
|
+
"./facets/classifier": "./src/facets/classifier.mjs",
|
|
36
|
+
"./facets/hybrid": "./src/facets/hybrid.mjs",
|
|
37
|
+
"./facets/service": "./src/facets/service.mjs",
|
|
38
|
+
"./facets/store": "./src/facets/store.mjs",
|
|
39
|
+
"./memory/event-log": "./src/memory/event-log.mjs",
|
|
40
|
+
"./memory/bm25": "./src/memory/bm25.mjs",
|
|
41
|
+
"./memory/summary-tree": "./src/memory/summary-tree.mjs",
|
|
42
|
+
"./memory/vector-index": "./src/memory/vector-index.mjs",
|
|
43
|
+
"./memory/planner": "./src/memory/planner.mjs",
|
|
44
|
+
"./memory/tokenize": "./src/memory/tokenize.mjs",
|
|
45
|
+
"./memory/event-model": "./src/memory/event-model.mjs",
|
|
46
|
+
"./memory/term-extractor": "./src/memory/term-extractor.mjs",
|
|
47
|
+
"./memory/referent-ledger": "./src/memory/referent-ledger.mjs",
|
|
48
|
+
"./memory/event-summary-tree": "./src/memory/event-summary-tree.mjs",
|
|
49
|
+
"./memory/calibration": "./src/memory/calibration.mjs",
|
|
50
|
+
"./memory/pre-turn": "./src/memory/pre-turn.mjs",
|
|
51
|
+
"./memory/language-router": "./src/memory/language-router.mjs",
|
|
52
|
+
"./memory/extraction-core": "./src/memory/extraction-core.mjs",
|
|
53
|
+
"./memory/extraction-score": "./src/memory/extraction-score.mjs",
|
|
54
|
+
"./memory/referent-candidates": "./src/memory/referent-candidates.mjs",
|
|
55
|
+
"./memory/structured-adapters": "./src/memory/structured-adapters.mjs",
|
|
56
|
+
"./memory/extraction-adapter": "./src/memory/extraction-adapter.mjs",
|
|
57
|
+
"./memory/coref-slots": "./src/memory/coref-slots.mjs",
|
|
58
|
+
"./memory/relik-adapter": "./src/memory/relik-adapter.mjs",
|
|
59
|
+
"./memory/extraction-provider": "./src/memory/extraction-provider.mjs",
|
|
60
|
+
"./memory/extraction-composite": "./src/memory/extraction-composite.mjs",
|
|
61
|
+
"./memory/extraction-pre-step": "./src/memory/extraction-pre-step.mjs",
|
|
62
|
+
"./peer": "./src/peer.mjs",
|
|
63
|
+
"./peer-tool": "./src/peer-tool.mjs"
|
|
64
|
+
},
|
|
65
|
+
"files": [
|
|
66
|
+
"src",
|
|
67
|
+
"client.js",
|
|
68
|
+
"cordis.patch.yml",
|
|
69
|
+
"locale/*.json",
|
|
70
|
+
"icon.svg",
|
|
71
|
+
"README.md",
|
|
72
|
+
"RELEASE-NOTES.md",
|
|
73
|
+
"bin",
|
|
74
|
+
"models",
|
|
75
|
+
"templates/rules-safe.md",
|
|
76
|
+
"templates/cmap.md",
|
|
77
|
+
"templates/keywords.md",
|
|
78
|
+
"templates/rules.md",
|
|
79
|
+
"templates/habits.md",
|
|
80
|
+
"templates/concepts.md",
|
|
81
|
+
"templates/rebuild.md",
|
|
82
|
+
"docs/*.md",
|
|
83
|
+
"guides",
|
|
84
|
+
"PANEL.md",
|
|
85
|
+
"INSTALL.md"
|
|
86
|
+
],
|
|
87
|
+
"dsh": {
|
|
88
|
+
"bundle": {
|
|
89
|
+
"patch": "./cordis.patch.yml"
|
|
90
|
+
},
|
|
91
|
+
"client": {
|
|
92
|
+
"platform": "web",
|
|
93
|
+
"immediately": true,
|
|
94
|
+
"inject": [
|
|
95
|
+
"@deepseek-ai/dsh-client-ui-sidebar",
|
|
96
|
+
"@deepseek-ai/dsh-client-ui-layout",
|
|
97
|
+
"@deepseek-ai/dsh-client-locale"
|
|
98
|
+
]
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
"scripts": {
|
|
102
|
+
"test": "node test/policy.test.mjs && node test/provenance.test.mjs && node test/range.test.mjs && node test/session-log.test.mjs && node test/tool-preview.test.mjs && node test/stats.test.mjs && node test/threads.test.mjs && node test/tags.test.mjs && node test/tag-reject.test.mjs && node test/tag-detect.test.mjs && node test/user-turn.test.mjs && node test/save-start.test.mjs && node test/backfill.test.mjs && node test/migrate.test.mjs && node test/dispatch-probe.test.mjs && node test/t0.test.mjs && node test/topic.test.mjs && node test/inject-policy.test.mjs && node test/tag-confirm.test.mjs && node test/recheck.test.mjs && node test/tag-maintenance.test.mjs && node test/facets.test.mjs && node test/recall-cue.test.mjs && node test/recall-tool.test.mjs && node test/pointer-only.test.mjs && node test/bc-pre-step.test.mjs && node test/bc-store.test.mjs && node test/bc-recall.test.mjs && node test/special-keywords.test.mjs && node test/peer-smoke.test.mjs && node test/bc-panel-state.test.mjs && node test/recall-source-filter.test.mjs && node test/cmap-file.test.mjs && node test/recall-width.test.mjs && node test/bc-index-updater.test.mjs && node test/session-guard.test.mjs && node test/recall-exact.test.mjs && node test/mechanical-note.test.mjs",
|
|
103
|
+
"check": "node --check src/index.mjs && node --check src/engine.mjs && node --check src/range.mjs && node --check src/state.mjs && node --check src/session-log.mjs && node --check src/session-log-tool.mjs && node --check src/threads.mjs && node --check src/threads-store.mjs && node --check src/threads-backend.mjs && node --check src/threads-core.mjs && node --check src/threads-tool.mjs && node --check src/tags.mjs && node --check src/tags-store.mjs && node --check src/folds-store.mjs && node --check src/deleted-store.mjs && node --check src/backfill.mjs && node --check src/save-start.mjs && node --check src/user-turn.mjs && node --check src/tag-reject.mjs && node --check src/tag-detect.mjs && node --check src/tool-preview.mjs && node --check client.js && node --check src/tag-maintenance.mjs && node --check src/facets/schema.mjs && node --check src/facets/extract.mjs && node --check src/facets/index.mjs && node --check src/facets/scanner.mjs && node --check bin/facet-mvp.mjs && node --check src/facets/classifier.mjs && node --check src/facets/hybrid.mjs && node --check bin/facet-validate.mjs && node --check bin/facet-scan.mjs && node --check bin/facet-train.mjs && node --check src/facets/worker.mjs && node --check src/facets/service.mjs && node --check src/facets/random.mjs && node --check bin/facet-random-validate.mjs && node --check src/facets/sensitivity.mjs && node --check bin/facet-curve.mjs && node --check src/facets/panel.mjs && node --check src/facets/panel-state.mjs && node --check bin/facet-panel.mjs && node --check src/facets/load.mjs && node --check bin/facet-load.mjs && node --check src/facets/fold-plan.mjs && node --check bin/facet-fold.mjs && node --check src/facets/online-knn.mjs && node --check bin/facet-online-validate.mjs && node --check src/facets/linear-probe.mjs && node --check src/facets/mlp-probe.mjs && node --check src/facets/mlp-worker.mjs && node --check src/facets/mlp-service.mjs && node --check bin/facet-mlp-scan.mjs && node --check src/memory/event-log.mjs && node --check src/memory/bm25.mjs && node --check src/memory/summary-tree.mjs && node --check src/memory/vector-index.mjs && node --check src/memory/planner.mjs && node --check src/memory/tokenize.mjs && node --check bin/memory-build.mjs && node --check bin/memory-build-summary.mjs && node --check bin/memory-build-vector.mjs && node --check bin/memory-query.mjs && node --check bin/memory-eval.mjs && node --check bin/memory-bench.mjs && node --check bin/memory-scale.mjs && node --check bin/memory-dry-run.mjs && node --check bin/memory-loop-test.mjs && node --check bin/memory-replay-hints.mjs && node --check bin/memory-load-gate-replay.mjs && node --check bin/memory-closed-loop.mjs && node --check bin/memory-scenario-test.mjs && node --check bin/memory-event-alias-test.mjs && node --check src/memory/event-model.mjs && node --check src/memory/term-extractor.mjs && node --check src/memory/referent-ledger.mjs && node --check src/memory/event-summary-tree.mjs && node --check src/memory/calibration.mjs && node --check bin/memory-calibration.mjs && node --check src/memory/pre-turn.mjs && node --check bin/memory-pre-turn-harness.mjs && node --check src/memory/language-router.mjs && node --check src/memory/extraction-core.mjs && node --check src/memory/extraction-score.mjs && node --check src/memory/referent-candidates.mjs && node --check src/memory/structured-adapters.mjs && node --check src/memory/extraction-adapter.mjs && node --check bin/memory-extraction-bench.mjs && node --check bin/memory-user-loop.mjs && node --check src/recall-tool.mjs && node --check src/memory/bc-recall.mjs && node --check src/memory/bc-label.mjs && node --check src/memory/bc-pre-step.mjs && node --check src/memory/bc-store.mjs && node --check src/memory/bc-index.mjs && node --check src/memory/bc-shift.mjs && node --check src/memory/bc-panel-state.mjs && node --check src/memory/recall-cue.mjs && node --check bin/plugin-integrity.mjs && node --check src/peer.mjs && node --check src/peer-tool.mjs && node --check src/memory/special-keywords.mjs && node --check bin/bc-add-keywords.mjs && node --check bin/bc-ingest-index.mjs && node --check src/memory/cmap-file.mjs && node --check src/memory/bc-index-updater.mjs && node --check bin/eval-label-rules.mjs && node --check bin/relabel-dry-run.mjs && node -e \"import('./src/memory/relabel-migrate.mjs')\" && node --check src/recall-exact-tool.mjs"
|
|
104
|
+
},
|
|
105
|
+
"peerDependencies": {
|
|
106
|
+
"@deepseek-ai/cordis": "*",
|
|
107
|
+
"@deepseek-ai/dsh-agent": "*",
|
|
108
|
+
"@deepseek-ai/dsh-compaction": "*",
|
|
109
|
+
"@deepseek-ai/dsh-compaction-basic": "*",
|
|
110
|
+
"@deepseek-ai/dsh-llm": "*",
|
|
111
|
+
"@deepseek-ai/dsh-session": "*",
|
|
112
|
+
"@deepseek-ai/dsh-token-meter": "*",
|
|
113
|
+
"@deepseek-ai/dsh-tools": "*"
|
|
114
|
+
},
|
|
115
|
+
"peerDependenciesMeta": {
|
|
116
|
+
"@deepseek-ai/dsh-compaction-basic": {
|
|
117
|
+
"optional": true
|
|
118
|
+
},
|
|
119
|
+
"@deepseek-ai/dsh-token-meter": {
|
|
120
|
+
"optional": true
|
|
121
|
+
},
|
|
122
|
+
"@deepseek-ai/dsh-tools": {
|
|
123
|
+
"optional": true
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
"engines": {
|
|
127
|
+
"node": ">=22"
|
|
128
|
+
},
|
|
129
|
+
"keywords": [
|
|
130
|
+
"dsh",
|
|
131
|
+
"dsh-plugin",
|
|
132
|
+
"compaction",
|
|
133
|
+
"continuity",
|
|
134
|
+
"provenance",
|
|
135
|
+
"context"
|
|
136
|
+
],
|
|
137
|
+
"dependencies": {
|
|
138
|
+
"@huggingface/transformers": "^4.3.2",
|
|
139
|
+
"sharp": "^0.35.5"
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { assetMarker, readAssetIndex, writeAsset, writeChildAsset } from './assets.mjs';
|
|
3
|
+
import { eventContentBlocks } from './tool-preview.mjs';
|
|
4
|
+
|
|
5
|
+
export const name = 'dsh-continuity/asset-tool';
|
|
6
|
+
|
|
7
|
+
const PARAMETERS = {
|
|
8
|
+
type: 'object',
|
|
9
|
+
additionalProperties: false,
|
|
10
|
+
properties: {
|
|
11
|
+
action: {
|
|
12
|
+
type: 'string',
|
|
13
|
+
enum: ['get', 'list'],
|
|
14
|
+
description: 'get = one parent-session asset; list = recent parent-session assets.',
|
|
15
|
+
},
|
|
16
|
+
seq: {
|
|
17
|
+
type: 'integer',
|
|
18
|
+
description: 'get: the original event seq.',
|
|
19
|
+
},
|
|
20
|
+
path: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
description: 'get: a registered relative path, e.g. assets/parent/image-42-abcd1234.png.',
|
|
23
|
+
},
|
|
24
|
+
limit: {
|
|
25
|
+
type: 'integer',
|
|
26
|
+
description: 'list: maximum rows (default 20, max 100).',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
required: ['action'],
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const CHILD_PARAMETERS = {
|
|
33
|
+
type: 'object',
|
|
34
|
+
additionalProperties: false,
|
|
35
|
+
properties: {
|
|
36
|
+
action: {
|
|
37
|
+
type: 'string',
|
|
38
|
+
enum: ['get', 'list'],
|
|
39
|
+
description: 'get = one child-session/PTC artifact; list = recent child artifacts.',
|
|
40
|
+
},
|
|
41
|
+
childSessionId: {
|
|
42
|
+
type: 'string',
|
|
43
|
+
description: 'Child session id, as shown in an [asset-child ...] marker.',
|
|
44
|
+
},
|
|
45
|
+
runId: {
|
|
46
|
+
type: 'string',
|
|
47
|
+
description: 'Optional PTC run id.',
|
|
48
|
+
},
|
|
49
|
+
seq: {
|
|
50
|
+
type: 'integer',
|
|
51
|
+
description: 'get: the child event seq.',
|
|
52
|
+
},
|
|
53
|
+
path: {
|
|
54
|
+
type: 'string',
|
|
55
|
+
description: 'get: a registered relative path, e.g. assets/ptc/run/child/image-...png.',
|
|
56
|
+
},
|
|
57
|
+
limit: {
|
|
58
|
+
type: 'integer',
|
|
59
|
+
description: 'list: maximum rows (default 20, max 100).',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
required: ['action'],
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
function defaultHome() {
|
|
66
|
+
return join(process.env.USERPROFILE ?? process.env.HOME ?? '', '.dsh', 'continuity');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function formatRow(row) {
|
|
70
|
+
return `${assetMarker(row)} sha256=${row.sha256 ?? '?'} name=${row.name ?? '?'}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function formatChildRow(row) {
|
|
74
|
+
return `${assetMarker(row, 'child')} sha256=${row.sha256 ?? '?'} name=${row.name ?? '?'}`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function createSessionAssetTool({ home = defaultHome(), sessionQuery = null } = {}) {
|
|
78
|
+
return {
|
|
79
|
+
name: 'session_asset',
|
|
80
|
+
description: 'Retrieve a folded non-text payload from the current session assets. '
|
|
81
|
+
+ 'Use after session_log shows an [asset-parent ...] marker. '
|
|
82
|
+
+ 'The payload is outside the context; this returns its registered path and metadata, not the bytes.',
|
|
83
|
+
parameters: PARAMETERS,
|
|
84
|
+
output: {
|
|
85
|
+
schema: { type: 'string' },
|
|
86
|
+
render: (_args, value) => [{ type: 'text', text: String(value ?? '') }],
|
|
87
|
+
},
|
|
88
|
+
timeoutMs: 20_000,
|
|
89
|
+
isConcurrencySafe: () => true,
|
|
90
|
+
async execute(args, exec) {
|
|
91
|
+
const input = args !== null && typeof args === 'object' ? args : {};
|
|
92
|
+
const action = input.action;
|
|
93
|
+
if (action !== 'get' && action !== 'list') {
|
|
94
|
+
throw new Error('session_asset: action must be "get" or "list".');
|
|
95
|
+
}
|
|
96
|
+
const sessionId = exec?.agent?.session?.id ?? exec?.agent?.id;
|
|
97
|
+
if (sessionId === undefined || sessionId === null) {
|
|
98
|
+
throw new Error('session_asset: no current session id.');
|
|
99
|
+
}
|
|
100
|
+
const rows = (await readAssetIndex({ home, sessionId: String(sessionId) }))
|
|
101
|
+
.filter((row) => row.owner === 'parent');
|
|
102
|
+
if (action === 'list') {
|
|
103
|
+
const limit = Math.min(100, Math.max(1, Number.isInteger(input.limit) ? input.limit : 20));
|
|
104
|
+
const shown = rows.slice(-limit).reverse();
|
|
105
|
+
return [
|
|
106
|
+
`session_asset list · session=${sessionId} · assets=${rows.length}`,
|
|
107
|
+
...shown.map(formatRow),
|
|
108
|
+
].join('\n');
|
|
109
|
+
}
|
|
110
|
+
if (input.seq === undefined && input.path === undefined) {
|
|
111
|
+
throw new Error('session_asset get: seq or path is required.');
|
|
112
|
+
}
|
|
113
|
+
const row = input.path !== undefined
|
|
114
|
+
? rows.find((entry) => entry.path === input.path)
|
|
115
|
+
: rows.find((entry) => Number(entry.seq) === Number(input.seq));
|
|
116
|
+
if (row === undefined && input.path === undefined && input.seq !== undefined
|
|
117
|
+
&& typeof sessionQuery?.readSession === 'function') {
|
|
118
|
+
try {
|
|
119
|
+
const snapshot = await sessionQuery.readSession(String(sessionId));
|
|
120
|
+
const event = (Array.isArray(snapshot?.events) ? snapshot.events : [])
|
|
121
|
+
.find((entry) => Number(entry?.seq) === Number(input.seq));
|
|
122
|
+
const recovered = [];
|
|
123
|
+
for (const block of eventContentBlocks(event) ?? []) {
|
|
124
|
+
if (block === null || typeof block !== 'object') continue;
|
|
125
|
+
if (!['image', 'file', 'audio', 'video'].includes(block.type)) continue;
|
|
126
|
+
const written = await writeAsset({
|
|
127
|
+
home,
|
|
128
|
+
sessionId: String(sessionId),
|
|
129
|
+
block,
|
|
130
|
+
seq: input.seq,
|
|
131
|
+
});
|
|
132
|
+
if (written.ok) recovered.push(written.row);
|
|
133
|
+
}
|
|
134
|
+
if (recovered.length > 0) {
|
|
135
|
+
return [
|
|
136
|
+
`session_asset get · session=${sessionId} · recovered from raw seq=${input.seq}`,
|
|
137
|
+
...recovered.map(formatRow),
|
|
138
|
+
`absolute=${join(home, 'sessions', String(sessionId), recovered[0].path)}`,
|
|
139
|
+
].join('\n');
|
|
140
|
+
}
|
|
141
|
+
} catch { /* fall through to missing */ }
|
|
142
|
+
}
|
|
143
|
+
if (row === undefined) {
|
|
144
|
+
return `session_asset get · session=${sessionId} · no registered asset for ${input.path ?? `seq=${input.seq}`}`;
|
|
145
|
+
}
|
|
146
|
+
return [
|
|
147
|
+
`session_asset get · session=${sessionId}`,
|
|
148
|
+
formatRow(row),
|
|
149
|
+
`absolute=${join(home, 'sessions', String(sessionId), row.path)}`,
|
|
150
|
+
].join('\n');
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function createChildAssetTool({ home = defaultHome(), sessionQuery = null } = {}) {
|
|
156
|
+
return {
|
|
157
|
+
name: 'child_asset',
|
|
158
|
+
description: 'Retrieve a folded child/PTC artifact from the parent session assets. '
|
|
159
|
+
+ 'Use after session_log shows an [asset-child ...] marker. '
|
|
160
|
+
+ 'This returns the registered path and metadata, not the bytes.',
|
|
161
|
+
parameters: CHILD_PARAMETERS,
|
|
162
|
+
output: {
|
|
163
|
+
schema: { type: 'string' },
|
|
164
|
+
render: (_args, value) => [{ type: 'text', text: String(value ?? '') }],
|
|
165
|
+
},
|
|
166
|
+
timeoutMs: 20_000,
|
|
167
|
+
isConcurrencySafe: () => true,
|
|
168
|
+
async execute(args, exec) {
|
|
169
|
+
const input = args !== null && typeof args === 'object' ? args : {};
|
|
170
|
+
const action = input.action;
|
|
171
|
+
if (action !== 'get' && action !== 'list') {
|
|
172
|
+
throw new Error('child_asset: action must be "get" or "list".');
|
|
173
|
+
}
|
|
174
|
+
const parentSessionId = exec?.agent?.session?.id ?? exec?.agent?.id;
|
|
175
|
+
if (parentSessionId === undefined || parentSessionId === null) {
|
|
176
|
+
throw new Error('child_asset: no current parent session id.');
|
|
177
|
+
}
|
|
178
|
+
const rows = (await readAssetIndex({ home, sessionId: String(parentSessionId) }))
|
|
179
|
+
.filter((row) => row.owner === 'child')
|
|
180
|
+
.filter((row) => input.childSessionId === undefined || row.childSessionId === input.childSessionId)
|
|
181
|
+
.filter((row) => input.runId === undefined || row.runId === input.runId);
|
|
182
|
+
if (action === 'list') {
|
|
183
|
+
const limit = Math.min(100, Math.max(1, Number.isInteger(input.limit) ? input.limit : 20));
|
|
184
|
+
const shown = rows.slice(-limit).reverse();
|
|
185
|
+
return [
|
|
186
|
+
`child_asset list · session=${parentSessionId} · assets=${rows.length}`,
|
|
187
|
+
...shown.map(formatChildRow),
|
|
188
|
+
].join('\n');
|
|
189
|
+
}
|
|
190
|
+
if (input.seq === undefined && input.path === undefined) {
|
|
191
|
+
throw new Error('child_asset get: seq or path is required.');
|
|
192
|
+
}
|
|
193
|
+
const row = input.path !== undefined
|
|
194
|
+
? rows.find((entry) => entry.path === input.path)
|
|
195
|
+
: rows.find((entry) => Number(entry.seq) === Number(input.seq));
|
|
196
|
+
if (row === undefined && input.path === undefined
|
|
197
|
+
&& input.childSessionId !== undefined && input.seq !== undefined
|
|
198
|
+
&& typeof sessionQuery?.readSession === 'function') {
|
|
199
|
+
try {
|
|
200
|
+
const snapshot = await sessionQuery.readSession(input.childSessionId);
|
|
201
|
+
const event = (Array.isArray(snapshot?.events) ? snapshot.events : [])
|
|
202
|
+
.find((entry) => Number(entry?.seq) === Number(input.seq));
|
|
203
|
+
const blocks = event?.data?.message?.content;
|
|
204
|
+
const recovered = [];
|
|
205
|
+
for (const block of Array.isArray(blocks) ? blocks : []) {
|
|
206
|
+
if (block === null || typeof block !== 'object') continue;
|
|
207
|
+
if (!['image', 'file', 'audio', 'video'].includes(block.type)) continue;
|
|
208
|
+
const written = await writeChildAsset({
|
|
209
|
+
home,
|
|
210
|
+
parentSessionId: String(parentSessionId),
|
|
211
|
+
childSessionId: input.childSessionId,
|
|
212
|
+
runId: input.runId ?? 'adhoc',
|
|
213
|
+
block,
|
|
214
|
+
seq: input.seq,
|
|
215
|
+
});
|
|
216
|
+
if (written.ok) recovered.push(written.row);
|
|
217
|
+
}
|
|
218
|
+
if (recovered.length > 0) {
|
|
219
|
+
return [
|
|
220
|
+
`child_asset get · session=${parentSessionId} · recovered from child=${input.childSessionId}`,
|
|
221
|
+
...recovered.map(formatChildRow),
|
|
222
|
+
`absolute=${join(home, 'sessions', String(parentSessionId), recovered[0].path)}`,
|
|
223
|
+
].join('\n');
|
|
224
|
+
}
|
|
225
|
+
} catch { /* fall through to the missing message */ }
|
|
226
|
+
}
|
|
227
|
+
if (row === undefined) {
|
|
228
|
+
return `child_asset get · session=${parentSessionId} · no registered child asset for ${input.path ?? `seq=${input.seq}`}`;
|
|
229
|
+
}
|
|
230
|
+
return [
|
|
231
|
+
`child_asset get · session=${parentSessionId}`,
|
|
232
|
+
formatChildRow(row),
|
|
233
|
+
`absolute=${join(home, 'sessions', String(parentSessionId), row.path)}`,
|
|
234
|
+
].join('\n');
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
}
|
package/src/assets.mjs
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import fsp from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
|
|
6
|
+
const MIME_EXT = Object.freeze({
|
|
7
|
+
'image/png': '.png',
|
|
8
|
+
'image/jpeg': '.jpg',
|
|
9
|
+
'image/webp': '.webp',
|
|
10
|
+
'image/gif': '.gif',
|
|
11
|
+
'image/svg+xml': '.svg',
|
|
12
|
+
'audio/mpeg': '.mp3',
|
|
13
|
+
'audio/ogg': '.ogg',
|
|
14
|
+
'audio/wav': '.wav',
|
|
15
|
+
'video/mp4': '.mp4',
|
|
16
|
+
'video/webm': '.webm',
|
|
17
|
+
'application/pdf': '.pdf',
|
|
18
|
+
'application/json': '.json',
|
|
19
|
+
'text/plain': '.txt',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const EXT_MIME = Object.freeze(Object.fromEntries(
|
|
23
|
+
Object.entries(MIME_EXT).map(([mime, ext]) => [ext, mime]),
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
function mimeFromPath(value) {
|
|
27
|
+
const ext = path.extname(String(value ?? '')).toLowerCase();
|
|
28
|
+
return EXT_MIME[ext] ?? null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function safeId(value, fallback) {
|
|
32
|
+
const text = String(value ?? '').replace(/[^a-zA-Z0-9._-]/g, '');
|
|
33
|
+
return text.length > 0 ? text.slice(0, 160) : fallback;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function safeName(value, fallback = 'asset.bin') {
|
|
37
|
+
const text = path.basename(String(value ?? '').replaceAll('\\', '/')).replace(/[^a-zA-Z0-9._ -]/g, '');
|
|
38
|
+
return text.length > 0 ? text.slice(0, 160) : fallback;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function decodeDataUrl(value) {
|
|
42
|
+
const text = String(value ?? '');
|
|
43
|
+
const marker = text.indexOf(',');
|
|
44
|
+
if (!text.startsWith('data:') || marker < 0) return null;
|
|
45
|
+
const header = text.slice(5, marker);
|
|
46
|
+
const payload = text.slice(marker + 1);
|
|
47
|
+
const isBase64 = /;base64(?:;|$)/i.test(header);
|
|
48
|
+
const mime = header.split(';')[0] || null;
|
|
49
|
+
return {
|
|
50
|
+
buffer: Buffer.from(payload, isBase64 ? 'base64' : 'utf8'),
|
|
51
|
+
mime,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function attachmentObjectPath(attachmentId) {
|
|
56
|
+
const match = /^sha256:([a-f0-9]{64})$/i.exec(String(attachmentId ?? ''));
|
|
57
|
+
if (match === null) return null;
|
|
58
|
+
const digest = match[1].toLowerCase();
|
|
59
|
+
return path.join(
|
|
60
|
+
process.env.USERPROFILE ?? process.env.HOME ?? '',
|
|
61
|
+
'.dsh',
|
|
62
|
+
'attachments',
|
|
63
|
+
'v1',
|
|
64
|
+
'objects',
|
|
65
|
+
digest.slice(0, 2),
|
|
66
|
+
digest,
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Return a local payload for a non-text content block, without fetching URLs.
|
|
72
|
+
* @returns {{ buffer: Buffer, sourcePath: string|null, mime: string|null }|null}
|
|
73
|
+
*/
|
|
74
|
+
export function blockPayload(block) {
|
|
75
|
+
if (block === null || typeof block !== 'object') return null;
|
|
76
|
+
const mime = block.mimeType ?? block.mime ?? block.attachment?.mimeType
|
|
77
|
+
?? block.attachment?.mediaType ?? block.attachment?.mime ?? block.source?.media_type ?? null;
|
|
78
|
+
const raw = block.source?.data ?? block.data ?? block.base64;
|
|
79
|
+
if (typeof raw === 'string' && raw.length > 0) {
|
|
80
|
+
const decoded = decodeDataUrl(raw);
|
|
81
|
+
if (decoded !== null) return { ...decoded, sourcePath: null, mime: mime ?? decoded.mime };
|
|
82
|
+
try {
|
|
83
|
+
const buffer = Buffer.from(raw, 'base64');
|
|
84
|
+
if (buffer.length > 0) return { buffer, sourcePath: null, mime };
|
|
85
|
+
} catch { /* fall through */ }
|
|
86
|
+
}
|
|
87
|
+
const sourcePath = block.attachment?.path ?? block.path ?? block.source?.path;
|
|
88
|
+
if (typeof sourcePath === 'string' && sourcePath.length > 0 && fs.existsSync(sourcePath)) {
|
|
89
|
+
return { buffer: fs.readFileSync(sourcePath), sourcePath, mime: mime ?? mimeFromPath(sourcePath) };
|
|
90
|
+
}
|
|
91
|
+
const stored = attachmentObjectPath(block.attachment?.attachmentId ?? block.attachmentId);
|
|
92
|
+
if (stored !== null && fs.existsSync(stored)) {
|
|
93
|
+
return { buffer: fs.readFileSync(stored), sourcePath: stored, mime: mime ?? mimeFromPath(stored) };
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function assetKind(block) {
|
|
99
|
+
return typeof block?.type === 'string' ? block.type : 'file';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function blockMeta(block) {
|
|
103
|
+
const kind = assetKind(block);
|
|
104
|
+
const payload = blockPayload(block);
|
|
105
|
+
const name = safeName(
|
|
106
|
+
block?.attachment?.name ?? block?.name ?? block?.fileName ?? block?.source?.name,
|
|
107
|
+
`${kind}-asset`,
|
|
108
|
+
);
|
|
109
|
+
const size = block?.attachment?.size ?? block?.attachment?.bytes ?? block?.size ?? block?.bytes;
|
|
110
|
+
return {
|
|
111
|
+
kind,
|
|
112
|
+
name,
|
|
113
|
+
mime: payload?.mime ?? block?.mimeType ?? block?.mime
|
|
114
|
+
?? mimeFromPath(block?.attachment?.path ?? block?.path ?? block?.source?.path ?? name),
|
|
115
|
+
bytes: Number.isFinite(size) ? size : (payload?.buffer.length ?? null),
|
|
116
|
+
sourcePath: payload?.sourcePath ?? null,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function sessionAssetsDir(home, sessionId) {
|
|
121
|
+
return path.join(home, 'sessions', safeId(sessionId, 'unknown'), 'assets');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function assetRelativePath({ kind, seq, sha256, mime, sourcePath, name, prefix = 'parent' }) {
|
|
125
|
+
const ext = MIME_EXT[mime] ?? (path.extname(sourcePath ?? name ?? '') || '.bin');
|
|
126
|
+
return path.posix.join(
|
|
127
|
+
prefix,
|
|
128
|
+
`${safeId(kind, 'asset')}-${safeId(seq, '0')}-${String(sha256).slice(0, 8)}${ext}`,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Write one block payload under the parent session assets and append one index
|
|
134
|
+
* row. The write is atomic; an existing hash-named file is reused.
|
|
135
|
+
*/
|
|
136
|
+
export async function writeAsset({
|
|
137
|
+
home,
|
|
138
|
+
sessionId,
|
|
139
|
+
block,
|
|
140
|
+
seq,
|
|
141
|
+
owner = 'parent',
|
|
142
|
+
childSessionId = null,
|
|
143
|
+
runId = null,
|
|
144
|
+
prefix = 'parent',
|
|
145
|
+
}) {
|
|
146
|
+
const payload = blockPayload(block);
|
|
147
|
+
if (payload === null) {
|
|
148
|
+
return { ok: false, reason: 'no-payload', meta: blockMeta(block) };
|
|
149
|
+
}
|
|
150
|
+
const meta = blockMeta(block);
|
|
151
|
+
const sha256 = createHash('sha256').update(payload.buffer).digest('hex');
|
|
152
|
+
const relative = assetRelativePath({
|
|
153
|
+
kind: meta.kind,
|
|
154
|
+
seq,
|
|
155
|
+
sha256,
|
|
156
|
+
mime: meta.mime,
|
|
157
|
+
sourcePath: meta.sourcePath,
|
|
158
|
+
name: meta.name,
|
|
159
|
+
prefix,
|
|
160
|
+
});
|
|
161
|
+
const directory = sessionAssetsDir(home, sessionId);
|
|
162
|
+
const absolute = path.join(directory, relative);
|
|
163
|
+
await fsp.mkdir(path.dirname(absolute), { recursive: true });
|
|
164
|
+
if (!fs.existsSync(absolute)) {
|
|
165
|
+
const temporary = `${absolute}.${randomUUID()}.tmp`;
|
|
166
|
+
await fsp.writeFile(temporary, payload.buffer, { flag: 'wx' });
|
|
167
|
+
await fsp.rename(temporary, absolute);
|
|
168
|
+
}
|
|
169
|
+
const row = {
|
|
170
|
+
owner,
|
|
171
|
+
sessionId: String(sessionId),
|
|
172
|
+
childSessionId: childSessionId === null ? null : String(childSessionId),
|
|
173
|
+
runId: runId === null ? null : String(runId),
|
|
174
|
+
seq: Number(seq),
|
|
175
|
+
kind: meta.kind,
|
|
176
|
+
mime: meta.mime,
|
|
177
|
+
name: meta.name,
|
|
178
|
+
bytes: payload.buffer.length,
|
|
179
|
+
sha256,
|
|
180
|
+
path: path.posix.join('assets', relative),
|
|
181
|
+
at: new Date().toISOString(),
|
|
182
|
+
};
|
|
183
|
+
const indexPath = path.join(directory, 'index.jsonl');
|
|
184
|
+
const existingRows = await readAssetIndex({ home, sessionId });
|
|
185
|
+
const existing = existingRows.find((entry) => entry.seq === Number(seq)
|
|
186
|
+
&& entry.sha256 === sha256
|
|
187
|
+
&& entry.path === row.path);
|
|
188
|
+
if (existing !== undefined) {
|
|
189
|
+
return { ok: true, row: existing, relative, absolute };
|
|
190
|
+
}
|
|
191
|
+
await fsp.appendFile(indexPath, `${JSON.stringify(row)}\n`, 'utf8');
|
|
192
|
+
return { ok: true, row, relative, absolute };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** Mirror a child/PTC payload under the parent session's ptc/ namespace. */
|
|
196
|
+
export async function writeChildAsset({
|
|
197
|
+
home,
|
|
198
|
+
parentSessionId,
|
|
199
|
+
childSessionId,
|
|
200
|
+
runId,
|
|
201
|
+
block,
|
|
202
|
+
seq,
|
|
203
|
+
}) {
|
|
204
|
+
const prefix = path.posix.join(
|
|
205
|
+
'ptc',
|
|
206
|
+
safeId(runId, 'run'),
|
|
207
|
+
safeId(childSessionId, 'child'),
|
|
208
|
+
);
|
|
209
|
+
return writeAsset({
|
|
210
|
+
home,
|
|
211
|
+
sessionId: parentSessionId,
|
|
212
|
+
block,
|
|
213
|
+
seq,
|
|
214
|
+
owner: 'child',
|
|
215
|
+
childSessionId,
|
|
216
|
+
runId,
|
|
217
|
+
prefix,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export async function readAssetIndex({ home, sessionId }) {
|
|
222
|
+
const file = path.join(sessionAssetsDir(home, sessionId), 'index.jsonl');
|
|
223
|
+
try {
|
|
224
|
+
const text = await fsp.readFile(file, 'utf8');
|
|
225
|
+
return text.split('\n').filter(Boolean).map((line) => JSON.parse(line));
|
|
226
|
+
} catch (error) {
|
|
227
|
+
if (error?.code === 'ENOENT') return [];
|
|
228
|
+
throw error;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export async function findAssetBySeq({ home, sessionId, seq }) {
|
|
233
|
+
const rows = await readAssetIndex({ home, sessionId });
|
|
234
|
+
return rows.filter((row) => Number(row.seq) === Number(seq));
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export function assetMarker(row, source = 'parent') {
|
|
238
|
+
if (source === 'child') {
|
|
239
|
+
return `[asset-child session=${row.childSessionId ?? row.sessionId} run=${row.runId ?? '?'}`
|
|
240
|
+
+ ` seq=${row.seq} mime=${row.mime ?? '?'} bytes=${row.bytes ?? '?'} path=${row.path}]`;
|
|
241
|
+
}
|
|
242
|
+
return `[asset-parent seq=${row.seq} mime=${row.mime ?? '?'}`
|
|
243
|
+
+ ` bytes=${row.bytes ?? '?'} path=${row.path}]`;
|
|
244
|
+
}
|