@esso0428/pi-subagents 0.15.5 → 0.15.6

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.
Files changed (73) hide show
  1. package/CHANGELOG.md +4 -22
  2. package/README.md +5 -5
  3. package/dist/agent-history-list.d.ts +18 -0
  4. package/dist/agent-history-list.js +68 -0
  5. package/dist/agent-history.d.ts +1 -1
  6. package/dist/agent-history.js +31 -34
  7. package/dist/agent-manager.d.ts +22 -8
  8. package/dist/agent-manager.js +100 -93
  9. package/dist/agent-runner.js +67 -86
  10. package/dist/agent-types.js +27 -45
  11. package/dist/context.js +2 -6
  12. package/dist/cross-extension-rpc.js +5 -9
  13. package/dist/custom-agents.js +15 -18
  14. package/dist/default-agents.js +1 -4
  15. package/dist/enabled-models.js +11 -16
  16. package/dist/env.js +1 -4
  17. package/dist/group-join.js +1 -5
  18. package/dist/index.js +273 -286
  19. package/dist/invocation-config.js +2 -6
  20. package/dist/memory.js +24 -34
  21. package/dist/model-resolver.js +1 -4
  22. package/dist/nico-overrides.js +14 -20
  23. package/dist/output-file.js +16 -22
  24. package/dist/prompts.js +1 -4
  25. package/dist/schedule-store.js +16 -21
  26. package/dist/schedule.js +8 -12
  27. package/dist/settings.js +15 -23
  28. package/dist/skill-loader.js +20 -23
  29. package/dist/status-note.js +1 -4
  30. package/dist/types.d.ts +0 -1
  31. package/dist/types.js +1 -4
  32. package/dist/ui/agent-widget.d.ts +1 -5
  33. package/dist/ui/agent-widget.js +25 -49
  34. package/dist/ui/conversation-blocks.d.ts +18 -0
  35. package/dist/ui/conversation-blocks.js +214 -0
  36. package/dist/ui/conversation-nvim.d.ts +7 -0
  37. package/dist/ui/conversation-nvim.js +116 -0
  38. package/dist/ui/conversation-search.d.ts +38 -0
  39. package/dist/ui/conversation-search.js +123 -0
  40. package/dist/ui/conversation-viewer.d.ts +55 -19
  41. package/dist/ui/conversation-viewer.js +398 -215
  42. package/dist/ui/fleet-list.d.ts +23 -11
  43. package/dist/ui/fleet-list.js +85 -78
  44. package/dist/ui/schedule-menu.js +1 -4
  45. package/dist/ui/viewer-keys.js +7 -10
  46. package/dist/usage.js +4 -10
  47. package/dist/worktree.js +26 -31
  48. package/package.json +1 -1
  49. package/src/agent-history-list.ts +91 -0
  50. package/src/agent-history.ts +12 -17
  51. package/src/agent-manager.ts +108 -81
  52. package/src/agent-runner.ts +5 -13
  53. package/src/index.ts +84 -89
  54. package/src/output-file.ts +1 -1
  55. package/src/types.ts +0 -1
  56. package/src/ui/agent-widget.ts +1 -8
  57. package/src/ui/conversation-blocks.ts +270 -0
  58. package/src/ui/conversation-nvim.ts +127 -0
  59. package/src/ui/conversation-search.ts +161 -0
  60. package/src/ui/conversation-viewer.ts +376 -205
  61. package/src/ui/fleet-list.ts +73 -52
  62. package/test/agent-history-list.test.ts +121 -0
  63. package/test/agent-manager-history.test.ts +59 -58
  64. package/test/agent-menu-history-navigation.test.ts +86 -0
  65. package/test/ui/conversation-blocks.test.ts +72 -0
  66. package/test/ui/conversation-search.test.ts +55 -0
  67. package/test/ui/conversation-viewer.test.ts +132 -0
  68. package/test/ui/fleet-list.test.ts +131 -0
  69. package/dist/ui/markdown-result.d.ts +0 -3
  70. package/dist/ui/markdown-result.js +0 -53
  71. package/src/ui/markdown-result.ts +0 -56
  72. package/test/agent-history.test.ts +0 -63
  73. package/test/ui/markdown-result.test.ts +0 -45
