@kanadego/dsh-heartbeat 1.9.1 → 1.9.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.
Files changed (36) hide show
  1. package/README.md +27 -5
  2. package/cordis.patch.yml +18 -39
  3. package/dist/{chunk-BQCXYE7N.js → chunk-3MDBU6WY.js} +2 -2
  4. package/dist/{chunk-HT57FOEF.js → chunk-AJ5HLAL7.js} +34 -11
  5. package/dist/chunk-AJ5HLAL7.js.map +1 -0
  6. package/dist/{chunk-OYVNWB5G.js → chunk-CUOSICYJ.js} +2 -2
  7. package/dist/{chunk-WRJCINZ7.js → chunk-IG6YMUHW.js} +4 -4
  8. package/dist/{chunk-KOOQOMQY.js → chunk-JDH2LDFS.js} +2 -2
  9. package/dist/chunk-K5Y6JP2B.js +399 -0
  10. package/dist/chunk-K5Y6JP2B.js.map +1 -0
  11. package/dist/{chunk-QOQ7EPZZ.js → chunk-KB5SMG3F.js} +3 -3
  12. package/dist/{chunk-2NB4QILF.js → chunk-XFNCTOW7.js} +2 -2
  13. package/dist/cli/index.js +9 -9
  14. package/dist/{inbox-JLT5G7TL.js → inbox-P26DDMWC.js} +3 -3
  15. package/dist/index.d.ts +33 -0
  16. package/dist/index.js +104 -20
  17. package/dist/index.js.map +1 -1
  18. package/dist/{migrate-WDVFHUP7.js → migrate-D4VKAKYT.js} +3 -3
  19. package/dist/{orchestrator-2ZLU7RGE.js → orchestrator-EUTZ3KG6.js} +10 -8
  20. package/dist/{pool-B34NTH6D.js → pool-UTXQJJ5C.js} +3 -3
  21. package/dist/{snapshot-JQDJ346Z.js → snapshot-K5VHETTK.js} +4 -4
  22. package/package.json +83 -83
  23. package/dist/chunk-7TW6DD6Q.js +0 -208
  24. package/dist/chunk-7TW6DD6Q.js.map +0 -1
  25. package/dist/chunk-HT57FOEF.js.map +0 -1
  26. /package/dist/{chunk-BQCXYE7N.js.map → chunk-3MDBU6WY.js.map} +0 -0
  27. /package/dist/{chunk-OYVNWB5G.js.map → chunk-CUOSICYJ.js.map} +0 -0
  28. /package/dist/{chunk-WRJCINZ7.js.map → chunk-IG6YMUHW.js.map} +0 -0
  29. /package/dist/{chunk-KOOQOMQY.js.map → chunk-JDH2LDFS.js.map} +0 -0
  30. /package/dist/{chunk-QOQ7EPZZ.js.map → chunk-KB5SMG3F.js.map} +0 -0
  31. /package/dist/{chunk-2NB4QILF.js.map → chunk-XFNCTOW7.js.map} +0 -0
  32. /package/dist/{inbox-JLT5G7TL.js.map → inbox-P26DDMWC.js.map} +0 -0
  33. /package/dist/{migrate-WDVFHUP7.js.map → migrate-D4VKAKYT.js.map} +0 -0
  34. /package/dist/{orchestrator-2ZLU7RGE.js.map → orchestrator-EUTZ3KG6.js.map} +0 -0
  35. /package/dist/{pool-B34NTH6D.js.map → pool-UTXQJJ5C.js.map} +0 -0
  36. /package/dist/{snapshot-JQDJ346Z.js.map → snapshot-K5VHETTK.js.map} +0 -0
package/dist/index.d.ts CHANGED
@@ -368,6 +368,29 @@ interface PathGuard {
368
368
  check(target: string): string | null;
369
369
  }
370
370
 
