killeros 1.5.5 → 1.5.6

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/CHANGELOG.md CHANGED
@@ -4,6 +4,14 @@ All notable changes to KillerOS are documented here.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [1.5.6] - 2026-08-05
8
+
9
+ ### Fixed
10
+
11
+ - Rejected unknown named subagent roles before child launch and returned the available roles instead of falling back to the write-capable `worker`.
12
+ - Kept the real child-boundary test isolated from parent Pi session variables and added direct coverage for inline parallel and chain spawns.
13
+ - Clarified and tested the shared `message` field limits: 20,000 characters for a spawn task alias and 4,000 characters for steering.
14
+
7
15
  ## [1.5.5] - 2026-08-05
8
16
 
9
17
  ### Added
package/README.md CHANGED
@@ -116,7 +116,7 @@ The tool supports a single `agent` plus `task` or its `message` alias, parallel
116
116
  | `resume` | `threadId` | `task` |
117
117
  | `close` | `threadId` | none |
118
118
 
119
- The three spawn shapes cannot be mixed. On a single spawn, `message` aliases `task`; supplying both is invalid. With `action: "steer"`, `message` remains required, and other lifecycle actions reject it. An unknown role name falls back to `worker` on a new spawn and reports that choice in the tool output. The `wait` action defaults to all queued or active children, waits up to 30 seconds by default, and never stops a child when it times out. The `resume` action keeps the same thread ID, name, session ID, and session directory and increments `attempt`; it requires the original named role and rejects inline roles. KillerOS rejects malformed requests before role discovery, project confirmation, thread creation, or child launch. The TUI shows a parallel or shared-pool schedule only after shape validation; malformed calls show `invalid request` instead of queued work. For example:
119
+ The three spawn shapes cannot be mixed. On a single spawn, `message` aliases `task` with the same 20,000-character limit; supplying both is invalid. With `action: "steer"`, `message` remains required and has a 4,000-character limit, while other lifecycle actions reject it. An unknown named role fails before child launch and reports the available roles. The `wait` action defaults to all queued or active children, waits up to 30 seconds by default, and never stops a child when it times out. The `resume` action keeps the same thread ID, name, session ID, and session directory and increments `attempt`; it requires the original named role and rejects inline roles. KillerOS rejects malformed requests before role discovery, project confirmation, thread creation, or child launch. The TUI shows a parallel or shared-pool schedule only after shape validation; malformed calls show `invalid request` instead of queued work. For example:
120
120
 
