little-coder 1.8.3 → 1.9.0
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/.pi/extensions/branding/branding.test.ts +42 -0
- package/.pi/extensions/branding/index.ts +56 -10
- package/.pi/extensions/extra-tools/glob.ts +3 -3
- package/.pi/extensions/extra-tools/index.ts +1 -1
- package/.pi/extensions/output-parser/index.ts +46 -16
- package/.pi/extensions/output-parser/parser.test.ts +123 -1
- package/.pi/extensions/output-parser/parser.ts +202 -0
- package/.pi/extensions/plan-mode/index.ts +377 -0
- package/.pi/extensions/plan-mode/plan-mode.test.ts +49 -0
- package/.pi/extensions/plan-mode/status.ts +79 -0
- package/.pi/extensions/prompt-history/index.ts +154 -0
- package/.pi/extensions/prompt-history/prompt-history.test.ts +72 -0
- package/.pi/extensions/read-guard-edit/index.ts +89 -0
- package/.pi/extensions/read-guard-edit/read-guard-edit.test.ts +100 -0
- package/.pi/extensions/skill-inject/index.ts +3 -0
- package/.pi/extensions/skill-inject/selector.test.ts +2 -2
- package/.pi/extensions/subagent/index.ts +201 -0
- package/.pi/extensions/subagent/live-spawn.test.ts +47 -0
- package/.pi/extensions/subagent/spawn.test.ts +97 -0
- package/.pi/extensions/subagent/spawn.ts +373 -0
- package/.pi/extensions/subagent/tracker.ts +139 -0
- package/AGENTS.md +5 -0
- package/CHANGELOG.md +36 -0
- package/README.md +19 -3
- package/bin/little-coder.mjs +56 -5
- package/package.json +2 -2
- package/skills/tools/dispatch.md +38 -0
package/bin/little-coder.mjs
CHANGED
|
@@ -36,6 +36,13 @@ if (tooOld) {
|
|
|
36
36
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
37
37
|
const pkgRoot = resolve(here, "..");
|
|
38
38
|
|
|
39
|
+
// Headless sub-coder fast-path. When the subagent extension re-invokes this
|
|
40
|
+
// launcher to spawn a child little-coder (--mode json -p), the update check and
|
|
41
|
+
// the global-settings merge below are pointless per-child overhead (network +
|
|
42
|
+
// disk) — and we want children to start fast. The env flag is set by
|
|
43
|
+
// .pi/extensions/subagent/spawn.ts::buildChildEnv.
|
|
44
|
+
const isSubagent = process.env.LITTLE_CODER_SUBAGENT === "1";
|
|
45
|
+
|
|
39
46
|
// ---- 3. Resolve the bundled pi CLI entry point ----
|
|
40
47
|
// We invoke pi's JS entry directly under the current Node binary instead of
|
|
41
48
|
// the `node_modules/.bin/pi` shim. Two reasons:
|
|
@@ -110,10 +117,12 @@ try {
|
|
|
110
117
|
} catch {
|
|
111
118
|
// ignore — update-check just won't fire if we can't read the version
|
|
112
119
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
120
|
+
if (!isSubagent) {
|
|
121
|
+
const exitAfterCheck = await checkForUpdate(currentVersion);
|
|
122
|
+
if (exitAfterCheck) {
|
|
123
|
+
// Successful update happened; user needs to re-run the new binary.
|
|
124
|
+
process.exit(0);
|
|
125
|
+
}
|
|
117
126
|
}
|
|
118
127
|
|
|
119
128
|
// ---- 6. Compose pi argv ----
|
|
@@ -124,10 +133,22 @@ if (exitAfterCheck) {
|
|
|
124
133
|
// Strip our own flags before forwarding to pi so it doesn't reject them.
|
|
125
134
|
const userArgs = process.argv.slice(2).filter((a) => a !== "--no-update-check");
|
|
126
135
|
const agentsMd = join(pkgRoot, "AGENTS.md");
|
|
136
|
+
|
|
137
|
+
// Default the thinking level to "medium" for interactive sessions (pi's own
|
|
138
|
+
// default is "minimal"). Only when the user hasn't asked for a level themselves
|
|
139
|
+
// (--thinking, or the --model "provider/id:level" shorthand) and this isn't a
|
|
140
|
+
// headless/sub-coder run (--mode rpc/json) where the caller controls thinking.
|
|
141
|
+
const userPickedThinking =
|
|
142
|
+
userArgs.includes("--thinking") ||
|
|
143
|
+
userArgs.some((a, i) => a === "--model" && /:/.test(userArgs[i + 1] || ""));
|
|
144
|
+
const headless = isSubagent || userArgs.includes("--mode") || userArgs.includes("-p");
|
|
145
|
+
const thinkingArgs = !userPickedThinking && !headless ? ["--thinking", "medium"] : [];
|
|
146
|
+
|
|
127
147
|
const piArgs = [
|
|
128
148
|
"--no-context-files",
|
|
129
149
|
"--no-extensions",
|
|
130
150
|
...(existsSync(agentsMd) ? ["--system-prompt", agentsMd] : []),
|
|
151
|
+
...thinkingArgs,
|
|
131
152
|
...extArgs,
|
|
132
153
|
...userArgs,
|
|
133
154
|
];
|
|
@@ -167,7 +188,10 @@ if (process.env.PI_SKIP_VERSION_CHECK === undefined) {
|
|
|
167
188
|
//
|
|
168
189
|
// Existing keys are preserved. We only write when the desired value differs
|
|
169
190
|
// from what's already on disk, so this is a no-op on warm launches.
|
|
170
|
-
|
|
191
|
+
//
|
|
192
|
+
// Skipped for headless sub-coders: they share the user's settings (already
|
|
193
|
+
// written by the interactive parent) and shouldn't each re-do the merge.
|
|
194
|
+
if (!isSubagent) try {
|
|
171
195
|
const agentDirEnv = process.env.PI_CODING_AGENT_DIR;
|
|
172
196
|
let agentDir;
|
|
173
197
|
if (agentDirEnv && agentDirEnv.trim().length > 0) {
|
|
@@ -219,6 +243,33 @@ try {
|
|
|
219
243
|
if (mutated) {
|
|
220
244
|
writeFileSync(globalSettingsPath, JSON.stringify(globalSettings, null, 2));
|
|
221
245
|
}
|
|
246
|
+
|
|
247
|
+
// ---- 8b. Free shift+tab for Plan Mode ----
|
|
248
|
+
// little-coder binds shift+tab to its plan-mode toggle (the plan-mode
|
|
249
|
+
// extension registers it). But shift+tab is pi's built-in "cycle thinking
|
|
250
|
+
// level", and pi (>= 0.79) refuses an extension shortcut that collides with a
|
|
251
|
+
// RESERVED built-in — it skips it with an "[Extension issues]" warning. pi
|
|
252
|
+
// builds its conflict map from the *resolved* keybindings, so moving the
|
|
253
|
+
// thinking-cycle action to another key in the user keybindings file removes
|
|
254
|
+
// shift+tab from that map and lets the extension claim it. We rebind the
|
|
255
|
+
// cycle to alt+t (the key plan-mode used to register itself) — only when the
|
|
256
|
+
// user hasn't already chosen their own binding for it, so a real user
|
|
257
|
+
// customization always wins. Non-destructive: every other binding is left
|
|
258
|
+
// untouched.
|
|
259
|
+
const keybindingsPath = join(agentDir, "keybindings.json");
|
|
260
|
+
let keybindings = {};
|
|
261
|
+
if (existsSync(keybindingsPath)) {
|
|
262
|
+
try {
|
|
263
|
+
const parsed = JSON.parse(readFileSync(keybindingsPath, "utf-8"));
|
|
264
|
+
if (parsed && typeof parsed === "object") keybindings = parsed;
|
|
265
|
+
} catch {
|
|
266
|
+
keybindings = {};
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (keybindings["app.thinking.cycle"] === undefined) {
|
|
270
|
+
keybindings["app.thinking.cycle"] = "alt+t";
|
|
271
|
+
writeFileSync(keybindingsPath, JSON.stringify(keybindings, null, 2));
|
|
272
|
+
}
|
|
222
273
|
} catch {
|
|
223
274
|
// Best-effort. If we can't write the settings (read-only HOME, etc.) pi
|
|
224
275
|
// falls back to its built-in defaults — the [Extensions] block will show
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "little-coder",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "A pi-based coding agent optimized for small local language models. Reproduces the whitepaper's scaffold-model-fit adaptations as pi extensions.",
|
|
5
5
|
"homepage": "https://github.com/itayinbarr/little-coder",
|
|
6
6
|
"repository": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"postinstall": "node scripts/patch-pi.mjs"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
41
|
+
"@earendil-works/pi-coding-agent": "^0.79.4",
|
|
42
42
|
"@sinclair/typebox": "^0.34.49",
|
|
43
43
|
"playwright": "^1.59.1"
|
|
44
44
|
},
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dispatch-guidance
|
|
3
|
+
type: tool-guidance
|
|
4
|
+
target_tool: dispatch
|
|
5
|
+
priority: 6
|
|
6
|
+
token_cost: 140
|
|
7
|
+
user-invocable: false
|
|
8
|
+
---
|
|
9
|
+
## Dispatch Tool (sub-coders)
|
|
10
|
+
Delegate focused research to isolated child little-coder sessions ("sub-coders").
|
|
11
|
+
Each runs in its own context window, can READ the repo and BROWSE online
|
|
12
|
+
(read, grep, glob, webfetch, websearch, browser, read-only bash) but CANNOT
|
|
13
|
+
edit or write files. Each returns a concise report. Use this to gather
|
|
14
|
+
information without filling your own context with raw file dumps or web pages.
|
|
15
|
+
|
|
16
|
+
SINGLE: `task` (string) — one research question.
|
|
17
|
+
PARALLEL: `tasks` — array of `{label, task}`, up to 4, run concurrently.
|
|
18
|
+
OPTIONAL: `cwd` (defaults to the current working directory).
|
|
19
|
+
|
|
20
|
+
RULES:
|
|
21
|
+
- Give each parallel task a short, distinct `label` — it shows in the live tracker.
|
|
22
|
+
- Ask narrow, answerable questions ("how does auth work in this repo?", not "do everything").
|
|
23
|
+
- You receive only each sub-coder's short report; the full transcript stays in the
|
|
24
|
+
tool's details (not in your context). Act on the reports.
|
|
25
|
+
- Sub-coders can't change files — do the editing yourself after they report back.
|
|
26
|
+
|
|
27
|
+
EXAMPLE (single):
|
|
28
|
+
```tool
|
|
29
|
+
{"name": "dispatch", "input": {"task": "Find where sessions are persisted in this repo and summarize the format."}}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
EXAMPLE (parallel):
|
|
33
|
+
```tool
|
|
34
|
+
{"name": "dispatch", "input": {"tasks": [
|
|
35
|
+
{"label": "repo auth", "task": "How does authentication work in this codebase? Cite files."},
|
|
36
|
+
{"label": "lib docs", "task": "Look up the current recommended API for the jose JWT library online."}
|
|
37
|
+
]}}
|
|
38
|
+
```
|