@herbertgao/pi-subagents 0.19.0 → 0.22.0-local.1
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 +8 -0
- package/docs/packages.md +211 -0
- package/docs/rpc.md +61 -63
- package/docs/workflows.md +24 -16
- package/package.json +6 -5
- package/src/agent-file-toggle.ts +51 -14
- package/src/agent-manager.ts +123 -55
- package/src/agent-runner.ts +144 -13
- package/src/agent-source-badge.ts +78 -0
- package/src/completion-outbox.ts +122 -0
- package/src/custom-agents.ts +171 -79
- package/src/index.ts +597 -296
- package/src/package-resources.ts +724 -0
- package/src/schedule.ts +1 -1
- package/src/settings.ts +66 -0
- package/src/types.ts +26 -4
- package/src/ui/agent-widget.ts +2 -0
- package/src/ui/conversation-viewer.ts +354 -32
- package/src/ui/fleet-list.ts +33 -15
- package/src/workflow/host.ts +6 -0
- package/src/workflow/saved.ts +48 -2
package/src/workflow/saved.ts
CHANGED
|
@@ -41,18 +41,36 @@ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs"
|
|
|
41
41
|
import { isAbsolute, join } from "node:path"
|
|
42
42
|
import { getAgentDir } from "@earendil-works/pi-coding-agent"
|
|
43
43
|
import { isSymlink, isUnsafeName, safeReadFile } from "../memory.js"
|
|
44
|
+
import {
|
|
45
|
+
isPackageResourceExcluded,
|
|
46
|
+
packageWorkflowDirs,
|
|
47
|
+
packageWorkflowFiles,
|
|
48
|
+
} from "../package-resources.js"
|
|
44
49
|
import { hasMetaDeclaration } from "./meta.js"
|
|
45
50
|
import { MAX_SCRIPT_LENGTH } from "./runtime.js"
|
|
46
51
|
|
|
47
52
|
/** Extension a saved workflow file carries. */
|
|
48
53
|
const WORKFLOW_EXTENSION = ".js"
|
|
49
54
|
|
|
50
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* The roots a `name` is looked up in, highest priority first.
|
|
57
|
+
*
|
|
58
|
+
* Directories declared by installed pi packages come last, so a project, shared
|
|
59
|
+
* workspace or personal script always wins the name. That is the same tier
|
|
60
|
+
* package-provided agents get, and the same tier pi gives package-provided
|
|
61
|
+
* skills — a package offers a workflow, it never takes a name away from you.
|
|
62
|
+
*
|
|
63
|
+
* The `packageWorkflows` gate and pi's project-trust answer are session state in
|
|
64
|
+
* package-resources.ts rather than parameters here, so a gate set in `/agents`
|
|
65
|
+
* reaches this without an options bag travelling through `resolveWorkflowScript`,
|
|
66
|
+
* `resolveWorkflowSource` and `readSavedWorkflow` purely to be consulted once.
|
|
67
|
+
*/
|
|
51
68
|
export function savedWorkflowRoots(cwd: string): string[] {
|
|
52
69
|
return [
|
|
53
70
|
join(cwd, ".pi", "workflows"),
|
|
54
71
|
join(cwd, ".agents", "workflows"),
|
|
55
72
|
join(getAgentDir(), "workflows"),
|
|
73
|
+
...packageWorkflowDirs(cwd),
|
|
56
74
|
]
|
|
57
75
|
}
|
|
58
76
|
|
|
@@ -82,6 +100,9 @@ export function readSavedWorkflow(name: string, cwd: string): SavedWorkflow {
|
|
|
82
100
|
for (const root of roots) {
|
|
83
101
|
if (isSymlink(root)) continue // reject a symlinked root entirely, as skill-loader does
|
|
84
102
|
const path = join(root, `${trimmed}${WORKFLOW_EXTENSION}`)
|
|
103
|
+
// A `!` entry in the declaring package's manifest. Only ever true for a path
|
|
104
|
+
// under a package root, so the local roots pay one set lookup for it.
|
|
105
|
+
if (isPackageResourceExcluded(path, cwd, "workflows")) continue
|
|
85
106
|
const script = safeReadFile(path)
|
|
86
107
|
if (script === undefined) continue
|
|
87
108
|
// Found the file, so stop looking — a shadowing name that turns out not to
|
|
@@ -97,6 +118,25 @@ export function readSavedWorkflow(name: string, cwd: string): SavedWorkflow {
|
|
|
97
118
|
return { ok: true, script, path }
|
|
98
119
|
}
|
|
99
120
|
|
|
121
|
+
// Last: a package that declared an individual file rather than a directory.
|
|
122
|
+
// It carries no root to look a name up in, so it is matched by name here
|
|
123
|
+
// instead — after every root, which keeps package scripts lowest-precedence.
|
|
124
|
+
const declared = packageWorkflowFiles(cwd).get(trimmed)
|
|
125
|
+
if (declared !== undefined) {
|
|
126
|
+
const script = safeReadFile(declared)
|
|
127
|
+
if (script !== undefined) {
|
|
128
|
+
if (!hasMetaDeclaration(script)) {
|
|
129
|
+
return {
|
|
130
|
+
ok: false,
|
|
131
|
+
message:
|
|
132
|
+
`"${declared}" is not a workflow script — it has no \`export const meta = { name, description }\` ` +
|
|
133
|
+
"declaration. Nothing was run.",
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return { ok: true, script, path: declared }
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
100
140
|
const known = listSavedWorkflows(cwd)
|
|
101
141
|
return {
|
|
102
142
|
ok: false,
|
|
@@ -158,9 +198,15 @@ export function listSavedWorkflows(cwd: string): string[] {
|
|
|
158
198
|
if (!entry.endsWith(WORKFLOW_EXTENSION)) continue
|
|
159
199
|
const name = entry.slice(0, -WORKFLOW_EXTENSION.length)
|
|
160
200
|
if (isUnsafeName(name)) continue
|
|
161
|
-
|
|
201
|
+
const path = join(root, entry)
|
|
202
|
+
if (isPackageResourceExcluded(path, cwd, "workflows")) continue
|
|
203
|
+
if (isWorkflowFile(path)) names.add(name)
|
|
162
204
|
}
|
|
163
205
|
}
|
|
206
|
+
for (const [name, path] of packageWorkflowFiles(cwd)) {
|
|
207
|
+
if (isUnsafeName(name)) continue
|
|
208
|
+
if (isWorkflowFile(path)) names.add(name)
|
|
209
|
+
}
|
|
164
210
|
return [...names].sort()
|
|
165
211
|
}
|
|
166
212
|
|