@vincemakes/kiso-subagent-ext 0.30.0 → 0.31.1

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.
@@ -34,7 +34,14 @@ const SIX_TOOLS = ["read_file", "list_dir", "search_text", "write_file", "edit_f
34
34
  const READ_ONLY = ["read_file", "list_dir", "search_text"];
35
35
  const ROLES = ["explorer", "implementer", "reviewer", "tester"];
36
36
 
37
- const DELEGATE_PARAMETERS = {
37
+ // DT1a-F2 (owner dogfood 2026-09-08): the model's first delegate call was
38
+ // refused twice — `scope` on an explorer, then an `acceptance` naming no
39
+ // configured check — because nothing in the schema said where scope applies
40
+ // or which checks exist. The field descriptions say so, and the configured
41
+ // check and profile names are written into the schema when the extension
42
+ // loads (the tool table is snapshotted per request — F7b — so this is the
43
+ // table the model reads).
44
+ const delegateParameters = (cfg) => ({
38
45
  type: "object",
39
46
  properties: {
40
47
  tasks: {
@@ -53,11 +60,21 @@ const DELEGATE_PARAMETERS = {
53
60
  // never a command; model names a configured profile; after names
54
61
  // a completed implementer's childId (tester only): the tester runs
55
62
  // in that worktree.
56
- scope: { type: "array", items: { type: "string", minLength: 1 }, maxItems: 32 },
57
- acceptance: { type: "object", properties: { check: { type: "string", minLength: 1 }, evaluator: { type: "string", minLength: 1 } }, additionalProperties: false },
58
- model: { type: "string", minLength: 1 },
59
- after: { type: "string", minLength: 1 },
60
- timeoutMs: { type: "integer", minimum: 1000 },
63
+ scope: {
64
+ type: "array",
65
+ items: { type: "string", minLength: 1 },
66
+ maxItems: 32,
67
+ description: "implementer and tester tasks ONLY (an explorer or reviewer task with scope is refused): path globs the child may write; a scoped child has no shell and a write outside the scope is refused",
68
+ },
69
+ acceptance: {
70
+ type: "object",
71
+ properties: { check: { type: "string", minLength: 1 }, evaluator: { type: "string", minLength: 1 } },
72
+ additionalProperties: false,
73
+ description: `optional; implementer and tester only. Exactly one of: { check } naming a check configured by the user (configured now: ${Object.keys(cfg.checks).length ? Object.keys(cfg.checks).join(", ") : "none configured — omit acceptance"}), or { evaluator } — an absolute path to an evaluator script OUTSIDE the project. Never a command: the parent runs the acceptance after the child completes`,
74
+ },
75
+ model: { type: "string", minLength: 1, description: `a model profile configured by the user (configured now: ${cfg.profiles.length ? cfg.profiles.map((x) => (typeof x === "string" ? x : x.name ?? x.id ?? JSON.stringify(x))).join(", ") : "none — omit model"})` },
76
+ after: { type: "string", minLength: 1, description: "tester only: the earlier task (by its index, 1-based) whose worktree this tester runs in" },
77
+ timeoutMs: { type: "integer", minimum: 1000, description: "the child's wall-clock budget in milliseconds" },
61
78
  },
62
79
  required: ["role", "task"],
63
80
  additionalProperties: false,
@@ -66,7 +83,7 @@ const DELEGATE_PARAMETERS = {
66
83
  },
67
84
  required: ["tasks"],
68
85
  additionalProperties: false,
69
- };
86
+ });
70
87
 
71
88
  export default async function createSubagentExtension() {
72
89
  const depth = Number.parseInt(process.env.KISO_SUBAGENT_DEPTH ?? "0", 10) || 0;
@@ -77,10 +94,10 @@ export default async function createSubagentExtension() {
77
94
  {
78
95
  name: "delegate",
79
96
  description: "run subagent tasks (explorer/implementer/reviewer/tester) in child kiso processes",
80
- parameters: DELEGATE_PARAMETERS,
97
+ parameters: delegateParameters(delegationConfig()),
81
98
  execute: async (input, ctx) => {
82
99
  const tasks = ((input ?? {}).tasks ?? []).slice(0, 8);
83
- if (tasks.length === 0) return { content: "delegate: no tasks", isError: true };
100
+ if (tasks.length === 0) return { content: "delegate: no tasks", isError: true, errorKind: "precondition" };
84
101
  const sessionsDir = join(process.env.KISO_HOME ?? join(homedir(), ".kiso"), "sessions");
85
102
  // P3: the loop now threads the session id through
86
103
  // ToolContext.sessionId — the discovery heuristic below is
@@ -96,7 +113,7 @@ export default async function createSubagentExtension() {
96
113
  // KISO_HOME — never a per-task free path.
97
114
  const home = process.env.KISO_HOME ?? join(homedir(), ".kiso");
98
115
  const manifestDir = artifactDir(home, sessionsDir);
99
- if (manifestDir === null) return { content: "delegate: refused — KISO_SUBAGENT_ARTIFACTS must lie under KISO_HOME", isError: true };
116
+ if (manifestDir === null) return { content: "delegate: refused — KISO_SUBAGENT_ARTIFACTS must lie under KISO_HOME", isError: true, errorKind: "precondition" };
100
117
  mkdirSync(manifestDir, { recursive: true });
101
118
  // DT-1a: every task is validated BEFORE any child runs — a refusal
102
119
  // spawns nothing (acceptance never carries a model-supplied command).
@@ -104,7 +121,11 @@ export default async function createSubagentExtension() {
104
121
  const parentCwd = process.cwd();
105
122
  for (let i = 0; i < tasks.length; i += 1) {
106
123
  const why = validateTask(tasks[i], cfg, parentCwd, manifestDir);
107
- if (why !== null) return { content: `delegate: refused — task ${i + 1}: ${why}`, isError: true };
124
+ // DT1a-F1 (owner dogfood 2026-09-08): a refusal BEFORE any child exists is a
125
+ // precondition — nothing ran, nothing could have partially applied — so the
126
+ // kernel must not append the non-idempotent "side effects may have partially
127
+ // applied" banner (loop.ts keys that banner on errorKind !== "precondition")
128
+ if (why !== null) return { content: `delegate: refused — task ${i + 1}: ${why}`, isError: true, errorKind: "precondition" };
108
129
  }
109
130
  const sections = await runLimited(tasks, CONCURRENCY, (task, i) =>
110
131
  runChild({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vincemakes/kiso-subagent-ext",
3
- "version": "0.30.0",
3
+ "version": "0.31.1",
4
4
  "description": "kiso official subagent extension — child kiso processes with role policies, kernel untouched",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -23,7 +23,7 @@
23
23
  "test": "vitest run"
24
24
  },
25
25
  "devDependencies": {
26
- "@vincemakes/kiso-core": "0.30.0",
26
+ "@vincemakes/kiso-core": "0.31.1",
27
27
  "@types/node": "^26.1.2",
28
28
  "typescript": "^5.7.2",
29
29
  "vitest": "^3.0.0"