@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,59 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Move the legacy global continuity index into sessions/<sessionId>/.
|
|
4
|
+
* Dry-run by default; --apply writes the new tree and moves the old files
|
|
5
|
+
* to *.migrated-<timestamp> backups (never deletes them).
|
|
6
|
+
*/
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import os from 'node:os';
|
|
10
|
+
import { loadIndexJsonl, saveIndexJsonl } from '../src/memory/bc-index.mjs';
|
|
11
|
+
import { defaultConceptsPath } from '../src/memory/concepts-file.mjs';
|
|
12
|
+
|
|
13
|
+
const arg = (name, fallback = null) => {
|
|
14
|
+
const at = process.argv.indexOf(`--${name}`);
|
|
15
|
+
return at >= 0 ? process.argv[at + 1] ?? fallback : fallback;
|
|
16
|
+
};
|
|
17
|
+
const has = (name) => process.argv.includes(`--${name}`);
|
|
18
|
+
const home = arg('home', process.env.USERPROFILE ?? process.env.HOME ?? os.homedir());
|
|
19
|
+
const sessionId = arg('session-id');
|
|
20
|
+
if (!sessionId) {
|
|
21
|
+
console.error('missing --session-id');
|
|
22
|
+
process.exit(2);
|
|
23
|
+
}
|
|
24
|
+
const dir = path.join(home, '.dsh', 'continuity');
|
|
25
|
+
const globalIndex = path.join(dir, 'bc-index.jsonl');
|
|
26
|
+
if (!fs.existsSync(globalIndex)) {
|
|
27
|
+
console.error(`no global index: ${globalIndex}`);
|
|
28
|
+
process.exit(2);
|
|
29
|
+
}
|
|
30
|
+
const targetDir = path.join(dir, 'sessions', String(sessionId));
|
|
31
|
+
const targetIndex = path.join(targetDir, 'bc-index.jsonl');
|
|
32
|
+
if (fs.existsSync(targetIndex)) {
|
|
33
|
+
console.error(`target already exists: ${targetIndex}`);
|
|
34
|
+
process.exit(3);
|
|
35
|
+
}
|
|
36
|
+
const records = loadIndexJsonl(globalIndex);
|
|
37
|
+
const stamped = records.map((record) => ({ ...record, sessionId: String(sessionId) }));
|
|
38
|
+
const report = { sessionId, source: globalIndex, target: targetIndex, records: stamped.length, apply: has('apply') };
|
|
39
|
+
console.log(JSON.stringify(report, null, 2));
|
|
40
|
+
if (!has('apply')) {
|
|
41
|
+
console.log('dry-run only; add --apply to migrate');
|
|
42
|
+
process.exit(0);
|
|
43
|
+
}
|
|
44
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
45
|
+
saveIndexJsonl(targetIndex, stamped);
|
|
46
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
47
|
+
for (const name of ['audit-state.json', 'expand-hint.jsonl', 'expand-hint.pending.json', 'bc-index-state.json', 'bc-vectors.json']) {
|
|
48
|
+
const from = path.join(dir, name);
|
|
49
|
+
if (!fs.existsSync(from)) continue;
|
|
50
|
+
if (name.endsWith('.json') || name.endsWith('.jsonl')) {
|
|
51
|
+
fs.writeFileSync(path.join(targetDir, name), fs.readFileSync(from, 'utf8').replace(/^\uFEFF/, ''), 'utf8');
|
|
52
|
+
} else {
|
|
53
|
+
fs.copyFileSync(from, path.join(targetDir, name));
|
|
54
|
+
}
|
|
55
|
+
fs.renameSync(from, path.join(dir, `${name}.migrated-${stamp}`));
|
|
56
|
+
}
|
|
57
|
+
fs.renameSync(globalIndex, path.join(dir, `bc-index.jsonl.migrated-${stamp}`));
|
|
58
|
+
console.log(`migrated ${stamped.length} records to ${targetDir}`);
|
|
59
|
+
console.log(`legacy files suffixed .migrated-${stamp}`);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Coreference pipeline using coreferee. Input JSONL: {id,text}. Output clusters."""
|
|
4
|
+
import json
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
import spacy
|
|
8
|
+
import coreferee
|
|
9
|
+
|
|
10
|
+
nlp = spacy.load("en_core_web_sm")
|
|
11
|
+
nlp.add_pipe("coreferee")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def clusters_for(text):
|
|
15
|
+
doc = nlp(text)
|
|
16
|
+
out = []
|
|
17
|
+
for chain in doc._.coref_chains:
|
|
18
|
+
mentions = []
|
|
19
|
+
for index in range(len(chain)):
|
|
20
|
+
mention = chain[index]
|
|
21
|
+
token_indexes = list(mention.token_indexes)
|
|
22
|
+
if not token_indexes:
|
|
23
|
+
continue
|
|
24
|
+
start_token = min(token_indexes)
|
|
25
|
+
end_token = max(token_indexes) + 1
|
|
26
|
+
span = doc[start_token:end_token]
|
|
27
|
+
mentions.append({
|
|
28
|
+
"text": span.text,
|
|
29
|
+
"start": span.start_char,
|
|
30
|
+
"end": span.end_char,
|
|
31
|
+
"isCanonical": index == chain.most_specific_mention_index,
|
|
32
|
+
})
|
|
33
|
+
if mentions:
|
|
34
|
+
out.append({"mentions": mentions})
|
|
35
|
+
return out
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
src, out = sys.argv[1], sys.argv[2]
|
|
39
|
+
rows = []
|
|
40
|
+
for line in open(src, encoding="utf-8"):
|
|
41
|
+
if not line.strip():
|
|
42
|
+
continue
|
|
43
|
+
item = json.loads(line)
|
|
44
|
+
rows.append({"id": item.get("id"), "text": item["text"], "clusters": clusters_for(item["text"])})
|
|
45
|
+
with open(out, "w", encoding="utf-8") as f:
|
|
46
|
+
json.dump({"n": len(rows), "rows": rows}, f, ensure_ascii=False, indent=2)
|
|
47
|
+
print(json.dumps({"n": len(rows), "with_clusters": sum(1 for r in rows if r["clusters"])}, ensure_ascii=False, indent=2))
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""One-shot coreference service: stdin {text}, stdout {ok, clusters}."""
|
|
4
|
+
import json
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
import coreferee
|
|
8
|
+
import spacy
|
|
9
|
+
|
|
10
|
+
sys.stdout.reconfigure(encoding="utf-8")
|
|
11
|
+
sys.stderr.reconfigure(encoding="utf-8")
|
|
12
|
+
|
|
13
|
+
nlp = spacy.load("en_core_web_sm")
|
|
14
|
+
nlp.add_pipe("coreferee")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def clusters_for(text):
|
|
18
|
+
doc = nlp(text)
|
|
19
|
+
out = []
|
|
20
|
+
for chain in doc._.coref_chains:
|
|
21
|
+
mentions = []
|
|
22
|
+
for index in range(len(chain)):
|
|
23
|
+
mention = chain[index]
|
|
24
|
+
token_indexes = list(mention.token_indexes)
|
|
25
|
+
if not token_indexes:
|
|
26
|
+
continue
|
|
27
|
+
span = doc[min(token_indexes):max(token_indexes) + 1]
|
|
28
|
+
mentions.append({
|
|
29
|
+
"text": span.text,
|
|
30
|
+
"start": span.start_char,
|
|
31
|
+
"end": span.end_char,
|
|
32
|
+
"isCanonical": index == chain.most_specific_mention_index,
|
|
33
|
+
})
|
|
34
|
+
if mentions:
|
|
35
|
+
out.append({"mentions": mentions})
|
|
36
|
+
return out
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def handle(request):
|
|
40
|
+
if request.get("health"):
|
|
41
|
+
return {"ok": True, "health": "ready"}
|
|
42
|
+
try:
|
|
43
|
+
return {"ok": True, "clusters": clusters_for(str(request.get("text", "")))}
|
|
44
|
+
except Exception as error:
|
|
45
|
+
return {"ok": False, "reason": type(error).__name__, "message": str(error)[:300]}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
if "--serve" in sys.argv:
|
|
49
|
+
for raw in sys.stdin.buffer:
|
|
50
|
+
line = raw.decode("utf-8", "replace").strip()
|
|
51
|
+
if not line:
|
|
52
|
+
continue
|
|
53
|
+
request = json.loads(line)
|
|
54
|
+
print(json.dumps({"id": request.get("id"), **handle(request)}, ensure_ascii=False), flush=True)
|
|
55
|
+
else:
|
|
56
|
+
request = json.loads(sys.stdin.buffer.read().decode("utf-8"))
|
|
57
|
+
print(json.dumps(handle(request), ensure_ascii=False))
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import os, json
|
|
3
|
+
from datasets import load_dataset
|
|
4
|
+
from transformers import BertTokenizer, AutoModelForTokenClassification, pipeline
|
|
5
|
+
p=os.path.join(os.environ['TEMP'],'ckip-tiny')
|
|
6
|
+
tok=BertTokenizer(vocab_file=os.path.join(p,'vocab.txt'))
|
|
7
|
+
model=AutoModelForTokenClassification.from_pretrained(p)
|
|
8
|
+
ner=pipeline('ner',model=model,tokenizer=tok,aggregation_strategy=None,device=-1)
|
|
9
|
+
ds=load_dataset('nlhappy/CLUE-NER',split='validation')
|
|
10
|
+
for i in range(2):
|
|
11
|
+
item=ds[i]
|
|
12
|
+
print('TEXT',item['text'][:120],flush=True)
|
|
13
|
+
print('TOKENS',tok.tokenize(item['text'][:30]),flush=True)
|
|
14
|
+
out=ner(item['text'][:120])
|
|
15
|
+
print('OUT',out[:5],flush=True)
|
|
16
|
+
print('GOLD',item['ents'][:5],flush=True)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import time
|
|
3
|
+
from transformers import AutoTokenizer, AutoModelForTokenClassification, pipeline
|
|
4
|
+
from datasets import load_dataset
|
|
5
|
+
print('start', flush=True)
|
|
6
|
+
t0=time.time()
|
|
7
|
+
tok=AutoTokenizer.from_pretrained('uer/roberta-base-finetuned-cluener2020-chinese')
|
|
8
|
+
print('tok',time.time()-t0,flush=True)
|
|
9
|
+
model=AutoModelForTokenClassification.from_pretrained('uer/roberta-base-finetuned-cluener2020-chinese')
|
|
10
|
+
print('model',time.time()-t0,flush=True)
|
|
11
|
+
ner=pipeline('ner',model=model,tokenizer=tok,aggregation_strategy='simple',device=-1)
|
|
12
|
+
print('pipe',time.time()-t0,flush=True)
|
|
13
|
+
ds=load_dataset('xusenlin/clue-ner',split='validation')
|
|
14
|
+
print('data',time.time()-t0,flush=True)
|
|
15
|
+
text=ds[0]['text'][:100]
|
|
16
|
+
print('text',text,flush=True)
|
|
17
|
+
print(ner(text),flush=True)
|
|
18
|
+
print('done',time.time()-t0,flush=True)
|
package/bin/doctor.mjs
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* DSH Continuity 体检(独立脚本,不依赖插件是否加载)。
|
|
4
|
+
*
|
|
5
|
+
* 为什么独立:最该诊断的情况就是「插件 client 没加载」——那时候插件自己的工具也不在。
|
|
6
|
+
*
|
|
7
|
+
* 查五件事:
|
|
8
|
+
* 1. 宿主 DSH 版本,以及宿主里有没有插件声明要 inject 的三个 client 包
|
|
9
|
+
* 2. 每个 profile 的 package.json:dsh-continuity 有没有装、是不是 link、在不在 bundles 里
|
|
10
|
+
* 3. 插件目录里 client.js 有没有右侧栏注册(sidebarRightTabs)
|
|
11
|
+
* 4. 结论:宿主太老 / 没进 bundles / 装的是老版本 / 都正常(那是缓存或浏览器)
|
|
12
|
+
*
|
|
13
|
+
* 用法:
|
|
14
|
+
* node dsh-continuity-doctor.mjs
|
|
15
|
+
* node dsh-continuity-doctor.mjs --dsh "<DSH 安装目录>" --profile "<profile 目录>"
|
|
16
|
+
*/
|
|
17
|
+
import fs from 'node:fs';
|
|
18
|
+
import os from 'node:os';
|
|
19
|
+
import path from 'node:path';
|
|
20
|
+
import { createRequire } from 'node:module';
|
|
21
|
+
|
|
22
|
+
const args = process.argv.slice(2);
|
|
23
|
+
const argOf = (name) => {
|
|
24
|
+
const index = args.indexOf(name);
|
|
25
|
+
return index >= 0 ? args[index + 1] : undefined;
|
|
26
|
+
};
|
|
27
|
+
const say = (line = '') => console.log(line);
|
|
28
|
+
if (args.includes('--fix-tags')) {
|
|
29
|
+
try {
|
|
30
|
+
const { runMaintenance } = await import('../src/tag-maintenance.mjs');
|
|
31
|
+
const result = await runMaintenance({ mode: 'manual', dryRun: args.includes('--dry-run') });
|
|
32
|
+
say(JSON.stringify(result, null, 2));
|
|
33
|
+
process.exit(result.healthy ? 0 : 1);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
say(`[doctor] tag maintenance failed: ${error?.message ?? error}`);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const readJson = (file) => { try { return JSON.parse(fs.readFileSync(file, 'utf8')); } catch { return null; } };
|
|
40
|
+
|
|
41
|
+
const REQUIRED_CLIENT_PACKAGES = [
|
|
42
|
+
'@deepseek-ai/dsh-client-ui-sidebar',
|
|
43
|
+
'@deepseek-ai/dsh-client-ui-layout',
|
|
44
|
+
'@deepseek-ai/dsh-client-locale',
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
const problems = [];
|
|
48
|
+
|
|
49
|
+
// ---------- 1. 宿主 ----------
|
|
50
|
+
// 注意:DSH_HOME 指的是 ~/.dsh(profile/数据的家),**不是**安装目录——
|
|
51
|
+
// 拿它当安装目录会得到"没有 app.asar"的假故障。安装目录只用 --dsh 或候选路径。
|
|
52
|
+
const findHostDir = () => {
|
|
53
|
+
const explicit = argOf('--dsh') ?? process.env.DSH_INSTALL ?? null;
|
|
54
|
+
if (explicit) return explicit;
|
|
55
|
+
const candidates = [
|
|
56
|
+
// Windows
|
|
57
|
+
process.env.LOCALAPPDATA ? path.join(process.env.LOCALAPPDATA, 'Programs', 'DeepSeek Harness') : null,
|
|
58
|
+
process.env.ProgramFiles ? path.join(process.env.ProgramFiles, 'DeepSeek Harness') : null,
|
|
59
|
+
// macOS
|
|
60
|
+
'/Applications/DeepSeek Harness.app',
|
|
61
|
+
path.join(os.homedir(), 'Applications', 'DeepSeek Harness.app'),
|
|
62
|
+
// Linux(AppImage 解包目录 / deb 安装目录 / 用户目录)
|
|
63
|
+
path.join(os.homedir(), '.local', 'share', 'deepseek-harness'),
|
|
64
|
+
'/opt/DeepSeek Harness',
|
|
65
|
+
'/usr/lib/deepseek-harness',
|
|
66
|
+
].filter(Boolean);
|
|
67
|
+
// 优先选真的带 app.asar 的那个(存在多个安装时,比如重复安装)。
|
|
68
|
+
const existing = candidates.filter((candidate) => fs.existsSync(candidate));
|
|
69
|
+
const withAsar = existing.find((candidate) => [
|
|
70
|
+
path.join(candidate, 'resources', 'app.asar'),
|
|
71
|
+
path.join(candidate, 'app.asar'),
|
|
72
|
+
path.join(candidate, 'Contents', 'Resources', 'app.asar'),
|
|
73
|
+
].some((file) => fs.existsSync(file)));
|
|
74
|
+
return withAsar ?? existing[0] ?? null;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/** version 文件可能在目录根、Resources/ 里,或 app bundle 的 Contents/ 下。 */
|
|
78
|
+
const findVersionFile = (dir) => {
|
|
79
|
+
const candidates = [
|
|
80
|
+
path.join(dir, 'version'),
|
|
81
|
+
path.join(dir, 'Contents', 'version'),
|
|
82
|
+
path.join(dir, 'Resources', 'version'),
|
|
83
|
+
path.join(dir, 'Contents', 'Resources', 'version'),
|
|
84
|
+
];
|
|
85
|
+
return candidates.find((file) => fs.existsSync(file)) ?? null;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Electron 会把 .asar 当目录(readFileSync 直接失败),要用 original-fs 绕过。
|
|
89
|
+
// 这也是"用 DSH 自带的 Electron 当 node 跑"时必须处理的一步。
|
|
90
|
+
function readAsarText(file) {
|
|
91
|
+
try {
|
|
92
|
+
const req = createRequire(import.meta.url);
|
|
93
|
+
const originalFs = req('original-fs');
|
|
94
|
+
return originalFs.readFileSync(file).toString('latin1');
|
|
95
|
+
} catch { /* 不是 Electron,或没有 original-fs */ }
|
|
96
|
+
try { return fs.readFileSync(file).toString('latin1'); } catch { return ''; }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function hostInfo(dir) {
|
|
100
|
+
const info = { dir, version: null, packages: {} };
|
|
101
|
+
const versionFile = findVersionFile(dir);
|
|
102
|
+
if (versionFile) info.version = fs.readFileSync(versionFile, 'utf8').trim();
|
|
103
|
+
const asar = [
|
|
104
|
+
path.join(dir, 'resources', 'app.asar'),
|
|
105
|
+
path.join(dir, 'app.asar'),
|
|
106
|
+
path.join(dir, 'Contents', 'Resources', 'app.asar'),
|
|
107
|
+
path.join(dir, 'Resources', 'app.asar'),
|
|
108
|
+
].find((file) => fs.existsSync(file));
|
|
109
|
+
if (!asar) { info.asarMissing = true; return info; }
|
|
110
|
+
const text = readAsarText(asar);
|
|
111
|
+
if (text.length === 0) { info.asarUnreadable = true; return info; }
|
|
112
|
+
for (const name of REQUIRED_CLIENT_PACKAGES) {
|
|
113
|
+
const at = text.indexOf('"name": "' + name + '"');
|
|
114
|
+
if (at < 0) { info.packages[name] = null; continue; }
|
|
115
|
+
const slice = text.slice(at, at + 240);
|
|
116
|
+
const match = /"version":\s*"([^"]+)"/.exec(slice);
|
|
117
|
+
info.packages[name] = match ? match[1] : '(版本未解析)';
|
|
118
|
+
}
|
|
119
|
+
return info;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
say('DSH Continuity 体检');
|
|
123
|
+
say('='.repeat(60));
|
|
124
|
+
say(`本机 ${process.platform} · node ${process.version}`);
|
|
125
|
+
say('');
|
|
126
|
+
|
|
127
|
+
const hostDir = findHostDir();
|
|
128
|
+
const host = hostDir ? hostInfo(hostDir) : null;
|
|
129
|
+
if (!host) {
|
|
130
|
+
say('✗ 没找到 DSH 安装目录(用 --dsh 指定,或设 DSH_INSTALL)。');
|
|
131
|
+
problems.push({ kind: 'no-host', detail: '找不到宿主目录,后面几项无法判定' });
|
|
132
|
+
} else {
|
|
133
|
+
say(`宿主目录 ${host.dir}`);
|
|
134
|
+
say(`宿主版本 ${host.version ?? '(没有 version 文件)'}`);
|
|
135
|
+
if (host.asarMissing) {
|
|
136
|
+
say('✗ 宿主里没有 app.asar(便携版或非常规安装)');
|
|
137
|
+
problems.push({ kind: 'no-asar', detail: '找不到 app.asar,无法确认宿主自带的 client 包' });
|
|
138
|
+
} else if (host.asarUnreadable) {
|
|
139
|
+
say('✗ app.asar 读不出来(可能是权限或 asar 处理方式,见 --dsh 指定后重试)');
|
|
140
|
+
problems.push({ kind: 'asar-unreadable', detail: 'app.asar 读不出来,无法确认宿主自带的 client 包' });
|
|
141
|
+
} else {
|
|
142
|
+
for (const name of REQUIRED_CLIENT_PACKAGES) {
|
|
143
|
+
const version = host.packages[name];
|
|
144
|
+
say(` ${version ? '✓' : '✗'} ${name.padEnd(46)} ${version ?? '宿主里没有'}`);
|
|
145
|
+
if (!version) problems.push({ kind: 'host-too-old', detail: '宿主缺 ' + name });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ---------- 2. profile ----------
|
|
151
|
+
function findProfiles() {
|
|
152
|
+
const explicit = argOf('--profile');
|
|
153
|
+
if (explicit) return [explicit];
|
|
154
|
+
// profile 根目录:DSH_PROFILES_ROOT 可覆盖;默认 ~/.dsh/profiles(DSH 桌面与 CLI 共用)
|
|
155
|
+
const roots = [
|
|
156
|
+
process.env.DSH_PROFILES_ROOT ?? path.join(os.homedir(), '.dsh', 'profiles'),
|
|
157
|
+
];
|
|
158
|
+
const out = [];
|
|
159
|
+
for (const root of roots) {
|
|
160
|
+
if (!fs.existsSync(root)) continue;
|
|
161
|
+
for (const entry of fs.readdirSync(root, { withFileTypes: true })) {
|
|
162
|
+
if (!entry.isDirectory()) continue;
|
|
163
|
+
const dir = path.join(root, entry.name);
|
|
164
|
+
if (fs.existsSync(path.join(dir, 'package.json'))) out.push(dir);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return out;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
say('');
|
|
171
|
+
say('profile');
|
|
172
|
+
say('-'.repeat(60));
|
|
173
|
+
const profiles = findProfiles();
|
|
174
|
+
if (profiles.length === 0) {
|
|
175
|
+
say('✗ 没找到 profile(~/.dsh/profiles/<名字>/package.json)。');
|
|
176
|
+
problems.push({ kind: 'no-profile', detail: '找不到 profile,插件装在哪里需要人工确认' });
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
let resolvedPluginDir = null;
|
|
180
|
+
let installedAnywhere = false;
|
|
181
|
+
for (const dir of profiles) {
|
|
182
|
+
const doc = readJson(path.join(dir, 'package.json'));
|
|
183
|
+
if (!doc) { say(`? ${dir}(package.json 读不了)`); continue; }
|
|
184
|
+
const spec = doc.dependencies?.['dsh-continuity'] ?? null;
|
|
185
|
+
const bundles = Array.isArray(doc.dsh?.profile?.bundles) ? doc.dsh.profile.bundles : [];
|
|
186
|
+
const inBundles = bundles.includes('dsh-continuity');
|
|
187
|
+
say(`${path.basename(dir)} ${spec ? `装 ${spec}` : '没装 dsh-continuity(这个 profile 不用它)'} · ${inBundles ? '在 bundles' : (spec ? '不在 bundles' : '—')}`);
|
|
188
|
+
if (!spec) continue; // 不用它的 profile 不算问题
|
|
189
|
+
installedAnywhere = true;
|
|
190
|
+
if (!inBundles) problems.push({ kind: 'not-in-bundles', detail: `${path.basename(dir)} 装了但 dsh.profile.bundles 里没有它(装了也不会加载)` });
|
|
191
|
+
|
|
192
|
+
// 解析实际目录:link:/file: 用它;否则看 node_modules
|
|
193
|
+
const specPath = /^(?:link|file):(.+)$/.exec(spec);
|
|
194
|
+
const pluginDir = specPath ? specPath[1] : path.join(dir, 'node_modules', 'dsh-continuity');
|
|
195
|
+
if (pluginDir && fs.existsSync(path.join(pluginDir, 'package.json'))) resolvedPluginDir = resolvedPluginDir ?? pluginDir;
|
|
196
|
+
}
|
|
197
|
+
if (!installedAnywhere) {
|
|
198
|
+
problems.push({ kind: 'not-installed', detail: '没有任何 profile 装 dsh-continuity' });
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ---------- 3. 插件 ----------
|
|
202
|
+
say('');
|
|
203
|
+
say('插件');
|
|
204
|
+
say('-'.repeat(60));
|
|
205
|
+
if (!resolvedPluginDir) {
|
|
206
|
+
say('✗ 解析不到插件目录(link/file 路径不存在,也没在 node_modules 里)。');
|
|
207
|
+
problems.push({ kind: 'plugin-dir-missing', detail: '插件目录不存在:装过但文件不在了' });
|
|
208
|
+
} else {
|
|
209
|
+
const doc = readJson(path.join(resolvedPluginDir, 'package.json'));
|
|
210
|
+
const clientFile = path.join(resolvedPluginDir, 'client.js');
|
|
211
|
+
const hasClient = fs.existsSync(clientFile);
|
|
212
|
+
let clientSource = '';
|
|
213
|
+
try { clientSource = fs.readFileSync(clientFile, 'utf8'); } catch { clientSource = ''; }
|
|
214
|
+
const hasSidebarRight = clientSource.includes('sidebarRightTabs');
|
|
215
|
+
const inject = Array.isArray(doc?.dsh?.client?.inject) ? doc.dsh.client.inject : [];
|
|
216
|
+
say(`目录 ${resolvedPluginDir}`);
|
|
217
|
+
say(`版本 ${doc?.version ?? '(读不到 package.json)'}`);
|
|
218
|
+
say(`client.js ${hasClient ? '在' : '不在'} · 右侧栏注册 ${hasSidebarRight ? '有' : '没有'}`);
|
|
219
|
+
say(`声明注入 ${inject.length > 0 ? inject.join(' · ') : '(没有声明)'}`);
|
|
220
|
+
if (!hasClient) problems.push({ kind: 'no-client-js', detail: '插件目录里没有 client.js(老版本或打包不完整)' });
|
|
221
|
+
if (hasClient && !hasSidebarRight) problems.push({ kind: 'old-client', detail: 'client.js 里没有 sidebarRightTabs:这个版本还不带右侧栏' });
|
|
222
|
+
for (const name of REQUIRED_CLIENT_PACKAGES) {
|
|
223
|
+
if (inject.length > 0 && !inject.includes(name)) {
|
|
224
|
+
problems.push({ kind: 'inject-mismatch', detail: `插件的 dsh.client.inject 里没有 ${name},可能在找别的宿主 API` });
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// ---------- 3.5 规则层 ----------
|
|
230
|
+
say('');
|
|
231
|
+
say('规则层');
|
|
232
|
+
say('-'.repeat(60));
|
|
233
|
+
const continuityHome = process.env.DSH_CONTINUITY_HOME
|
|
234
|
+
? process.env.DSH_CONTINUITY_HOME
|
|
235
|
+
: path.join(os.homedir(), '.dsh', 'continuity');
|
|
236
|
+
const agentsFile = path.join(os.homedir(), '.dsh', 'AGENTS.md');
|
|
237
|
+
const rulesFile = path.join(continuityHome, 'rules.md');
|
|
238
|
+
const habitsFile = path.join(continuityHome, 'habits.md');
|
|
239
|
+
const agentsText = (() => { try { return fs.readFileSync(agentsFile, 'utf8'); } catch { return ''; } })();
|
|
240
|
+
const pointerOk = agentsText.includes('## Continuity 的 rules.md')
|
|
241
|
+
|| agentsText.includes('## Continuity 的规则层');
|
|
242
|
+
say(`AGENTS 指针 ${pointerOk ? '有' : '缺少'}`);
|
|
243
|
+
if (!pointerOk) problems.push({ kind: 'agents-pointer-missing', detail: `AGENTS.md 缺少 Continuity 指针:${agentsFile}` });
|
|
244
|
+
for (const [name, file] of [['rules.md', rulesFile], ['habits.md', habitsFile]]) {
|
|
245
|
+
const ok = fs.existsSync(file);
|
|
246
|
+
say(`${name.padEnd(10)} ${ok ? '有' : '缺少'}`);
|
|
247
|
+
if (!ok) problems.push({ kind: 'rules-layer-missing', detail: `${name} 不存在:${file}(先跑 install-templates --apply)` });
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ---------- 4. 结论 ----------
|
|
251
|
+
say('');
|
|
252
|
+
say('结论');
|
|
253
|
+
say('-'.repeat(60));
|
|
254
|
+
const kinds = new Set(problems.map((problem) => problem.kind));
|
|
255
|
+
if (problems.length === 0) {
|
|
256
|
+
say('✓ 宿主、profile、插件、client 声明都对得上。');
|
|
257
|
+
say(' UI 还是不出现 → 界面缓存:硬刷新(Ctrl/Cmd+Shift+R)或重启 GUI。');
|
|
258
|
+
say(' 仍没有 → DevTools Console 里找 inject / Cannot find module 的报错,把原文发回来。');
|
|
259
|
+
} else {
|
|
260
|
+
for (const problem of problems) say(`✗ [${problem.kind}] ${problem.detail}`);
|
|
261
|
+
say('');
|
|
262
|
+
if (kinds.has('host-too-old')) say('→ 先升 DSH 宿主到带这三个 client 包的版本;宿主不升,插件这边改不了。');
|
|
263
|
+
if (kinds.has('not-in-bundles')) say('→ 把 "dsh-continuity" 加进该 profile 的 dsh.profile.bundles(或重装插件让管理界面写进去)。');
|
|
264
|
+
if (kinds.has('not-installed') || kinds.has('plugin-dir-missing')) say('→ 插件没装好:用管理界面重装,或 npm pack 的 tgz 解到 profile 的 node_modules。');
|
|
265
|
+
if (kinds.has('old-client') || kinds.has('no-client-js')) say('→ 插件版本太旧:升到带右侧栏的 0.4.x。');
|
|
266
|
+
if (kinds.has('inject-mismatch')) say('→ 插件与宿主的 client API 不匹配:宿主与插件版本要一起看。');
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
say('');
|
|
270
|
+
say('把整段输出发回即可,不用附别的东西。');
|
|
271
|
+
say('');
|
|
272
|
+
say('没装 node 也能跑——用 DSH 自带的 Electron 当 node:');
|
|
273
|
+
say(' Windows: set ELECTRON_RUN_AS_NODE=1 && "<DSH 安装目录>\\DeepSeek Harness.exe" --expose-internals dsh-continuity-doctor.mjs');
|
|
274
|
+
say(' macOS: ELECTRON_RUN_AS_NODE=1 "/Applications/DeepSeek Harness.app/Contents/MacOS/DeepSeek Harness" --expose-internals dsh-continuity-doctor.mjs');
|
|
275
|
+
say('指定位置:--dsh "<安装目录>"、--profile "<profile 目录>"、DSH_PROFILES_ROOT=<profiles 根>');
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import json
|
|
3
|
+
import sys
|
|
4
|
+
from collections import Counter
|
|
5
|
+
|
|
6
|
+
data = json.load(open(sys.argv[1], encoding="utf-8"))
|
|
7
|
+
rows = data["rows"]
|
|
8
|
+
fp = []
|
|
9
|
+
fn = []
|
|
10
|
+
gold_count = Counter()
|
|
11
|
+
pred_count = Counter()
|
|
12
|
+
for row in rows:
|
|
13
|
+
gold = {(g["text"].replace(" ", ""), g["label"]) for g in row["gold"]}
|
|
14
|
+
pred = {(p["text"].replace(" ", ""), p["label"]) for p in row["pred"]}
|
|
15
|
+
for _, label in gold:
|
|
16
|
+
gold_count[label] += 1
|
|
17
|
+
for _, label in pred:
|
|
18
|
+
pred_count[label] += 1
|
|
19
|
+
for text, label in pred - gold:
|
|
20
|
+
fp.append({"text": text, "label": label, "sentence": row["text"]})
|
|
21
|
+
for text, label in gold - pred:
|
|
22
|
+
fn.append({"text": text, "label": label, "sentence": row["text"]})
|
|
23
|
+
summary = {
|
|
24
|
+
"score": data["score"],
|
|
25
|
+
"gold_by_label": dict(gold_count),
|
|
26
|
+
"pred_by_label": dict(pred_count),
|
|
27
|
+
"fp_by_label": dict(Counter(x["label"] for x in fp)),
|
|
28
|
+
"fn_by_label": dict(Counter(x["label"] for x in fn)),
|
|
29
|
+
"fp_samples": fp[:30],
|
|
30
|
+
"fn_samples": fn[:30],
|
|
31
|
+
}
|
|
32
|
+
json.dump(summary, open(sys.argv[2], "w", encoding="utf-8"), ensure_ascii=False, indent=2)
|
|
33
|
+
print(json.dumps({k: v for k, v in summary.items() if not k.endswith("samples")}, ensure_ascii=False, indent=2))
|