@kontextmind/kxm 0.7.196 → 0.7.198
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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +13 -1
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +7 -1
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/dist/runtime-supervisor.js +3 -2
- package/plugins/kxm/dist/runtime.js +3 -2
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/route-fallback.ts +5 -2
- package/plugins/kxm/src/suggest.ts +12 -1
package/CHANGELOG.md
CHANGED
|
@@ -714,13 +714,25 @@ All notable user-facing changes are documented here. The project follows [Semant
|
|
|
714
714
|
|
|
715
715
|
### Fixed
|
|
716
716
|
|
|
717
|
+
- **A rate-limit response that mentions abort can still fall back.**
|
|
718
|
+
`classifyRouteFailure` treated any text containing `abort` as cancellation
|
|
719
|
+
before it read HTTP 429, so an opted-in role did not walk. Status 429, 408,
|
|
720
|
+
413, 500, 502, 503, and 504 are classified first. `AbortError`,
|
|
721
|
+
`process_aborted`, and an explicit cancellation stay cancelled.
|
|
722
|
+
`tool_policy` is its own class instead of `policy_refusal`. Neither class
|
|
723
|
+
walks.
|
|
724
|
+
|
|
725
|
+
- **`kxm suggest` matches workflow keywords as whole words.**
|
|
726
|
+
A substring match sent "guide" and "build" to the feature workflow because
|
|
727
|
+
they contain `ui`, "author" to vulnerability remediation because it contains
|
|
728
|
+
`auth`, and "change" to bug-fix because it contains `hang`. Hyphenated
|
|
729
|
+
keywords such as `circuit-breaker` still match as one token.
|
|
717
730
|
- **A first run says what to do next when Git or the hub is missing.**
|
|
718
731
|
`kxm init` outside a Git worktree still exits 1 with `git_root_required` and
|
|
719
732
|
now says to run `git init`, then `kxm init` again. `kxm hub view` adds
|
|
720
733
|
`hint` when both probes are unreachable or time out: on loopback, start a
|
|
721
734
|
hub with `kxm hub start`; on a remote URL, check the address and
|
|
722
735
|
`kxm hub bind`.
|
|
723
|
-
|
|
724
736
|
- **`kxm vision assert --route` selects the Pi model, and an unadmitted route names the fix.**
|
|
725
737
|
The flag used to change only the admission check. Pi still ran
|
|
726
738
|
`zai-coding-cn/glm-5.3-flash`. Another admitted id is now `pi --model <id>`
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"name": "kxm",
|
|
4
4
|
"displayName": "KXM",
|
|
5
|
-
"version": "0.7.
|
|
5
|
+
"version": "0.7.198",
|
|
6
6
|
"description": "Headless multi-agent orchestration, durable workflows, and a live operator dashboard for Pi and Claude Code",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "KontextMind",
|
package/plugins/kxm/dist/cli.js
CHANGED
|
@@ -38624,6 +38624,12 @@ var WORKFLOW_PATTERNS = [
|
|
|
38624
38624
|
skills: ["kxm-session", "kxm-context-memory", "kxm-routing-improve"]
|
|
38625
38625
|
}
|
|
38626
38626
|
];
|
|
38627
|
+
function keywordHit(normalized, words, keyword) {
|
|
38628
|
+
if (words.includes(keyword)) return true;
|
|
38629
|
+
if (!keyword.includes("-")) return false;
|
|
38630
|
+
const escaped = keyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
38631
|
+
return new RegExp(`(?:^|[^a-z0-9])${escaped}(?:$|[^a-z0-9])`).test(normalized);
|
|
38632
|
+
}
|
|
38627
38633
|
function suggestWorkflowAndRoles(prompt, options = {}) {
|
|
38628
38634
|
const normalized = prompt.toLowerCase();
|
|
38629
38635
|
const words = normalized.split(/\W+/).filter(Boolean);
|
|
@@ -38632,7 +38638,7 @@ function suggestWorkflowAndRoles(prompt, options = {}) {
|
|
|
38632
38638
|
let bestScore = 0;
|
|
38633
38639
|
const reasons = [];
|
|
38634
38640
|
for (const pattern of WORKFLOW_PATTERNS) {
|
|
38635
|
-
const matchedWords = pattern.keywords.filter((keyword) =>
|
|
38641
|
+
const matchedWords = pattern.keywords.filter((keyword) => keywordHit(normalized, words, keyword));
|
|
38636
38642
|
if (matchedWords.length > bestScore) {
|
|
38637
38643
|
bestScore = matchedWords.length;
|
|
38638
38644
|
bestPattern = pattern;
|
|
@@ -25462,7 +25462,7 @@ function sessionTokenFixHint(policy) {
|
|
|
25462
25462
|
}
|
|
25463
25463
|
|
|
25464
25464
|
// plugins/kxm/src/mcp-server.ts
|
|
25465
|
-
var VERSION = "0.7.
|
|
25465
|
+
var VERSION = "0.7.198";
|
|
25466
25466
|
var CONFIGURE_PLUGIN = "/plugin configure kxm@kxm";
|
|
25467
25467
|
var inbox = /* @__PURE__ */ new Map();
|
|
25468
25468
|
var notifiedInbox = /* @__PURE__ */ new Set();
|
|
@@ -25216,10 +25216,10 @@ function classifyRouteFailure(input) {
|
|
|
25216
25216
|
class: failureClass,
|
|
25217
25217
|
walkable: WALKABLE_CLASSES.includes(failureClass)
|
|
25218
25218
|
});
|
|
25219
|
-
if (name === "aborterror" || /\b(?:user_cancelled|cancelled|cancellation)\b/.test(text) || code === "process_aborted"
|
|
25219
|
+
if (name === "aborterror" || /\b(?:user_cancelled|cancelled|cancellation)\b/.test(text) || code === "process_aborted") {
|
|
25220
25220
|
return result("cancelled");
|
|
25221
25221
|
}
|
|
25222
|
-
if (/policy_refusal|content_policy|
|
|
25222
|
+
if (/policy_refusal|content_policy|usage policy|safety/.test(text) || text.includes("policy refusal")) {
|
|
25223
25223
|
return result("policy_refusal");
|
|
25224
25224
|
}
|
|
25225
25225
|
if (code.includes("not_authenticated") || /unauthori[sz]ed|authentication|invalid api key|auth_failed|\bauth\b/.test(text) || status === 401 || status === 403) {
|
|
@@ -25249,6 +25249,7 @@ function classifyRouteFailure(input) {
|
|
|
25249
25249
|
if (status === 500 || status === 503 || /provider_unavailable|model unavailable|service unavailable|overloaded|model_not_found|no available model/.test(text)) {
|
|
25250
25250
|
return result("provider_unavailable");
|
|
25251
25251
|
}
|
|
25252
|
+
if (text.includes("abort")) return result("cancelled");
|
|
25252
25253
|
return result("unknown");
|
|
25253
25254
|
}
|
|
25254
25255
|
function parseFallbackPolicy(value) {
|
|
@@ -25960,10 +25960,10 @@ function classifyRouteFailure(input) {
|
|
|
25960
25960
|
class: failureClass,
|
|
25961
25961
|
walkable: WALKABLE_CLASSES.includes(failureClass)
|
|
25962
25962
|
});
|
|
25963
|
-
if (name === "aborterror" || /\b(?:user_cancelled|cancelled|cancellation)\b/.test(text) || code === "process_aborted"
|
|
25963
|
+
if (name === "aborterror" || /\b(?:user_cancelled|cancelled|cancellation)\b/.test(text) || code === "process_aborted") {
|
|
25964
25964
|
return result("cancelled");
|
|
25965
25965
|
}
|
|
25966
|
-
if (/policy_refusal|content_policy|
|
|
25966
|
+
if (/policy_refusal|content_policy|usage policy|safety/.test(text) || text.includes("policy refusal")) {
|
|
25967
25967
|
return result("policy_refusal");
|
|
25968
25968
|
}
|
|
25969
25969
|
if (code.includes("not_authenticated") || /unauthori[sz]ed|authentication|invalid api key|auth_failed|\bauth\b/.test(text) || status === 401 || status === 403) {
|
|
@@ -25993,6 +25993,7 @@ function classifyRouteFailure(input) {
|
|
|
25993
25993
|
if (status === 500 || status === 503 || /provider_unavailable|model unavailable|service unavailable|overloaded|model_not_found|no available model/.test(text)) {
|
|
25994
25994
|
return result("provider_unavailable");
|
|
25995
25995
|
}
|
|
25996
|
+
if (text.includes("abort")) return result("cancelled");
|
|
25996
25997
|
return result("unknown");
|
|
25997
25998
|
}
|
|
25998
25999
|
function parseFallbackPolicy(value) {
|
package/plugins/kxm/package.json
CHANGED
|
@@ -11,7 +11,7 @@ import { deliverInboxNotification } from "./inbox.ts";
|
|
|
11
11
|
import type { HubEvent, MessageRecord } from "./protocol.ts";
|
|
12
12
|
import { sessionTokenFixHint } from "./session-token-hint.ts";
|
|
13
13
|
|
|
14
|
-
const VERSION = "0.7.
|
|
14
|
+
const VERSION = "0.7.198";
|
|
15
15
|
const CONFIGURE_PLUGIN = "/plugin configure kxm@kxm";
|
|
16
16
|
const inbox = new Map<string, MessageRecord>();
|
|
17
17
|
const notifiedInbox = new Set<string>();
|
|
@@ -116,10 +116,10 @@ export function classifyRouteFailure(input: {
|
|
|
116
116
|
walkable: (WALKABLE_CLASSES as readonly string[]).includes(failureClass),
|
|
117
117
|
});
|
|
118
118
|
|
|
119
|
-
if (name === "aborterror" || /\b(?:user_cancelled|cancelled|cancellation)\b/.test(text) || code === "process_aborted"
|
|
119
|
+
if (name === "aborterror" || /\b(?:user_cancelled|cancelled|cancellation)\b/.test(text) || code === "process_aborted") {
|
|
120
120
|
return result("cancelled");
|
|
121
121
|
}
|
|
122
|
-
if (/policy_refusal|content_policy|
|
|
122
|
+
if (/policy_refusal|content_policy|usage policy|safety/.test(text) || text.includes("policy refusal")) {
|
|
123
123
|
return result("policy_refusal");
|
|
124
124
|
}
|
|
125
125
|
if (code.includes("not_authenticated") || /unauthori[sz]ed|authentication|invalid api key|auth_failed|\bauth\b/.test(text) || status === 401 || status === 403) {
|
|
@@ -156,6 +156,9 @@ export function classifyRouteFailure(input: {
|
|
|
156
156
|
) {
|
|
157
157
|
return result("provider_unavailable");
|
|
158
158
|
}
|
|
159
|
+
// After the status classes. A 429 body that says the request was aborted is
|
|
160
|
+
// still a rate limit and may walk. A bare abort, with no walkable status, stays cancelled.
|
|
161
|
+
if (text.includes("abort")) return result("cancelled");
|
|
159
162
|
return result("unknown");
|
|
160
163
|
}
|
|
161
164
|
|
|
@@ -96,6 +96,17 @@ const WORKFLOW_PATTERNS: WorkflowPattern[] = [
|
|
|
96
96
|
];
|
|
97
97
|
|
|
98
98
|
type TemplateStep = { id: string; kind: string; agent?: string; repositories?: Record<string, string> };
|
|
99
|
+
|
|
100
|
+
/** Whole tokens only. A substring match made `ui` hit `build` and `guide`,
|
|
101
|
+
* `auth` hit `author`, and `hang` hit `change`, so those prompts took the
|
|
102
|
+
* wrong workflow. Hyphenated keywords stay one token (`circuit-breaker`). */
|
|
103
|
+
function keywordHit(normalized: string, words: readonly string[], keyword: string): boolean {
|
|
104
|
+
if (words.includes(keyword)) return true;
|
|
105
|
+
if (!keyword.includes("-")) return false;
|
|
106
|
+
const escaped = keyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
107
|
+
return new RegExp(`(?:^|[^a-z0-9])${escaped}(?:$|[^a-z0-9])`).test(normalized);
|
|
108
|
+
}
|
|
109
|
+
|
|
99
110
|
type SuggestionHarness = Pick<HarnessStatus, "id" | "detected" | "authenticated" | "dispatch">;
|
|
100
111
|
|
|
101
112
|
export function suggestWorkflowAndRoles(
|
|
@@ -110,7 +121,7 @@ export function suggestWorkflowAndRoles(
|
|
|
110
121
|
const reasons: string[] = [];
|
|
111
122
|
|
|
112
123
|
for (const pattern of WORKFLOW_PATTERNS) {
|
|
113
|
-
const matchedWords = pattern.keywords.filter((keyword) =>
|
|
124
|
+
const matchedWords = pattern.keywords.filter((keyword) => keywordHit(normalized, words, keyword));
|
|
114
125
|
if (matchedWords.length > bestScore) {
|
|
115
126
|
bestScore = matchedWords.length;
|
|
116
127
|
bestPattern = pattern;
|