@arhen/pi-core-subagent 1.3.65 → 1.3.67

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/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # @arhen/pi-core-subagent
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/%40arhen%2Fpi-core-subagent?color=cb3837&logo=npm)](https://www.npmjs.com/package/@arhen/pi-core-subagent)
4
- [![CI](https://img.shields.io/github/actions/workflow/status/arhen/pi-extensions/pi-core-subagent.yml?branch=main&logo=github&label=CI)](https://github.com/arhen/pi-extensions/actions/workflows/pi-core-subagent.yml)
4
+ [![CI](https://img.shields.io/github/actions/workflow/status/arhen/pi-extensions/ci.yml?branch=main&logo=github&label=CI)](https://github.com/arhen/pi-extensions/actions/workflows/ci.yml)
5
5
  [![license](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
6
6
  [![pi extension](https://img.shields.io/badge/pi-extension-7c3aed)](https://github.com/earendil-works/pi)
7
7
 
@@ -327,9 +327,12 @@ still applies Pi\'s global script-only policy; this extension does not override
327
327
  - `/subagents mode codemode` — explicitly select script-based routing (direct fallback when unavailable).
328
328
  - `/subagents mode direct` — return to legacy direct behavior.
329
329
 
330
- Choice is stored per session branch. New sessions/branches without a preference start direct;
331
- existing explicit choices remain intact. Published 1.3.63 defaulted to `auto`: this compatibility
332
- correction requires the corrected source/package, not a retroactive change to that npm release.
330
+ Choice is stored globally in `~/.pi/agent/subagents-config.json` (the same file as `auto-limit`,
331
+ written with a merge, never a clobber) and applies to every session — reload, resume, fork and tree
332
+ navigation included. Sessions that chose a mode before the preference moved into that file keep their
333
+ branch entry only while the config has no `mode`; the built-in default is still `direct`. Published
334
+ 1.3.63 defaulted to `auto`: this compatibility correction requires the corrected source/package, not
335
+ a retroactive change to that npm release.
333
336
 
334
337
  ## Commands
335
338
 
package/package.json CHANGED
@@ -1,16 +1,15 @@
1
1
  {
2
2
  "name": "@arhen/pi-core-subagent",
3
- "version": "1.3.65",
3
+ "version": "1.3.67",
4
4
  "type": "module",
5
5
  "description": "pi extension: fast in-process subagents with a dependency-graph scheduler (needs edges gate tasks and carry upstream output into dependent prompts), plus background runs, intercom and agent-to-agent mailbox. Leader defines agents inline.",
6
6
  "license": "MIT",
7
7
  "main": "./src/index.ts",
8
8
  "scripts": {
9
- "test": "bun test",
10
9
  "typecheck": "tsc --noEmit",
11
10
  "lint": "biome check .",
12
- "format": "biome format --write .",
13
- "check": "bun run typecheck && bun run lint && bun test"
11
+ "test": "bun test",
12
+ "check": "npm run typecheck && npm run lint && npm test"
14
13
  },
15
14
  "files": [
16
15
  "src",
@@ -40,11 +39,6 @@
40
39
  "./src/index.ts"
41
40
  ]
42
41
  },
43
- "devDependencies": {
44
- "@biomejs/biome": "^2.5.8",
45
- "@types/bun": "^1.3.14",
46
- "typescript": "^7.0.2"
47
- },
48
42
  "repository": {
49
43
  "type": "git",
50
44
  "url": "https://github.com/arhen/pi-extensions",
package/src/config.ts ADDED
@@ -0,0 +1,60 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { writeFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { getAgentDir } from "@earendil-works/pi-coding-agent";
5
+
6
+ /**
7
+ * Shared user config for the extension: exposure mode plus the auto-limit ceiling. One file, so a
8
+ * write of one key must never drop the other — every writer merges through `writeSubagentConfig`.
9
+ */
10
+ export const SUBAGENT_CONFIG_FILENAME = "subagents-config.json";
11
+
12
+ /**
13
+ * Presentation preference for the subagent toolset, stored globally in `subagents-config.json`.
14
+ * - auto: native codemode presentation when the codemode tool is active, direct otherwise.
15
+ * - direct (default): legacy native declarations and active-tool script callability.
16
+ * - codemode: subagent tools are callable from codemode scripts but not declared or listed.
17
+ */
18
+ export type SubagentMode = "auto" | "direct" | "codemode";
19
+
20
+ export const DEFAULT_SUBAGENT_MODE: SubagentMode = "direct";
21
+
22
+ export function isSubagentMode(value: unknown): value is SubagentMode {
23
+ return value === "auto" || value === "direct" || value === "codemode";
24
+ }
25
+
26
+ /** Resolved per call, so a test or `PI_CODING_AGENT_DIR` override applies to the running process. */
27
+ export function subagentConfigPath(): string {
28
+ return join(getAgentDir(), SUBAGENT_CONFIG_FILENAME);
29
+ }
30
+
31
+ /**
32
+ * Tolerant read: a missing, unreadable or non-object file degrades to an empty object, so a config
33
+ * typo can neither break delegation nor hide the built-in defaults.
34
+ */
35
+ export function readSubagentConfig(path = subagentConfigPath()): Record<string, unknown> {
36
+ try {
37
+ const raw: unknown = JSON.parse(readFileSync(path, "utf8"));
38
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return {};
39
+ return raw as Record<string, unknown>;
40
+ } catch {
41
+ return {};
42
+ }
43
+ }
44
+
45
+ /** The stored exposure mode, or undefined when the file has no usable one. */
46
+ export function readStoredMode(path = subagentConfigPath()): SubagentMode | undefined {
47
+ const mode = readSubagentConfig(path).mode;
48
+ return isSubagentMode(mode) ? mode : undefined;
49
+ }
50
+
51
+ let writeQueue: Promise<unknown> = Promise.resolve();
52
+
53
+ /** Read-modify-write on a single queue, so concurrent writers of different keys cannot clobber each other. */
54
+ export function writeSubagentConfig(patch: Record<string, unknown>, path = subagentConfigPath()): Promise<void> {
55
+ const write = writeQueue.then(async () => {
56
+ await writeFile(path, `${JSON.stringify({ ...readSubagentConfig(path), ...patch }, null, 2)}\n`);
57
+ });
58
+ writeQueue = write.catch(() => {});
59
+ return write;
60
+ }