121
121
  ```json
122
122
  {"agent":"reviewer","task":"Review the change","name":"auth-audit","model":"provider/model","thinking":"high"}
@@ -1166,7 +1166,7 @@ function createSubagentParams(limits: Pick<SubagentLimits, "maxTasks" | "maxRead
1166
1166
  action: Type.Optional(StringEnum(SUBAGENT_ACTIONS, { default: SUBAGENT_ACTION.spawn, description: "Spawn, list, inspect, steer, interrupt, collect, wait, resume, or close. Omit threadId when spawning" })),
1167
1167
  threadId: Type.Optional(threadId),
1168
1168
  name: Type.Optional(Type.String({ minLength: 1, maxLength: 48, pattern: THREAD_NAME_PATTERN, description: "Parent-scoped child display name" })),
1169
- message: Type.Optional(Type.String({ minLength: 1, maxLength: Math.max(4_000, limits.taskCharacters), description: "Task alias when spawning; steering message with action steer" })),
1169
+ message: Type.Optional(Type.String({ minLength: 1, maxLength: Math.max(4_000, limits.taskCharacters), description: `Spawn task alias up to ${limits.taskCharacters.toLocaleString("en-US")} characters; steer message up to 4,000 characters` })),
1170
1170
  all: Type.Optional(Type.Literal(true, { description: "Target every active or queued child thread for interrupt or wait" })),
1171
1171
  timeoutMs: Type.Optional(Type.Integer({ minimum: 1, maximum: MAX_WAIT_TIMEOUT_MS, description: "Wait timeout in milliseconds; defaults to 30 seconds" })),
1172
1172
  agent: Type.Optional(agentSchema),
@@ -2292,26 +2292,18 @@ export function registerSubagentTool(pi: ExtensionAPI, options: SubagentRuntimeO
2292
2292
  const rawInputs: TaskInput[] = spawnRequest.kind === "spawn-single"
2293
2293
  ? [{ agent: spawnRequest.input.agent, task: spawnRequest.input.task, ...(spawnRequest.input.name ? { name: spawnRequest.input.name } : {}) }]
2294
2294
  : spawnRequest.kind === "spawn-parallel" ? spawnRequest.input.tasks : spawnRequest.input.chain;
2295
- const fallbackNotices: string[] = [];
2296
- const rolesForInputs = rawInputs.map((input) => {
2295
+ const rolesForInputs = rawInputs.map((input) => {
2297
2296
  if (typeof input.agent !== "string") {
2298
2297
  const parentTools = new Set(pi.getActiveTools());
2299
2298
  for (const tool of input.agent.tools) {
2300
2299
  if (!parentTools.has(tool)) throw new Error(`Inline role ${JSON.stringify(input.agent.name)} tool ${JSON.stringify(tool)} is not active for the parent`);
2301
2300
  }
2302
2301
  return inlineAgentRole(input.agent);
2303
- }
2302
+ }
2304
2303
  const selected = roles.get(input.agent);
2305
2304
  if (selected) return selected;
2306
- if (isResume) {
2307
- const available = discovery.agents.map((agent) => `${agent.name} (${agent.source})`).join(", ") || "none";
2308
- throw new Error(`Unknown subagent ${JSON.stringify(input.agent)}. Available: ${available}`);
2309
- }
2310
- const worker = roles.get("worker");
2311
- if (!worker) throw new Error(`Unknown subagent ${JSON.stringify(input.agent)} and fallback role "worker" is unavailable`);
2312
- const notice = `Unknown role ${JSON.stringify(input.agent)} - used worker`;
2313
- if (!fallbackNotices.includes(notice)) fallbackNotices.push(notice);
2314
- return worker;
2305
+ const available = discovery.agents.map((agent) => `${agent.name} (${agent.source})`).join(", ") || "none";
2306
+ throw new Error(`Unknown subagent ${JSON.stringify(input.agent)}. Available: ${available}`);
2315
2307
  });
2316
2308
  const inputs: Array<Omit<TaskInput, "agent"> & { agent: string }> = rawInputs.map((input, index) => ({
2317
2309
  ...input,
@@ -2351,7 +2343,7 @@ export function registerSubagentTool(pi: ExtensionAPI, options: SubagentRuntimeO
2351
2343
  ? `Parallel schedule: all tasks run through a shared pool of up to ${writerConcurrency}${writerConcurrencyOverride === undefined ? " (safe default)" : " (explicit)"}. Write-capable tasks are serialized in the shared parent worktree.`
2352
2344
  : `Parallel schedule: read-only tasks run concurrently up to ${limits.maxReadConcurrency}.`
2353
2345
  : undefined;
2354
- const executionNote = [...fallbackNotices, ...(scheduleNote ? [scheduleNote] : [])].join("\n") || undefined;
2346
+ const executionNote = scheduleNote;
2355
2347
 
2356
2348
  const inFlight = threads.listAll().filter((thread) => ["queued", "active"].includes(thread.state)).length;
2357
2349
  if (inFlight + inputs.length > limits.maxTasks) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "killeros",
3
- "version": "1.5.5",
3
+ "version": "1.5.6",
4
4
  "description": "A production-hardened TUI and workflow extension for the Pi coding agent.",
5
5
  "type": "module",
6
6
  "keywords": [