371
+ type RelocateResult = {
372
+ action: 'relocated';
373
+ /** Package-local tree the data came from (now deleted). */
374
+ srcDir: string;
375
+ dstDir: string;
376
+ backupDir: string;
377
+ files: number;
378
+ bytes: number;
379
+ /** Plaintext JSON/JSONL that does not parse (verified byte-identical). */
380
+ warnings: string[];
381
+ /** Paths that could not be deleted after the move (cosmetic leftovers). */
382
+ leftovers: string[];
383
+ } | {
384
+ action: 'skipped';
385
+ reason: 'source-missing' | 'no-payload' | 'destination-exists';
386
+ } | {
387
+ action: 'failed';
388
+ stage: 'backup' | 'copy' | 'verify' | 'commit';
389
+ problems: string[];
390
+ /** Null when the backup itself could not be created. */
391
+ backupDir: string | null;
392
+ };
393
+
371
394
  interface WorkspacePaths {
372
395
  /** Guard boundary and the only writable tree at runtime. */
373
396
  dataDir: string;
@@ -379,6 +402,11 @@ interface WorkspacePaths {
379
402
  packageRoot: string;
380
403
  configDir: string;
381
404
  assetsDir: string;
405
+ /**
406
+ * Set only when a legacy package-local data dir was found: the outcome of
407
+ * the one-time relocation. Absent for explicit dirs and fresh installs.
408
+ */
409
+ relocation?: RelocateResult;
382
410
  }
383
411
 
384
412
  interface OrchestratorDeps {
@@ -403,6 +431,11 @@ interface OrchestratorDeps {
403
431
  policy: Policy;
404
432
  /** Agent preset the heartbeat agent joins (composition entry `agentPreset`). */
405
433
  agentPreset?: string;
434
+ /** Awaited right before the preset mount: the plugin registers its preset at
435
+ * runtime (issue #2 — the composition must not name a host package), and the
436
+ * mount must not race that registration. Resolves at once when registration
437
+ * was skipped or the host has no registry API. */
438
+ presetRegistration?: () => Promise<void>;
406
439
  /** Extra tool names the engine-room allow-list should include (config
407
440
  * `extraTools`, comma-separated in the composition entry). Only names that
408
441
  * actually exist in the global layer are applied. */
package/dist/index.js CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  sessionEventCount,
28
28
  sessionEvents,
29
29
  startOrchestrator
30
- } from "./chunk-HT57FOEF.js";
30
+ } from "./chunk-AJ5HLAL7.js";
31
31
  import {
32
32
  appendEntry,
33
33
  ledgerFilePath,
@@ -36,7 +36,7 @@ import {
36
36
  readLedger,
37
37
  readWeeklyReport,
38
38
  scanPending
39
- } from "./chunk-WRJCINZ7.js";
39
+ } from "./chunk-IG6YMUHW.js";
40
40
  import {
41
41
  getRuntime,
42
42
  setRuntime
@@ -49,19 +49,19 @@ import {
49
49
  loadPool,
50
50
  restoreSeed,
51
51
  seedsFilePath
52
- } from "./chunk-KOOQOMQY.js";
53
- import "./chunk-BQCXYE7N.js";
52
+ } from "./chunk-JDH2LDFS.js";
53
+ import "./chunk-3MDBU6WY.js";
54
54
  import "./chunk-IV2ZWQA3.js";
55
- import "./chunk-QOQ7EPZZ.js";
55
+ import "./chunk-KB5SMG3F.js";
56
56
  import {
57
57
  appendAuditLine,
58
58
  loadProfile,
59
59
  profileFilePath
60
- } from "./chunk-OYVNWB5G.js";
60
+ } from "./chunk-CUOSICYJ.js";
61
61
  import {
62
62
  initWorkspace,
63
63
  writeText
64
- } from "./chunk-7TW6DD6Q.js";
64
+ } from "./chunk-K5Y6JP2B.js";
65
65
  import {
66
66
  atomicWriteFileSync,
67
67
  atomicWriteJsonSync
@@ -1483,7 +1483,7 @@ function buildEndpoints(deps, isLive) {
1483
1483
  async "migrate.export"(p) {
1484
1484
  const passphrase = String(p.passphrase ?? "");
1485
1485
  if (!passphrase) return err("bad-request", "\u9700\u8981\u8BBE\u7F6E\u53E3\u4EE4");
1486
- const { collectMigrationEntries, encryptContainer } = await import("./migrate-WDVFHUP7.js");
1486
+ const { collectMigrationEntries, encryptContainer } = await import("./migrate-D4VKAKYT.js");
1487
1487
  const { entries } = collectMigrationEntries(guard, paths);
1488
1488
  if (entries.length === 0) return err("bad-request", "\u6CA1\u6709\u53EF\u6253\u5305\u7684\u8BB0\u5FC6\u6587\u4EF6\uFF08data/ \u662F\u7A7A\u7684\uFF09");
1489
1489
  const out = path4.join(paths.exportsDir, `heartbeat-memory-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.hbmig`);
@@ -1495,7 +1495,7 @@ function buildEndpoints(deps, isLive) {
1495
1495
  const passphrase = String(p.passphrase ?? "");
1496
1496
  const file = String(p.file ?? "");
1497
1497
  if (!passphrase || !file) return err("bad-request", "\u9700\u8981\u5BB9\u5668\u8DEF\u5F84\u4E0E\u53E3\u4EE4");
1498
- const { decryptContainer, applyMigrationEntries } = await import("./migrate-WDVFHUP7.js");
1498
+ const { decryptContainer, applyMigrationEntries } = await import("./migrate-D4VKAKYT.js");
1499
1499
  let text;
1500
1500
  try {
1501
1501
  text = fs4.readFileSync(file, "utf8");
@@ -1680,6 +1680,47 @@ function registerStatusbarSection(ctx, guard, paths, opts) {
1680
1680
  });
1681
1681
  }
1682
1682
 
1683
+ // src/core/preset-definition.ts
1684
+ function heartbeatPresetDefinition(id = "heartbeat") {
1685
+ return {
1686
+ id,
1687
+ name: "\u5FC3\u8DF3\u6A21\u5F0F",
1688
+ description: "\u5FC3\u8DF3 agent \u4E13\u7528\uFF1A\u4EC5 web_search + \u4E0A\u4E0B\u6587\u6298\u53E0\uFF1B\u65E0 shell\u3001\u65E0\u6587\u4EF6\u3001\u65E0\u5B50\u4EE3\u7406\u3002",
1689
+ order: 20,
1690
+ plugins: [
1691
+ {
1692
+ id: "compaction",
1693
+ name: "cordis:group",
1694
+ group: true,
1695
+ isolate: { compaction: true, toolResultPruner: true },
1696
+ config: [
1697
+ { id: "compaction-basic", name: "@deepseek-ai/dsh-compaction-basic" },
1698
+ { id: "command-compact", name: "@deepseek-ai/dsh-command-compact" },
1699
+ {
1700
+ id: "tool-result-pruner",
1701
+ name: "@deepseek-ai/dsh-compaction-tool-result-pruner",
1702
+ config: { thresholdChars: 8192, headChars: 4096, tailChars: 1024 }
1703
+ }
1704
+ ]
1705
+ },
1706
+ { id: "tool-web", name: "@deepseek-ai/dsh-tool-web", config: { fetch: false, searchTimeoutMs: 6e4 } }
1707
+ ]
1708
+ };
1709
+ }
1710
+ async function registerHeartbeatPreset(service, id = "heartbeat", enabled = true) {
1711
+ if (!enabled) return { action: "skipped-disabled", id };
1712
+ const registrar = service;
1713
+ if (registrar === void 0 || registrar === null || typeof registrar.register !== "function") {
1714
+ return { action: "skipped-no-api", id };
1715
+ }
1716
+ try {
1717
+ await registrar.register(heartbeatPresetDefinition(id));
1718
+ return { action: "registered", id };
1719
+ } catch (e) {
1720
+ return { action: "error", id, detail: String(e).slice(0, 200) };
1721
+ }
1722
+ }
1723
+
1683
1724
  // src/ledger/tool.ts
1684
1725
  var MAX_TEXT = 120;
1685
1726
  function clean(v) {
@@ -1809,7 +1850,8 @@ function apply(ctx, config = {}) {
1809
1850
  guard,
1810
1851
  policy,
1811
1852
  agentPreset: config.agentPreset || "heartbeat",
1812
- extraTools: (config.extraTools ?? "").split(",").map((s) => s.trim()).filter(Boolean)
1853
+ extraTools: (config.extraTools ?? "").split(",").map((s) => s.trim()).filter(Boolean),
1854
+ presetRegistration: () => presetRegistration ?? Promise.resolve()
1813
1855
  };
1814
1856
  setRuntime({
1815
1857
  paths,
@@ -1822,23 +1864,36 @@ function apply(ctx, config = {}) {
1822
1864
  tokenSaver: () => tokenSaverRef
1823
1865
  }
1824
1866
  });
1867
+ let presetRegistration;
1825
1868
  ctx.inject(["agentPresets"], (presetCtx) => {
1826
1869
  const service = presetCtx.agentPresets;
1870
+ const presetId = config.agentPreset || "heartbeat";
1871
+ const installEnabled = config.installPreset !== false;
1872
+ const audit = (entry) => {
1873
+ try {
1874
+ appendAuditLine(guard.assert(paths.logsDir + "/heartbeat.jsonl"), entry);
1875
+ } catch (e) {
1876
+ ctx.logger.warn("heartbeat: preset audit failed (%s)", String(e).slice(0, 120));
1877
+ }
1878
+ };
1879
+ presetRegistration = registerHeartbeatPreset(service, presetId, installEnabled).then((result2) => {
1880
+ audit({ event: "preset_register", ...result2 });
1881
+ if (result2.action === "error") {
1882
+ ctx.logger.warn("heartbeat: preset register failed (%s) \u2014 the engine room runs without it", result2.detail ?? "");
1883
+ } else if (result2.action === "registered") {
1884
+ ctx.logger.info("heartbeat: preset %s registered at runtime", result2.id);
1885
+ } else {
1886
+ ctx.logger.info("heartbeat: preset registration skipped (%s)", result2.action);
1887
+ }
1888
+ });
1827
1889
  const root = userPresetRoot(service?.roots);
1828
1890
  const result = installBundledPreset({
1829
1891
  moduleUrl: import.meta.url,
1830
- id: config.agentPreset || "heartbeat",
1892
+ id: presetId,
1831
1893
  ...root === void 0 ? { rosterKnown: service !== void 0 } : { root },
1832
- enabled: config.installPreset !== false
1894
+ enabled: installEnabled
1833
1895
  });
1834
- try {
1835
- appendAuditLine(guard.assert(paths.logsDir + "/heartbeat.jsonl"), {
1836
- event: "preset_install",
1837
- ...result
1838
- });
1839
- } catch (e) {
1840
- ctx.logger.warn("heartbeat: preset_install audit failed (%s)", String(e).slice(0, 120));
1841
- }
1896
+ audit({ event: "preset_install", ...result });
1842
1897
  const line = describeInstall(result);
1843
1898
  if (result.action === "error" || result.action === "skipped-no-root") {
1844
1899
  ctx.logger.warn("heartbeat: %s", line);
@@ -1917,6 +1972,35 @@ function apply(ctx, config = {}) {
1917
1972
  guard.assert(paths.logsDir + "/heartbeat.jsonl"),
1918
1973
  { event: "plugin_init", dataDir: paths.dataDir }
1919
1974
  );
1975
+ if (paths.relocation) {
1976
+ const auditFile = guard.assert(paths.logsDir + "/heartbeat.jsonl");
1977
+ if (paths.relocation.action === "relocated") {
1978
+ appendAuditLine(auditFile, {
1979
+ event: "data_dir_relocated",
1980
+ from: paths.relocation.srcDir,
1981
+ to: paths.relocation.dstDir,
1982
+ files: paths.relocation.files,
1983
+ bytes: paths.relocation.bytes,
1984
+ warnings: paths.relocation.warnings,
1985
+ leftovers: paths.relocation.leftovers
1986
+ });
1987
+ ctx.logger.info(
1988
+ "heartbeat: data dir moved out of the package (%s files, %s bytes)",
1989
+ paths.relocation.files,
1990
+ paths.relocation.bytes
1991
+ );
1992
+ } else if (paths.relocation.action === "failed") {
1993
+ appendAuditLine(auditFile, {
1994
+ event: "data_dir_relocate_failed",
1995
+ stage: paths.relocation.stage,
1996
+ problems: paths.relocation.problems
1997
+ });
1998
+ ctx.logger.warn(
1999
+ "heartbeat: data dir relocation failed (%s); continuing in the package dir",
2000
+ paths.relocation.stage
2001
+ );
2002
+ }
2003
+ }
1920
2004
  const uiGet = () => ({
1921
2005
  intervalMin: getRuntime().policy.heartbeat.intervalMin,
1922
2006
  maxDailySend: getRuntime().policy.gate.maxDailySend,