@ymy88/pi-subagents 0.0.0-stage → 0.24.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.
Files changed (196) hide show
  1. package/CHANGELOG.md +904 -0
  2. package/CONTRIBUTING.md +72 -0
  3. package/LICENSE +21 -0
  4. package/README.md +1170 -2
  5. package/SECURITY.md +95 -0
  6. package/dist/abortable.d.ts +12 -0
  7. package/dist/abortable.js +42 -0
  8. package/dist/agent-color.d.ts +35 -0
  9. package/dist/agent-color.js +123 -0
  10. package/dist/agent-file-toggle.d.ts +133 -0
  11. package/dist/agent-file-toggle.js +287 -0
  12. package/dist/agent-manager.d.ts +552 -0
  13. package/dist/agent-manager.js +1466 -0
  14. package/dist/agent-record-entry.d.ts +96 -0
  15. package/dist/agent-record-entry.js +121 -0
  16. package/dist/agent-runner.d.ts +310 -0
  17. package/dist/agent-runner.js +1195 -0
  18. package/dist/agent-source-badge.d.ts +50 -0
  19. package/dist/agent-source-badge.js +74 -0
  20. package/dist/agent-types.d.ts +119 -0
  21. package/dist/agent-types.js +286 -0
  22. package/dist/child-context.d.ts +2 -0
  23. package/dist/child-context.js +12 -0
  24. package/dist/completion-outbox.d.ts +63 -0
  25. package/dist/completion-outbox.js +104 -0
  26. package/dist/context.d.ts +12 -0
  27. package/dist/context.js +56 -0
  28. package/dist/cross-extension-rpc.d.ts +72 -0
  29. package/dist/cross-extension-rpc.js +153 -0
  30. package/dist/custom-agents.d.ts +77 -0
  31. package/dist/custom-agents.js +396 -0
  32. package/dist/default-agents.d.ts +7 -0
  33. package/dist/default-agents.js +121 -0
  34. package/dist/enabled-models.d.ts +49 -0
  35. package/dist/enabled-models.js +145 -0
  36. package/dist/env.d.ts +6 -0
  37. package/dist/env.js +28 -0
  38. package/dist/group-join.d.ts +32 -0
  39. package/dist/group-join.js +116 -0
  40. package/dist/index.d.ts +50 -0
  41. package/dist/index.js +4111 -0
  42. package/dist/invocation-config.d.ts +108 -0
  43. package/dist/invocation-config.js +83 -0
  44. package/dist/memory.d.ts +53 -0
  45. package/dist/memory.js +165 -0
  46. package/dist/mention-clone.d.ts +79 -0
  47. package/dist/mention-clone.js +155 -0
  48. package/dist/mention.d.ts +81 -0
  49. package/dist/mention.js +131 -0
  50. package/dist/model-resolver.d.ts +36 -0
  51. package/dist/model-resolver.js +95 -0
  52. package/dist/model-scope.d.ts +49 -0
  53. package/dist/model-scope.js +48 -0
  54. package/dist/nested-tools.d.ts +57 -0
  55. package/dist/nested-tools.js +303 -0
  56. package/dist/output-file.d.ts +43 -0
  57. package/dist/output-file.js +153 -0
  58. package/dist/package-resources.d.ts +240 -0
  59. package/dist/package-resources.js +519 -0
  60. package/dist/prompts.d.ts +76 -0
  61. package/dist/prompts.js +121 -0
  62. package/dist/schedule-store.d.ts +38 -0
  63. package/dist/schedule-store.js +155 -0
  64. package/dist/schedule.d.ts +109 -0
  65. package/dist/schedule.js +359 -0
  66. package/dist/settings.d.ts +398 -0
  67. package/dist/settings.js +282 -0
  68. package/dist/skill-loader.d.ts +24 -0
  69. package/dist/skill-loader.js +93 -0
  70. package/dist/status-note.d.ts +61 -0
  71. package/dist/status-note.js +85 -0
  72. package/dist/structured-output.d.ts +61 -0
  73. package/dist/structured-output.js +112 -0
  74. package/dist/types.d.ts +391 -0
  75. package/dist/types.js +5 -0
  76. package/dist/ui/agent-mention.d.ts +82 -0
  77. package/dist/ui/agent-mention.js +187 -0
  78. package/dist/ui/agent-widget.d.ts +219 -0
  79. package/dist/ui/agent-widget.js +585 -0
  80. package/dist/ui/conversation-viewer.d.ts +177 -0
  81. package/dist/ui/conversation-viewer.js +905 -0
  82. package/dist/ui/fleet-list.d.ts +211 -0
  83. package/dist/ui/fleet-list.js +489 -0
  84. package/dist/ui/schedule-menu.d.ts +16 -0
  85. package/dist/ui/schedule-menu.js +94 -0
  86. package/dist/ui/select-item.d.ts +27 -0
  87. package/dist/ui/select-item.js +34 -0
  88. package/dist/ui/viewer-keys.d.ts +22 -0
  89. package/dist/ui/viewer-keys.js +18 -0
  90. package/dist/ui/workflow-card.d.ts +175 -0
  91. package/dist/ui/workflow-card.js +332 -0
  92. package/dist/ui/workflow-dialog.d.ts +305 -0
  93. package/dist/ui/workflow-dialog.js +843 -0
  94. package/dist/ui/workflow-menu.d.ts +60 -0
  95. package/dist/ui/workflow-menu.js +147 -0
  96. package/dist/usage.d.ts +135 -0
  97. package/dist/usage.js +120 -0
  98. package/dist/workflow/collisions.d.ts +95 -0
  99. package/dist/workflow/collisions.js +88 -0
  100. package/dist/workflow/entry.d.ts +32 -0
  101. package/dist/workflow/entry.js +29 -0
  102. package/dist/workflow/host.d.ts +62 -0
  103. package/dist/workflow/host.js +419 -0
  104. package/dist/workflow/journal.d.ts +97 -0
  105. package/dist/workflow/journal.js +120 -0
  106. package/dist/workflow/json-schema.d.ts +52 -0
  107. package/dist/workflow/json-schema.js +112 -0
  108. package/dist/workflow/meta.d.ts +67 -0
  109. package/dist/workflow/meta.js +317 -0
  110. package/dist/workflow/progress.d.ts +224 -0
  111. package/dist/workflow/progress.js +361 -0
  112. package/dist/workflow/runtime.d.ts +334 -0
  113. package/dist/workflow/runtime.js +830 -0
  114. package/dist/workflow/saved.d.ts +102 -0
  115. package/dist/workflow/saved.js +247 -0
  116. package/dist/workflow/task.d.ts +136 -0
  117. package/dist/workflow/task.js +207 -0
  118. package/dist/workflow/tool-description.d.ts +38 -0
  119. package/dist/workflow/tool-description.js +199 -0
  120. package/dist/workflow/worker-source.d.ts +47 -0
  121. package/dist/workflow/worker-source.js +778 -0
  122. package/dist/worktree.d.ts +52 -0
  123. package/dist/worktree.js +164 -0
  124. package/dist/xml.d.ts +10 -0
  125. package/dist/xml.js +12 -0
  126. package/docs/packages.md +211 -0
  127. package/docs/rpc.md +192 -0
  128. package/docs/workflows.md +447 -0
  129. package/examples/agent-tool-description.md +42 -0
  130. package/examples/workflows/compose.js +51 -0
  131. package/examples/workflows/fan-out-audit.js +47 -0
  132. package/examples/workflows/gated-fix.js +60 -0
  133. package/examples/workflows/lib/count-child.js +27 -0
  134. package/examples/workflows/review-panel.js +63 -0
  135. package/examples/workflows/structured-findings.js +78 -0
  136. package/package.json +74 -4
  137. package/src/abortable.ts +43 -0
  138. package/src/agent-color.ts +161 -0
  139. package/src/agent-file-toggle.ts +297 -0
  140. package/src/agent-manager.ts +1735 -0
  141. package/src/agent-record-entry.ts +153 -0
  142. package/src/agent-runner.ts +1468 -0
  143. package/src/agent-source-badge.ts +75 -0
  144. package/src/agent-types.ts +346 -0
  145. package/src/child-context.ts +15 -0
  146. package/src/completion-outbox.ts +116 -0
  147. package/src/context.ts +58 -0
  148. package/src/cross-extension-rpc.ts +221 -0
  149. package/src/custom-agents.ts +452 -0
  150. package/src/default-agents.ts +125 -0
  151. package/src/enabled-models.ts +180 -0
  152. package/src/env.ts +33 -0
  153. package/src/group-join.ts +141 -0
  154. package/src/index.ts +4433 -0
  155. package/src/invocation-config.ts +155 -0
  156. package/src/memory.ts +179 -0
  157. package/src/mention-clone.ts +195 -0
  158. package/src/mention.ts +141 -0
  159. package/src/model-resolver.ts +118 -0
  160. package/src/model-scope.ts +70 -0
  161. package/src/nested-tools.ts +426 -0
  162. package/src/output-file.ts +164 -0
  163. package/src/package-resources.ts +652 -0
  164. package/src/prompts.ts +171 -0
  165. package/src/schedule-store.ts +153 -0
  166. package/src/schedule.ts +386 -0
  167. package/src/settings.ts +650 -0
  168. package/src/skill-loader.ts +102 -0
  169. package/src/status-note.ts +90 -0
  170. package/src/structured-output.ts +130 -0
  171. package/src/types.ts +404 -0
  172. package/src/ui/agent-mention.ts +216 -0
  173. package/src/ui/agent-widget.ts +661 -0
  174. package/src/ui/conversation-viewer.ts +928 -0
  175. package/src/ui/fleet-list.ts +559 -0
  176. package/src/ui/schedule-menu.ts +105 -0
  177. package/src/ui/select-item.ts +45 -0
  178. package/src/ui/viewer-keys.ts +43 -0
  179. package/src/ui/workflow-card.ts +470 -0
  180. package/src/ui/workflow-dialog.ts +1115 -0
  181. package/src/ui/workflow-menu.ts +193 -0
  182. package/src/usage.ts +167 -0
  183. package/src/workflow/collisions.ts +123 -0
  184. package/src/workflow/entry.ts +47 -0
  185. package/src/workflow/host.ts +467 -0
  186. package/src/workflow/journal.ts +164 -0
  187. package/src/workflow/json-schema.ts +129 -0
  188. package/src/workflow/meta.ts +325 -0
  189. package/src/workflow/progress.ts +551 -0
  190. package/src/workflow/runtime.ts +1219 -0
  191. package/src/workflow/saved.ts +259 -0
  192. package/src/workflow/task.ts +302 -0
  193. package/src/workflow/tool-description.ts +200 -0
  194. package/src/workflow/worker-source.ts +781 -0
  195. package/src/worktree.ts +205 -0
  196. package/src/xml.ts +13 -0
