killeros 2.0.22 → 2.1.23

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.23] - 2026-09-04
8
+
9
+ ### Changed
10
+
11
+ - Simplified `/goal` to five forms with proof-by-prose and silent file proof, removing configured completion checks.
12
+
13
+ ### Fixed
14
+
15
+ - Kept the automatic 20-turn goal pause silent as documented.
16
+ - Stripped sentence punctuation from unquoted inferred goal paths and picked token units after rounding so 999.6 shows as 1k and 999999 as 1M.
17
+ - Increased change-receipt Git timeouts to five seconds and stopped timeout failures from showing warning notifications.
18
+
19
+ ## [2.1.22] - 2026-09-03
20
+
21
+ ### Added
22
+
23
+ - Added named goal completion checks, per-goal turn limits, and branch-aware `/goal history`.
24
+ - Added per-response TUI receipts for net Git changes and recognized verification results.
25
+
26
+ ### Changed
27
+
28
+ - Defaulted new goals to 20 turns, added safe `/goal checks` discovery, preserved blocker evidence in history, and separated pure goal parsing and history formatting.
29
+ - Refreshed footer Git telemetry from throttled filesystem changes instead of every completed turn, while retaining branch and 30-second fallback scans.
30
+
31
+ ### Fixed
32
+
33
+ - Prevented Linux CI test workers from waiting indefinitely on extension-owned handles after their tests finish.
34
+ - Made change receipts use a final repository scan, disable current Git filters, report line-ending-only edits, and recheck file goals after completion commands.
35
+ - Released automatic-compaction request state when Pi rejects an ordinary continuation before accepting its hidden message.
36
+ - Resumed ordinary tasks exactly once after automatic compaction and interrupted-turn settlement, keeping the hidden continuation pending until Pi accepts it.
37
+ - Allowed Git footer scans up to five seconds, contained rejected refreshes, and kept the last successful file-change status after transient failures.
38
+ - 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.
39
+ - Rejected unsafe persisted goal counters, contained file-verification inference errors, and prevented stale completion checks from completing a newly restored goal.
40
+ - 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.
41
+
7
42
  ## [2.0.22] - 2026-08-30
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 pause after 20 turns; `/goal resume` grants another 20.
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,14 +34,17 @@ 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.22`. 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.23`. 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>
44
- /goal edit|pause|resume|clear
43
+ /goal View the current goal
44
+ /goal <objective> Set an objective
45
+ /goal pause Stop automatic continuation
46
+ /goal resume Resume automatic continuation
47
+ /goal clear Remove the current goal
45
48
  /variants Reasoning-level selector (/variants high sets directly)
46
49
  /codex-fast Toggle Codex fast mode
47
50
  /notification Configure the completion sound
@@ -55,7 +58,7 @@ Pin a release by appending its tag, for example `@v2.0.22`. Add `-l` to install
55
58
  | Mode | What works |
56
59
  | --- | --- |
57
60
  | TUI | Everything |
58
- | RPC | Goals, proactive compaction; no TUI components, `/goal edit`, `/init`, sounds, title indicator |
61
+ | RPC | Goals, proactive compaction; no TUI components, `/init`, sounds, title indicator |
59
62
  | Print/JSON | No interactive questions, `/goal`, `/init`, or proactive compaction |
60
63
 
61
64
  ## Configuration
@@ -74,6 +77,20 @@ The packaged `killeros` theme activates on TUI start. Compaction triggers by def
74
77
 
75
78
  `handoffMaxTokens` caps the `/handoff` summary output at 8192 tokens by default; raise it when long sessions truncate the summary.
76
79
 
80
+ State proof in the objective so the agent can verify it with its normal tools:
81
+
82
+ ```text
83
+ /goal Reduce p95 checkout latency below 120 ms, verified by the checkout benchmark, while keeping the correctness suite green
84
+ ```
85
+
86
+ A direct quoted file target binds silent file proof:
87
+
88
+ ```text
89
+ /goal Fix `killeros/footer.ts`, verified by npm test
90
+ ```
91
+
92
+ KillerOS captures the file baseline at goal start and only completes when the file is created or changed. New goals pause after 20 turns without warning. An explicit `/goal resume` on an exhausted goal grants another 20 turns; compaction recovery never grants turns. Restored goals keep their persisted limit.
93
+
77
94
  Completion sounds are off by default; change with `/notification` in TUI mode. The tab-title indicator requires a Nerd Font.
78
95
 
79
96
  ## 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);