@kontextmind/kxm 0.7.92 → 0.7.93

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 (91) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.kxm/workflows/default.yaml +1 -1
  3. package/CHANGELOG.md +204 -0
  4. package/README.md +3 -0
  5. package/docs/README.md +3 -0
  6. package/docs/agent-skills.md +123 -60
  7. package/docs/architecture.md +5 -2
  8. package/docs/cli-reference.md +3527 -0
  9. package/docs/config-reference.md +1943 -0
  10. package/docs/configuration.md +29 -3
  11. package/docs/continuous-improvement.md +122 -10
  12. package/docs/contracts/routing.md +95 -11
  13. package/docs/harness-routing.md +616 -0
  14. package/docs/kxm-handbook.md +106 -19
  15. package/docs/templates/README.md +1 -1
  16. package/docs/test-matrix.md +12 -6
  17. package/docs/troubleshooting.md +2 -2
  18. package/examples/project/.kxm/workflows/fix.yaml +1 -1
  19. package/examples/project/.kxm/workflows/improve.yaml +1 -1
  20. package/package.json +1 -1
  21. package/plugins/kxm/.claude-plugin/plugin.json +9 -10
  22. package/plugins/kxm/README.md +238 -56
  23. package/plugins/kxm/dist/claude-hook.js +10083 -0
  24. package/plugins/kxm/dist/cli.js +3068 -2446
  25. package/plugins/kxm/dist/client.js +64 -0
  26. package/plugins/kxm/dist/core.js +102 -9
  27. package/plugins/kxm/dist/extension.js +210 -68
  28. package/plugins/kxm/dist/mcp-server.js +217 -40
  29. package/plugins/kxm/dist/runtime-supervisor.js +1628 -157
  30. package/plugins/kxm/dist/runtime.js +1874 -298
  31. package/plugins/kxm/dist/server.js +416 -82
  32. package/plugins/kxm/package.json +1 -1
  33. package/plugins/kxm/skills/hints.json +1 -1
  34. package/plugins/kxm/skills/kxm/SKILL.md +48 -24
  35. package/plugins/kxm/skills/kxm/references/protocol.md +3 -3
  36. package/plugins/kxm/skills/kxm-context-memory/SKILL.md +61 -21
  37. package/plugins/kxm/skills/kxm-definitions/SKILL.md +9 -0
  38. package/plugins/kxm/skills/kxm-harness-auth/SKILL.md +82 -16
  39. package/plugins/kxm/skills/kxm-harvest/SKILL.md +1 -1
  40. package/plugins/kxm/skills/kxm-hub-ops/SKILL.md +55 -27
  41. package/plugins/kxm/skills/kxm-insights/SKILL.md +1 -1
  42. package/plugins/kxm/skills/kxm-mind/SKILL.md +2 -2
  43. package/plugins/kxm/skills/{kxm-setup → kxm-mind-setup}/SKILL.md +4 -4
  44. package/plugins/kxm/skills/kxm-peer/SKILL.md +68 -93
  45. package/plugins/kxm/skills/kxm-project-setup/SKILL.md +156 -23
  46. package/plugins/kxm/skills/kxm-projects/SKILL.md +1 -1
  47. package/plugins/kxm/skills/kxm-protocol/SKILL.md +1 -1
  48. package/plugins/kxm/skills/kxm-query/SKILL.md +1 -1
  49. package/plugins/kxm/skills/kxm-routing-improve/SKILL.md +74 -15
  50. package/plugins/kxm/skills/kxm-runs/SKILL.md +46 -17
  51. package/plugins/kxm/skills/kxm-session/SKILL.md +64 -36
  52. package/plugins/kxm/skills/kxm-skill-lifecycle/SKILL.md +44 -15
  53. package/plugins/kxm/skills/kxm-tasks/SKILL.md +16 -4
  54. package/plugins/kxm/skills/kxm-triage/SKILL.md +1 -1
  55. package/plugins/kxm/skills/kxm-work/SKILL.md +1 -1
  56. package/plugins/kxm/skills/kxm-workflow/SKILL.md +60 -19
  57. package/plugins/kxm/src/arbiter.ts +67 -22
  58. package/plugins/kxm/src/autocomplete.ts +1 -1
  59. package/plugins/kxm/src/claude-hook.ts +192 -0
  60. package/plugins/kxm/src/cli/project.ts +11 -5
  61. package/plugins/kxm/src/cli/system.ts +85 -13
  62. package/plugins/kxm/src/cli/types.ts +4 -1
  63. package/plugins/kxm/src/cli/workflows.ts +18 -16
  64. package/plugins/kxm/src/cli.ts +23 -13
  65. package/plugins/kxm/src/client.ts +15 -4
  66. package/plugins/kxm/src/commands.ts +19 -9
  67. package/plugins/kxm/src/config.ts +42 -7
  68. package/plugins/kxm/src/context-packet.ts +14 -2
  69. package/plugins/kxm/src/context.ts +16 -5
  70. package/plugins/kxm/src/dispatch-context.ts +286 -0
  71. package/plugins/kxm/src/engine-plan.ts +40 -0
  72. package/plugins/kxm/src/engine.ts +138 -6
  73. package/plugins/kxm/src/hub-env.ts +17 -1
  74. package/plugins/kxm/src/hub.ts +92 -29
  75. package/plugins/kxm/src/improve-sources.ts +228 -0
  76. package/plugins/kxm/src/improve.ts +325 -140
  77. package/plugins/kxm/src/local-snapshot.ts +101 -42
  78. package/plugins/kxm/src/mcp-server.ts +129 -30
  79. package/plugins/kxm/src/project-config.ts +25 -0
  80. package/plugins/kxm/src/protocol.ts +11 -0
  81. package/plugins/kxm/src/relevance.ts +138 -0
  82. package/plugins/kxm/src/retrospective.ts +16 -10
  83. package/plugins/kxm/src/runtime-service.ts +8 -1
  84. package/plugins/kxm/src/runtime-supervisor.ts +16 -2
  85. package/plugins/kxm/src/session-token-hint.ts +17 -0
  86. package/plugins/kxm/src/suggest.ts +7 -7
  87. package/plugins/kxm/src/workflow-manager.ts +80 -78
  88. package/plugins/kxm/src/workflow.ts +202 -12
  89. package/scripts/build-runtime.mjs +7 -1
  90. package/scripts/check-generated.mjs +1 -0
  91. package/scripts/emit-codex-artifacts.mjs +1 -1
