@kontextmind/kxm 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.kxm/agents/coordinator.yaml +9 -0
  3. package/.kxm/agents/critic-arch.yaml +13 -0
  4. package/.kxm/agents/critic-cli.yaml +13 -0
  5. package/.kxm/agents/implementer.yaml +13 -0
  6. package/.kxm/gates.yaml +8 -0
  7. package/.kxm/producers.yaml +22 -0
  8. package/.kxm/project.yaml +15 -0
  9. package/.kxm/roles/writer.yaml +5 -0
  10. package/.kxm/workflows/default.yaml +47 -0
  11. package/CHANGELOG.md +39 -7
  12. package/README.md +1 -0
  13. package/docs/README.md +2 -0
  14. package/docs/agent-skills.md +118 -0
  15. package/docs/architecture.md +1 -1
  16. package/docs/assignment-runner.md +21 -8
  17. package/docs/configuration.md +2 -2
  18. package/docs/kxm-handbook.md +3 -3
  19. package/docs/operator-pi-packages.md +63 -0
  20. package/docs/skills/repo-work-delivery.md +102 -0
  21. package/docs/test-matrix.md +4 -3
  22. package/docs/troubleshooting.md +19 -0
  23. package/docs/vnext/validation.md +9 -0
  24. package/docs/webhook-workflows.md +2 -2
  25. package/examples/README.md +1 -1
  26. package/package.json +16 -17
  27. package/plugins/kxm/.claude-plugin/plugin.json +1 -1
  28. package/plugins/kxm/README.md +1 -1
  29. package/plugins/kxm/dist/cli.js +6875 -3672
  30. package/plugins/kxm/dist/core.js +214 -34
  31. package/plugins/kxm/dist/extension.js +7721 -85
  32. package/plugins/kxm/dist/mcp-server.js +75 -21
  33. package/plugins/kxm/dist/runtime.js +5403 -1014
  34. package/plugins/kxm/dist/server.js +3008 -2268
  35. package/plugins/kxm/dist/vnext-runtime-supervisor.js +5751 -631
  36. package/plugins/kxm/package.json +1 -1
  37. package/plugins/kxm/skills/SUITE.md +5 -0
  38. package/plugins/kxm/skills/hints.json +73 -0
  39. package/plugins/kxm/skills/kxm/SKILL.md +30 -83
  40. package/plugins/kxm/skills/kxm-context-memory/SKILL.md +69 -0
  41. package/plugins/kxm/skills/kxm-definitions/SKILL.md +65 -0
  42. package/plugins/kxm/skills/kxm-harness-auth/SKILL.md +34 -0
  43. package/plugins/kxm/skills/kxm-harvest/SKILL.md +48 -0
  44. package/plugins/kxm/skills/kxm-hub-ops/SKILL.md +34 -0
  45. package/plugins/kxm/skills/kxm-insights/SKILL.md +48 -0
  46. package/plugins/kxm/skills/kxm-mind/SKILL.md +59 -0
  47. package/plugins/kxm/skills/kxm-peer/SKILL.md +110 -0
  48. package/plugins/kxm/skills/kxm-project-setup/SKILL.md +35 -0
  49. package/plugins/kxm/skills/kxm-projects/SKILL.md +43 -0
  50. package/plugins/kxm/skills/kxm-protocol/SKILL.md +66 -0
  51. package/plugins/kxm/skills/kxm-query/SKILL.md +45 -0
  52. package/plugins/kxm/skills/kxm-routing-improve/SKILL.md +30 -0
  53. package/plugins/kxm/skills/kxm-runs/SKILL.md +29 -0
  54. package/plugins/kxm/skills/kxm-setup/SKILL.md +55 -0
  55. package/plugins/kxm/skills/kxm-skill-lifecycle/SKILL.md +31 -0
  56. package/plugins/kxm/skills/kxm-tasks/SKILL.md +33 -0
  57. package/plugins/kxm/skills/kxm-triage/SKILL.md +47 -0
  58. package/plugins/kxm/skills/kxm-work/SKILL.md +44 -0
  59. package/plugins/kxm/skills/kxm-workflow/SKILL.md +45 -0
  60. package/plugins/kxm/src/autocomplete.ts +9 -3
  61. package/plugins/kxm/src/cli.ts +1077 -11
  62. package/plugins/kxm/src/commands.ts +150 -8
  63. package/plugins/kxm/src/config.ts +7 -4
  64. package/plugins/kxm/src/context-packet.ts +172 -0
  65. package/plugins/kxm/src/extension.ts +36 -1
  66. package/plugins/kxm/src/external-effects.ts +356 -7
  67. package/plugins/kxm/src/hub.ts +2 -4
  68. package/plugins/kxm/src/improve.ts +72 -0
  69. package/plugins/kxm/src/mcp-server.ts +1 -1
  70. package/plugins/kxm/src/model-inventory.ts +127 -0
  71. package/plugins/kxm/src/policy-draft.d.mts +55 -0
  72. package/plugins/kxm/src/policy-draft.mjs +565 -0
  73. package/plugins/kxm/src/price-calc.ts +17 -18
  74. package/plugins/kxm/src/prices.ts +32 -16
  75. package/plugins/kxm/src/producers.ts +71 -0
  76. package/plugins/kxm/src/restricted-yaml.d.mts +31 -0
  77. package/plugins/kxm/src/restricted-yaml.mjs +145 -0
  78. package/plugins/kxm/src/role.ts +375 -0
  79. package/plugins/kxm/src/routing.ts +99 -1
  80. package/plugins/kxm/src/session-work.ts +9 -2
  81. package/plugins/kxm/src/studio-layout.ts +660 -17
  82. package/plugins/kxm/src/suggest.ts +7 -13
  83. package/plugins/kxm/src/telemetry.ts +82 -0
  84. package/plugins/kxm/src/tui.ts +140 -0
  85. package/plugins/kxm/src/vnext-config.ts +15 -110
  86. package/plugins/kxm/src/vnext-engine.ts +198 -62
  87. package/plugins/kxm/src/vnext-harness.ts +263 -81
  88. package/plugins/kxm/src/vnext-oneshot-evidence.ts +85 -0
  89. package/plugins/kxm/src/vnext-oneshot-process.ts +149 -0
  90. package/plugins/kxm/src/vnext-oneshot-producer.ts +170 -233
  91. package/plugins/kxm/src/vnext-runtime-store.ts +35 -1
  92. package/plugins/kxm/src/vnext-runtime-supervisor.ts +120 -5
  93. package/plugins/kxm/src/vnext-runtime.ts +14 -0
  94. package/plugins/kxm/src/workflow-manager.ts +392 -0
  95. package/plugins/kxm/src/workflow-tui.ts +255 -0
  96. package/schemas/policy-draft/README.md +17 -0
  97. package/schemas/policy-draft/model.v2.schema.json +140 -0
  98. package/schemas/policy-draft/role.v2.schema.json +91 -0
  99. package/schemas/vnext/role.schema.json +76 -0
  100. package/schemas/vnext/run-event.schema.json +1 -0
  101. package/scripts/assignment-run.d.mts +1 -1
  102. package/scripts/assignment-run.mjs +44 -35
  103. package/scripts/check-generated.mjs +33 -9
  104. package/scripts/emit-codex-artifacts.mjs +255 -11
  105. package/scripts/harness-run.d.mts +12 -4
  106. package/scripts/harness-run.mjs +65 -17
  107. package/scripts/kxm-hub.mjs +6 -0
  108. package/scripts/native-critic.d.mts +5 -0
  109. package/scripts/native-critic.mjs +60 -0
  110. package/.kxm/config/README.md +0 -5
  111. package/.kxm/config/agents.json +0 -43
  112. package/.kxm/config/env.example +0 -56
  113. package/.kxm/config/update.example.yaml +0 -9
  114. package/.kxm/config/workflows/fix.json +0 -160
  115. package/.kxm/config/workflows/jira-development.json +0 -116
  116. package/.kxm/config/workflows/provenance-quorum.json +0 -150
  117. package/.kxm/config/workflows/v04-dogfood.json +0 -72
