killeros 2.0.21 → 2.1.22

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,41 @@ All notable changes to KillerOS are documented here.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [2.1.22] - 2026-09-03
8
+
9
+ ### Added
10
+
11
+ - Added named goal completion checks, per-goal turn limits, and branch-aware `/goal history`.
12
+ - Added per-response TUI receipts for net Git changes and recognized verification results.
13
+
14
+ ### Changed
15
+
16
+ - Defaulted new goals to 20 turns, added safe `/goal checks` discovery, preserved blocker evidence in history, and separated pure goal parsing and history formatting.
17
+ - Refreshed footer Git telemetry from throttled filesystem changes instead of every completed turn, while retaining branch and 30-second fallback scans.
18
+
19
+ ### Fixed
20
+
21
+ - Prevented Linux CI test workers from waiting indefinitely on extension-owned handles after their tests finish.
22
+ - Made change receipts use a final repository scan, disable current Git filters, report line-ending-only edits, and recheck file goals after completion commands.
23
+ - Released automatic-compaction request state when Pi rejects an ordinary continuation before accepting its hidden message.
24
+ - Resumed ordinary tasks exactly once after automatic compaction and interrupted-turn settlement, keeping the hidden continuation pending until Pi accepts it.
25
+ - Allowed Git footer scans up to five seconds, contained rejected refreshes, and kept the last successful file-change status after transient failures.
26
+ - Recorded only exact check commands in response receipts, replaced verification claims with observed-check copy, and reserved `/goal` command words so malformed controls cannot start objectives.
27
+ - Rejected unsafe persisted goal counters, contained file-verification inference errors, and prevented stale completion checks from completing a newly restored goal.
28
+ - Kept lifecycle hooks stable for corrupt payload serialization, `NaN` direct timeouts, abort races, stream errors, and synchronous process completion without tightening custom process adapter contracts.
29
+
30
+ ## [2.0.22] - 2026-08-30
31
+
32
+ ### Changed
33
+
34
+ - Replaced the footer's changed-file total with a colored modified, added, and deleted breakdown.
35
+
36
+ ### Fixed
37
+
38
+ - Preserved the existing `createGitStatusRefresh` changed-file count callback contract.
39
+ - Rejected linked `AGENTS.local.md` files before reading personal instructions.
40
+ - Confirmed Windows hook process-tree cleanup before settling cancellations and timeouts, even when `taskkill` is absent from `PATH`.
41
+
7
42
  ## [2.0.21] - 2026-08-29
8
43
 
9
44
  ### Changed
package/Killeros.ts CHANGED
@@ -7,7 +7,9 @@ import {
7
7
  registerSlashAutocomplete,
8
8
  } from "./killeros/commands.ts";
9
9
  import { registerFooter } from "./killeros/footer.ts";
10
- import { registerGoal, registerGoalSettlement } from "./killeros/goals.ts";
10
+ import { registerGoalInterface } from "./killeros/goal-interface.ts";
11
+ import { registerGoalRuntime } from "./killeros/goal-runtime.ts";
12
+ import { registerGoalSettlement } from "./killeros/goal-settlement.ts";
11
13
  import { registerHandoff } from "./killeros/handoff.ts";
12
14
  import { registerLifecycleHooks } from "./killeros/hooks.ts";
13
15
  import { registerInitCommand, registerInitSettlement } from "./killeros/init.ts";