@@ -1,8 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolveAgentInvocationConfig = resolveAgentInvocationConfig;
4
- exports.resolveJoinMode = resolveJoinMode;
5
- function resolveAgentInvocationConfig(agentConfig, params) {
1
+ export function resolveAgentInvocationConfig(agentConfig, params) {
6
2
  return {
7
3
  modelInput: agentConfig?.model ?? params.model,
8
4
  modelFromParams: agentConfig?.model == null && params.model != null,
@@ -14,6 +10,6 @@ function resolveAgentInvocationConfig(agentConfig, params) {
14
10
  isolation: agentConfig?.isolation ?? params.isolation,
15
11
  };
16
12
  }
17
- function resolveJoinMode(defaultJoinMode, runInBackground) {
13
+ export function resolveJoinMode(defaultJoinMode, runInBackground) {
18
14
  return runInBackground ? defaultJoinMode : undefined;
19
15
  }
package/dist/memory.js CHANGED
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * memory.ts — Persistent agent memory: per-agent memory directories that persist across sessions.
4
3
  *
@@ -11,26 +10,17 @@
11
10
  * is still honored (read + write) when it exists and the new location doesn't,
12
11
  * so existing memories aren't orphaned.
13
12
  */
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.isUnsafeName = isUnsafeName;
16
- exports.isSymlink = isSymlink;
17
- exports.safeReadFile = safeReadFile;
18
- exports.resolveMemoryDir = resolveMemoryDir;
19
- exports.ensureMemoryDir = ensureMemoryDir;
20
- exports.readMemoryIndex = readMemoryIndex;
21
- exports.buildMemoryBlock = buildMemoryBlock;
22
- exports.buildReadOnlyMemoryBlock = buildReadOnlyMemoryBlock;
23
- const node_fs_1 = require("node:fs");
24
- const node_os_1 = require("node:os");
25
- const node_path_1 = require("node:path");
26
- const pi_coding_agent_1 = require("@earendil-works/pi-coding-agent");
13
+ import { existsSync, lstatSync, mkdirSync, readFileSync } from "node:fs";
14
+ import { homedir } from "node:os";
15
+ import { join, } from "node:path";
16
+ import { getAgentDir } from "@earendil-works/pi-coding-agent";
27
17
  /** Maximum lines to read from MEMORY.md */
28
18
  const MAX_MEMORY_LINES = 200;
29
19
  /**
30
20
  * Returns true if a name contains characters not allowed in agent/skill names.
31
21
  * Uses a whitelist: only alphanumeric, hyphens, underscores, and dots (no leading dot).
32
22
  */
33
- function isUnsafeName(name) {
23
+ export function isUnsafeName(name) {
34
24
  if (!name || name.length > 128)
35
25
  return true;
36
26
  return !/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(name);
@@ -38,9 +28,9 @@ function isUnsafeName(name) {
38
28
  /**
39
29
  * Returns true if the given path is a symlink (defense against symlink attacks).
40
30
  */
41
- function isSymlink(filePath) {
31
+ export function isSymlink(filePath) {
42
32
  try {
43
- return (0, node_fs_1.lstatSync)(filePath).isSymbolicLink();
33
+ return lstatSync(filePath).isSymbolicLink();
44
34
  }
45
35
  catch {
46
36
  return false;
@@ -50,13 +40,13 @@ function isSymlink(filePath) {
50
40
  * Safely read a file, rejecting symlinks.
51
41
  * Returns undefined if the file doesn't exist, is a symlink, or can't be read.
52
42
  */
53
- function safeReadFile(filePath) {
54
- if (!(0, node_fs_1.existsSync)(filePath))
43
+ export function safeReadFile(filePath) {
44
+ if (!existsSync(filePath))
55
45
  return undefined;
56
46
  if (isSymlink(filePath))
57
47
  return undefined;
58
48
  try {
59
- return (0, node_fs_1.readFileSync)(filePath, "utf-8");
49
+ return readFileSync(filePath, "utf-8");
60
50
  }
61
51
  catch {
62
52
  return undefined;
@@ -66,26 +56,26 @@ function safeReadFile(filePath) {
66
56
  * Resolve the memory directory path for a given agent + scope + cwd.
67
57
  * Throws if agentName contains path traversal characters.
68
58
  */
69
- function resolveMemoryDir(agentName, scope, cwd) {
59
+ export function resolveMemoryDir(agentName, scope, cwd) {
70
60
  if (isUnsafeName(agentName)) {
71
61
  throw new Error(`Unsafe agent name for memory directory: "${agentName}"`);
72
62
  }
73
63
  switch (scope) {
74
64
  case "user": {
75
- const current = (0, node_path_1.join)((0, pi_coding_agent_1.getAgentDir)(), "agent-memory", agentName);
65
+ const current = join(getAgentDir(), "agent-memory", agentName);
76
66
  // Legacy location from when this path was hardcoded. Keep using it if it
77
67
  // already holds this agent's memory and the new location hasn't been
78
68
  // created yet — otherwise existing memories would be silently orphaned.
79
- const legacy = (0, node_path_1.join)((0, node_os_1.homedir)(), ".pi", "agent-memory", agentName);
80
- if (!(0, node_fs_1.existsSync)(current) && (0, node_fs_1.existsSync)(legacy) && !isSymlink(legacy)) {
69
+ const legacy = join(homedir(), ".pi", "agent-memory", agentName);
70
+ if (!existsSync(current) && existsSync(legacy) && !isSymlink(legacy)) {
81
71
  return legacy;
82
72
  }
83
73
  return current;
84
74
  }
85
75
  case "project":
86
- return (0, node_path_1.join)(cwd, ".pi", "agent-memory", agentName);
76
+ return join(cwd, ".pi", "agent-memory", agentName);
87
77
  case "local":
88
- return (0, node_path_1.join)(cwd, ".pi", "agent-memory-local", agentName);
78
+ return join(cwd, ".pi", "agent-memory-local", agentName);
89
79
  }
90
80
  }
91
81
  /**
@@ -93,25 +83,25 @@ function resolveMemoryDir(agentName, scope, cwd) {
93
83
  * Refuses to create directories if any component in the path is a symlink
94
84
  * to prevent symlink-based directory traversal attacks.
95
85
  */
96
- function ensureMemoryDir(memoryDir) {
86
+ export function ensureMemoryDir(memoryDir) {
97
87
  // If the directory already exists, verify it's not a symlink
98
- if ((0, node_fs_1.existsSync)(memoryDir)) {
88
+ if (existsSync(memoryDir)) {
99
89
  if (isSymlink(memoryDir)) {
100
90
  throw new Error(`Refusing to use symlinked memory directory: ${memoryDir}`);
101
91
  }
102
92
  return;
103
93
  }
104
- (0, node_fs_1.mkdirSync)(memoryDir, { recursive: true });
94
+ mkdirSync(memoryDir, { recursive: true });
105
95
  }
106
96
  /**
107
97
  * Read the first N lines of MEMORY.md from the memory directory, if it exists.
108
98
  * Returns undefined if no MEMORY.md exists or if the path is a symlink.
109
99
  */
110
- function readMemoryIndex(memoryDir) {
100
+ export function readMemoryIndex(memoryDir) {
111
101
  // Reject symlinked memory directories
112
102
  if (isSymlink(memoryDir))
113
103
  return undefined;
114
- const memoryFile = (0, node_path_1.join)(memoryDir, "MEMORY.md");
104
+ const memoryFile = join(memoryDir, "MEMORY.md");
115
105
  const content = safeReadFile(memoryFile);
116
106
  if (content === undefined)
117
107
  return undefined;
@@ -125,7 +115,7 @@ function readMemoryIndex(memoryDir) {
125
115
  * Build the memory block to inject into the agent's system prompt.
126
116
  * Also ensures the memory directory exists (creates it if needed).
127
117
  */
128
- function buildMemoryBlock(agentName, scope, cwd) {
118
+ export function buildMemoryBlock(agentName, scope, cwd) {
129
119
  const memoryDir = resolveMemoryDir(agentName, scope, cwd);
130
120
  // Create the memory directory so the agent can immediately write to it
131
121
  ensureMemoryDir(memoryDir);
@@ -138,7 +128,7 @@ Memory scope: ${scope}
138
128
  This memory persists across sessions. Use it to build up knowledge over time.`;
139
129
  const memoryContent = existingMemory
140
130
  ? `\n\n## Current MEMORY.md\n${existingMemory}`
141
- : `\n\nNo MEMORY.md exists yet. Create one at ${(0, node_path_1.join)(memoryDir, "MEMORY.md")} to start building persistent memory.`;
131
+ : `\n\nNo MEMORY.md exists yet. Create one at ${join(memoryDir, "MEMORY.md")} to start building persistent memory.`;
142
132
  const instructions = `
143
133
 
144
134
  ## Memory Instructions
@@ -161,7 +151,7 @@ This memory persists across sessions. Use it to build up knowledge over time.`;
161
151
  * Build a read-only memory block for agents that lack write/edit tools.
162
152
  * Does NOT create the memory directory — agents can only consume existing memory.
163
153
  */
164
- function buildReadOnlyMemoryBlock(agentName, scope, cwd) {
154
+ export function buildReadOnlyMemoryBlock(agentName, scope, cwd) {
165
155
  const memoryDir = resolveMemoryDir(agentName, scope, cwd);
166
156
  const existingMemory = readMemoryIndex(memoryDir);
167
157
  const header = `# Agent Memory (read-only)
@@ -1,15 +1,12 @@
1
- "use strict";
2
1
  /**
3
2
  * Model resolution: exact match ("provider/modelId") with fuzzy fallback.
4
3
  */
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.resolveModel = resolveModel;
7
4
  /**
8
5
  * Resolve a model string to a Model instance.
9
6
  * Tries exact match first ("provider/modelId"), then fuzzy match against all available models.
10
7
  * Returns the Model on success, or an error message string on failure.
11
8
  */
12
- function resolveModel(input, registry) {
9
+ export function resolveModel(input, registry) {
13
10
  // Available models (those with auth configured)
14
11
  const all = (registry.getAvailable?.() ?? registry.getAll());
15
12
  const availableSet = new Set(all.map(m => `${m.provider}/${m.id}`.toLowerCase()));
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * nico-overrides.ts — Read and apply agent overrides from `npm:pi-subagents`-style
4
3
  * `settings.json` (`subagents.agentOverrides`).
@@ -17,15 +16,10 @@
17
16
  * [] | false → false (none)
18
17
  * omitted → true (all, fallback)
19
18
  */
20
- Object.defineProperty(exports, "__esModule", { value: true });
21
- exports.readNicoAgentOverrides = readNicoAgentOverrides;
22
- exports.resolveNicoSkills = resolveNicoSkills;
23
- exports.applyNicoOverride = applyNicoOverride;
24
- exports.applyNicoOverridesToMap = applyNicoOverridesToMap;
25
- const node_fs_1 = require("node:fs");
26
- const node_path_1 = require("node:path");
27
- const pi_coding_agent_1 = require("@earendil-works/pi-coding-agent");
28
- const agent_types_js_1 = require("./agent-types.js");
19
+ import { existsSync, readFileSync } from "node:fs";
20
+ import { join } from "node:path";
21
+ import { getAgentDir } from "@earendil-works/pi-coding-agent";
22
+ import { BUILTIN_TOOL_NAMES } from "./agent-types.js";
29
23
  // ============================================================================
30
24
  // Reader
31
25
  // ============================================================================
@@ -33,11 +27,11 @@ const agent_types_js_1 = require("./agent-types.js");
33
27
  * Read subagents.agentOverrides and subagents.defaultModel from both local
34
28
  * and global Nico-style settings.json. Local overrides global on key collision.
35
29
  */
36
- function readNicoAgentOverrides(cwd) {
30
+ export function readNicoAgentOverrides(cwd) {
37
31
  const merged = {};
38
32
  let defaultModel;
39
33
  // Global: ~/.pi/agent/settings.json
40
- const globalPath = (0, node_path_1.join)((0, pi_coding_agent_1.getAgentDir)(), "settings.json");
34
+ const globalPath = join(getAgentDir(), "settings.json");
41
35
  const globalSettings = readNicoSettingsFile(globalPath);
42
36
  if (globalSettings) {
43
37
  mergeOverrides(merged, globalSettings.agentOverrides);
@@ -45,8 +39,8 @@ function readNicoAgentOverrides(cwd) {
45
39
  defaultModel = globalSettings.defaultModel;
46
40
  }
47
41
  // Local: .pi/settings.json
48
- const localPath = (0, node_path_1.join)(cwd, ".pi", "settings.json");
49
- if ((0, node_fs_1.existsSync)(localPath)) {
42
+ const localPath = join(cwd, ".pi", "settings.json");
43
+ if (existsSync(localPath)) {
50
44
  const localSettings = readNicoSettingsFile(localPath);
51
45
  if (localSettings) {
52
46
  mergeOverrides(merged, localSettings.agentOverrides);
@@ -57,10 +51,10 @@ function readNicoAgentOverrides(cwd) {
57
51
  return { overrides: merged, defaultModel };
58
52
  }
59
53
  function readNicoSettingsFile(filePath) {
60
- if (!(0, node_fs_1.existsSync)(filePath))
54
+ if (!existsSync(filePath))
61
55
  return undefined;
62
56
  try {
63
- const raw = JSON.parse((0, node_fs_1.readFileSync)(filePath, "utf-8"));
57
+ const raw = JSON.parse(readFileSync(filePath, "utf-8"));
64
58
  const sub = raw?.subagents;
65
59
  if (!sub || typeof sub !== "object")
66
60
  return undefined;
@@ -81,7 +75,7 @@ function mergeOverrides(target, source) {
81
75
  // ============================================================================
82
76
  // Skill converter: Nico string[] → tintinweb true | string[] | false
83
77
  // ============================================================================
84
- function resolveNicoSkills(skills) {
78
+ export function resolveNicoSkills(skills) {
85
79
  // Not set → inherit all (tintinweb default)
86
80
  if (skills === undefined)
87
81
  return true;
@@ -101,7 +95,7 @@ function resolveNicoSkills(skills) {
101
95
  * Apply a Nico-style override to an existing tintinweb AgentConfig.
102
96
  * JSON values directly overwrite the config (highest priority).
103
97
  */
104
- function applyNicoOverride(agent, override, nicoDefaultModel) {
98
+ export function applyNicoOverride(agent, override, nicoDefaultModel) {
105
99
  let modified = false;
106
100
  let next = agent;
107
101
  // model: explicit override wins; else use defaultModel when agent has none
@@ -141,7 +135,7 @@ function createAgentFromOverride(name, override, defaultModel) {
141
135
  description: `Auto-registered from npm:pi-subagents JSON settings`,
142
136
  builtinToolNames: override.tools !== undefined
143
137
  ? (override.tools === false ? [] : [...override.tools])
144
- : [...agent_types_js_1.BUILTIN_TOOL_NAMES],
138
+ : [...BUILTIN_TOOL_NAMES],
145
139
  extensions: true,
146
140
  skills: resolveNicoSkills(override.skills),
147
141
  model: override.model !== undefined ? (override.model === false ? undefined : override.model) : defaultModel,
@@ -162,7 +156,7 @@ function createAgentFromOverride(name, override, defaultModel) {
162
156
  * Apply all Nico overrides to a map of agents (mutating in-place).
163
157
  * Agents that don't exist yet are auto-registered from the override.
164
158
  */
165
- function applyNicoOverridesToMap(agents, overrides, defaultModel) {
159
+ export function applyNicoOverridesToMap(agents, overrides, defaultModel) {
166
160
  for (const [name, override] of Object.entries(overrides)) {
167
161
  const existing = agents.get(name);
168
162
  if (existing) {
@@ -1,25 +1,19 @@
1
- "use strict";
2
1
  /**
3
2
  * output-file.ts — Streaming JSONL output file for agent transcripts.
4
3
  *
5
4
  * Creates a per-agent output file that streams conversation turns as JSONL,
6
5
  * matching Claude Code's task output file format.
7
6
  */
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.encodeCwd = encodeCwd;
10
- exports.createOutputFilePath = createOutputFilePath;
11
- exports.writeInitialEntry = writeInitialEntry;
12
- exports.streamToOutputFile = streamToOutputFile;
13
- const node_fs_1 = require("node:fs");
14
- const node_os_1 = require("node:os");
15
- const node_path_1 = require("node:path");
7
+ import { appendFileSync, chmodSync, mkdirSync, writeFileSync } from "node:fs";
8
+ import { tmpdir } from "node:os";
9
+ import { join } from "node:path";
16
10
  /**
17
11
  * Encode a cwd path as a filesystem-safe directory name. Handles:
18
12
  * - POSIX: "/home/user/project" → "home-user-project"
19
13
  * - Windows: "C:\Users\foo\project" → "Users-foo-project"
20
14
  * - UNC: "\\\\server\\share\\project" → "server-share-project"
21
15
  */
22
- function encodeCwd(cwd) {
16
+ export function encodeCwd(cwd) {
23
17
  return cwd
24
18
  .replace(/[/\\]/g, "-") // both separators → dash
25
19
  .replace(/^[A-Za-z]:-/, "") // strip Windows drive prefix ("C:-")
@@ -27,25 +21,25 @@ function encodeCwd(cwd) {
27
21
  }
28
22
  /** Create the output file path, ensuring the directory exists.
29
23
  * Mirrors Claude Code's layout: /tmp/{prefix}-{uid}/{encoded-cwd}/{sessionId}/tasks/{agentId}.output */
30
- function createOutputFilePath(cwd, agentId, sessionId) {
24
+ export function createOutputFilePath(cwd, agentId, sessionId) {
31
25
  const encoded = encodeCwd(cwd);
32
- const root = (0, node_path_1.join)((0, node_os_1.tmpdir)(), `pi-subagents-${process.getuid?.() ?? 0}`);
33
- (0, node_fs_1.mkdirSync)(root, { recursive: true, mode: 0o700 });
26
+ const root = join(tmpdir(), `pi-subagents-${process.getuid?.() ?? 0}`);
27
+ mkdirSync(root, { recursive: true, mode: 0o700 });
34
28
  // chmod is a no-op on Windows and throws on some Windows filesystems.
35
29
  // On Unix we still want to enforce 0o700 past umask, so only swallow on Windows.
36
30
  try {
37
- (0, node_fs_1.chmodSync)(root, 0o700);
31
+ chmodSync(root, 0o700);
38
32
  }
39
33
  catch (err) {
40
34
  if (process.platform !== "win32")
41
35
  throw err;
42
36
  }
43
- const dir = (0, node_path_1.join)(root, encoded, sessionId, "tasks");
44
- (0, node_fs_1.mkdirSync)(dir, { recursive: true });
45
- return (0, node_path_1.join)(dir, `${agentId}.output`);
37
+ const dir = join(root, encoded, sessionId, "tasks");
38
+ mkdirSync(dir, { recursive: true });
39
+ return join(dir, `${agentId}.output`);
46
40
  }
47
41
  /** Write the initial user prompt entry. */
48
- function writeInitialEntry(path, agentId, prompt, cwd) {
42
+ export function writeInitialEntry(path, agentId, prompt, cwd) {
49
43
  const entry = {
50
44
  isSidechain: true,
51
45
  agentId,
@@ -54,15 +48,15 @@ function writeInitialEntry(path, agentId, prompt, cwd) {
54
48
  timestamp: new Date().toISOString(),
55
49
  cwd,
56
50
  };
57
- (0, node_fs_1.writeFileSync)(path, JSON.stringify(entry) + "\n", "utf-8");
51
+ writeFileSync(path, JSON.stringify(entry) + "\n", "utf-8");
58
52
  }
59
53
  /**
60
54
  * Subscribe to session events and flush new messages to the output file on each turn_end.
61
55
  * Returns a cleanup function that does a final flush and unsubscribes.
62
56
  */
63
- function streamToOutputFile(session, path, agentId, cwd, historyPath) {
64
- const outputPaths = historyPath && historyPath !== path ? [path, historyPath] : [path];
57
+ export function streamToOutputFile(session, path, agentId, cwd, historyPath) {
65
58
  let writtenCount = 1; // initial user prompt already written
59
+ const outputPaths = historyPath && historyPath !== path ? [path, historyPath] : [path];
66
60
  const flush = () => {
67
61
  const messages = session.messages;
68
62
  while (writtenCount < messages.length) {
@@ -77,7 +71,7 @@ function streamToOutputFile(session, path, agentId, cwd, historyPath) {
77
71
  };
78
72
  for (const outputPath of outputPaths) {
79
73
  try {
80
- (0, node_fs_1.appendFileSync)(outputPath, JSON.stringify(entry) + "\n", "utf-8");
74
+ appendFileSync(outputPath, JSON.stringify(entry) + "\n", "utf-8");
81
75
  }
82
76
  catch { /* ignore write errors */ }
83
77
  }
package/dist/prompts.js CHANGED
@@ -1,9 +1,6 @@
1
- "use strict";
2
1
  /**
3
2
  * prompts.ts — System prompt builder for agents.
4
3
  */
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.buildAgentPrompt = buildAgentPrompt;
7
4
  /**
8
5
  * Build the system prompt for an agent from its config.
9
6
  *
@@ -21,7 +18,7 @@ exports.buildAgentPrompt = buildAgentPrompt;
21
18
  * @param parentSystemPrompt The parent agent's effective system prompt (for append mode).
22
19
  * @param extras Optional extra sections to inject (memory, preloaded skills).
23
20
  */
24
- function buildAgentPrompt(config, cwd, env, parentSystemPrompt, extras) {
21
+ export function buildAgentPrompt(config, cwd, env, parentSystemPrompt, extras) {
25
22
  const activeAgentTag = `<active_agent name="${config.name}"/>\n\n`;
26
23
  const envBlock = `# Environment
27
24
  Working directory: ${cwd}
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * schedule-store.ts — File-backed store for scheduled subagents.
4
3
  *
@@ -10,11 +9,8 @@
10
9
  * mutation acquires a PID-based exclusion lock, re-reads the latest state
11
10
  * from disk, applies the change, atomic-writes via temp+rename, releases.
12
11
  */
13
- Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.ScheduleStore = void 0;
15
- exports.resolveStorePath = resolveStorePath;
16
- const node_fs_1 = require("node:fs");
17
- const node_path_1 = require("node:path");
12
+ import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
13
+ import { dirname, join } from "node:path";
18
14
  const LOCK_RETRY_MS = 50;
19
15
  const LOCK_MAX_RETRIES = 100;
20
16
  function isProcessRunning(pid) {
@@ -29,15 +25,15 @@ function isProcessRunning(pid) {
29
25
  function acquireLock(lockPath) {
30
26
  for (let i = 0; i < LOCK_MAX_RETRIES; i++) {
31
27
  try {
32
- (0, node_fs_1.writeFileSync)(lockPath, `${process.pid}`, { flag: "wx" });
28
+ writeFileSync(lockPath, `${process.pid}`, { flag: "wx" });
33
29
  return;
34
30
  }
35
31
  catch (e) {
36
32
  if (e.code === "EEXIST") {
37
33
  try {
38
- const pid = parseInt((0, node_fs_1.readFileSync)(lockPath, "utf-8"), 10);
34
+ const pid = parseInt(readFileSync(lockPath, "utf-8"), 10);
39
35
  if (pid && !isProcessRunning(pid)) {
40
- (0, node_fs_1.unlinkSync)(lockPath);
36
+ unlinkSync(lockPath);
41
37
  continue;
42
38
  }
43
39
  }
@@ -53,15 +49,15 @@ function acquireLock(lockPath) {
53
49
  }
54
50
  function releaseLock(lockPath) {
55
51
  try {
56
- (0, node_fs_1.unlinkSync)(lockPath);
52
+ unlinkSync(lockPath);
57
53
  }
58
54
  catch { /* ignore */ }
59
55
  }
60
56
  /** Resolve the storage path for a session-scoped store. */
61
- function resolveStorePath(cwd, sessionId) {
62
- return (0, node_path_1.join)(cwd, ".pi", "subagent-schedules", `${sessionId}.json`);
57
+ export function resolveStorePath(cwd, sessionId) {
58
+ return join(cwd, ".pi", "subagent-schedules", `${sessionId}.json`);
63
59
  }
64
- class ScheduleStore {
60
+ export class ScheduleStore {
65
61
  filePath;
66
62
  lockPath;
67
63
  jobs = new Map();
@@ -72,14 +68,14 @@ class ScheduleStore {
72
68
  }
73
69
  /** Create the backing directory lazily — only when we're about to persist. */
74
70
  ensureDir() {
75
- (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(this.filePath), { recursive: true });
71
+ mkdirSync(dirname(this.filePath), { recursive: true });
76
72
  }
77
73
  /** Load from disk into the in-memory cache. Silent on parse errors. */
78
74
  load() {
79
- if (!(0, node_fs_1.existsSync)(this.filePath))
75
+ if (!existsSync(this.filePath))
80
76
  return;
81
77
  try {
82
- const data = JSON.parse((0, node_fs_1.readFileSync)(this.filePath, "utf-8"));
78
+ const data = JSON.parse(readFileSync(this.filePath, "utf-8"));
83
79
  this.jobs.clear();
84
80
  for (const j of data.jobs ?? [])
85
81
  this.jobs.set(j.id, j);
@@ -90,8 +86,8 @@ class ScheduleStore {
90
86
  save() {
91
87
  const data = { version: 1, jobs: [...this.jobs.values()] };
92
88
  const tmp = this.filePath + ".tmp";
93
- (0, node_fs_1.writeFileSync)(tmp, JSON.stringify(data, null, 2));
94
- (0, node_fs_1.renameSync)(tmp, this.filePath);
89
+ writeFileSync(tmp, JSON.stringify(data, null, 2));
90
+ renameSync(tmp, this.filePath);
95
91
  }
96
92
  /** Acquire lock → reload → mutate → save → release. */
97
93
  withLock(fn) {
@@ -149,12 +145,11 @@ class ScheduleStore {
149
145
  }
150
146
  /** Delete the backing file (used when no jobs remain, optional cleanup). */
151
147
  deleteFileIfEmpty() {
152
- if (this.jobs.size === 0 && (0, node_fs_1.existsSync)(this.filePath)) {
148
+ if (this.jobs.size === 0 && existsSync(this.filePath)) {
153
149
  try {
154
- (0, node_fs_1.unlinkSync)(this.filePath);
150
+ unlinkSync(this.filePath);
155
151
  }
156
152
  catch { /* ignore */ }
157
153
  }
158
154
  }
159
155
  }
160
- exports.ScheduleStore = ScheduleStore;
package/dist/schedule.js CHANGED
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * schedule.ts — `SubagentScheduler`: timer-driven dispatcher of scheduled subagents.
4
3
  *
@@ -15,12 +14,10 @@
15
14
  * - Result delivery is implicit: spawn → background completion → existing
16
15
  * `subagent-notification` followUp path. No new delivery code.
17
16
  */
18
- Object.defineProperty(exports, "__esModule", { value: true });
19
- exports.SubagentScheduler = void 0;
20
- const croner_1 = require("croner");
21
- const nanoid_1 = require("nanoid");
22
- const model_resolver_js_1 = require("./model-resolver.js");
23
- class SubagentScheduler {
17
+ import { Cron } from "croner";
18
+ import { nanoid } from "nanoid";
19
+ import { resolveModel } from "./model-resolver.js";
20
+ export class SubagentScheduler {
24
21
  jobs = new Map();
25
22
  intervals = new Map();
26
23
  store;
@@ -65,7 +62,7 @@ class SubagentScheduler {
65
62
  buildJob(input) {
66
63
  const detected = SubagentScheduler.detectSchedule(input.schedule);
67
64
  return {
68
- id: (0, nanoid_1.nanoid)(10),
65
+ id: nanoid(10),
69
66
  name: input.name,
70
67
  description: input.description,
71
68
  schedule: detected.normalized,
@@ -168,7 +165,7 @@ class SubagentScheduler {
168
165
  }
169
166
  }
170
167
  else {
171
- const cron = new croner_1.Cron(job.schedule, () => this.executeJob(job.id));
168
+ const cron = new Cron(job.schedule, () => this.executeJob(job.id));
172
169
  this.jobs.set(job.id, cron);
173
170
  }
174
171
  }
@@ -210,7 +207,7 @@ class SubagentScheduler {
210
207
  // if resolution fails; the spawn path handles undefined model gracefully.
211
208
  let resolvedModel;
212
209
  if (job.model) {
213
- const r = (0, model_resolver_js_1.resolveModel)(job.model, ctx.modelRegistry);
210
+ const r = resolveModel(job.model, ctx.modelRegistry);
214
211
  if (typeof r !== "string")
215
212
  resolvedModel = r;
216
213
  }
@@ -316,7 +313,7 @@ class SubagentScheduler {
316
313
  }
317
314
  try {
318
315
  // Croner validates by construction.
319
- new croner_1.Cron(expr, () => { });
316
+ new Cron(expr, () => { });
320
317
  return { valid: true };
321
318
  }
322
319
  catch (e) {
@@ -339,4 +336,3 @@ class SubagentScheduler {
339
336
  return parseInt(m[1], 10) * { s: 1000, m: 60_000, h: 3_600_000, d: 86_400_000 }[m[2]];
340
337
  }
341
338
  }
342
- exports.SubagentScheduler = SubagentScheduler;