@pi-harness/pi-harness 0.1.29 → 0.1.31
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 +1 -1
- package/apps/web/dist/assets/index-D9ZcvGXi.js +25 -0
- package/apps/web/dist/assets/{index-xF647pQJ.css → index-DJsNIiIo.css} +1 -1
- package/apps/web/dist/index.html +2 -2
- package/apps/web/package.json +1 -15
- package/apps/web/profile/cordis.yml +0 -221
- package/apps/web/server-dist/bin.js +4 -2
- package/apps/web/server-dist/bin.js.map +1 -1
- package/apps/web/src/server/bin.ts +4 -2
- package/apps/web/src/style.css +3 -0
- package/apps/web/test/bin.test.ts +6 -0
- package/node_modules/@pi-harness/api-gateway/dist/index.d.ts.map +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/index.js +43 -12
- package/node_modules/@pi-harness/api-gateway/dist/index.js.map +1 -1
- package/node_modules/@pi-harness/api-gateway/package.json +1 -27
- package/node_modules/@pi-harness/cli/dist/bin.js +2 -1
- package/node_modules/@pi-harness/cli/dist/bin.js.map +1 -1
- package/node_modules/@pi-harness/cli/dist/main.d.ts +2 -0
- package/node_modules/@pi-harness/cli/dist/main.d.ts.map +1 -1
- package/node_modules/@pi-harness/cli/dist/main.js +8 -1
- package/node_modules/@pi-harness/cli/dist/main.js.map +1 -1
- package/node_modules/@pi-harness/cli/package.json +1 -1
- package/node_modules/@pi-harness/cli/profiles/default/cordis.yml +0 -87
- package/node_modules/@pi-harness/host-webserver/package.json +1 -1
- package/node_modules/@pi-harness/web-app/package.json +1 -1
- package/package.json +8 -35
- package/packages/api-gateway/dist/index.d.ts.map +1 -1
- package/packages/api-gateway/dist/index.js +43 -12
- package/packages/api-gateway/dist/index.js.map +1 -1
- package/packages/api-gateway/package.json +1 -27
- package/packages/api-gateway/src/index.ts +55 -17
- package/packages/api-gateway/test/index.test.ts +157 -2
- package/packages/api-gateway/test/packed-package.test.ts +106 -10
- package/packages/api-gateway/test/release-contract.test.ts +10 -5
- package/packages/bundle-web-app/package.json +1 -1
- package/packages/cli/dist/bin.js +2 -1
- package/packages/cli/dist/bin.js.map +1 -1
- package/packages/cli/dist/main.d.ts +2 -0
- package/packages/cli/dist/main.d.ts.map +1 -1
- package/packages/cli/dist/main.js +8 -1
- package/packages/cli/dist/main.js.map +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/cli/profiles/default/cordis.yml +0 -87
- package/packages/cli/src/bin.ts +2 -1
- package/packages/cli/src/main.ts +10 -1
- package/packages/cli/test/binary.test.ts +5 -1
- package/packages/cli/test/broken-pipe.test.ts +1 -1
- package/packages/cli/test/cli.test.ts +1 -0
- package/packages/cli/test/main.test.ts +1 -0
- package/packages/cli/test/profiles/plugins/cordis.yml +122 -0
- package/packages/cli/test/profiles.integration.test.ts +40 -23
- package/packages/host-webserver/package.json +1 -1
- package/apps/web/dist/assets/index-DCkzrlCA.js +0 -25
|
@@ -26,231 +26,10 @@
|
|
|
26
26
|
- bash
|
|
27
27
|
- edit
|
|
28
28
|
- write
|
|
29
|
-
- id: agent-teams
|
|
30
|
-
name: "@pi-harness/plugin-agent-teams"
|
|
31
|
-
config: {}
|
|
32
|
-
- id: modlens
|
|
33
|
-
name: "@pi-harness/plugin-modlens"
|
|
34
|
-
config: {}
|
|
35
|
-
- id: git-time-capsule
|
|
36
|
-
name: "@pi-harness/plugin-git-time-capsule"
|
|
37
|
-
config: {}
|
|
38
|
-
- id: dependency-checker
|
|
39
|
-
name: "@pi-harness/plugin-dependency-checker"
|
|
40
|
-
config: {}
|
|
41
|
-
- id: at-file
|
|
42
|
-
name: "@pi-harness/plugin-at-file"
|
|
43
|
-
config: {}
|
|
44
|
-
- id: test-harness
|
|
45
|
-
name: "@pi-harness/plugin-test-harness"
|
|
46
|
-
config: {}
|
|
47
|
-
- id: session-insights
|
|
48
|
-
name: "@pi-harness/plugin-session-insights"
|
|
49
|
-
config: {}
|
|
50
|
-
- id: readme-gen
|
|
51
|
-
name: "@pi-harness/plugin-readme-gen"
|
|
52
|
-
config: {}
|
|
53
|
-
- id: i18n-pair
|
|
54
|
-
name: "@pi-harness/plugin-i18n-pair"
|
|
55
|
-
config: {}
|
|
56
|
-
- id: cleaner
|
|
57
|
-
name: "@pi-harness/plugin-cleaner"
|
|
58
|
-
config: {}
|
|
59
|
-
- id: sql-lens
|
|
60
|
-
name: "@pi-harness/plugin-sql-lens"
|
|
61
|
-
config: {}
|
|
62
|
-
- id: docker-sandbox
|
|
63
|
-
name: "@pi-harness/plugin-docker-sandbox"
|
|
64
|
-
config: {}
|
|
65
|
-
- id: mcp-client
|
|
66
|
-
name: "@pi-harness/plugin-mcp-client"
|
|
67
|
-
config: {}
|
|
68
|
-
- id: mcp-panel
|
|
69
|
-
name: "@pi-harness/plugin-mcp-panel"
|
|
70
|
-
config: {}
|
|
71
|
-
- id: browser-fetch
|
|
72
|
-
name: "@pi-harness/plugin-browser-fetch"
|
|
73
|
-
config: {}
|
|
74
|
-
- id: web-research
|
|
75
|
-
name: "@pi-harness/plugin-web-research"
|
|
76
|
-
config: {}
|
|
77
|
-
- id: browser-session
|
|
78
|
-
name: "@pi-harness/plugin-browser-session"
|
|
79
|
-
config: {}
|
|
80
|
-
- id: yaml-validator
|
|
81
|
-
name: "@pi-harness/plugin-yaml-validator"
|
|
82
|
-
config: {}
|
|
83
|
-
- id: mock-server
|
|
84
|
-
name: "@pi-harness/plugin-mock-server"
|
|
85
|
-
config: {}
|
|
86
|
-
- id: cli-notifier
|
|
87
|
-
name: "@pi-harness/plugin-cli-notifier"
|
|
88
|
-
config: {}
|
|
89
|
-
- id: obsidian-sync
|
|
90
|
-
name: "@pi-harness/plugin-obsidian-sync"
|
|
91
|
-
config: {}
|
|
92
|
-
- id: context-doctor
|
|
93
|
-
name: "@pi-harness/plugin-context-doctor"
|
|
94
|
-
config: {}
|
|
95
|
-
- id: history-compressor
|
|
96
|
-
name: "@pi-harness/plugin-history-compressor"
|
|
97
|
-
config: {}
|
|
98
|
-
- id: reviewer-bot
|
|
99
|
-
name: "@pi-harness/plugin-reviewer-bot"
|
|
100
|
-
config: {}
|
|
101
|
-
- id: auto-mode
|
|
102
|
-
name: "@pi-harness/plugin-auto-mode"
|
|
103
|
-
config: {}
|
|
104
|
-
- id: plan-execute
|
|
105
|
-
name: "@pi-harness/plugin-plan-execute"
|
|
106
|
-
config: {}
|
|
107
|
-
- id: plugin-finder
|
|
108
|
-
name: "@pi-harness/plugin-plugin-finder"
|
|
109
|
-
config: {}
|
|
110
|
-
- id: memory
|
|
111
|
-
name: "@pi-harness/plugin-memory"
|
|
112
|
-
config: {}
|
|
113
|
-
- id: graph-memory
|
|
114
|
-
name: "@pi-harness/plugin-graph-memory"
|
|
115
|
-
config: {}
|
|
116
|
-
- id: taskboard
|
|
117
|
-
name: "@pi-harness/plugin-taskboard"
|
|
118
|
-
config: {}
|
|
119
|
-
- id: synapse
|
|
120
|
-
name: "@pi-harness/plugin-synapse"
|
|
121
|
-
config: {}
|
|
122
|
-
- id: hol-guard
|
|
123
|
-
name: "@pi-harness/plugin-hol-guard"
|
|
124
|
-
config: {}
|
|
125
|
-
- id: plugin-radar
|
|
126
|
-
name: "@pi-harness/plugin-plugin-radar"
|
|
127
|
-
config: {}
|
|
128
|
-
- id: plugin-stars
|
|
129
|
-
name: "@pi-harness/plugin-plugin-stars"
|
|
130
|
-
config: {}
|
|
131
|
-
- id: plugin-check
|
|
132
|
-
name: "@pi-harness/plugin-plugin-check"
|
|
133
|
-
config: {}
|
|
134
|
-
- id: annotation
|
|
135
|
-
name: "@pi-harness/plugin-annotation"
|
|
136
|
-
config: {}
|
|
137
|
-
- id: cost-meter
|
|
138
|
-
name: "@pi-harness/plugin-cost-meter"
|
|
139
|
-
config:
|
|
140
|
-
dailyBudget: 0
|
|
141
|
-
- id: undo-savepoint
|
|
142
|
-
name: "@pi-harness/plugin-undo-savepoint"
|
|
143
|
-
config: {}
|
|
144
|
-
- id: skill-catalog
|
|
145
|
-
name: "@pi-harness/plugin-skill-catalog"
|
|
146
|
-
config: {}
|
|
147
|
-
- id: canvas-draw
|
|
148
|
-
name: "@pi-harness/plugin-canvas-draw"
|
|
149
|
-
config: {}
|
|
150
|
-
- id: image-compressor
|
|
151
|
-
name: "@pi-harness/plugin-image-compressor"
|
|
152
|
-
config: {}
|
|
153
|
-
- id: workspace-search
|
|
154
|
-
name: "@pi-harness/plugin-workspace-search"
|
|
155
|
-
config: {}
|
|
156
|
-
- id: prompt-guard
|
|
157
|
-
name: "@pi-harness/plugin-prompt-guard"
|
|
158
|
-
config: {}
|
|
159
|
-
- id: code2skill
|
|
160
|
-
name: "@pi-harness/plugin-code2skill"
|
|
161
|
-
config: {}
|
|
162
|
-
- id: tab-manager
|
|
163
|
-
name: "@pi-harness/plugin-tab-manager"
|
|
164
|
-
config: {}
|
|
165
|
-
- id: genui
|
|
166
|
-
name: "@pi-harness/plugin-genui"
|
|
167
|
-
config: {}
|
|
168
|
-
- id: anchored-standard
|
|
169
|
-
name: "@pi-harness/plugin-anchored-standard"
|
|
170
|
-
config: {}
|
|
171
|
-
- id: telemetry-blocker
|
|
172
|
-
name: "@pi-harness/plugin-telemetry-blocker"
|
|
173
|
-
config: {}
|
|
174
|
-
- id: change-verifier
|
|
175
|
-
name: "@pi-harness/plugin-change-verifier"
|
|
176
|
-
config: {}
|
|
177
|
-
- id: context
|
|
178
|
-
name: "@pi-harness/plugin-context"
|
|
179
|
-
config: {}
|
|
180
29
|
- id: runtime
|
|
181
30
|
name: "@pi-harness/core/plugins/runtime"
|
|
182
31
|
config:
|
|
183
32
|
thinkingLevel: medium
|
|
184
|
-
- id: plugin-dev
|
|
185
|
-
name: "@pi-harness/plugin-plugin-dev"
|
|
186
|
-
config: {}
|
|
187
|
-
- id: openpets
|
|
188
|
-
name: "@pi-harness/plugin-openpets"
|
|
189
|
-
config: {}
|
|
190
|
-
- id: session-bridge
|
|
191
|
-
name: "@pi-harness/plugin-session-bridge"
|
|
192
|
-
config: {}
|
|
193
|
-
- id: skill-guard
|
|
194
|
-
name: "@pi-harness/plugin-skill-guard"
|
|
195
|
-
config: {}
|
|
196
|
-
- id: recall-unread
|
|
197
|
-
name: "@pi-harness/plugin-recall-unread"
|
|
198
|
-
config: {}
|
|
199
|
-
- id: turn-rewind
|
|
200
|
-
name: "@pi-harness/plugin-turn-rewind"
|
|
201
|
-
config: {}
|
|
202
|
-
- id: session-export
|
|
203
|
-
name: "@pi-harness/plugin-session-export"
|
|
204
|
-
config: {}
|
|
205
|
-
- id: session-search
|
|
206
|
-
name: "@pi-harness/plugin-session-search"
|
|
207
|
-
config: {}
|
|
208
|
-
- id: session-compare
|
|
209
|
-
name: "@pi-harness/plugin-session-compare"
|
|
210
|
-
config: {}
|
|
211
|
-
- id: secure-audit
|
|
212
|
-
name: "@pi-harness/plugin-secure-audit"
|
|
213
|
-
config: {}
|
|
214
|
-
- id: session-bookmarks
|
|
215
|
-
name: "@pi-harness/plugin-session-bookmarks"
|
|
216
|
-
config: {}
|
|
217
|
-
- id: llm-verifier
|
|
218
|
-
name: "@pi-harness/plugin-llm-verifier"
|
|
219
|
-
config: {}
|
|
220
|
-
- id: module-search
|
|
221
|
-
name: "@pi-harness/plugin-module-search"
|
|
222
|
-
config: {}
|
|
223
|
-
- id: workspace-navigator
|
|
224
|
-
name: "@pi-harness/plugin-workspace-navigator"
|
|
225
|
-
config: {}
|
|
226
|
-
- id: better-sidebar
|
|
227
|
-
name: "@pi-harness/plugin-better-sidebar"
|
|
228
|
-
config: {}
|
|
229
|
-
- id: archify
|
|
230
|
-
name: "@pi-harness/plugin-archify"
|
|
231
|
-
config: {}
|
|
232
|
-
- id: reverse-skill
|
|
233
|
-
name: "@pi-harness/plugin-reverse-skill"
|
|
234
|
-
config: {}
|
|
235
|
-
- id: colleague-skill
|
|
236
|
-
name: "@pi-harness/plugin-colleague-skill"
|
|
237
|
-
config: {}
|
|
238
|
-
- id: prompt-library
|
|
239
|
-
name: "@pi-harness/plugin-prompt-library"
|
|
240
|
-
config: {}
|
|
241
|
-
- id: token-guard
|
|
242
|
-
name: "@pi-harness/plugin-token-guard"
|
|
243
|
-
config:
|
|
244
|
-
maxPercent: 90
|
|
245
|
-
- id: fail-logger
|
|
246
|
-
name: "@pi-harness/plugin-fail-logger"
|
|
247
|
-
config: {}
|
|
248
|
-
- id: vision-toolkit
|
|
249
|
-
name: "@pi-harness/plugin-vision-toolkit"
|
|
250
|
-
config: {}
|
|
251
|
-
- id: runtime-doctor
|
|
252
|
-
name: "@pi-harness/plugin-runtime-doctor"
|
|
253
|
-
config: {}
|
|
254
33
|
- id: webserver
|
|
255
34
|
name: "@pi-harness/host-webserver"
|
|
256
35
|
config:
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { bootHarness, coreUpdateNotice, provideLaunchContext } from "@pi-harness/core";
|
|
5
|
+
import { bootHarness, coreUpdateNotice, prepareHarnessProfile, provideLaunchContext } from "@pi-harness/core";
|
|
6
6
|
import "@pi-harness/host-webserver";
|
|
7
7
|
// An unhandled 'error' event on a stream throws, so an EPIPE from a reader that closed early (`pi-harness | head -1`) would kill the process before the signal handlers can run the graceful shutdown. Swallowing the event leaves the write silently dropped, which is what a closed pipe means.
|
|
8
8
|
process.stdout.on("error", () => { });
|
|
@@ -41,7 +41,9 @@ const cwd = process.cwd();
|
|
|
41
41
|
const configuredAgentDir = process.env.PI_AGENT_DIR?.trim();
|
|
42
42
|
const agentDir = configuredAgentDir === undefined || configuredAgentDir.length === 0 ? join(homedir(), ".pi", "agent") : resolve(cwd, configuredAgentDir);
|
|
43
43
|
const staticDir = fileURLToPath(new URL("../dist", import.meta.url));
|
|
44
|
-
const
|
|
44
|
+
const builtinProfilePath = fileURLToPath(new URL("../profile/cordis.yml", import.meta.url));
|
|
45
|
+
// The web console installs marketplace plugins with npm and then imports them, so the profile it edits and the node_modules it installs into live in a directory the user owns rather than inside the installed package, which npm replaces on every upgrade.
|
|
46
|
+
const profilePath = await prepareHarnessProfile({ builtinProfilePath, profileName: "web", cwd });
|
|
45
47
|
process.env.PI_HARNESS_WEB_DIST = staticDir;
|
|
46
48
|
process.env.PI_HARNESS_HOST = host;
|
|
47
49
|
process.env.PI_HARNESS_PORT = String(port);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/server/bin.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/server/bin.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { join, resolve } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { bootHarness, coreUpdateNotice, provideLaunchContext } from "@pi-harness/core";
|
|
6
|
+
import { bootHarness, coreUpdateNotice, prepareHarnessProfile, provideLaunchContext } from "@pi-harness/core";
|
|
7
7
|
import "@pi-harness/host-webserver";
|
|
8
8
|
import type { WebServer } from "@pi-harness/host-webserver";
|
|
9
9
|
|
|
@@ -46,7 +46,9 @@ const cwd = process.cwd();
|
|
|
46
46
|
const configuredAgentDir = process.env.PI_AGENT_DIR?.trim();
|
|
47
47
|
const agentDir = configuredAgentDir === undefined || configuredAgentDir.length === 0 ? join(homedir(), ".pi", "agent") : resolve(cwd, configuredAgentDir);
|
|
48
48
|
const staticDir = fileURLToPath(new URL("../dist", import.meta.url));
|
|
49
|
-
const
|
|
49
|
+
const builtinProfilePath = fileURLToPath(new URL("../profile/cordis.yml", import.meta.url));
|
|
50
|
+
// The web console installs marketplace plugins with npm and then imports them, so the profile it edits and the node_modules it installs into live in a directory the user owns rather than inside the installed package, which npm replaces on every upgrade.
|
|
51
|
+
const profilePath = await prepareHarnessProfile({ builtinProfilePath, profileName: "web", cwd });
|
|
50
52
|
process.env.PI_HARNESS_WEB_DIST = staticDir;
|
|
51
53
|
process.env.PI_HARNESS_HOST = host;
|
|
52
54
|
process.env.PI_HARNESS_PORT = String(port);
|
package/apps/web/src/style.css
CHANGED
|
@@ -2041,6 +2041,9 @@ button:disabled {
|
|
|
2041
2041
|
.plugin-action-error {
|
|
2042
2042
|
@apply [margin:10px_0_0_37px] [color:var(--color-red)] [font-size:11px];
|
|
2043
2043
|
}
|
|
2044
|
+
.plugin-action-notice {
|
|
2045
|
+
@apply [margin:10px_0_0_37px] [color:#8a5a00] [font-size:11px];
|
|
2046
|
+
}
|
|
2044
2047
|
.plugin-confirm-backdrop {
|
|
2045
2048
|
@apply [position:fixed] [inset:0] [z-index:60] [display:grid] [place-items:center] [padding:24px] [background:rgba(15,_23,_42,_0.32)] [backdrop-filter:blur(6px)];
|
|
2046
2049
|
}
|
|
@@ -44,6 +44,7 @@ async function runLauncher(
|
|
|
44
44
|
probe?: (consoleUrl: string) => Promise<void>,
|
|
45
45
|
): Promise<LauncherRun> {
|
|
46
46
|
const agentDir = await makeTempDir("agent");
|
|
47
|
+
const harnessHome = await makeTempDir("home");
|
|
47
48
|
const child = spawn(process.execPath, [BIN], {
|
|
48
49
|
stdio: ["ignore", "pipe", "pipe"],
|
|
49
50
|
...(spawnCwd === undefined ? {} : { cwd: spawnCwd }),
|
|
@@ -51,6 +52,7 @@ async function runLauncher(
|
|
|
51
52
|
...process.env,
|
|
52
53
|
PI_HARNESS_PORT: "0",
|
|
53
54
|
PI_AGENT_DIR: agentDir,
|
|
55
|
+
PI_HARNESS_HOME: harnessHome,
|
|
54
56
|
PI_HARNESS_PROVIDER: "anthropic",
|
|
55
57
|
PI_HARNESS_MODEL: "claude-sonnet-4-5",
|
|
56
58
|
...extraEnv,
|
|
@@ -95,12 +97,14 @@ async function runLauncher(
|
|
|
95
97
|
// Runs the built launcher until it exits on its own, for the startup guards that must abort before a console URL is ever printed.
|
|
96
98
|
async function runLauncherToExit(extraEnv: Record<string, string>): Promise<LauncherExit> {
|
|
97
99
|
const agentDir = await makeTempDir("guard");
|
|
100
|
+
const harnessHome = await makeTempDir("guard-home");
|
|
98
101
|
const child = spawn(process.execPath, [BIN], {
|
|
99
102
|
stdio: ["ignore", "pipe", "pipe"],
|
|
100
103
|
env: {
|
|
101
104
|
...process.env,
|
|
102
105
|
PI_HARNESS_PORT: "0",
|
|
103
106
|
PI_AGENT_DIR: agentDir,
|
|
107
|
+
PI_HARNESS_HOME: harnessHome,
|
|
104
108
|
PI_HARNESS_PROVIDER: "anthropic",
|
|
105
109
|
PI_HARNESS_MODEL: "claude-sonnet-4-5",
|
|
106
110
|
PI_HARNESS_DISABLE_UPDATE_CHECK: "1",
|
|
@@ -198,6 +202,7 @@ describe("web launcher", () => {
|
|
|
198
202
|
|
|
199
203
|
test("keeps serving and shuts down gracefully when a closed stdout pipe breaks the console URL write", async () => {
|
|
200
204
|
const agentDir = await makeTempDir("epipe");
|
|
205
|
+
const harnessHome = await makeTempDir("epipe-home");
|
|
201
206
|
const port = await reserveLoopbackPort();
|
|
202
207
|
const child = spawn(process.execPath, [BIN], {
|
|
203
208
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -205,6 +210,7 @@ describe("web launcher", () => {
|
|
|
205
210
|
...process.env,
|
|
206
211
|
PI_HARNESS_PORT: String(port),
|
|
207
212
|
PI_AGENT_DIR: agentDir,
|
|
213
|
+
PI_HARNESS_HOME: harnessHome,
|
|
208
214
|
PI_HARNESS_PROVIDER: "anthropic",
|
|
209
215
|
PI_HARNESS_MODEL: "claude-sonnet-4-5",
|
|
210
216
|
PI_HARNESS_DISABLE_UPDATE_CHECK: "1",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;;;;mBAmuBlC,OAAO;;AAHxB,wBA+4CE"}
|
|
@@ -3,10 +3,11 @@ import { mkdir, mkdtemp, readFile, realpath, rename, rm, stat, unlink, writeFile
|
|
|
3
3
|
import { basename, dirname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
5
|
import { SessionManager } from "@earendil-works/pi-coding-agent";
|
|
6
|
-
import { atomicWriteFile } from "@pi-harness/core";
|
|
6
|
+
import { atomicWriteFile, isPiToolRegistryLeasedError } from "@pi-harness/core";
|
|
7
7
|
import { MARKETPLACE_CAPABILITIES, MARKETPLACE_CATEGORIES, MARKETPLACE_PLUGINS, attachMarketplaceStatistics, createMarketplaceStatisticsLoader, paginateMarketplace, searchMarketplace, marketplaceNpmPackageName, sortMarketplaceByRecommendation, } from "./marketplace.js";
|
|
8
8
|
import { parseGitWorktrees } from "./workspaces.js";
|
|
9
9
|
const loadMarketplaceStatistics = createMarketplaceStatisticsLoader();
|
|
10
|
+
const RUNTIME_ENTRY_NAME = "@pi-harness/core/plugins/runtime";
|
|
10
11
|
const DEFAULT_BODY_LIMIT_BYTES = 64 * 1024;
|
|
11
12
|
const IMPORT_CONTENT_LIMIT_BYTES = 10 * 1024 * 1024;
|
|
12
13
|
// The import body carries the JSONL content as a JSON string, so quotes and newlines are escaped; leave headroom above the content limit for that overhead.
|
|
@@ -434,15 +435,23 @@ function runProcess(executable, args, cwd) {
|
|
|
434
435
|
});
|
|
435
436
|
});
|
|
436
437
|
}
|
|
437
|
-
|
|
438
|
+
// A plugin registers its tools before pi-runtime acquires the tool registry, so an installed entry has to sit in the runtime's own group ahead of the runtime. Appended at the end of the profile it would load after the runtime and fail on every subsequent start.
|
|
439
|
+
function marketplaceProfileEntry(plugin, indent) {
|
|
440
|
+
const child = `${indent} `;
|
|
441
|
+
const group = plugin.profile.group === true ? `\n${child}group: true` : "";
|
|
442
|
+
return `${indent}- id: marketplace-${plugin.id}\n${child}name: ${JSON.stringify(plugin.packageName)}${group}\n${child}config: ${JSON.stringify(plugin.profile.config)}\n`;
|
|
443
|
+
}
|
|
444
|
+
async function appendMarketplaceProfile(configPath, plugin, beforeEntryId) {
|
|
438
445
|
const source = await readFile(configPath, "utf8");
|
|
439
446
|
if (source.includes(`name: ${JSON.stringify(plugin.packageName)}`))
|
|
440
447
|
return source;
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
448
|
+
const anchor = beforeEntryId === undefined ? null : source.match(new RegExp(`^([ \\t]*)- id: ${beforeEntryId.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")}[ \\t]*$`, "mu"));
|
|
449
|
+
if (anchor === null) {
|
|
450
|
+
await writeFile(configPath, `${source.replace(/\s*$/u, "")}\n${marketplaceProfileEntry(plugin, "")}`, "utf8");
|
|
451
|
+
return source;
|
|
452
|
+
}
|
|
453
|
+
const start = anchor.index ?? 0;
|
|
454
|
+
await writeFile(configPath, source.slice(0, start) + marketplaceProfileEntry(plugin, anchor[1] ?? "") + source.slice(start), "utf8");
|
|
446
455
|
return source;
|
|
447
456
|
}
|
|
448
457
|
async function updateMarketplaceProfile(configPath, entryId, update) {
|
|
@@ -590,7 +599,7 @@ async function isFile(path) {
|
|
|
590
599
|
return false;
|
|
591
600
|
}
|
|
592
601
|
}
|
|
593
|
-
// The loader resolves a bare plugin specifier from the profile file upwards
|
|
602
|
+
// The loader resolves a bare plugin specifier by walking node_modules from the profile file upwards, never from the shell the harness was started in, so a marketplace package has to land in the package that owns the profile or it installs successfully and then fails to load. Under a built-in profile that package is the harness home, which is why the launcher boots a copy there instead of the read-only one inside its own installation.
|
|
594
603
|
async function marketplaceInstallDirectory(configPath, fallback) {
|
|
595
604
|
let directory = dirname(resolve(configPath));
|
|
596
605
|
let parent = dirname(directory);
|
|
@@ -602,6 +611,17 @@ async function marketplaceInstallDirectory(configPath, fallback) {
|
|
|
602
611
|
}
|
|
603
612
|
return fallback;
|
|
604
613
|
}
|
|
614
|
+
// Where an installed plugin belongs in the running loader: inside the group that owns pi-runtime, immediately ahead of it. A profile without a runtime entry (the stdio CLI profile does have one, a hand-written profile may not) places the entry at the end of the root instead.
|
|
615
|
+
function runtimePlacement(loader) {
|
|
616
|
+
const entries = [...loader.entries()];
|
|
617
|
+
const runtime = entries.find((entry) => entry.options.name === RUNTIME_ENTRY_NAME);
|
|
618
|
+
if (runtime === undefined)
|
|
619
|
+
return undefined;
|
|
620
|
+
const group = entries.find((entry) => entry.subgroup === runtime.parent);
|
|
621
|
+
const position = runtime.parent.data.indexOf(runtime.options);
|
|
622
|
+
// The loader addresses a nested group by its qualified id (`profile:agent`), while the profile file names the entry by its own id.
|
|
623
|
+
return { groupEntryId: group?.id ?? null, position: position < 0 ? Infinity : position, beforeEntryId: runtime.options.id };
|
|
624
|
+
}
|
|
605
625
|
function pickDirectory() {
|
|
606
626
|
return new Promise((resolvePath, reject) => {
|
|
607
627
|
execFile("osascript", ["-e", 'POSIX path of (choose folder with prompt "选择 Pi 工作区")'], { timeout: 120_000, maxBuffer: 64 * 1024 }, (error, stdout, stderr) => {
|
|
@@ -1057,27 +1077,33 @@ export default {
|
|
|
1057
1077
|
const packageLockPath = join(installDirectory, "package-lock.json");
|
|
1058
1078
|
const packageJsonBefore = await readFile(packageJsonPath, "utf8").catch(() => undefined);
|
|
1059
1079
|
const packageLockBefore = await readFile(packageLockPath, "utf8").catch(() => undefined);
|
|
1080
|
+
const placement = runtimePlacement(loader);
|
|
1060
1081
|
let profileBefore;
|
|
1061
1082
|
let entryId;
|
|
1062
1083
|
try {
|
|
1063
1084
|
const specifier = `${marketplaceNpmPackageName(plugin.packageName)}@${plugin.version}`;
|
|
1064
1085
|
await runProcess("npm", ["install", "--save-exact", "--package-lock=false", specifier], installDirectory);
|
|
1065
|
-
profileBefore = await appendMarketplaceProfile(configPath, plugin);
|
|
1086
|
+
profileBefore = await appendMarketplaceProfile(configPath, plugin, placement?.beforeEntryId);
|
|
1066
1087
|
entryId = await loader.create({
|
|
1067
1088
|
id: `marketplace-${plugin.id}`,
|
|
1068
1089
|
name: plugin.packageName,
|
|
1069
1090
|
...(plugin.profile.group === true ? { group: true } : {}),
|
|
1070
1091
|
config: plugin.profile.config,
|
|
1071
|
-
});
|
|
1092
|
+
}, placement?.groupEntryId ?? null, placement?.position ?? Infinity);
|
|
1072
1093
|
const entry = loader.resolve(entryId);
|
|
1073
1094
|
if (entry.fiber === undefined)
|
|
1074
1095
|
throw new Error(`Plugin ${plugin.packageName} did not create a runtime fiber`);
|
|
1075
1096
|
await entry.fiber.await();
|
|
1076
|
-
sendJson(response, 200, { plugin, installed: true });
|
|
1097
|
+
sendJson(response, 200, { plugin, installed: true, restartRequired: false });
|
|
1077
1098
|
}
|
|
1078
1099
|
catch (error) {
|
|
1079
1100
|
if (entryId !== undefined)
|
|
1080
1101
|
await loader.remove(entryId).catch(() => { });
|
|
1102
|
+
// The runtime holds the tool registry for its whole life and snapshots the tool set when it takes it, so a plugin that contributes tools cannot join a harness that is already running. The package and its profile entry stay in place and the plugin arrives on the next start; rolling the install back would leave the user unable to install it at all.
|
|
1103
|
+
if (isPiToolRegistryLeasedError(error)) {
|
|
1104
|
+
sendJson(response, 200, { plugin, installed: true, restartRequired: true });
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1081
1107
|
if (profileBefore !== undefined)
|
|
1082
1108
|
await writeFile(configPath, profileBefore, "utf8").catch(() => { });
|
|
1083
1109
|
// A manifest npm created for this install is removed rather than left behind; restoring is only possible when one existed before.
|
|
@@ -1138,9 +1164,14 @@ export default {
|
|
|
1138
1164
|
const before = await updateMarketplaceProfile(configPath, profileEntryId, { disabled: !payload.enabled });
|
|
1139
1165
|
try {
|
|
1140
1166
|
await entry.update({ disabled: !payload.enabled });
|
|
1141
|
-
sendJson(response, 200, { plugin: pluginSummary(entry) });
|
|
1167
|
+
sendJson(response, 200, { plugin: pluginSummary(entry), restartRequired: false });
|
|
1142
1168
|
}
|
|
1143
1169
|
catch (error) {
|
|
1170
|
+
// Re-enabling a plugin that contributes tools cannot take effect in a harness the runtime already leased, so the profile keeps the change and the plugin comes back on the next start. Reverting it would leave a plugin that can be switched off but never on again.
|
|
1171
|
+
if (isPiToolRegistryLeasedError(error)) {
|
|
1172
|
+
sendJson(response, 200, { plugin: pluginSummary(entry), restartRequired: true });
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1144
1175
|
await writeFile(configPath, before, "utf8").catch(() => { });
|
|
1145
1176
|
sendJson(response, 502, { error: errorText(error) });
|
|
1146
1177
|
}
|