@@ -39,7 +41,8 @@ export default function Killeros(pi: ExtensionAPI, options: KillerosOptions = {}
39
41
  const goalRuntime = createGoalRuntime();
40
42
  const commandResolver = createSlashCommandResolver(pi);
41
43
  registerShellUi(pi, commandResolver);
42
- registerGoal(pi, goalRuntime, initRuntime);
44
+ registerGoalInterface(pi, goalRuntime, initRuntime);
45
+ registerGoalRuntime(pi, goalRuntime, initRuntime);
43
46
  registerPersonalInstructions(pi, initRuntime);
44
47
  registerQuestionTool(pi);
45
48
  registerAliases(pi);
package/README.md CHANGED
@@ -5,7 +5,7 @@ A TypeScript extension for the [Pi coding agent](https://github.com/earendil-wor
5
5
  ## What you get
6
6
 
7
7
  - A custom TUI: startup card with version, model, provider, working directory, and Git branch; a dark theme with coral accents; a multiline editor with slash-command completion; a footer that tracks model, context, and goal state; settled task receipts with duration and token usage.
8
- - `/goal`: set an objective and Pi keeps working toward it across turns, compaction, reloads, and branch navigation. Pause, resume, edit, or clear it anytime.
8
+ - `/goal`: set an objective and Pi keeps working toward it across turns, compaction, reloads, and branch navigation. New goals default to 20 turns. Named checks and turn limits control completion and unattended work.
9
9
  - `/init`: generates a root `AGENTS.md` from repository evidence, preserving compatible existing rules.
10
10
  - `/variants`: pick a reasoning level supported by the active model.
11
11
  - `/codex-fast`: toggles the `priority` service tier on Codex requests.
@@ -34,13 +34,18 @@ Or from GitHub:
34
34
  pi install git:github.com/KyrosHendrix/pi-KillerOS
35
35
  ```
36
36
 
37
- Pin a release by appending its tag, for example `@v2.0.21`. Add `-l` to install only for the current project. Restart Pi after installing.
37
+ Pin a release by appending its tag, for example `@v2.1.22`. Add `-l` to install only for the current project. Restart Pi after installing.
38
38
 
39
39
  ## Commands
40
40
 
41
41
  ```text
42
42
  /init Generate root AGENTS.md from repository evidence
43
- /goal Open goal status, or set an objective with /goal <objective>
43
+ /goal Open status, or set with /goal <objective>
44
+ /goal start [--check name] [--turns count] -- <objective>
45
+ /goal check <name|clear> Set or clear a named completion check
46
+ /goal checks List configured completion-check names
47
+ /goal limit <count|clear> Set a limit or clear it for unlimited turns
48
+ /goal history [count] Show transitions and blocker evidence on this branch
44
49
  /goal edit|pause|resume|clear
45
50
  /variants Reasoning-level selector (/variants high sets directly)
46
51
  /codex-fast Toggle Codex fast mode
@@ -74,6 +79,23 @@ The packaged `killeros` theme activates on TUI start. Compaction triggers by def
74
79
 
75
80
  `handoffMaxTokens` caps the `/handoff` summary output at 8192 tokens by default; raise it when long sessions truncate the summary.
76
81
 
82
+ Trusted projects can define up to 32 named goal checks in `.pi/killeros-hooks.json`:
83
+
84
+ ```json
85
+ {
86
+ "goalChecks": {
87
+ "quality": {
88
+ "command": "npm run check && npm test",
89
+ "timeoutMs": 300000
90
+ }
91
+ }
92
+ }
93
+ ```
94
+
95
+ Use `/goal checks` to list configured names. Use `/goal start -- <objective>` when an objective begins with `start`, `check`, `checks`, `limit`, `history`, `clear`, `edit`, `pause`, or `resume`. Bind a check with `/goal start --check quality -- <objective>` or `/goal check quality`. KillerOS stores the check name and definition hash, not the command. If the project changes the command or timeout, bind the check again before completing the goal.
96
+
97
+ New goals use a 20-turn limit unless `/goal start --turns <count> -- <objective>` supplies another value. Use `/goal limit <count>` to change the current goal or `/goal limit clear` to allow unlimited turns. Restored goals keep their persisted limit.
98
+
77
99
  Completion sounds are off by default; change with `/notification` in TUI mode. The tab-title indicator requires a Nerd Font.
78
100
 
79
101
  ## Development
@@ -35,10 +35,16 @@ export interface AutoCompactionDependencies {
35
35
  goal?: AutoCompactionGoalHandlers;
36
36
  }
37
37
 
38
- interface AutoCompactionRequest {
38
+ type AutoCompactionRequest = {
39
+ phase: "compacting";
39
40
  goal: boolean;
40
41
  token: symbol;
41
- }
42
+ turnSettled: boolean;
43
+ compactionCompleted: boolean;
44
+ } | {
45
+ phase: "continuation-dispatched";
46
+ goal: false;
47
+ };
42
48
 
43
49
  function isRecord(value: unknown): value is Record<string, unknown> {
44
50
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
@@ -157,7 +163,7 @@ export function registerAutoCompaction(
157
163
  goal: boolean,
158
164
  error: unknown,
159
165
  ): void => {
160
- if (!request || request.token !== token) return;
166
+ if (request?.phase !== "compacting" || request.token !== token) return;
161
167
  if (isSessionTooSmallCompactionError(error)) {
162
168
  finishSkip(ctx, goal);
163
169
  return;
@@ -165,6 +171,26 @@ export function registerAutoCompaction(
165
171
  finishFailure(ctx, goal, error);
166
172
  };
167
173
 
174
+ /** Dispatches one ordinary continuation after compaction and the interrupted run have both finished. */
175
+ const finalizeOrdinaryContinuation = (ctx: ExtensionContext, token: symbol): void => {
176
+ if (request?.phase !== "compacting"
177
+ || request.token !== token
178
+ || request.goal
179
+ || !request.turnSettled
180
+ || !request.compactionCompleted) return;
181
+ request = { phase: "continuation-dispatched", goal: false };
182
+ try {
183
+ pi.sendMessage({
184
+ customType: AUTO_COMPACTION_MESSAGE_TYPE,
185
+ content: AUTO_COMPACTION_MESSAGE,
186
+ display: false,
187
+ }, { triggerTurn: true, deliverAs: "followUp" });
188
+ } catch (error) {
189
+ request = undefined;
190
+ notifyFailure(ctx, error);
191
+ }
192
+ };
193
+
168
194
  pi.on("turn_end", (_event, ctx) => {
169
195
  if (!supportedMode(ctx) || request) return;
170
196
 
@@ -204,7 +230,13 @@ export function registerAutoCompaction(
204
230
  armed = false;
205
231
  const token = Symbol();
206
232
  const goal = dependencies.goal?.isActive(ctx) === true;
207
- request = { goal, token };
233
+ request = {
234
+ phase: "compacting",
235
+ goal,
236
+ token,
237
+ turnSettled: false,
238
+ compactionCompleted: false,
239
+ };
208
240
  if (goal && dependencies.goal) {
209
241
  try {
210
242
  dependencies.goal.onRequested();
@@ -217,9 +249,9 @@ export function registerAutoCompaction(
217
249
  try {
218
250
  ctx.compact({
219
251
  onComplete: () => {
220
- if (!request || request.token !== token) return;
221
- request = undefined;
252
+ if (request?.phase !== "compacting" || request.token !== token) return;
222
253
  if (goal && dependencies.goal) {
254
+ request = undefined;
223
255
  try {
224
256
  dependencies.goal.onCompleted(ctx);
225
257
  } catch (error) {
@@ -227,15 +259,8 @@ export function registerAutoCompaction(
227
259
  }
228
260
  return;
229
261
  }
230
- try {
231
- pi.sendMessage({
232
- customType: AUTO_COMPACTION_MESSAGE_TYPE,
233
- content: AUTO_COMPACTION_MESSAGE,
234
- display: false,
235
- }, { triggerTurn: true, deliverAs: "followUp" });
236
- } catch (error) {
237
- notifyFailure(ctx, error);
238
- }
262
+ request.compactionCompleted = true;
263
+ finalizeOrdinaryContinuation(ctx, token);
239
264
  },
240
265
  onError: (error) => finishRequestError(ctx, token, goal, error),
241
266
  });
@@ -244,6 +269,22 @@ export function registerAutoCompaction(
244
269
  }
245
270
  });
246
271
 
272
+ pi.on("agent_settled", (_event, ctx) => {
273
+ if (request?.phase === "continuation-dispatched") {
274
+ request = undefined;
275
+ notifyFailure(ctx, new Error("continuation was not accepted"));
276
+ return;
277
+ }
278
+ if (request?.phase !== "compacting" || request.goal) return;
279
+ request.turnSettled = true;
280
+ finalizeOrdinaryContinuation(ctx, request.token);
281
+ });
282
+ pi.on("message_start", (event) => {
283
+ if (request?.phase === "continuation-dispatched"
284
+ && event.message.role === "custom"
285
+ && event.message.customType === AUTO_COMPACTION_MESSAGE_TYPE) request = undefined;
286
+ });
287
+
247
288
  pi.on("session_start", resetForLifecycle);
248
289
  pi.on("session_shutdown", resetForLifecycle);
249
290
  pi.on("session_tree", resetForLifecycle);