@@ -14545,8 +14545,117 @@ var MAX_CONTENT_CHARS = 32e3;
14545
14545
  var MAX_AGENT_HOST_CHARS = 64;
14546
14546
  var MAX_LEASE_TTL_MS = 10 * 6e4;
14547
14547
  var DEFAULT_LEASE_TTL_MS = 5 * 6e4;
14548
+ var IMPROVEMENT_AREAS = [
14549
+ "harness",
14550
+ "gates",
14551
+ "implementation",
14552
+ "workflow",
14553
+ "documentation",
14554
+ "security",
14555
+ "other"
14556
+ ];
14557
+
14558
+ // plugins/kxm/src/redact.ts
14559
+ var SECRET_PATTERNS = [
14560
+ /\bsk-[A-Za-z0-9_-]{8,}\b/g,
14561
+ /\bsk-ant-[A-Za-z0-9_-]{8,}\b/g,
14562
+ /\bghp_[A-Za-z0-9_]{20,}\b/g,
14563
+ /\bgithub_pat_[A-Za-z0-9_]{20,}\b/g,
14564
+ /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/gi,
14565
+ /\bBearer\s+[A-Za-z0-9._~+/=-]+\b/gi,
14566
+ /\bya29\.[A-Za-z0-9._~+/-]+=*/g,
14567
+ /\b1\/\/[A-Za-z0-9_-]+/g,
14568
+ /\b1\/[A-Za-z0-9_-]{20,}/g,
14569
+ /("?(?:access_token|refresh_token|id_token|sessionKey|session_key|claude_oauth_token|anthropicApiKey)"?\s*[:=]\s*")[^"]*(")/gi,
14570
+ /\bKXM_[A-Z0-9_]*(TOKEN|SECRET|KEY)[A-Z0-9_]*=\S+/gi,
14571
+ /\b(GITHUB_TOKEN|GH_TOKEN|KXM_AUTH_TOKEN|KXM_WORKFLOW_SIGNAL_SECRET|ANTHROPIC_API_KEY|ANTHROPIC_AUTH_TOKEN|CLAUDE_API_KEY)=\S+/gi,
14572
+ /\b[A-Fa-f0-9]{64}\b/g
14573
+ ];
14574
+ function redactSecrets(value) {
14575
+ let result2 = value;
14576
+ for (const pattern of SECRET_PATTERNS) {
14577
+ result2 = result2.replace(pattern, "[redacted]");
14578
+ }
14579
+ return result2;
14580
+ }
14581
+
14582
+ // plugins/kxm/src/relevance.ts
14583
+ var RELEVANCE_STOPWORDS = Object.freeze(/* @__PURE__ */ new Set([
14584
+ "a",
14585
+ "an",
14586
+ "and",
14587
+ "are",
14588
+ "as",
14589
+ "at",
14590
+ "be",
14591
+ "been",
14592
+ "but",
14593
+ "by",
14594
+ "can",
14595
+ "could",
14596
+ "did",
14597
+ "do",
14598
+ "does",
14599
+ "for",
14600
+ "from",
14601
+ "had",
14602
+ "has",
14603
+ "have",
14604
+ "how",
14605
+ "if",
14606
+ "in",
14607
+ "into",
14608
+ "is",
14609
+ "it",
14610
+ "its",
14611
+ "of",
14612
+ "on",
14613
+ "or",
14614
+ "our",
14615
+ "should",
14616
+ "so",
14617
+ "than",
14618
+ "that",
14619
+ "the",
14620
+ "their",
14621
+ "them",
14622
+ "then",
14623
+ "there",
14624
+ "these",
14625
+ "they",
14626
+ "this",
14627
+ "those",
14628
+ "to",
14629
+ "was",
14630
+ "we",
14631
+ "were",
14632
+ "what",
14633
+ "when",
14634
+ "where",
14635
+ "which",
14636
+ "while",
14637
+ "who",
14638
+ "why",
14639
+ "will",
14640
+ "with",
14641
+ "would",
14642
+ "you",
14643
+ "your"
14644
+ ]));
14548
14645
 
14549
14646
  // plugins/kxm/src/workflow.ts
14647
+ var JOURNAL_CATEGORIES = [
14648
+ "plan",
14649
+ "decision",
14650
+ "contradiction",
14651
+ "error",
14652
+ "lesson",
14653
+ "observation",
14654
+ "hypothesis",
14655
+ "experiment",
14656
+ "state-change",
14657
+ "skill-candidate"
14658
+ ];
14550
14659
  function canonicalWorkflowEvidenceKey(value) {
14551
14660
  return value.trim().replace(/\s+/gu, " ").toLowerCase();
14552
14661
  }
@@ -15344,7 +15453,7 @@ var AGENT_COMMANDS = [
15344
15453
  group: "workflow",
15345
15454
  verb: "run",
15346
15455
  label: "Get workflow run",
15347
- description: "Get a workflow's stages and journal of plans, decisions, contradictions, errors, and lessons.",
15456
+ description: "Get a workflow's stages and its learning journal (plans, decisions, contradictions, errors, lessons, and the other journal categories).",
15348
15457
  parameters: {
15349
15458
  type: "object",
15350
15459
  properties: {
@@ -15418,20 +15527,24 @@ var AGENT_COMMANDS = [
15418
15527
  group: "workflow",
15419
15528
  verb: "record",
15420
15529
  label: "Record workflow journal entry",
15421
- description: "Record a plan, decision, contradiction, error, or lesson for continuous improvement.",
15530
+ description: "Record a plan, decision, contradiction, error, lesson, observation, hypothesis, experiment, state-change, or skill-candidate for continuous improvement. Pass stageId to bind the entry to that stage: the hub derives the attempt, and area defaults to the stage's declared area. Lessons and skill-candidates require evidence.",
15422
15531
  parameters: {
15423
15532
  type: "object",
15424
15533
  properties: {
15425
15534
  runId: { type: "string", description: "Active durable workflow run ID" },
15426
15535
  category: {
15427
15536
  type: "string",
15428
- enum: ["plan", "decision", "contradiction", "error", "lesson"],
15537
+ enum: [...JOURNAL_CATEGORIES],
15429
15538
  description: "Category of journal entry"
15430
15539
  },
15431
15540
  area: {
15432
15541
  type: "string",
15433
- enum: ["harness", "gates", "implementation", "workflow", "documentation", "security", "other"],
15434
- description: "System area"
15542
+ enum: [...IMPROVEMENT_AREAS],
15543
+ description: "System area; required unless stageId names a stage that declares an area"
15544
+ },
15545
+ stageId: {
15546
+ type: "string",
15547
+ description: "Stage the entry belongs to; the hub binds the attempt from the stage's state"
15435
15548
  },
15436
15549
  severity: {
15437
15550
  type: "string",
@@ -15454,13 +15567,14 @@ var AGENT_COMMANDS = [
15454
15567
  description: "Related previous journal entry IDs"
15455
15568
  }
15456
15569
  },
15457
- required: ["runId", "category", "area", "summary"],
15570
+ required: ["runId", "category", "summary"],
15458
15571
  additionalProperties: false
15459
15572
  },
15460
15573
  async execute(client, args) {
15461
15574
  return await client.recordWorkflowEntry(requiredString(args.runId, "runId"), {
15462
15575
  category: requiredString(args.category, "category"),
15463
- area: requiredString(args.area, "area"),
15576
+ ...optionalString(args.area) ? { area: optionalString(args.area) } : {},
15577
+ ...optionalString(args.stageId) ? { stageId: optionalString(args.stageId) } : {},
15464
15578
  ...optionalString(args.severity) ? { severity: optionalString(args.severity) } : {},
15465
15579
  summary: requiredString(args.summary, "summary"),
15466
15580
  ...optionalString(args.details) ? { details: optionalString(args.details) } : {},
@@ -15537,7 +15651,7 @@ var AGENT_COMMANDS = [
15537
15651
  group: "workflow",
15538
15652
  verb: "improve-report",
15539
15653
  label: "Summarize improvement report",
15540
- description: "Summarize workflow errors, contradictions, and lessons by improvement area.",
15654
+ description: "Summarize workflow errors, contradictions, lessons, and skill candidates by improvement area, plus ranked cross-run signals: duplicates merged across runs and scored by frequency x severity x run-attempt cost x evidence confidence, security first, with redacted text.",
15541
15655
  parameters: {
15542
15656
  type: "object",
15543
15657
  properties: {},
@@ -15591,7 +15705,7 @@ var AGENT_COMMANDS = [
15591
15705
  group: "context",
15592
15706
  verb: "recall",
15593
15707
  label: "Recall context metadata",
15594
- description: "Search durable context records for a project by query; returns bounded metadata only.",
15708
+ description: "Search durable context records for a project by query. Ranks exact-phrase matches first, then token relevance, then id; returns bounded metadata with a numeric relevance per item, never summaries.",
15595
15709
  parameters: {
15596
15710
  type: "object",
15597
15711
  properties: {
@@ -15861,6 +15975,7 @@ import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as rea
15861
15975
  import { homedir as homedir2 } from "node:os";
15862
15976
  import { dirname as dirname2, join as join2, resolve as resolve2 } from "node:path";
15863
15977
  var KXM_CONFIG_SCHEMA = "kxm.config.v1";
15978
+ var IMPROVEMENT_PROMOTION_POLICIES = ["manual_pr", "critic_quorum", "auto_threshold"];
15864
15979
  var DEFAULT_KXM_CONFIG = {
15865
15980
  schema: KXM_CONFIG_SCHEMA,
15866
15981
  user: {
@@ -15934,6 +16049,30 @@ function normalizeHubConfig(raw) {
15934
16049
  const autoStart = raw?.autoStart;
15935
16050
  return { autoStart: autoStart === "off" || autoStart === "background" ? autoStart : DEFAULT_KXM_CONFIG.hub.autoStart };
15936
16051
  }
16052
+ function recordOf(raw) {
16053
+ return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
16054
+ }
16055
+ function finiteNumber(value) {
16056
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
16057
+ }
16058
+ function normalizeImprovementConfig(raw) {
16059
+ const value = recordOf(raw);
16060
+ const threshold = recordOf(value.autoThreshold);
16061
+ const policy = value.promotionPolicy;
16062
+ const halfLife = finiteNumber(value.telemetryHalfLifeDays);
16063
+ const minRuns = finiteNumber(threshold.minRuns);
16064
+ const minPassRate = finiteNumber(threshold.minPassRate);
16065
+ const minCostSavings = finiteNumber(threshold.minCostSavings);
16066
+ return {
16067
+ promotionPolicy: IMPROVEMENT_PROMOTION_POLICIES.includes(policy) ? policy : "manual_pr",
16068
+ telemetryHalfLifeDays: halfLife !== void 0 && halfLife > 0 && halfLife <= 3650 ? halfLife : 14,
16069
+ autoThreshold: {
16070
+ minRuns: minRuns !== void 0 && Number.isInteger(minRuns) && minRuns >= 1 && minRuns <= 1e6 ? minRuns : 10,
16071
+ minPassRate: minPassRate !== void 0 && minPassRate >= 0 && minPassRate <= 1 ? minPassRate : 0.95,
16072
+ minCostSavings: minCostSavings !== void 0 && minCostSavings >= 0 ? minCostSavings : 0.5
16073
+ }
16074
+ };
16075
+ }
15937
16076
  function loadKxmConfig(repoRoot = process.cwd(), options = {}) {
15938
16077
  const userDir = userConfigDirectory(options.userConfigDir);
15939
16078
  const userConfigFile = join2(userDir, "config.yaml");
@@ -15971,7 +16110,7 @@ function loadKxmConfig(repoRoot = process.cwd(), options = {}) {
15971
16110
  dash: mergedAll.dash ?? {},
15972
16111
  sync: mergedAll.sync ?? {},
15973
16112
  hub: normalizeHubConfig(mergedAll.hub),
15974
- improvement: mergedAll.improvement ?? DEFAULT_KXM_CONFIG.improvement,
16113
+ improvement: normalizeImprovementConfig(mergedAll.improvement),
15975
16114
  routing: mergedAll.routing ?? DEFAULT_KXM_CONFIG.routing,
15976
16115
  telemetry: mergedAll.telemetry ?? DEFAULT_KXM_CONFIG.telemetry,
15977
16116
  loadedFrom: {
@@ -16256,30 +16395,6 @@ function findKxmRepoRoot(fromUrl = import.meta.url) {
16256
16395
  );
16257
16396
  }
16258
16397
 
16259
- // plugins/kxm/src/redact.ts
16260
- var SECRET_PATTERNS = [
16261
- /\bsk-[A-Za-z0-9_-]{8,}\b/g,
16262
- /\bsk-ant-[A-Za-z0-9_-]{8,}\b/g,
16263
- /\bghp_[A-Za-z0-9_]{20,}\b/g,
16264
- /\bgithub_pat_[A-Za-z0-9_]{20,}\b/g,
16265
- /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/gi,
16266
- /\bBearer\s+[A-Za-z0-9._~+/=-]+\b/gi,
16267
- /\bya29\.[A-Za-z0-9._~+/-]+=*/g,
16268
- /\b1\/\/[A-Za-z0-9_-]+/g,
16269
- /\b1\/[A-Za-z0-9_-]{20,}/g,
16270
- /("?(?:access_token|refresh_token|id_token|sessionKey|session_key|claude_oauth_token|anthropicApiKey)"?\s*[:=]\s*")[^"]*(")/gi,
16271
- /\bKXM_[A-Z0-9_]*(TOKEN|SECRET|KEY)[A-Z0-9_]*=\S+/gi,
16272
- /\b(GITHUB_TOKEN|GH_TOKEN|KXM_AUTH_TOKEN|KXM_WORKFLOW_SIGNAL_SECRET|ANTHROPIC_API_KEY|ANTHROPIC_AUTH_TOKEN|CLAUDE_API_KEY)=\S+/gi,
16273
- /\b[A-Fa-f0-9]{64}\b/g
16274
- ];
16275
- function redactSecrets(value) {
16276
- let result2 = value;
16277
- for (const pattern of SECRET_PATTERNS) {
16278
- result2 = result2.replace(pattern, "[redacted]");
16279
- }
16280
- return result2;
16281
- }
16282
-
16283
16398
  // plugins/kxm/src/hub-autostart.ts
16284
16399
  var HUB_AUTOSTART_LOG_NAME = "hub-autostart.log";
16285
16400
  var CLAIM_POLL_MS = 50;
@@ -36527,6 +36642,8 @@ function readRoutingRecords(path) {
36527
36642
  }
36528
36643
 
36529
36644
  // plugins/kxm/src/local-snapshot.ts
36645
+ var DEFAULT_BUSY_TIMEOUT_MS = 5e3;
36646
+ var RUNTIME_PROJECT_KEY = /^[A-Za-z0-9_-][A-Za-z0-9._-]*$/;
36530
36647
  function processExists(pid) {
36531
36648
  try {
36532
36649
  process.kill(pid, 0);
@@ -36535,8 +36652,8 @@ function processExists(pid) {
36535
36652
  return error2.code === "EPERM";
36536
36653
  }
36537
36654
  }
36538
- function readJsonRows(database, sql) {
36539
- const rows = database.prepare(sql).all();
36655
+ function readJsonRows(database, sql, params = []) {
36656
+ const rows = database.prepare(sql).all(...params);
36540
36657
  const out = [];
36541
36658
  for (const row of rows) {
36542
36659
  try {
@@ -36611,11 +36728,15 @@ function readPlanMetadata(database) {
36611
36728
  return [];
36612
36729
  }
36613
36730
  }
36614
- function countRows(database, table, where = "") {
36615
- const row = database.prepare(`SELECT COUNT(*) AS count FROM ${table}${where}`).get();
36731
+ function countRows(database, table, where = "", params = []) {
36732
+ const row = database.prepare(`SELECT COUNT(*) AS count FROM ${table}${where}`).get(...params);
36616
36733
  return Number(row?.count ?? 0);
36617
36734
  }
36618
- function readOpenMessageMetadata(database) {
36735
+ var OPEN_MESSAGE_WHERE = " WHERE json_extract(record, '$.status') IN ('queued', 'delivered')";
36736
+ var SCOPED_MESSAGE_WHERE = `${OPEN_MESSAGE_WHERE}
36737
+ AND json_extract(record, '$.project') = ?
36738
+ AND COALESCE(json_extract(record, '$.toName'), json_extract(record, '$.to')) = ?`;
36739
+ function readOpenMessageMetadata(database, where = OPEN_MESSAGE_WHERE, params = []) {
36619
36740
  const rows = database.prepare(`
36620
36741
  SELECT
36621
36742
  json_extract(record, '$.id') AS id,
@@ -36625,11 +36746,10 @@ function readOpenMessageMetadata(database) {
36625
36746
  json_extract(record, '$.delivery') AS delivery,
36626
36747
  json_extract(record, '$.createdAt') AS createdAt,
36627
36748
  json_extract(record, '$.correlationId') AS correlationId
36628
- FROM messages
36629
- WHERE json_extract(record, '$.status') IN ('queued', 'delivered')
36749
+ FROM messages${where}
36630
36750
  ORDER BY json_extract(record, '$.createdAt') DESC
36631
36751
  LIMIT 16
36632
- `).all();
36752
+ `).all(...params);
36633
36753
  const messages = [];
36634
36754
  for (const row of rows) {
36635
36755
  if (typeof row.id !== "string" || row.status !== "queued" && row.status !== "delivered" || typeof row.fromName !== "string" || typeof row.toName !== "string" || row.delivery !== "steer" && row.delivery !== "followUp" && row.delivery !== "nextTurn" || typeof row.createdAt !== "string") continue;
@@ -36678,7 +36798,29 @@ function resolveKxmStateRoot(stateDir, options) {
36678
36798
  if (existsSync8(base)) return base;
36679
36799
  return void 0;
36680
36800
  }
36801
+ function readRuntimeRuns(eventDb, projectId) {
36802
+ const where = projectId === void 0 ? "" : " WHERE project_id = ?";
36803
+ const params = projectId === void 0 ? [] : [projectId];
36804
+ const runRows = eventDb.prepare(`
36805
+ SELECT run_id, project_id, workflow_id, status, created_at, updated_at
36806
+ FROM runs${where} ORDER BY created_at DESC, run_id DESC LIMIT 8
36807
+ `).all(...params);
36808
+ const countRow = eventDb.prepare(`SELECT COUNT(*) AS total FROM runs${where}`).get(...params);
36809
+ return {
36810
+ total: Number(countRow?.total ?? runRows.length),
36811
+ runs: runRows.map((r) => ({
36812
+ id: r.run_id,
36813
+ status: r.status,
36814
+ definitionId: r.workflow_id,
36815
+ project: r.project_id,
36816
+ updatedAt: r.updated_at || r.created_at
36817
+ }))
36818
+ };
36819
+ }
36681
36820
  function loadLocalMeshSnapshot(dataPath, stateDir, options) {
36821
+ const busyTimeoutMs = Math.max(0, Math.trunc(Number(options?.busyTimeoutMs ?? DEFAULT_BUSY_TIMEOUT_MS)) || 0);
36822
+ const busyTimeout = `PRAGMA busy_timeout = ${busyTimeoutMs}`;
36823
+ const scope = options?.scope;
36682
36824
  let hasLegacy = false;
36683
36825
  let agents = [];
36684
36826
  let openMessages = [];
@@ -36690,13 +36832,24 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
36690
36832
  hasLegacy = true;
36691
36833
  const database = openReadOnlyDatabase(dataPath);
36692
36834
  try {
36693
- database.exec("PRAGMA busy_timeout = 5000");
36835
+ database.exec(busyTimeout);
36694
36836
  agents = readJsonRows(database, "SELECT record FROM agents");
36695
- openMessages = readOpenMessageMetadata(database);
36696
- openMessageTotal = countRows(database, "messages", " WHERE json_extract(record, '$.status') IN ('queued', 'delivered')");
36697
- legacyRuns = readJsonRows(database, "SELECT record FROM workflow_runs ORDER BY rowid DESC LIMIT 8");
36698
- legacyRunTotal = countRows(database, "workflow_runs");
36699
- plans = readPlanMetadata(database);
36837
+ if (!scope) {
36838
+ openMessages = readOpenMessageMetadata(database);
36839
+ openMessageTotal = countRows(database, "messages", OPEN_MESSAGE_WHERE);
36840
+ legacyRuns = readJsonRows(database, "SELECT record FROM workflow_runs ORDER BY rowid DESC LIMIT 8");
36841
+ legacyRunTotal = countRows(database, "workflow_runs");
36842
+ plans = readPlanMetadata(database);
36843
+ } else {
36844
+ if (scope.recipientName) {
36845
+ const messageParams = [scope.hubProject, scope.recipientName];
36846
+ openMessages = readOpenMessageMetadata(database, SCOPED_MESSAGE_WHERE, messageParams);
36847
+ openMessageTotal = countRows(database, "messages", SCOPED_MESSAGE_WHERE, messageParams);
36848
+ }
36849
+ const runWhere = " WHERE json_extract(record, '$.project') = ?";
36850
+ legacyRuns = readJsonRows(database, `SELECT record FROM workflow_runs${runWhere} ORDER BY rowid DESC LIMIT 8`, [scope.hubProject]);
36851
+ legacyRunTotal = countRows(database, "workflow_runs", runWhere, [scope.hubProject]);
36852
+ }
36700
36853
  } finally {
36701
36854
  database.close();
36702
36855
  }
@@ -36704,7 +36857,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
36704
36857
  let hasKxm = false;
36705
36858
  const kxmRuns = [];
36706
36859
  let kxmRunTotal = 0;
36707
- const kxmStateRoot = resolveKxmStateRoot(stateDir, options);
36860
+ const kxmStateRoot = scope && !scope.runtimeProjectId ? void 0 : resolveKxmStateRoot(stateDir, options);
36708
36861
  if (kxmStateRoot) {
36709
36862
  const runtimeDir = join11(kxmStateRoot, "runtime");
36710
36863
  const registryDbPath = join11(runtimeDir, "registry.db");
@@ -36715,8 +36868,8 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
36715
36868
  try {
36716
36869
  const regDb = openReadOnlyDatabase(registryDbPath);
36717
36870
  try {
36718
- regDb.exec("PRAGMA busy_timeout = 5000");
36719
- const pRows = regDb.prepare("SELECT project_key FROM projects").all();
36871
+ regDb.exec(busyTimeout);
36872
+ const pRows = scope ? regDb.prepare("SELECT project_key FROM projects WHERE project_id = ?").all(scope.runtimeProjectId) : regDb.prepare("SELECT project_key FROM projects").all();
36720
36873
  for (const row of pRows) {
36721
36874
  if (row.project_key) projectKeys.add(row.project_key);
36722
36875
  }
@@ -36726,7 +36879,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
36726
36879
  } catch {
36727
36880
  }
36728
36881
  }
36729
- if (existsSync8(projectsDir)) {
36882
+ if (!scope && existsSync8(projectsDir)) {
36730
36883
  try {
36731
36884
  for (const entry of readdirSync(projectsDir, { withFileTypes: true })) {
36732
36885
  if (entry.isDirectory()) {
@@ -36737,28 +36890,17 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
36737
36890
  }
36738
36891
  }
36739
36892
  for (const key of projectKeys) {
36893
+ if (scope && !RUNTIME_PROJECT_KEY.test(key)) continue;
36740
36894
  const eventDbPath = join11(projectsDir, key, "run-events.db");
36741
36895
  if (existsSync8(eventDbPath)) {
36742
36896
  hasKxm = true;
36743
36897
  try {
36744
36898
  const eventDb = openReadOnlyDatabase(eventDbPath);
36745
36899
  try {
36746
- eventDb.exec("PRAGMA busy_timeout = 5000");
36747
- const runRows = eventDb.prepare(`
36748
- SELECT run_id, project_id, workflow_id, status, created_at, updated_at
36749
- FROM runs ORDER BY created_at DESC, run_id DESC LIMIT 8
36750
- `).all();
36751
- const countRow = eventDb.prepare("SELECT COUNT(*) AS total FROM runs").get();
36752
- kxmRunTotal += Number(countRow?.total ?? runRows.length);
36753
- for (const r of runRows) {
36754
- kxmRuns.push({
36755
- id: r.run_id,
36756
- status: r.status,
36757
- definitionId: r.workflow_id,
36758
- project: r.project_id,
36759
- updatedAt: r.updated_at || r.created_at
36760
- });
36761
- }
36900
+ eventDb.exec(busyTimeout);
36901
+ const { runs: runs2, total } = readRuntimeRuns(eventDb, scope?.runtimeProjectId);
36902
+ kxmRunTotal += total;
36903
+ kxmRuns.push(...runs2);
36762
36904
  } finally {
36763
36905
  eventDb.close();
36764
36906
  }