@@ -0,0 +1,240 @@
1
+ /**
2
+ * package-resources.ts — Discover agent and workflow files that installed pi
3
+ * packages declare in their `package.json`.
4
+ *
5
+ * ## Why this exists
6
+ *
7
+ * Pi already ships four resource types inside packages — `extensions`, `skills`,
8
+ * `prompts`, `themes` — resolved from a `pi` manifest key or, when there is no
9
+ * `pi` key at all, from convention directories. Subagents are *our* concept, so
10
+ * pi knows nothing about them and a package author's only option was to copy
11
+ * `.md` files into `.pi/agents/` on every container start (#109).
12
+ *
13
+ * ## The contract
14
+ *
15
+ * Two-sided, deliberately:
16
+ *
17
+ * 1. The package author opts in by naming the paths in `package.json`.
18
+ * 2. The user opts in by running `pi install`, which is already the trust
19
+ * decision for that package — pi executes its `extensions/` and injects its
20
+ * `skills/` into the system prompt with no further prompt. A declared `.md`
21
+ * agent is strictly less privileged than either, so it rides the boundary
22
+ * the user already crossed rather than inventing a second one.
23
+ *
24
+ * There is deliberately **no convention-directory fallback**. Pi scans `skills/`
25
+ * only when a package has no `pi` key whatsoever; we never scan an undeclared
26
+ * `agents/`. A package that happens to carry an `agents/` folder for some other
27
+ * tool must not start contributing subagents to pi because it was installed for
28
+ * an unrelated reason.
29
+ *
30
+ * ## Which packages are visible
31
+ *
32
+ * Only what pi itself has configured — `settings.json -> packages[]`, global and
33
+ * project — read through pi's own `DefaultPackageManager.listConfiguredPackages()`.
34
+ * That call is synchronous, pure, and never installs anything; it also resolves
35
+ * npm / git / local install roots, pnpm global roots and legacy fallbacks, which
36
+ * is why it is worth borrowing rather than reimplementing.
37
+ *
38
+ * `node_modules` is never scanned. Being a transitive dependency of the user's
39
+ * project means nothing here — the same rule pi applies to itself.
40
+ *
41
+ * ## Accepted manifest spellings
42
+ *
43
+ * All four mean the same thing. The `pi-subagents` top-level key exists for
44
+ * cross-compatibility with `nicobailon/pi-subagents`, which reads the same two
45
+ * shapes, so a package author writes one manifest that works on either extension.
46
+ *
47
+ * "pi": { "subagents": { "agents": ["./agents"], "workflows": ["./flows"] } }
48
+ * "pi": { "subagents": ["./agents"] } // shorthand for { agents }
49
+ * "pi-subagents": { "agents": ["./agents"] }
50
+ * "pi-subagents": ["./agents"] // shorthand for { agents }
51
+ *
52
+ * Adding `pi.subagents` is safe for pi itself: its `readPiManifest` reads only
53
+ * `extensions`/`skills`/`prompts`/`themes` and ignores every other key.
54
+ */
55
+ /** Resource kinds a package may declare. Agents are `.md`, workflows are `.js`. */
56
+ export type PackageResourceKind = "agents" | "workflows";
57
+ /**
58
+ * Per-file size ceiling for package-provided resources, matching Claude Code's
59
+ * plugin-agent limit. These files come from third-party packages and are read
60
+ * eagerly on every agent load; a pathological one should be skipped, not
61
+ * `readFileSync`'d into the session.
62
+ */
63
+ export declare const MAX_PACKAGE_RESOURCE_BYTES = 1048576;
64
+ /** One installed pi package that declared something we understand. */
65
+ export interface PiPackage {
66
+ /** The settings source string, e.g. `npm:@foo/bar@1.0.0` or an absolute path. */
67
+ source: string;
68
+ /** `package.json` `name`, when the manifest could be read. */
69
+ name?: string;
70
+ /** Unscoped, lowercased short name (`@scope/foo` becomes `foo`) for allowlist matching. */
71
+ shortName?: string;
72
+ /** Which settings scope configured it. */
73
+ scope: "user" | "project";
74
+ /** Absolute path of the installed package root. */
75
+ root: string;
76
+ /**
77
+ * What its manifest declared. Carried here rather than re-read downstream:
78
+ * `listPiPackages` has to parse the manifest anyway to know whether the
79
+ * package declares anything at all, and reading it twice would leave two
80
+ * places that could disagree about what a package said.
81
+ */
82
+ declared: DeclaredEntries;
83
+ }
84
+ /**
85
+ * The gate for one resource kind, as persisted in our settings:
86
+ * `true` (default) = every declaring package, `false` = none, `string[]` =
87
+ * only packages whose short name, full name, or source matches an entry.
88
+ */
89
+ export type PackageGate = boolean | string[] | undefined;
90
+ export interface PackageDiscoveryOptions {
91
+ /**
92
+ * Pi's project-trust state for `cwd`, from `ctx.isProjectTrusted()`. When
93
+ * false, `.pi/settings.json` is not read — so a package configured only by an
94
+ * untrusted project is invisible to us, exactly as it is to pi. Omitted falls
95
+ * back to the session state set by {@link setProjectTrusted}.
96
+ */
97
+ projectTrusted?: boolean;
98
+ /** Gate override. Omitted falls back to the session state for the kind. */
99
+ gate?: PackageGate;
100
+ }
101
+ /** Apply the `packageAgents` setting. Drops the cache, since roots may change. */
102
+ export declare function setPackageAgentsGate(gate: PackageGate): void;
103
+ /** Apply the `packageWorkflows` setting. Drops the cache, since roots may change. */
104
+ export declare function setPackageWorkflowsGate(gate: PackageGate): void;
105
+ export declare function getPackageAgentsGate(): PackageGate;
106
+ export declare function getPackageWorkflowsGate(): PackageGate;
107
+ /**
108
+ * Seed the trust state from pi's *saved* decision, before any session exists.
109
+ *
110
+ * The correction on `session_start` is too late for one thing that matters: the
111
+ * `Agent` tool's description — the list of agent types the model is told about —
112
+ * is built once at activation, so an agent registered after it never reaches the
113
+ * model even though dispatch would accept it. That is exactly the shape a team
114
+ * ships agents in: a package named in a committed `.pi/settings.json`, which is
115
+ * invisible until the project is trusted.
116
+ *
117
+ * Pi keeps that decision in `<agentDir>/trust.json`, keyed by canonical path
118
+ * with the nearest ancestor winning, so on the second and every later session in
119
+ * a trusted repo the answer is already on disk. No saved decision falls back to
120
+ * the global `defaultProjectTrust`, which is what pi does; `"ask"` resolves to
121
+ * untrusted here, because the prompt has not been answered yet and guessing yes
122
+ * would be the wrong direction to guess.
123
+ *
124
+ * Best-effort by design: any failure leaves the state untrusted, and
125
+ * `session_start` still delivers pi's real answer either way.
126
+ */
127
+ export declare function seedProjectTrust(cwd: string): void;
128
+ /**
129
+ * Record pi's project-trust answer. Drops the cache when the answer changes,
130
+ * since a project's `packages[]` becomes visible or invisible with it. A repeat
131
+ * of the same answer is a no-op — `session_start` fires on every new, resumed
132
+ * and forked session, and it has its own reason to invalidate.
133
+ */
134
+ export declare function setProjectTrusted(trusted: boolean): void;
135
+ /** Reset every session-scoped value. Tests only — the extension never un-loads. */
136
+ export declare function resetPackageState(): void;
137
+ /** What a package declared, after normalising the accepted spellings. */
138
+ export interface DeclaredEntries {
139
+ agents?: string[];
140
+ workflows?: string[];
141
+ }
142
+ /** Absolute paths a declaration resolved to, split by what the loader needs. */
143
+ export interface ResolvedResourcePaths {
144
+ dirs: string[];
145
+ files: string[];
146
+ /**
147
+ * Canonical paths of `!` entries. Kept separate from `dirs`/`files` rather
148
+ * than subtracted from them because an exclusion usually names a file *inside*
149
+ * an included directory, which is not enumerated until load time.
150
+ */
151
+ excluded: ReadonlySet<string>;
152
+ }
153
+ /**
154
+ * Read the subagent declaration out of a parsed `package.json`.
155
+ *
156
+ * `pi.subagents` wins over the top-level `pi-subagents` when a package carries
157
+ * both — the pi-namespaced key is the primary spelling here, and a package that
158
+ * writes both almost certainly means them to be identical anyway.
159
+ */
160
+ export declare function readSubagentManifest(pkg: unknown): DeclaredEntries | undefined;
161
+ /** `@scope/foo` becomes `foo`, lowercased. The name a user types in an allowlist. */
162
+ export declare function unscopedShortName(name: string): string;
163
+ /**
164
+ * Resolve one kind's declared entries into concrete absolute paths inside the
165
+ * package: directories to scan, and individual files.
166
+ *
167
+ * Split into `{ dirs, files }` rather than a flat list because the agent loader
168
+ * takes directories (it does its own `readdirSync` and frontmatter handling),
169
+ * while a manifest entry naming a single file has to be surfaced on its own.
170
+ *
171
+ * `!entry` marks an exclusion. Exact paths only — pi's own `!` is gitignore-style
172
+ * glob negation, and globs are not supported here for the reason above.
173
+ */
174
+ export declare function resolveDeclaredPaths(root: string, entries: string[] | undefined, kind: PackageResourceKind): ResolvedResourcePaths;
175
+ /**
176
+ * Every installed pi package that declares subagent resources, in pi's own
177
+ * order (global entries first, then project). Duplicates by root are collapsed —
178
+ * a package listed in both scopes is one package on disk.
179
+ */
180
+ export declare function listPiPackages(cwd: string, projectTrusted?: boolean): PiPackage[];
181
+ /**
182
+ * Whether `pkg` passes the gate. `true`/omitted admits everything; an array
183
+ * matches case-insensitively against the unscoped short name, the full package
184
+ * name, or the settings source string — users reach for whichever of the three
185
+ * they happen to have in front of them.
186
+ */
187
+ export declare function packageAllowed(pkg: PiPackage, gate: PackageGate): boolean;
188
+ /** Drop the memoized package scan. Called on `/reload` and after settings changes. */
189
+ export declare function invalidatePackageCache(): void;
190
+ /**
191
+ * Name of the installed package that provided `path`, or undefined when no
192
+ * admitted package owns it. What `/agents` shows so a package agent can name its
193
+ * origin, and what a user needs in order to write a `packageAgents` allowlist.
194
+ *
195
+ * `kind` selects which gate to consult, because the two are configured
196
+ * separately: a package may be admitted for agents but not for workflows.
197
+ *
198
+ * A plain prefix test is enough. `resolveDeclaredPaths` builds every declared
199
+ * path as `resolve(root, entry)` without canonicalizing it — only the
200
+ * containment check and the exclusion set go through `realOrSelf` — so a
201
+ * `sourcePath` the loader derived from one is textually inside the root it came
202
+ * from. The `sep` anchor keeps `…/node_modules/foo` from claiming
203
+ * `…/node_modules/foo-bar`.
204
+ */
205
+ export declare function packageNameForPath(path: string, cwd: string, kind?: PackageResourceKind, opts?: PackageDiscoveryOptions): string | undefined;
206
+ /**
207
+ * Directories of package-declared agent files, lowest-precedence first.
208
+ * Fed to `loadCustomAgents` ahead of the global and project roots.
209
+ */
210
+ export declare function packageAgentDirs(cwd: string, opts?: PackageDiscoveryOptions): string[];
211
+ /** Individually declared agent `.md` files (a manifest entry naming a file, not a directory). */
212
+ export declare function packageAgentFiles(cwd: string, opts?: PackageDiscoveryOptions): string[];
213
+ /**
214
+ * Whether a `!` entry in some package manifest excludes this path.
215
+ *
216
+ * Checked at load time rather than subtracted during resolution, because the
217
+ * common exclusion — `["./agents", "!./agents/wip.md"]` — names a file inside a
218
+ * directory that is not enumerated until the loader reads it.
219
+ */
220
+ export declare function isPackageResourceExcluded(path: string, cwd: string, kind: PackageResourceKind, opts?: PackageDiscoveryOptions): boolean;
221
+ /**
222
+ * Directories of package-declared workflow scripts, appended to
223
+ * `savedWorkflowRoots` so a name resolves there last.
224
+ */
225
+ export declare function packageWorkflowDirs(cwd: string, opts?: PackageDiscoveryOptions): string[];
226
+ /**
227
+ * Individually declared workflow scripts, as `name -> absolute path`.
228
+ *
229
+ * A name lookup wants a directory, and a declared *file* has none — but standing
230
+ * its parent directory in as a root would make every sibling `.js` resolvable,
231
+ * so `workflows: ["./one.js"]` would quietly offer the package's other scripts
232
+ * too, and `["./index.js"]` would offer everything at the package root. That is
233
+ * the opposite of the rule the whole feature rests on, that a package only
234
+ * contributes what it names. An exact map keeps the declaration honest, and
235
+ * matches how a declared agent file is already handled.
236
+ *
237
+ * Later entries lose a name clash, so a package's own directory-sourced script
238
+ * is not displaced by a file entry from a package resolved after it.
239
+ */
240
+ export declare function packageWorkflowFiles(cwd: string, opts?: PackageDiscoveryOptions): Map<string, string>;