killeros 2.0.7 → 2.0.9
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 +21 -0
- package/Killeros.ts +28 -8
- package/README.md +145 -141
- package/killeros/commands.ts +108 -34
- package/killeros/decision-gated-workflow.ts +76 -0
- package/killeros/question.ts +24 -6
- package/killeros/shell-ui.ts +109 -5
- package/killeros/workflow-gate.ts +347 -0
- package/package.json +4 -4
- package/killeros/concise.ts +0 -69
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,27 @@ All notable changes to KillerOS are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [2.0.9] - 2026-08-15
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Highlighted exact, currently registered slash commands in the TUI editor with the theme's shared command-blue link role while preserving autocomplete boundaries and ANSI cursor styling.
|
|
12
|
+
|
|
13
|
+
## [2.0.8] - 2026-08-15
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- Added a reusable, opt-in pre-turn gate for explicitly activated decision-gated workflows. It opens the shared structured question UI before skill expansion, keeps the selected policy active, blocks unknown and disallowed tools, and clears safely across lifecycle boundaries.
|
|
18
|
+
- Added a disposable decision-gated workflow fixture and focused coverage for activation ordering, pending safety, policy allowlists, lifecycle cleanup, adapter reuse, and Pi 0.84.2 compatibility.
|
|
19
|
+
|
|
20
|
+
### Removed
|
|
21
|
+
|
|
22
|
+
- Removed KillerOS's always-on concise response policy and provider-specific concise defaults; Pi now owns response-style guidance.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- Raised the locked direct Pi development packages to 0.84.2 while keeping the peer dependency floor at 0.84.1.
|
|
27
|
+
|
|
7
28
|
## [2.0.7] - 2026-08-13
|
|
8
29
|
|
|
9
30
|
### Changed
|
package/Killeros.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { registerRequestActivity } from "./killeros/activity.ts";
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
createSlashCommandResolver,
|
|
5
|
+
registerAliases,
|
|
6
|
+
registerSlashAutocomplete,
|
|
7
|
+
} from "./killeros/commands.ts";
|
|
5
8
|
import { registerFooter } from "./killeros/footer.ts";
|
|
6
9
|
import { registerGoal, registerGoalSettlement } from "./killeros/goals.ts";
|
|
7
10
|
import { registerLifecycleHooks } from "./killeros/hooks.ts";
|
|
@@ -11,33 +14,50 @@ import {
|
|
|
11
14
|
type CompletionNotificationDependencies,
|
|
12
15
|
} from "./killeros/notifications.ts";
|
|
13
16
|
import { registerPersonalInstructions } from "./killeros/personal-instructions.ts";
|
|
14
|
-
import { registerQuestionTool } from "./killeros/question.ts";
|
|
17
|
+
import { registerQuestionTool, type QuestionRunner } from "./killeros/question.ts";
|
|
18
|
+
import { createDecisionGatedWorkflowAdapter } from "./killeros/decision-gated-workflow.ts";
|
|
15
19
|
import { createGoalRuntime, createInitRuntime } from "./killeros/runtime.ts";
|
|
16
20
|
import { registerShellUi } from "./killeros/shell-ui.ts";
|
|
17
21
|
import { registerVariants } from "./killeros/variants.ts";
|
|
18
22
|
import { registerWorkedFor } from "./killeros/worked-for.ts";
|
|
23
|
+
import { registerWorkflowGate, type WorkflowAdapter } from "./killeros/workflow-gate.ts";
|
|
19
24
|
|
|
20
|
-
export { CONCISE_SYSTEM_PROMPT, isConciseEnabled, isConcisedEnabled } from "./killeros/concise.ts";
|
|
21
25
|
export { contextPercentRemaining, formatCost, formatContextProgress } from "./killeros/footer.ts";
|
|
22
26
|
export { executeHook } from "./killeros/hooks.ts";
|
|
23
27
|
export { INIT_WORKFLOW_PROMPT } from "./killeros/init.ts";
|
|
24
28
|
export { buildInitEvidence, listInitEvidence, readInitEvidence } from "./killeros/init-evidence.ts";
|
|
25
29
|
export { captureInitTargetBaseline, installInitAgentsFile, validateGeneratedGuidance, writeInitAgentsFile } from "./killeros/init-target.ts";
|
|
30
|
+
export { createDecisionGatedWorkflowAdapter } from "./killeros/decision-gated-workflow.ts";
|
|
31
|
+
export { explicitSkillActivation, registerWorkflowGate } from "./killeros/workflow-gate.ts";
|
|
32
|
+
export type {
|
|
33
|
+
WorkflowAdapter,
|
|
34
|
+
WorkflowGateController,
|
|
35
|
+
WorkflowGateState,
|
|
36
|
+
WorkflowPolicy,
|
|
37
|
+
WorkflowTerminalReason,
|
|
38
|
+
WorkflowToolAuthorization,
|
|
39
|
+
} from "./killeros/workflow-gate.ts";
|
|
26
40
|
|
|
27
41
|
export interface KillerosOptions {
|
|
28
42
|
completionNotifications?: CompletionNotificationDependencies;
|
|
43
|
+
decisionGatedWorkflows?: readonly WorkflowAdapter[];
|
|
29
44
|
}
|
|
30
45
|
|
|
31
46
|
export default function Killeros(pi: ExtensionAPI, options: KillerosOptions = {}): void {
|
|
32
47
|
const initRuntime = createInitRuntime();
|
|
33
48
|
const goalRuntime = createGoalRuntime();
|
|
34
|
-
|
|
35
|
-
|
|
49
|
+
const commandResolver = createSlashCommandResolver(pi);
|
|
50
|
+
registerShellUi(pi, commandResolver);
|
|
36
51
|
registerGoal(pi, goalRuntime, initRuntime);
|
|
37
52
|
registerPersonalInstructions(pi, initRuntime);
|
|
38
|
-
registerQuestionTool(pi);
|
|
53
|
+
const questionRunner: QuestionRunner = registerQuestionTool(pi);
|
|
54
|
+
registerWorkflowGate(
|
|
55
|
+
pi,
|
|
56
|
+
questionRunner,
|
|
57
|
+
options.decisionGatedWorkflows ?? [createDecisionGatedWorkflowAdapter()],
|
|
58
|
+
);
|
|
39
59
|
registerAliases(pi);
|
|
40
|
-
registerSlashAutocomplete(pi);
|
|
60
|
+
registerSlashAutocomplete(pi, commandResolver);
|
|
41
61
|
registerFooter(pi, goalRuntime);
|
|
42
62
|
registerVariants(pi);
|
|
43
63
|
registerInitCommand(pi, initRuntime, goalRuntime);
|
package/README.md
CHANGED
|
@@ -1,147 +1,151 @@
|
|
|
1
|
-
# KillerOS
|
|
2
|
-
|
|
3
|
-
A production-hardened Pi extension that combines a custom TUI, repository initialization, long-running goals, reasoning controls, interactive questions, command aliases
|
|
4
|
-
|
|
5
|
-
## Requirements
|
|
6
|
-
|
|
7
|
-
- Node.js `22.19.0` or later
|
|
8
|
-
- Pi `0.84.
|
|
9
|
-
- Interactive TUI mode for the custom header, editor, footer, `question` tool, and `/init`
|
|
10
|
-
|
|
11
|
-
The extension is strict TypeScript. Pi provides the runtime modules.
|
|
12
|
-
|
|
13
|
-
## Install
|
|
14
|
-
|
|
15
|
-
### npm
|
|
16
|
-
|
|
17
|
-
Install KillerOS:
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
pi install npm:killeros
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
### Git
|
|
24
|
-
|
|
25
|
-
Install the latest commit:
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
pi install git:github.com/KyrosHendrix/pi-KillerOS
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
Pin an install to a release:
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
pi install git:github.com/KyrosHendrix/pi-KillerOS@v2.0.
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Add `-l` to either command for a project-only install. Restart Pi after installing.
|
|
38
|
-
|
|
39
|
-
## Features
|
|
40
|
-
|
|
41
|
-
- 52-column Compact startup card with inline version, polished model/provider identity, adjacent `/model`, directory, conditional Git branch, and a shuffled session-stable tip
|
|
42
|
-
- Cohesive dark theme with coral accents and neutral tool-call containers across pending, success, and error states
|
|
1
|
+
# KillerOS
|
|
2
|
+
|
|
3
|
+
A production-hardened Pi extension that combines a custom TUI, repository initialization, long-running goals, reasoning controls, interactive questions, and command aliases.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- Node.js `22.19.0` or later
|
|
8
|
+
- Pi `0.84.2` or later
|
|
9
|
+
- Interactive TUI mode for the custom header, editor, footer, `question` tool, and `/init`
|
|
10
|
+
|
|
11
|
+
The extension is strict TypeScript. Pi provides the runtime modules.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
### npm
|
|
16
|
+
|
|
17
|
+
Install KillerOS:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pi install npm:killeros
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Git
|
|
24
|
+
|
|
25
|
+
Install the latest commit:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pi install git:github.com/KyrosHendrix/pi-KillerOS
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Pin an install to a release:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pi install git:github.com/KyrosHendrix/pi-KillerOS@v2.0.9
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Add `-l` to either command for a project-only install. Restart Pi after installing.
|
|
38
|
+
|
|
39
|
+
## Features
|
|
40
|
+
|
|
41
|
+
- 52-column Compact startup card with inline version, polished model/provider identity, adjacent `/model`, directory, conditional Git branch, and a shuffled session-stable tip
|
|
42
|
+
- Cohesive dark theme with coral accents and neutral tool-call containers across pending, success, and error states
|
|
43
43
|
- Animated orange 12-frame activity glyph loop at 120 ms per frame with contextual copy derived from request, tool, result, and response events, plus a quiet hidden-thinking label
|
|
44
44
|
- Frameless multiline editor with one focus-aware `❯`, a shuffled session-stable empty-state suggestion, overflow-only scroll indicators, Shift+Enter support, and slash-command autocomplete; KillerOS preserves an editor factory configured by another extension
|
|
45
45
|
- One compact TUI transcript line reporting truthful `Done`, `Stopped`, or `Failed` settlement with elapsed time while preserving older `✻ Worked for …` entries
|
|
46
46
|
- Compact two-deck footer with session state above workspace state; model, context, and active goals stay prioritized as reasoning, time, cost, branch, and path reduce by available width
|
|
47
|
-
- Pi-owned context compaction with active goals continuing from Pi's settled boundary after manual, threshold, and overflow compaction
|
|
48
|
-
- Optional completion sounds after successful or failed settled requests, excluding manual aborts
|
|
49
|
-
- `/variants` selector and direct reasoning-level arguments
|
|
50
|
-
- Codex-style `/goal` with an interactive status/action panel, durable objectives, immediate pause and clear cancellation, automatic continuation, explicit completion, and durable blocker audits
|
|
51
|
-
- Automatic `/init` guideline synthesis with a frozen safe evidence map, protected existing policy, and the four packaged behavioral sections adapted from `writing-great-guidelines`
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
|
|
57
|
-
## Commands
|
|
58
|
-
|
|
59
|
-
```text
|
|
60
|
-
/init Generate root AGENTS.md from repository evidence
|
|
61
|
-
/goal Open current goal status and valid actions
|
|
62
|
-
/goal <objective> Set an objective and start working
|
|
63
|
-
/goal edit Edit and reactivate the current goal
|
|
64
|
-
/goal pause Stop the current goal turn and automatic continuation
|
|
65
|
-
/goal resume Resume automatic continuation
|
|
66
|
-
/goal clear Stop current goal work and remove the goal
|
|
67
|
-
/variants Open the reasoning-level selector
|
|
68
|
-
/variants high Set a reasoning level directly
|
|
69
|
-
/notification Configure the completion sound
|
|
70
|
-
/clear Start a new session after confirmation
|
|
71
|
-
/exit Quit Pi gracefully
|
|
72
|
-
```
|
|
73
|
-
|
|
47
|
+
- Pi-owned context compaction with active goals continuing from Pi's settled boundary after manual, threshold, and overflow compaction
|
|
48
|
+
- Optional completion sounds after successful or failed settled requests, excluding manual aborts
|
|
49
|
+
- `/variants` selector and direct reasoning-level arguments
|
|
50
|
+
- Codex-style `/goal` with an interactive status/action panel, durable objectives, immediate pause and clear cancellation, automatic continuation, explicit completion, and durable blocker audits
|
|
51
|
+
- Automatic `/init` guideline synthesis with a frozen safe evidence map, protected existing policy, and the four packaged behavioral sections adapted from `writing-great-guidelines`
|
|
52
|
+
- Opt-in decision-gated workflows that ask a structured policy question before explicit skill expansion, preserve the selected allowlist, and fail closed across tool and session boundaries
|
|
53
|
+
- `question` tool with single-select and opt-in bounded multi-select, height-bounded option windows, configured Pi keybindings, live option/input progress, proposal previews, custom answers, history, cancellation, and compact expandable transcript rendering
|
|
54
|
+
- Mid-prompt slash completion with current Pi `0.84.2` commands, extensions, prompts, and skills; paths, URLs, and invalid commands remain plain text
|
|
55
|
+
- Goal-aware `/clear` that confirms, aborts active work, waits for settlement, and starts a new session, plus `/exit` for graceful shutdown
|
|
56
|
+
|
|
57
|
+
## Commands
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
/init Generate root AGENTS.md from repository evidence
|
|
61
|
+
/goal Open current goal status and valid actions
|
|
62
|
+
/goal <objective> Set an objective and start working
|
|
63
|
+
/goal edit Edit and reactivate the current goal
|
|
64
|
+
/goal pause Stop the current goal turn and automatic continuation
|
|
65
|
+
/goal resume Resume automatic continuation
|
|
66
|
+
/goal clear Stop current goal work and remove the goal
|
|
67
|
+
/variants Open the reasoning-level selector
|
|
68
|
+
/variants high Set a reasoning level directly
|
|
69
|
+
/notification Configure the completion sound
|
|
70
|
+
/clear Start a new session after confirmation
|
|
71
|
+
/exit Quit Pi gracefully
|
|
72
|
+
```
|
|
73
|
+
|
|
74
74
|
`/goal` requires a saved session in TUI or RPC mode. Goal state is stored in versioned session entries on the active branch and restored after reload, resume, fork, or tree navigation. Active goals inject their unchanged objective every turn and continue one settled turn at a time. The model must use KillerOS’s private goal tool to report completion. For an objective that clearly asks to create, write, save, or generate a named file-like deliverable at one quoted absolute path, KillerOS saves that exact path with the goal and verifies that a regular file exists there before accepting completion. Other objectives retain model-reported completion. Blocking requires one stable lowercase blocker key recorded on three consecutive goal turns; a changed key, skipped turn, resume, or edit resets the streak. Final prose alone does not end the loop.
|
|
75
|
-
|
|
76
|
-
`/goal pause` and `/goal clear` save paused or cleared state before aborting current goal work, so settlement cannot restart it. Aborted turns, provider failures, and continuation failures otherwise pause safely. Failed edit and replacement writes dispatch no edited objective; an active prior objective pauses fail-closed, while inactive durable state remains unchanged. Replacing unfinished work requires confirmation, and `/goal edit` requires TUI mode.
|
|
77
|
-
|
|
78
|
-
`/init` freezes a safe project-file map and exposes only dedicated read and list operations while it generates root `AGENTS.md`. Git-ignored files, known secret paths, private-key formats, other guidance, dependencies, links, non-regular files, and files outside that map are unavailable. Existing root `AGENTS.md` is separate protected policy: compatible rules are preserved, a real policy conflict leaves it unchanged with a reason, and any concurrent target change aborts installation without replacing the newer file.
|
|
79
|
-
|
|
80
|
-
The generated file uses the four behavioral sections adapted from `writing-great-guidelines`; no external skill installation is required. `/init` asks no setup questions, starts no second model process, writes no other file, and reloads Pi resources only after a successful write.
|
|
81
|
-
|
|
82
|
-
###
|
|
83
|
-
|
|
75
|
+
|
|
76
|
+
`/goal pause` and `/goal clear` save paused or cleared state before aborting current goal work, so settlement cannot restart it. Aborted turns, provider failures, and continuation failures otherwise pause safely. Failed edit and replacement writes dispatch no edited objective; an active prior objective pauses fail-closed, while inactive durable state remains unchanged. Replacing unfinished work requires confirmation, and `/goal edit` requires TUI mode.
|
|
77
|
+
|
|
78
|
+
`/init` freezes a safe project-file map and exposes only dedicated read and list operations while it generates root `AGENTS.md`. Git-ignored files, known secret paths, private-key formats, other guidance, dependencies, links, non-regular files, and files outside that map are unavailable. Existing root `AGENTS.md` is separate protected policy: compatible rules are preserved, a real policy conflict leaves it unchanged with a reason, and any concurrent target change aborts installation without replacing the newer file.
|
|
79
|
+
|
|
80
|
+
The generated file uses the four behavioral sections adapted from `writing-great-guidelines`; no external skill installation is required. `/init` asks no setup questions, starts no second model process, writes no other file, and reloads Pi resources only after a successful write.
|
|
81
|
+
|
|
82
|
+
### Decision-gated workflows
|
|
83
|
+
|
|
84
|
+
Explicit `/skill:decision-gated-workflow` activation opens the shared question UI before Pi expands the skill. `Normal` allows only interview and read-only tools; `With docs` additionally permits agreed glossary, context-map, and ADR paths. The selected policy remains active until the workflow is explicitly finished or cancelled, and lifecycle changes clear it safely. Extensions can supply additional adapters through `KillerosOptions.decisionGatedWorkflows`.
|
|
85
|
+
|
|
86
|
+
### Interactive questions
|
|
87
|
+
|
|
84
88
|
Single-select remains the default. Explicit `minSelections: 1` and `maxSelections: 1` are equivalent to omitting both bounds; other single-select bounds are rejected. An agent opts into multi-select with `mode: "multiple"` and may set `minSelections` and `maxSelections`; the custom answer counts as one selection.
|
|
85
|
-
|
|
86
|
-
In multi-select, use Space or a visible number to toggle an option, `/` to filter, and Enter to submit. The filter accepts spaces; Enter applies it and Escape returns to the choices. Checked options remain selected when the filter changes. Select **Type a custom answer** with Enter to add or edit one custom item alongside checked options.
|
|
87
|
-
|
|
88
|
-
Supported reasoning levels are `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, and `max`. KillerOS limits choices to levels supported by the current model.
|
|
89
|
-
|
|
90
|
-
## Configuration
|
|
91
|
-
|
|
92
|
-
KillerOS activates its packaged `killeros` theme when a TUI session starts. Tool-call backgrounds stay neutral across pending, successful, and failed states; restrained text and icons preserve status visibility.
|
|
93
|
-
|
|
94
|
-
The completion sound is a global user preference stored in Pi's agent directory and is off by default. Run `/notification` in TUI mode to enable or disable it; enabling does not play a preview. Enabled TUI tabs append ``, which requires a Nerd Font in the terminal tab UI. An unsupported font may show a box without affecting sound. KillerOS uses the terminal's audible bell and cannot produce sound when the terminal disables it.
|
|
95
|
-
|
|
96
|
-
KillerOS displays session costs in USD. The footer uses Pi's human-readable model name when available, keeps the provider visually secondary, and renders context as `percent left (tokens)` without a progress bar. An active goal replaces the right-side path with warning-yellow `/goal is active (...)` and keeps exact seconds in minute and hour formats. Paused and blocked goals retain their existing placement; completed goals remain in transcript history and `/goal` status rather than the footer. At narrow widths, context pressure and actionable goal state take priority.
|
|
97
|
-
|
|
98
|
-
Pi decides when compaction runs and Pi writes the summary, applies manual focus instructions, tracks files, retries summarization, and handles overflow recovery. KillerOS does not add a second threshold or replace Pi's summary. Active `/goal` work continues from Pi's settled boundary, after Pi finishes retries, compaction, and queued work.
|
|
99
|
-
|
|
100
|
-
Manual `/compact` aborts the current goal turn before summarization, so KillerOS records an honest temporary pause for that exact goal revision. After Pi saves the manual summary, KillerOS resumes that revision automatically. A failed or cancelled manual compaction stays paused; run `/goal pause` during the pause to cancel automatic recovery.
|
|
101
|
-
|
|
102
|
-
For trusted projects, KillerOS loads `AGENTS.local.md` after Pi's shared repository context. A one-line `@path` or `@~/path` file imports personal guidance from another location.
|
|
103
|
-
|
|
104
|
-
Lifecycle hooks are loaded from `.pi/killeros-hooks.json` at session start. Supported event keys are `tool_call`, `tool_result`, and `agent_settled`. Optional matchers are JavaScript regular expressions over Pi tool names, so they are valid only for `tool_call` and `tool_result`; KillerOS rejects an `agent_settled` hook that defines a matcher. Hook commands run from the repository root with `KILLEROS_EVENT`, `KILLEROS_TOOL`, and `KILLEROS_PAYLOAD` environment variables. Failed `tool_call` hooks block the tool, while later-event failures notify the user. Aborting the parent request stops the hook process tree with bounded graceful and forced cleanup without reporting cancellation as a hook failure.
|
|
105
|
-
|
|
106
|
-
## Behavior by mode
|
|
107
|
-
|
|
108
|
-
| Mode | Behavior |
|
|
109
|
-
|---|---|
|
|
110
|
-
| TUI | All features are available, including the completion sound and tab-title indicator |
|
|
111
|
-
| RPC | Goal set/view/pause/resume/clear
|
|
112
|
-
| Print/JSON |
|
|
113
|
-
|
|
114
|
-
## Validation
|
|
115
|
-
|
|
116
|
-
Before release, run:
|
|
117
|
-
|
|
118
|
-
```bash
|
|
119
|
-
npm ci
|
|
120
|
-
npm run check
|
|
121
|
-
npm test
|
|
122
|
-
npm pack --dry-run
|
|
123
|
-
pi -ne -e . --mode rpc
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
The package manifest lists Pi’s built-in modules as peer dependencies, so npm does not bundle a second copy.
|
|
127
|
-
|
|
128
|
-
## Publish
|
|
129
|
-
|
|
130
|
-
To create a GitHub release, update the version in `package.json` and `package-lock.json`, add the matching `CHANGELOG.md` section, and push the release commit to `main`. After the full CI workflow passes, the release workflow creates the matching tag and GitHub release from that verified commit.
|
|
131
|
-
|
|
132
|
-
Do not manually tag a normal release. If automation must recover a missing GitHub release, push the matching version tag; the same workflow validates the tag against the package and changelog before creating the release.
|
|
133
|
-
|
|
134
|
-
The [`pi-package`](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/packages.md) keyword makes a published npm release visible in Pi’s package catalog. GitHub release automation does not publish to npm. Publish there separately after validation:
|
|
135
|
-
|
|
136
|
-
```bash
|
|
137
|
-
npm login
|
|
138
|
-
npm publish
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
## Security
|
|
142
|
-
|
|
143
|
-
Pi extensions run with your user permissions. Review the source before installing KillerOS globally. KillerOS executes lifecycle hook commands only for projects Pi marks as trusted; review `.pi/killeros-hooks.json` before enabling project trust.
|
|
144
|
-
|
|
145
|
-
## License
|
|
146
|
-
|
|
147
|
-
[MIT](LICENSE) © 2026 KyrosHendrix
|
|
89
|
+
|
|
90
|
+
In multi-select, use Space or a visible number to toggle an option, `/` to filter, and Enter to submit. The filter accepts spaces; Enter applies it and Escape returns to the choices. Checked options remain selected when the filter changes. Select **Type a custom answer** with Enter to add or edit one custom item alongside checked options.
|
|
91
|
+
|
|
92
|
+
Supported reasoning levels are `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, and `max`. KillerOS limits choices to levels supported by the current model.
|
|
93
|
+
|
|
94
|
+
## Configuration
|
|
95
|
+
|
|
96
|
+
KillerOS activates its packaged `killeros` theme when a TUI session starts. Tool-call backgrounds stay neutral across pending, successful, and failed states; restrained text and icons preserve status visibility.
|
|
97
|
+
|
|
98
|
+
The completion sound is a global user preference stored in Pi's agent directory and is off by default. Run `/notification` in TUI mode to enable or disable it; enabling does not play a preview. Enabled TUI tabs append ``, which requires a Nerd Font in the terminal tab UI. An unsupported font may show a box without affecting sound. KillerOS uses the terminal's audible bell and cannot produce sound when the terminal disables it.
|
|
99
|
+
|
|
100
|
+
KillerOS displays session costs in USD. The footer uses Pi's human-readable model name when available, keeps the provider visually secondary, and renders context as `percent left (tokens)` without a progress bar. An active goal replaces the right-side path with warning-yellow `/goal is active (...)` and keeps exact seconds in minute and hour formats. Paused and blocked goals retain their existing placement; completed goals remain in transcript history and `/goal` status rather than the footer. At narrow widths, context pressure and actionable goal state take priority.
|
|
101
|
+
|
|
102
|
+
Pi decides when compaction runs and Pi writes the summary, applies manual focus instructions, tracks files, retries summarization, and handles overflow recovery. KillerOS does not add a second threshold or replace Pi's summary. Active `/goal` work continues from Pi's settled boundary, after Pi finishes retries, compaction, and queued work.
|
|
103
|
+
|
|
104
|
+
Manual `/compact` aborts the current goal turn before summarization, so KillerOS records an honest temporary pause for that exact goal revision. After Pi saves the manual summary, KillerOS resumes that revision automatically. A failed or cancelled manual compaction stays paused; run `/goal pause` during the pause to cancel automatic recovery.
|
|
105
|
+
|
|
106
|
+
For trusted projects, KillerOS loads `AGENTS.local.md` after Pi's shared repository context. A one-line `@path` or `@~/path` file imports personal guidance from another location.
|
|
107
|
+
|
|
108
|
+
Lifecycle hooks are loaded from `.pi/killeros-hooks.json` at session start. Supported event keys are `tool_call`, `tool_result`, and `agent_settled`. Optional matchers are JavaScript regular expressions over Pi tool names, so they are valid only for `tool_call` and `tool_result`; KillerOS rejects an `agent_settled` hook that defines a matcher. Hook commands run from the repository root with `KILLEROS_EVENT`, `KILLEROS_TOOL`, and `KILLEROS_PAYLOAD` environment variables. Failed `tool_call` hooks block the tool, while later-event failures notify the user. Aborting the parent request stops the hook process tree with bounded graceful and forced cleanup without reporting cancellation as a hook failure.
|
|
109
|
+
|
|
110
|
+
## Behavior by mode
|
|
111
|
+
|
|
112
|
+
| Mode | Behavior |
|
|
113
|
+
|---|---|
|
|
114
|
+
| TUI | All features are available, including the completion sound and tab-title indicator |
|
|
115
|
+
| RPC | Goal set/view/pause/resume/clear work; TUI components, `/goal edit`, `/init`, completion sounds, and the title indicator are disabled |
|
|
116
|
+
| Print/JSON | Interactive questions, `/goal`, and `/init` fail explicitly; completion sounds and the title indicator are disabled |
|
|
117
|
+
|
|
118
|
+
## Validation
|
|
119
|
+
|
|
120
|
+
Before release, run:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npm ci
|
|
124
|
+
npm run check
|
|
125
|
+
npm test
|
|
126
|
+
npm pack --dry-run
|
|
127
|
+
pi -ne -e . --mode rpc
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The package manifest lists Pi’s built-in modules as peer dependencies, so npm does not bundle a second copy.
|
|
131
|
+
|
|
132
|
+
## Publish
|
|
133
|
+
|
|
134
|
+
To create a GitHub release, update the version in `package.json` and `package-lock.json`, add the matching `CHANGELOG.md` section, and push the release commit to `main`. After the full CI workflow passes, the release workflow creates the matching tag and GitHub release from that verified commit.
|
|
135
|
+
|
|
136
|
+
Do not manually tag a normal release. If automation must recover a missing GitHub release, push the matching version tag; the same workflow validates the tag against the package and changelog before creating the release.
|
|
137
|
+
|
|
138
|
+
The [`pi-package`](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/packages.md) keyword makes a published npm release visible in Pi’s package catalog. GitHub release automation does not publish to npm. Publish there separately after validation:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
npm login
|
|
142
|
+
npm publish
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Security
|
|
146
|
+
|
|
147
|
+
Pi extensions run with your user permissions. Review the source before installing KillerOS globally. KillerOS executes lifecycle hook commands only for projects Pi marks as trusted; review `.pi/killeros-hooks.json` before enabling project trust.
|
|
148
|
+
|
|
149
|
+
## License
|
|
150
|
+
|
|
151
|
+
[MIT](LICENSE) © 2026 KyrosHendrix
|
package/killeros/commands.ts
CHANGED
|
@@ -30,6 +30,19 @@ interface CommandInfo {
|
|
|
30
30
|
syntaxHint?: string;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
export interface SlashCommandToken {
|
|
34
|
+
name: string;
|
|
35
|
+
start: number;
|
|
36
|
+
end: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface SlashCommandResolver {
|
|
40
|
+
clearFallbackCommands(): void;
|
|
41
|
+
updateFallbackCommands(items: readonly AutocompleteItem[]): void;
|
|
42
|
+
getCommandCatalog(baseSuggestions?: readonly AutocompleteItem[]): ReadonlyMap<string, CommandInfo>;
|
|
43
|
+
isValidCommand(name: string): boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
33
46
|
const BUILTIN_COMMANDS: ReadonlyArray<{ name: string; description: string }> = [
|
|
34
47
|
{ name: "settings", description: "Open settings menu" },
|
|
35
48
|
{ name: "model", description: "Select model" },
|
|
@@ -70,6 +83,87 @@ interface TaggedAutocompleteItem extends AutocompleteItem {
|
|
|
70
83
|
killerosCommand?: string;
|
|
71
84
|
}
|
|
72
85
|
|
|
86
|
+
const SLASH_COMMAND_PREFIX_PATTERN = /(?:^|[ \t])\/([^\s/]*)$/u;
|
|
87
|
+
const SLASH_COMMAND_TOKEN_PATTERN = /(?:^|[ \t])\/([^\s/]+)(?=$|[ \t])/gu;
|
|
88
|
+
|
|
89
|
+
export function getSlashCommandPrefix(line: string): { prefix: string; slashIndex: number } | undefined {
|
|
90
|
+
const match = SLASH_COMMAND_PREFIX_PATTERN.exec(line);
|
|
91
|
+
if (!match || match.index === undefined) return undefined;
|
|
92
|
+
const prefix = match[1] ?? "";
|
|
93
|
+
const slashIndex = match.index + (match[0].startsWith("/") ? 0 : 1);
|
|
94
|
+
return { prefix, slashIndex };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function findSlashCommandTokens(line: string): SlashCommandToken[] {
|
|
98
|
+
const tokens: SlashCommandToken[] = [];
|
|
99
|
+
for (const match of line.matchAll(SLASH_COMMAND_TOKEN_PATTERN)) {
|
|
100
|
+
const name = match[1];
|
|
101
|
+
if (name === undefined || match.index === undefined) continue;
|
|
102
|
+
const start = match.index + (match[0].startsWith("/") ? 0 : 1);
|
|
103
|
+
tokens.push({ name, start, end: start + name.length + 1 });
|
|
104
|
+
}
|
|
105
|
+
return tokens;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function commandNameFromAutocompleteItem(item: AutocompleteItem): string {
|
|
109
|
+
return (item.value || item.label).replace(/^\//u, "").trim().split(/\s+/u)[0] ?? "";
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function createSlashCommandResolver(
|
|
113
|
+
pi: Pick<ExtensionAPI, "getCommands">,
|
|
114
|
+
): SlashCommandResolver {
|
|
115
|
+
let fallbackCommands = new Map<string, string | undefined>();
|
|
116
|
+
|
|
117
|
+
const getCommandCatalog = (baseSuggestions: readonly AutocompleteItem[] = []): ReadonlyMap<string, CommandInfo> => {
|
|
118
|
+
const commands = new Map<string, CommandInfo>();
|
|
119
|
+
BUILTIN_COMMANDS.forEach((command) => commands.set(command.name, {
|
|
120
|
+
...command,
|
|
121
|
+
category: "Built-in",
|
|
122
|
+
syntaxHint: COMMAND_SYNTAX_HINTS[command.name],
|
|
123
|
+
}));
|
|
124
|
+
|
|
125
|
+
for (const command of pi.getCommands()) {
|
|
126
|
+
const category: CommandInfo["category"] = command.source === "skill"
|
|
127
|
+
? "Skill"
|
|
128
|
+
: command.source === "prompt"
|
|
129
|
+
? "Prompt"
|
|
130
|
+
: "Extension";
|
|
131
|
+
commands.set(command.name, {
|
|
132
|
+
name: command.name,
|
|
133
|
+
description: command.description,
|
|
134
|
+
category,
|
|
135
|
+
syntaxHint: COMMAND_SYNTAX_HINTS[command.name],
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const baseCommands = baseSuggestions.length > 0
|
|
140
|
+
? new Map(baseSuggestions.map((item) => [commandNameFromAutocompleteItem(item), item.description] as const))
|
|
141
|
+
: fallbackCommands;
|
|
142
|
+
for (const [name, description] of baseCommands) {
|
|
143
|
+
if (name && !commands.has(name)) {
|
|
144
|
+
commands.set(name, { name, description, category: "Built-in" });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return commands;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
clearFallbackCommands() {
|
|
152
|
+
fallbackCommands = new Map<string, string | undefined>();
|
|
153
|
+
},
|
|
154
|
+
updateFallbackCommands(items) {
|
|
155
|
+
fallbackCommands = new Map(
|
|
156
|
+
items.map((item) => [commandNameFromAutocompleteItem(item), item.description] as const)
|
|
157
|
+
.filter(([name]) => Boolean(name)),
|
|
158
|
+
);
|
|
159
|
+
},
|
|
160
|
+
getCommandCatalog,
|
|
161
|
+
isValidCommand(name) {
|
|
162
|
+
return getCommandCatalog().has(name);
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
73
167
|
function scoreCommandMatch(name: string, prefix: string): number {
|
|
74
168
|
if (!prefix) return 1;
|
|
75
169
|
const normalizedName = name.toLocaleLowerCase();
|
|
@@ -80,47 +174,26 @@ function scoreCommandMatch(name: string, prefix: string): number {
|
|
|
80
174
|
return 0;
|
|
81
175
|
}
|
|
82
176
|
|
|
83
|
-
export function registerSlashAutocomplete(
|
|
177
|
+
export function registerSlashAutocomplete(
|
|
178
|
+
pi: ExtensionAPI,
|
|
179
|
+
resolver: SlashCommandResolver = createSlashCommandResolver(pi),
|
|
180
|
+
): SlashCommandResolver {
|
|
84
181
|
const usage = new Map<string, number>();
|
|
85
182
|
pi.on("session_start", (_event, ctx) => {
|
|
86
183
|
if (ctx.mode !== "tui") return;
|
|
184
|
+
resolver.clearFallbackCommands();
|
|
87
185
|
ctx.ui.addAutocompleteProvider((current) => ({
|
|
88
186
|
triggerCharacters: ["/"],
|
|
89
187
|
async getSuggestions(lines, cursorLine, cursorCol, options) {
|
|
90
188
|
const line = lines[cursorLine] ?? "";
|
|
91
189
|
const beforeCursor = line.slice(0, cursorCol);
|
|
92
|
-
const
|
|
93
|
-
if (!
|
|
190
|
+
const prefixMatch = getSlashCommandPrefix(beforeCursor);
|
|
191
|
+
if (!prefixMatch) return current.getSuggestions(lines, cursorLine, cursorCol, options);
|
|
94
192
|
|
|
95
|
-
const prefix =
|
|
193
|
+
const prefix = prefixMatch.prefix.toLocaleLowerCase();
|
|
96
194
|
const baseSuggestions = await current.getSuggestions(lines, cursorLine, cursorCol, options);
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
...command,
|
|
100
|
-
category: "Built-in",
|
|
101
|
-
syntaxHint: COMMAND_SYNTAX_HINTS[command.name],
|
|
102
|
-
}));
|
|
103
|
-
|
|
104
|
-
for (const command of pi.getCommands()) {
|
|
105
|
-
const category: CommandInfo["category"] = command.source === "skill"
|
|
106
|
-
? "Skill"
|
|
107
|
-
: command.source === "prompt"
|
|
108
|
-
? "Prompt"
|
|
109
|
-
: "Extension";
|
|
110
|
-
commands.set(command.name, {
|
|
111
|
-
name: command.name,
|
|
112
|
-
description: command.description,
|
|
113
|
-
category,
|
|
114
|
-
syntaxHint: COMMAND_SYNTAX_HINTS[command.name],
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
for (const item of baseSuggestions?.items ?? []) {
|
|
119
|
-
const name = (item.value || item.label).replace(/^\//, "").trim().split(/\s+/)[0] ?? "";
|
|
120
|
-
if (name && !commands.has(name)) {
|
|
121
|
-
commands.set(name, { name, description: item.description, category: "Built-in" });
|
|
122
|
-
}
|
|
123
|
-
}
|
|
195
|
+
resolver.updateFallbackCommands(baseSuggestions?.items ?? []);
|
|
196
|
+
const commands = resolver.getCommandCatalog(baseSuggestions?.items ?? []);
|
|
124
197
|
|
|
125
198
|
const ranked = [...commands.values()]
|
|
126
199
|
.map((command) => ({
|
|
@@ -151,9 +224,9 @@ export function registerSlashAutocomplete(pi: ExtensionAPI): void {
|
|
|
151
224
|
const line = lines[cursorLine] ?? "";
|
|
152
225
|
const beforeCursor = line.slice(0, cursorCol);
|
|
153
226
|
const afterCursor = line.slice(cursorCol);
|
|
154
|
-
const
|
|
155
|
-
if (!
|
|
156
|
-
const slashIndex =
|
|
227
|
+
const prefixMatch = getSlashCommandPrefix(beforeCursor);
|
|
228
|
+
if (!prefixMatch) return current.applyCompletion(lines, cursorLine, cursorCol, item, prefix);
|
|
229
|
+
const slashIndex = prefixMatch.slashIndex;
|
|
157
230
|
const newBefore = beforeCursor.slice(0, slashIndex) + item.value;
|
|
158
231
|
const nextLines = [...lines];
|
|
159
232
|
nextLines[cursorLine] = newBefore + afterCursor;
|
|
@@ -164,4 +237,5 @@ export function registerSlashAutocomplete(pi: ExtensionAPI): void {
|
|
|
164
237
|
},
|
|
165
238
|
}));
|
|
166
239
|
});
|
|
240
|
+
return resolver;
|
|
167
241
|
}
|