@@ -2984,7 +2984,7 @@ var require_compile = __commonJS({
2984
2984
  const schOrFunc = root.refs[ref];
2985
2985
  if (schOrFunc)
2986
2986
  return schOrFunc;
2987
- let _sch = resolve.call(this, root, ref);
2987
+ let _sch = resolve2.call(this, root, ref);
2988
2988
  if (_sch === void 0) {
2989
2989
  const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
2990
2990
  const { schemaId } = this.opts;
@@ -3011,7 +3011,7 @@ var require_compile = __commonJS({
3011
3011
  function sameSchemaEnv(s1, s2) {
3012
3012
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
3013
3013
  }
3014
- function resolve(root, ref) {
3014
+ function resolve2(root, ref) {
3015
3015
  let sch;
3016
3016
  while (typeof (sch = this.refs[ref]) == "string")
3017
3017
  ref = sch;
@@ -3836,7 +3836,7 @@ var require_fast_uri = __commonJS({
3836
3836
  }
3837
3837
  return uri;
3838
3838
  }
3839
- function resolve(baseURI, relativeURI, options) {
3839
+ function resolve2(baseURI, relativeURI, options) {
3840
3840
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
3841
3841
  const {
3842
3842
  parsed: baseParsed,
@@ -4198,7 +4198,7 @@ var require_fast_uri = __commonJS({
4198
4198
  var fastUri = {
4199
4199
  SCHEMES,
4200
4200
  normalize,
4201
- resolve,
4201
+ resolve: resolve2,
4202
4202
  resolveComponent,
4203
4203
  equal,
4204
4204
  serialize,
@@ -14508,7 +14508,7 @@ var Protocol = class {
14508
14508
  return;
14509
14509
  }
14510
14510
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
14511
- await new Promise((resolve) => setTimeout(resolve, pollInterval));
14511
+ await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
14512
14512
  options?.signal?.throwIfAborted();
14513
14513
  }
14514
14514
  } catch (error2) {
@@ -14525,7 +14525,7 @@ var Protocol = class {
14525
14525
  */
14526
14526
  request(request, resultSchema, options) {
14527
14527
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
14528
- return new Promise((resolve, reject) => {
14528
+ return new Promise((resolve2, reject) => {
14529
14529
  const earlyReject = (error2) => {
14530
14530
  reject(error2);
14531
14531
  };
@@ -14603,7 +14603,7 @@ var Protocol = class {
14603
14603
  if (!parseResult.success) {
14604
14604
  reject(parseResult.error);
14605
14605
  } else {
14606
- resolve(parseResult.data);
14606
+ resolve2(parseResult.data);
14607
14607
  }
14608
14608
  } catch (error2) {
14609
14609
  reject(error2);
@@ -14864,12 +14864,12 @@ var Protocol = class {
14864
14864
  }
14865
14865
  } catch {
14866
14866
  }
14867
- return new Promise((resolve, reject) => {
14867
+ return new Promise((resolve2, reject) => {
14868
14868
  if (signal.aborted) {
14869
14869
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
14870
14870
  return;
14871
14871
  }
14872
- const timeoutId = setTimeout(resolve, interval);
14872
+ const timeoutId = setTimeout(resolve2, interval);
14873
14873
  signal.addEventListener("abort", () => {
14874
14874
  clearTimeout(timeoutId);
14875
14875
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -15745,12 +15745,12 @@ var StdioServerTransport = class {
15745
15745
  this.onclose?.();
15746
15746
  }
15747
15747
  send(message) {
15748
- return new Promise((resolve) => {
15748
+ return new Promise((resolve2) => {
15749
15749
  const json = serializeMessage(message);
15750
15750
  if (this._stdout.write(json)) {
15751
- resolve();
15751
+ resolve2();
15752
15752
  } else {
15753
- this._stdout.once("drain", resolve);
15753
+ this._stdout.once("drain", resolve2);
15754
15754
  }
15755
15755
  });
15756
15756
  }
@@ -16025,7 +16025,7 @@ var HubClient = class {
16025
16025
  if (signal?.aborted) throw new MeshWaitError("aborted", messageId);
16026
16026
  const message = await this.getMessage(messageId);
16027
16027
  if (["replied", "cancelled", "expired", "error"].includes(message.status)) return message;
16028
- await new Promise((resolve, reject) => {
16028
+ await new Promise((resolve2, reject) => {
16029
16029
  const onAbort = () => {
16030
16030
  signal?.removeEventListener("abort", onAbort);
16031
16031
  clearTimeout(timer);
@@ -16033,7 +16033,7 @@ var HubClient = class {
16033
16033
  };
16034
16034
  const timer = setTimeout(() => {
16035
16035
  signal?.removeEventListener("abort", onAbort);
16036
- resolve();
16036
+ resolve2();
16037
16037
  }, Math.min(500, Math.max(1, deadline - Date.now())));
16038
16038
  signal?.addEventListener("abort", onAbort, { once: true });
16039
16039
  if (signal?.aborted) onAbort();
@@ -16088,7 +16088,7 @@ var HubClient = class {
16088
16088
  } catch (error2) {
16089
16089
  if (this.stopped || error2 instanceof Error && error2.name === "AbortError") return;
16090
16090
  }
16091
- if (!this.stopped) await new Promise((resolve) => setTimeout(resolve, this.options.reconnectMs));
16091
+ if (!this.stopped) await new Promise((resolve2) => setTimeout(resolve2, this.options.reconnectMs));
16092
16092
  }
16093
16093
  }
16094
16094
  headers(includeIdentity = true) {
@@ -16170,6 +16170,9 @@ var HubClient = class {
16170
16170
  };
16171
16171
 
16172
16172
  // plugins/kxm/src/commands.ts
16173
+ import { chmodSync, existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
16174
+ import { homedir } from "node:os";
16175
+ import { dirname, join, resolve } from "node:path";
16173
16176
  function requiredString(value, name) {
16174
16177
  if (typeof value !== "string" || value.trim() === "") throw new Error(`${name} is required`);
16175
16178
  return value.trim();
@@ -16890,6 +16893,12 @@ function parseSessionToken(token) {
16890
16893
  const raw = Buffer.from(token.trim(), "base64url").toString("utf8");
16891
16894
  const parsed = JSON.parse(raw);
16892
16895
  if (parsed && typeof parsed === "object" && parsed.schema === "kxm.session-token.v1" && typeof parsed.sessionId === "string") {
16896
+ if (parsed.expiresAt) {
16897
+ const expiryTime = new Date(parsed.expiresAt).getTime();
16898
+ if (!Number.isNaN(expiryTime) && Date.now() >= expiryTime) {
16899
+ return void 0;
16900
+ }
16901
+ }
16893
16902
  return parsed;
16894
16903
  }
16895
16904
  } catch {
@@ -16897,6 +16906,13 @@ function parseSessionToken(token) {
16897
16906
  }
16898
16907
  return void 0;
16899
16908
  }
16909
+ function resolveUserConfigDirectory(overrideDir) {
16910
+ if (overrideDir) return resolve(overrideDir);
16911
+ return resolve(process.env.KXM_USER_CONFIG_DIR?.trim() || join(homedir(), ".config", "kxm"));
16912
+ }
16913
+ function sessionTokenPath(userConfigDir) {
16914
+ return join(resolveUserConfigDirectory(userConfigDir), "session.token");
16915
+ }
16900
16916
  function matchToolPattern(pattern, toolName) {
16901
16917
  if (pattern === "*" || pattern === toolName) return true;
16902
16918
  if (pattern.endsWith("*")) {
@@ -16939,7 +16955,7 @@ function isToolAllowed(commandName, policy) {
16939
16955
  }
16940
16956
  return true;
16941
16957
  }
16942
- function enforceToolPolicy(commandName, env = process.env) {
16958
+ function enforceToolPolicy(commandName, env = process.env, options) {
16943
16959
  const attemptTokenRaw = env.KXM_ATTEMPT_TOKEN?.trim();
16944
16960
  if (attemptTokenRaw) {
16945
16961
  const attempt = parseAttemptToken(attemptTokenRaw);
@@ -16953,13 +16969,51 @@ function enforceToolPolicy(commandName, env = process.env) {
16953
16969
  detail: `command ${commandName} is denied by attempt tool policy`
16954
16970
  };
16955
16971
  }
16972
+ if (commandName === "kxm_promote" || commandName === "promote") {
16973
+ const explicitAllow = attempt.toolPolicy?.allow ?? attempt.toolPolicy?.allowedTools;
16974
+ if (!Array.isArray(explicitAllow) || !explicitAllow.includes("kxm_promote") && !explicitAllow.includes("promote") && !explicitAllow.includes("*")) {
16975
+ return {
16976
+ allowed: false,
16977
+ error: "attempt_token_admin_denied",
16978
+ detail: "AttemptToken worker cannot perform operator state promotion without explicit policy grant"
16979
+ };
16980
+ }
16981
+ }
16982
+ if (options?.runId && attempt.runId && options.runId !== attempt.runId) {
16983
+ return {
16984
+ allowed: false,
16985
+ error: "attempt_token_scope_violation",
16986
+ detail: `attempt token runId ${attempt.runId} does not match request runId ${options.runId}`
16987
+ };
16988
+ }
16956
16989
  return { allowed: true };
16957
16990
  }
16958
- const sessionTokenRaw = env.KXM_SESSION_TOKEN?.trim();
16959
- if (sessionTokenRaw) {
16960
- const session = parseSessionToken(sessionTokenRaw);
16991
+ const envSessionRaw = env.KXM_SESSION_TOKEN?.trim();
16992
+ if (envSessionRaw) {
16993
+ const session = parseSessionToken(envSessionRaw);
16994
+ if (!session) {
16995
+ return { allowed: false, error: "session_token_invalid", detail: "KXM_SESSION_TOKEN is malformed or expired" };
16996
+ }
16997
+ if (!isToolAllowed(commandName, session.toolPolicy)) {
16998
+ return {
16999
+ allowed: false,
17000
+ error: "tool_policy_denied",
17001
+ detail: `command ${commandName} is denied by session tool policy`
17002
+ };
17003
+ }
17004
+ return { allowed: true };
17005
+ }
17006
+ const tokenFile = sessionTokenPath(env.KXM_USER_CONFIG_DIR);
17007
+ if (existsSync(tokenFile)) {
17008
+ let tokenRaw;
17009
+ try {
17010
+ tokenRaw = readFileSync(tokenFile, "utf8").trim();
17011
+ } catch {
17012
+ return { allowed: false, error: "session_token_invalid", detail: "Session token file on disk could not be read" };
17013
+ }
17014
+ const session = tokenRaw ? parseSessionToken(tokenRaw) : void 0;
16961
17015
  if (!session) {
16962
- return { allowed: false, error: "session_token_invalid", detail: "KXM_SESSION_TOKEN is malformed" };
17016
+ return { allowed: false, error: "session_token_invalid", detail: "Session token on disk is malformed or expired" };
16963
17017
  }
16964
17018
  if (!isToolAllowed(commandName, session.toolPolicy)) {
16965
17019
  return {
@@ -16982,7 +17036,7 @@ async function deliverInboxNotification(messageId, delivered, notify) {
16982
17036
  }
16983
17037
 
16984
17038
  // plugins/kxm/src/mcp-server.ts
16985
- var VERSION = "0.6.0";
17039
+ var VERSION = "0.7.0";
16986
17040
  var inbox = /* @__PURE__ */ new Map();
16987
17041
  var notifiedInbox = /* @__PURE__ */ new Set();
16988
17042
  var meshClient;