@kvman/kvcoder 0.1.0 → 0.1.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 (48) hide show
  1. package/dist/api.d.ts +34 -0
  2. package/dist/api.d.ts.map +1 -1
  3. package/dist/connectors/delegate.d.ts.map +1 -1
  4. package/dist/connectors/delegate.js +1 -0
  5. package/dist/connectors/delegate.js.map +1 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +4 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/prompt/session-prompt.d.ts +1 -1
  10. package/dist/prompt/session-prompt.d.ts.map +1 -1
  11. package/dist/prompt/session-prompt.js +17 -2
  12. package/dist/prompt/session-prompt.js.map +1 -1
  13. package/dist/registry/register-connectors.d.ts +1 -0
  14. package/dist/registry/register-connectors.d.ts.map +1 -1
  15. package/dist/registry/register-connectors.js +32 -4
  16. package/dist/registry/register-connectors.js.map +1 -1
  17. package/dist/registry/register-slash-commands.d.ts +6 -0
  18. package/dist/registry/register-slash-commands.d.ts.map +1 -0
  19. package/dist/registry/register-slash-commands.js +85 -0
  20. package/dist/registry/register-slash-commands.js.map +1 -0
  21. package/dist/schemas/records.d.ts +1 -0
  22. package/dist/schemas/records.d.ts.map +1 -1
  23. package/dist/schemas/records.js +2 -0
  24. package/dist/schemas/records.js.map +1 -1
  25. package/dist/schemas/registry.d.ts +32 -0
  26. package/dist/schemas/registry.d.ts.map +1 -1
  27. package/dist/schemas/registry.js +9 -2
  28. package/dist/schemas/registry.js.map +1 -1
  29. package/dist/sessions/new-session.d.ts.map +1 -1
  30. package/dist/sessions/new-session.js +1 -0
  31. package/dist/sessions/new-session.js.map +1 -1
  32. package/dist/store/collections.d.ts +18 -0
  33. package/dist/store/collections.d.ts.map +1 -1
  34. package/dist/store/collections.js +5 -2
  35. package/dist/store/collections.js.map +1 -1
  36. package/dist/turns/start-turn.d.ts +1 -0
  37. package/dist/turns/start-turn.d.ts.map +1 -1
  38. package/dist/web/components/call.js +142 -238
  39. package/dist/web/components/connectors.js +1174 -1549
  40. package/dist/web/components/conversation.js +1912 -2708
  41. package/dist/web/components/mcp-sign-in.js +86 -120
  42. package/dist/web/components/model.js +226 -331
  43. package/dist/web/components/question.js +129 -185
  44. package/dist/web/components/sessions.js +90 -138
  45. package/docs/connectors.md +21 -1
  46. package/locales/ar.json +4 -0
  47. package/locales/en.json +4 -0
  48. package/package.json +4 -4
@@ -1,6 +1,6 @@
1
- import { Fragment as e, computed as t, createBlock as n, createElementBlock as r, createElementVNode as i, createTextVNode as a, createVNode as o, defineComponent as s, h as c, inject as l, onUnmounted as u, openBlock as d, renderList as f, shallowRef as p, toDisplayString as m, watch as h } from "vue";
1
+ import { Fragment as e, computed as t, createBlock as n, createElementBlock as r, createElementVNode as i, createTextVNode as a, createVNode as o, defineComponent as s, h as c, inject as l, onUnmounted as u, openBlock as d, renderList as f, shallowRef as p, toDisplayString as m, unref as h, watch as g } from "vue";
2
2
  //#region ../../node_modules/.pnpm/@lucide+vue@1.49.0_vue@3.5.43_typescript@6.0.3_/node_modules/@lucide/vue/dist/esm/shared/src/build/defaultAttributes.mjs
3
- var g = {
3
+ var _ = {
4
4
  xmlns: "http://www.w3.org/2000/svg",
5
5
  width: 24,
6
6
  height: 24,
@@ -10,25 +10,25 @@ var g = {
10
10
  "stroke-width": 2,
11
11
  "stroke-linecap": "round",
12
12
  "stroke-linejoin": "round"
13
- }, _ = (...e) => e.filter((e, t, n) => !!e && e.trim() !== "" && n.indexOf(e) === t).join(" ").trim();
13
+ }, v = (...e) => e.filter((e, t, n) => !!e && e.trim() !== "" && n.indexOf(e) === t).join(" ").trim();
14
14
  //#endregion
15
15
  //#region ../../node_modules/.pnpm/@lucide+vue@1.49.0_vue@3.5.43_typescript@6.0.3_/node_modules/@lucide/vue/dist/esm/shared/src/build/buildLucideIconNode.mjs
16
- function v(e) {
16
+ function y(e) {
17
17
  return e != null;
18
18
  }
19
- function y(e, t = {}) {
20
- let n = t.attributeNames ?? {}, r = (e) => n[e] ?? e, i = e.size ?? e.width ?? g.width, a = e.size ?? e.height ?? g.height, o = e.aliases?.filter((e) => typeof e == "string" && e.trim() !== "").map((e) => `lucide-${e}`) ?? [], s = [...e.name ? [`lucide-${e.name}`] : [], ...o], c = t.className?.split(" ").filter(Boolean) ?? [], l = t.includeDefaultClasses === !1 ? _(...c) : _("lucide", ...s, ...c), u = t.absoluteStrokeWidth ? Number(t.strokeWidth ?? g["stroke-width"]) * Number(e.size ?? e.width ?? g.width) / Number(t.size ?? t.width ?? g.width) : t.strokeWidth ?? g["stroke-width"];
19
+ function b(e, t = {}) {
20
+ let n = t.attributeNames ?? {}, r = (e) => n[e] ?? e, i = e.size ?? e.width ?? _.width, a = e.size ?? e.height ?? _.height, o = e.aliases?.filter((e) => typeof e == "string" && e.trim() !== "").map((e) => `lucide-${e}`) ?? [], s = [...e.name ? [`lucide-${e.name}`] : [], ...o], c = t.className?.split(" ").filter(Boolean) ?? [], l = t.includeDefaultClasses === !1 ? v(...c) : v("lucide", ...s, ...c), u = t.absoluteStrokeWidth ? Number(t.strokeWidth ?? _["stroke-width"]) * Number(e.size ?? e.width ?? _.width) / Number(t.size ?? t.width ?? _.width) : t.strokeWidth ?? _["stroke-width"];
21
21
  return [
22
22
  "svg",
23
23
  {
24
- ...Object.entries(g).reduce((e, [t, n]) => (e[r(t)] = n, e), {}),
24
+ ...Object.entries(_).reduce((e, [t, n]) => (e[r(t)] = n, e), {}),
25
25
  ..."color" in t && t.color && { [r("stroke")]: t.color },
26
- ..."size" in t && v(t.size) && {
26
+ ..."size" in t && y(t.size) && {
27
27
  [r("width")]: t.size,
28
28
  [r("height")]: t.size
29
29
  },
30
- ..."width" in t && v(t.width) && { [r("width")]: t.width },
31
- ..."height" in t && v(t.height) && { [r("height")]: t.height },
30
+ ..."width" in t && y(t.width) && { [r("width")]: t.width },
31
+ ..."height" in t && y(t.height) && { [r("height")]: t.height },
32
32
  [r("stroke-width")]: u,
33
33
  ...l && { [r("class")]: l },
34
34
  [r("viewBox")]: `0 0 ${i} ${a}`,
@@ -50,49 +50,49 @@ function y(e, t = {}) {
50
50
  }
51
51
  //#endregion
52
52
  //#region ../../node_modules/.pnpm/@lucide+vue@1.49.0_vue@3.5.43_typescript@6.0.3_/node_modules/@lucide/vue/dist/esm/shared/src/utils/hasA11yProp.mjs
53
- var b = (e) => {
53
+ var x = (e) => {
54
54
  for (let t in e) if (t.startsWith("aria-") || t === "role" || t === "title") return !0;
55
55
  return !1;
56
- }, x = (e) => e === "", S = (e) => e?.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), C = /* @__PURE__ */ Symbol("lucide-icons");
57
- function w() {
58
- return l(C, {});
56
+ }, S = (e) => e === "", C = (e) => e?.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), w = /* @__PURE__ */ Symbol("lucide-icons");
57
+ function T() {
58
+ return l(w, {});
59
59
  }
60
60
  //#endregion
61
61
  //#region ../../node_modules/.pnpm/@lucide+vue@1.49.0_vue@3.5.43_typescript@6.0.3_/node_modules/@lucide/vue/dist/esm/Icon.mjs
62
- var T = ({ name: e, iconNode: t, "icon-node": n, icon: r = {
63
- name: e && S(e),
62
+ var E = ({ name: e, iconNode: t, "icon-node": n, icon: r = {
63
+ name: e && C(e),
64
64
  node: t ?? n ?? [],
65
65
  size: 24,
66
66
  aliases: []
67
67
  }, absoluteStrokeWidth: i, "absolute-stroke-width": a, nonScalingStroke: o, "non-scaling-stroke": s, strokeWidth: l, "stroke-width": u, size: d, width: f = d, height: p = d, color: m, ...h }, { slots: g }) => {
68
- let { size: _, color: v, strokeWidth: C = 2, absoluteStrokeWidth: T = !1, nonScalingStroke: E = !1, class: D = "" } = w(), O = x(i) || x(a) || i === !0 || a === !0 || T === !0, k = x(o) || x(s) || o === !0 || s === !0 || E === !0;
68
+ let { size: _, color: v, strokeWidth: y = 2, absoluteStrokeWidth: w = !1, nonScalingStroke: E = !1, class: D = "" } = T(), O = S(i) || S(a) || i === !0 || a === !0 || w === !0, k = S(o) || S(s) || o === !0 || s === !0 || E === !0;
69
69
  delete h.class;
70
- let A = g.default?.(), [, j, M = []] = y(r, {
70
+ let A = g.default?.(), [, j, M = []] = b(r, {
71
71
  color: m ?? v,
72
72
  width: f ?? d ?? _,
73
73
  height: p ?? d ?? _,
74
- strokeWidth: l ?? u ?? C,
74
+ strokeWidth: l ?? u ?? y,
75
75
  absoluteStrokeWidth: O,
76
76
  nonScalingStroke: k,
77
77
  className: D,
78
- hasA11yProp: A != null && A.length > 0 || b(h),
78
+ hasA11yProp: A != null && A.length > 0 || x(h),
79
79
  attributes: h
80
80
  });
81
81
  return c("svg", j, [...M.map(([e, t]) => c(e, t)), ...A ?? []]);
82
82
  };
83
83
  //#endregion
84
84
  //#region ../../node_modules/.pnpm/@lucide+vue@1.49.0_vue@3.5.43_typescript@6.0.3_/node_modules/@lucide/vue/dist/esm/createLucideIcon.mjs
85
- function E(e, t = []) {
85
+ function D(e, t = []) {
86
86
  let n = typeof e == "string" ? {
87
87
  name: e,
88
88
  node: t
89
89
  } : e;
90
- return (e, { slots: t }) => c(T, {
90
+ return (e, { slots: t }) => c(E, {
91
91
  ...e,
92
92
  icon: n
93
93
  }, t.default ? { default: t.default } : void 0);
94
94
  }
95
- var D = E({
95
+ var O = D({
96
96
  name: "plus",
97
97
  size: 24,
98
98
  node: [["path", {
@@ -105,160 +105,112 @@ var D = E({
105
105
  });
106
106
  //#endregion
107
107
  //#region web/src/kvman.ts
108
- function O() {
108
+ function k() {
109
109
  let e = l("kvman");
110
110
  if (e === void 0) throw Error("kvcoder components run inside kvwebui, which provides kvman.");
111
111
  return e;
112
112
  }
113
- var k = () => document.documentElement.lang === "" ? void 0 : document.documentElement.lang;
114
- function A(e) {
113
+ var A = () => document.documentElement.lang === "" ? void 0 : document.documentElement.lang;
114
+ function j(e) {
115
115
  return typeof e == "object" && e && !Array.isArray(e) ? Object.fromEntries(Object.entries(e)) : {};
116
116
  }
117
- function j(e, t) {
117
+ function M(e, t) {
118
118
  return t === "" ? e("kvcoder.ui.newChat") : t;
119
119
  }
120
- function M(e) {
120
+ function N(e) {
121
121
  let t = e.indexOf("/");
122
122
  return t < 0 ? `kernel.errors.${e}` : `${e.slice(0, t)}.errors.${e.slice(t + 1)}`;
123
123
  }
124
- function N(e) {
124
+ function P(e) {
125
125
  if (!(e instanceof Error) || !("problem" in e)) return;
126
126
  let t = e.problem;
127
127
  if (typeof t == "object" && t && "code" in t && typeof t.code == "string") return {
128
128
  code: t.code,
129
- params: P("params" in t ? t.params : void 0)
129
+ params: F("params" in t ? t.params : void 0)
130
130
  };
131
131
  }
132
- function P(e) {
133
- return Object.fromEntries(Object.entries(A(e)).map(([e, t]) => [e, typeof t == "string" ? t : JSON.stringify(t)]));
132
+ function F(e) {
133
+ return Object.fromEntries(Object.entries(j(e)).map(([e, t]) => [e, typeof t == "string" ? t : JSON.stringify(t)]));
134
134
  }
135
- function F(e, t) {
136
- let n = N(t);
137
- e.toast(n === void 0 ? "kvcoder.ui.failed" : M(n.code), n?.params ?? {}, "error");
135
+ function I(e, t) {
136
+ let n = P(t);
137
+ e.toast(n === void 0 ? "kvcoder.ui.failed" : N(n.code), n?.params ?? {}, "error");
138
138
  }
139
139
  //#endregion
140
140
  //#region web/src/SessionList.vue?vue&type=script&setup=true&lang.ts
141
- var I = /*@__PURE__*/ s({
141
+ var L = ["aria-label"], R = { class: "kvc-group" }, z = [
142
+ "aria-current",
143
+ "data-test",
144
+ "onClick"
145
+ ], B = ["aria-label"], V = {
146
+ key: 1,
147
+ class: "kvc-chip kvc-warn",
148
+ "data-test": "needs-you"
149
+ }, H = {
150
+ key: 2,
151
+ class: "kvc-muted"
152
+ }, U = /* @__PURE__ */ s({
142
153
  __name: "SessionList",
143
- props: { sessionId: {
144
- type: null,
145
- required: !1
146
- } },
147
- setup(e, { expose: n }) {
148
- n();
149
- let r = e, i = O(), a = p([]);
150
- async function o() {
154
+ props: { sessionId: {} },
155
+ setup(n) {
156
+ let s = n, c = k(), l = p([]);
157
+ async function _() {
151
158
  try {
152
- a.value = await i.exec("kvcoder.session.list", { limit: 200 });
159
+ l.value = await c.exec("kvcoder.session.list", { limit: 200 });
153
160
  } catch (e) {
154
- F(i, e);
161
+ I(c, e);
155
162
  }
156
163
  }
157
- let s = () => new Date((/* @__PURE__ */ new Date()).toDateString()).getTime(), c = t(() => {
158
- let e = s();
164
+ let v = () => new Date((/* @__PURE__ */ new Date()).toDateString()).getTime(), y = t(() => {
165
+ let e = v();
159
166
  return [{
160
167
  key: "today",
161
- items: a.value.filter((t) => Date.parse(t.updatedAt) >= e)
168
+ items: l.value.filter((t) => Date.parse(t.updatedAt) >= e)
162
169
  }, {
163
170
  key: "earlier",
164
- items: a.value.filter((t) => Date.parse(t.updatedAt) < e)
171
+ items: l.value.filter((t) => Date.parse(t.updatedAt) < e)
165
172
  }].filter((e) => e.items.length > 0);
166
- }), l = (e) => {
173
+ }), b = (e) => {
167
174
  let t = new Date(e.updatedAt);
168
- return t.getTime() >= s() ? t.toLocaleTimeString(k(), {
175
+ return t.getTime() >= v() ? t.toLocaleTimeString(A(), {
169
176
  hour: "2-digit",
170
177
  minute: "2-digit"
171
- }) : t.toLocaleDateString(k(), {
178
+ }) : t.toLocaleDateString(A(), {
172
179
  month: "short",
173
180
  day: "numeric"
174
181
  });
175
- }, d = setInterval(() => void o(), 5e3);
176
- u(() => clearInterval(d)), h([() => r.sessionId, () => i.workspace.value.id], () => void o(), { immediate: !0 });
177
- let f = {
178
- props: r,
179
- kvman: i,
180
- sessions: a,
181
- load: o,
182
- startOfToday: s,
183
- groups: c,
184
- when: l,
185
- timer: d,
186
- get Plus() {
187
- return D;
188
- },
189
- get titleText() {
190
- return j;
191
- }
192
- };
193
- return Object.defineProperty(f, "__isScriptSetup", {
194
- enumerable: !1,
195
- value: !0
196
- }), f;
182
+ }, x = setInterval(() => void _(), 5e3);
183
+ return u(() => clearInterval(x)), g([() => s.sessionId, () => c.workspace.value.id], () => void _(), { immediate: !0 }), (t, n) => (d(), r("nav", {
184
+ class: "kvc-sessions",
185
+ "aria-label": h(c).t("kvcoder.ui.chats"),
186
+ "data-test": "sessions"
187
+ }, [i("button", {
188
+ type: "button",
189
+ class: "kvc-button kvc-primary",
190
+ style: { "margin-block-end": "6px" },
191
+ "data-test": "new-chat",
192
+ onClick: n[0] ||= (e) => h(c).navigate("kvcoder.chat")
193
+ }, [o(h(O), { size: 16 }), a(m(h(c).t("kvcoder.ui.newChat")), 1)]), (d(!0), r(e, null, f(y.value, (t) => (d(), r(e, { key: t.key }, [i("span", R, m(h(c).t(`kvcoder.ui.${t.key}`)), 1), (d(!0), r(e, null, f(t.items, (e) => (d(), r("button", {
194
+ key: e.id,
195
+ type: "button",
196
+ class: "kvc-session",
197
+ "aria-current": e.id === s.sessionId ? "page" : void 0,
198
+ "data-test": `session-${e.id}`,
199
+ onClick: (t) => h(c).navigate("kvcoder.session", { sessionId: e.id })
200
+ }, [i("span", null, m(h(M)(h(c).t, e.title)), 1), e.status === "running" ? (d(), r("span", {
201
+ key: 0,
202
+ class: "kvc-spin",
203
+ "aria-label": h(c).t("kvcoder.ui.status.running"),
204
+ "data-test": "running"
205
+ }, null, 8, B)) : e.status === "waiting" ? (d(), r("span", V, m(h(c).t("kvcoder.ui.needsYou")), 1)) : (d(), r("span", H, m(b(e)), 1))], 8, z))), 128))], 64))), 128))], 8, L));
197
206
  }
198
- }), L = (e, t) => {
199
- let n = e.__vccOpts || e;
200
- for (let [e, r] of t) n[e] = r;
201
- return n;
202
- }, R = ["aria-label"], z = { class: "kvc-group" }, B = [
203
- "aria-current",
204
- "data-test",
205
- "onClick"
206
- ], V = ["aria-label"], H = {
207
- key: 1,
208
- class: "kvc-chip kvc-warn",
209
- "data-test": "needs-you"
210
- }, U = {
211
- key: 2,
212
- class: "kvc-muted"
213
- };
214
- function W(t, n, s, c, l, u) {
215
- return d(), r("nav", {
216
- class: "kvc-sessions",
217
- "aria-label": c.kvman.t("kvcoder.ui.chats"),
218
- "data-test": "sessions"
219
- }, [i("button", {
220
- type: "button",
221
- class: "kvc-button kvc-primary",
222
- style: { "margin-block-end": "6px" },
223
- "data-test": "new-chat",
224
- onClick: n[0] ||= (e) => c.kvman.navigate("kvcoder.chat")
225
- }, [o(c.Plus, { size: 16 }), a(m(c.kvman.t("kvcoder.ui.newChat")), 1)]), (d(!0), r(e, null, f(c.groups, (t) => (d(), r(e, { key: t.key }, [i("span", z, m(c.kvman.t(`kvcoder.ui.${t.key}`)), 1), (d(!0), r(e, null, f(t.items, (e) => (d(), r("button", {
226
- key: e.id,
227
- type: "button",
228
- class: "kvc-session",
229
- "aria-current": e.id === c.props.sessionId ? "page" : void 0,
230
- "data-test": `session-${e.id}`,
231
- onClick: (t) => c.kvman.navigate("kvcoder.session", { sessionId: e.id })
232
- }, [i("span", null, m(c.titleText(c.kvman.t, e.title)), 1), e.status === "running" ? (d(), r("span", {
233
- key: 0,
234
- class: "kvc-spin",
235
- "aria-label": c.kvman.t("kvcoder.ui.status.running"),
236
- "data-test": "running"
237
- }, null, 8, V)) : e.status === "waiting" ? (d(), r("span", H, m(c.kvman.t("kvcoder.ui.needsYou")), 1)) : (d(), r("span", U, m(c.when(e)), 1))], 8, B))), 128))], 64))), 128))], 8, R);
238
- }
239
- var G = /*#__PURE__*/ L(I, [["render", W], ["__file", "/home/runner/work/kvman/kvman/extensions/kvcoder/web/src/SessionList.vue"]]), K = /*@__PURE__*/ s({
207
+ }), W = /* @__PURE__ */ s({
240
208
  __name: "sessions",
241
- props: { sessionId: {
242
- type: String,
243
- required: !1
244
- } },
245
- setup(e, { expose: t }) {
246
- t();
247
- let n = {
248
- props: e,
249
- SessionList: G
250
- };
251
- return Object.defineProperty(n, "__isScriptSetup", {
252
- enumerable: !1,
253
- value: !0
254
- }), n;
209
+ props: { sessionId: {} },
210
+ setup(e) {
211
+ let t = e;
212
+ return (e, r) => (d(), n(U, { "session-id": t.sessionId }, null, 8, ["session-id"]));
255
213
  }
256
214
  });
257
215
  //#endregion
258
- //#region web/components/sessions.vue
259
- function q(e, t, r, i, a, o) {
260
- return d(), n(i.SessionList, { "session-id": i.props.sessionId }, null, 8, ["session-id"]);
261
- }
262
- var J = /*#__PURE__*/ L(K, [["render", q], ["__file", "/home/runner/work/kvman/kvman/extensions/kvcoder/web/components/sessions.vue"]]);
263
- //#endregion
264
- export { J as default };
216
+ export { W as default };
@@ -68,6 +68,26 @@ The agent calls a binary connector with two commands. `exec { args?, background?
68
68
 
69
69
  `kvcoder.connector.unregister { name }` removes one of the caller's own connectors; a missing name does nothing. `kvcoder.connector.list` answers every registered connector and program, each with `enabled`. The setting `kvcoder.connectors.disabled` lists the names that are turned off, kvcoder's own seven included: such a connector is left out of the prompt and can't be called, from the next step.
70
70
 
71
+ ## A connector that is off until enabled
72
+
73
+ Register a connector with `optIn: true`, the only value the field takes, when it belongs only in chats that asked for it.
74
+
75
+ - It is in no chat's connector index and no `run` enum, and a call to it gets the answer for a connector that doesn't exist.
76
+ - Its owner switches it on for one chat: `kvcoder.connector.enable { sessionId, names }`. Each name must be an `optIn` connector of the caller (`VALIDATION_FAILED`); an unknown session fails `kvcoder/SESSION_NOT_FOUND`, and a subagent's `VALIDATION_FAILED`.
77
+ - The chat keeps it across restarts. A subagent has it only when its chat enabled it and its worker lists it. A fork starts with none. Nothing switches one off again, and `kvcoder.connectors.disabled` still turns it off.
78
+ - `kvcoder.connector.list` rows have `optIn`.
79
+
80
+ ## Slash commands
81
+
82
+ `kvcoder.slash.register { commands: [{ name, description, command, message? }] }` adds commands to the send box, after kvcoder's own six.
83
+
84
+ - `name`: lowercase kebab case; kvcoder's own names and another extension's fail `kvcoder/NAME_TAKEN`, and a name given twice `VALIDATION_FAILED`. All of a call's commands are stored, or none.
85
+ - `description` and `message`: translation keys of the caller's catalog.
86
+ - `command`: a public command of the caller (`VALIDATION_FAILED` otherwise). The send box calls it with `{ sessionId, argument }`, where `argument` is the text after the name, `''` when there is none.
87
+ - With `message`, a command that succeeded is followed by the person's message: the argument, or with none the text of `message`. A command that failed shows its Problem and sends nothing.
88
+ - `kvcoder.slash.unregister { name }` removes the caller's own; `kvcoder.slash.list` answers `[{ name, description, command, message?, owner }]`, by name.
89
+ - With no chat open yet, the list is greyed and nothing runs.
90
+
71
91
  ## Built-in connectors
72
92
 
73
93
  kvcoder's own connectors are `shell` (one line in the real shell), `fs` (read, list, search, write, and edit files in the workspace folder), `artifact` (a document shown beside the chat), `background` (follow up on what was started with `background: true`), `ask` (a question that suspends the turn), `delegate` (`delegate run { worker, task, background? }` hands a task to a worker, which runs it in a helper session; the workers are the setting `kvcoder.delegate.workers`, and it is a connector of a session only while a worker is turned on), and `mcp` (the tools of the MCP servers the person added; it is a connector of a session only while the workspace has a server). Their names are taken: registering one fails `kvcoder/NAME_TAKEN`.
@@ -81,6 +101,6 @@ kvcoder's own connectors are `shell` (one line in the real shell), `fs` (read, l
81
101
 
82
102
  ## Lifetime
83
103
 
84
- - Connectors last one run. kvcoder clears them in its own `kernel.started` handler, which runs first because registering extensions declare kvcoder as a dependency. Each extension registers its connectors again from its own `kernel.started` handler. A hot reload of kvcoder reruns its dependents' handlers too.
104
+ - Connectors and slash commands last one run. kvcoder clears them in its own `kernel.started` handler, which runs first because registering extensions declare kvcoder as a dependency. Each extension registers its connectors and slash commands again from its own `kernel.started` handler. A hot reload of kvcoder reruns its dependents' handlers too.
85
105
  - Sections are stored until removed; see [Sections](sections.md).
86
106
  - When kvcoder reads, it ignores any connector whose owner isn't loaded.
package/locales/ar.json CHANGED
@@ -164,6 +164,10 @@
164
164
  "kvcoder.connector.register.description": "يسجّل موصّلًا يستدعيه الوكيل بأداته run: أوامر المستدعي العامة، أو برنامجًا يعمل في الطرفية.",
165
165
  "kvcoder.connector.unregister.description": "يزيل أحد موصّلات المستدعي.",
166
166
  "kvcoder.connector.list.description": "يسرد الموصّلات التي يمكن للوكيل استخدامها.",
167
+ "kvcoder.connector.enable.description": "يشغّل موصّلات المستدعي الاختيارية (optIn) في محادثة واحدة.",
168
+ "kvcoder.slash.register.description": "يسجّل أوامر الشرطة المائلة في مربع الإرسال، وكلٌّ منها يشغّل أحد أوامر المستدعي العامة.",
169
+ "kvcoder.slash.unregister.description": "يزيل أحد أوامر الشرطة المائلة للمستدعي.",
170
+ "kvcoder.slash.list.description": "يسرد أوامر الشرطة المائلة التي أضافتها الإضافات إلى مربع الإرسال.",
167
171
  "kvcoder.section.set.description": "يضبط أحد أقسام المستدعي في تعليمات النظام.",
168
172
  "kvcoder.section.remove.description": "يزيل أحد أقسام المستدعي؛ ولا يفعل شيئًا إن لم يكن القسم موجودًا.",
169
173
  "kvcoder.section.list.description": "يسرد الأقسام التي تدخل في تعليمات محادثة، أو أقسام مساحة العمل عند عدم تحديد محادثة.",
package/locales/en.json CHANGED
@@ -164,6 +164,10 @@
164
164
  "kvcoder.connector.register.description": "Registers a connector the agent calls with its run tool: the caller's public commands, or a program run in the shell.",
165
165
  "kvcoder.connector.unregister.description": "Removes one of the caller's connectors.",
166
166
  "kvcoder.connector.list.description": "Lists the connectors the agent may use.",
167
+ "kvcoder.connector.enable.description": "Switches the caller's own optIn connectors on for one chat.",
168
+ "kvcoder.slash.register.description": "Registers slash commands of the send box, each running one of the caller's public commands.",
169
+ "kvcoder.slash.unregister.description": "Removes one of the caller's slash commands.",
170
+ "kvcoder.slash.list.description": "Lists the slash commands that extensions added to the send box.",
167
171
  "kvcoder.section.set.description": "Sets one of the caller's sections of the system prompt.",
168
172
  "kvcoder.section.remove.description": "Removes one of the caller's sections; a missing one does nothing.",
169
173
  "kvcoder.section.list.description": "Lists the sections a session's prompt reaches, or the workspace's without a session.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kvman/kvcoder",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "kvcoder: the app-building harness, with one run tool over connectors, sections, and its conversation UI.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -36,16 +36,16 @@
36
36
  "@kvman/sdk": "^0.1.0"
37
37
  },
38
38
  "dependencies": {
39
- "@kvman/kvai": "0.1.0",
39
+ "@kvman/kvai": "0.1.1",
40
40
  "@lucide/vue": "1.49.0",
41
41
  "@modelcontextprotocol/sdk": "1.32.1",
42
42
  "cross-spawn": "7.0.6",
43
43
  "vue": "3.5.43"
44
44
  },
45
45
  "devDependencies": {
46
- "@kvman/kvwebui": "0.1.0",
46
+ "@kvman/kvwebui": "0.1.1",
47
47
  "@kvman/sdk": "0.1.0",
48
- "@kvman/testkit": "0.1.0",
48
+ "@kvman/testkit": "0.1.2",
49
49
  "@types/cross-spawn": "6.0.6",
50
50
  "@vitejs/plugin-vue": "6.0.9",
51
51
  "@vue/test-utils": "2.5.1",