pi-harness-workspace 0.1.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 (185) hide show
  1. package/README.md +152 -0
  2. package/apps/web/dist/assets/index-C4tLweAB.js +20 -0
  3. package/apps/web/dist/assets/index-DPgRbQ4_.css +1 -0
  4. package/apps/web/dist/index.html +14 -0
  5. package/apps/web/index.html +13 -0
  6. package/apps/web/package.json +24 -0
  7. package/apps/web/profile/cordis.yml +44 -0
  8. package/apps/web/server-dist/bin.d.ts +3 -0
  9. package/apps/web/server-dist/bin.d.ts.map +1 -0
  10. package/apps/web/server-dist/bin.js +67 -0
  11. package/apps/web/server-dist/bin.js.map +1 -0
  12. package/apps/web/src/command-palette.ts +84 -0
  13. package/apps/web/src/file-diff.ts +42 -0
  14. package/apps/web/src/main.ts +12 -0
  15. package/apps/web/src/runtime.css +4 -0
  16. package/apps/web/src/server/bin.ts +64 -0
  17. package/apps/web/src/style.css +7 -0
  18. package/apps/web/tsconfig.build.json +1 -0
  19. package/apps/web/tsconfig.json +1 -0
  20. package/package.json +41 -0
  21. package/packages/api-gateway/dist/index.d.ts +8 -0
  22. package/packages/api-gateway/dist/index.d.ts.map +1 -0
  23. package/packages/api-gateway/dist/index.js +582 -0
  24. package/packages/api-gateway/dist/index.js.map +1 -0
  25. package/packages/api-gateway/package.json +22 -0
  26. package/packages/api-gateway/src/index.ts +577 -0
  27. package/packages/api-gateway/test/index.test.ts +327 -0
  28. package/packages/api-gateway/tsconfig.build.json +1 -0
  29. package/packages/api-gateway/tsconfig.json +1 -0
  30. package/packages/bundle-web-app/cordis.patch.yml +12 -0
  31. package/packages/bundle-web-app/dist/index.d.ts +12 -0
  32. package/packages/bundle-web-app/dist/index.d.ts.map +1 -0
  33. package/packages/bundle-web-app/dist/index.js +63 -0
  34. package/packages/bundle-web-app/dist/index.js.map +1 -0
  35. package/packages/bundle-web-app/package.json +22 -0
  36. package/packages/bundle-web-app/src/index.ts +69 -0
  37. package/packages/bundle-web-app/test/index.test.ts +29 -0
  38. package/packages/bundle-web-app/tsconfig.build.json +1 -0
  39. package/packages/bundle-web-app/tsconfig.json +1 -0
  40. package/packages/cli/dist/args.d.ts +16 -0
  41. package/packages/cli/dist/args.d.ts.map +1 -0
  42. package/packages/cli/dist/args.js +53 -0
  43. package/packages/cli/dist/args.js.map +1 -0
  44. package/packages/cli/dist/bin.d.ts +3 -0
  45. package/packages/cli/dist/bin.d.ts.map +1 -0
  46. package/packages/cli/dist/bin.js +40 -0
  47. package/packages/cli/dist/bin.js.map +1 -0
  48. package/packages/cli/dist/main.d.ts +14 -0
  49. package/packages/cli/dist/main.d.ts.map +1 -0
  50. package/packages/cli/dist/main.js +148 -0
  51. package/packages/cli/dist/main.js.map +1 -0
  52. package/packages/cli/dist/node-stdio.d.ts +10 -0
  53. package/packages/cli/dist/node-stdio.d.ts.map +1 -0
  54. package/packages/cli/dist/node-stdio.js +34 -0
  55. package/packages/cli/dist/node-stdio.js.map +1 -0
  56. package/packages/cli/dist/relaunch.d.ts +5 -0
  57. package/packages/cli/dist/relaunch.d.ts.map +1 -0
  58. package/packages/cli/dist/relaunch.js +52 -0
  59. package/packages/cli/dist/relaunch.js.map +1 -0
  60. package/packages/cli/package.json +25 -0
  61. package/packages/cli/src/args.ts +50 -0
  62. package/packages/cli/src/bin.ts +41 -0
  63. package/packages/cli/src/main.ts +155 -0
  64. package/packages/cli/src/node-stdio.ts +40 -0
  65. package/packages/cli/src/relaunch.ts +48 -0
  66. package/packages/cli/test/args.test.ts +28 -0
  67. package/packages/cli/test/cli.test.ts +153 -0
  68. package/packages/cli/test/relaunch.test.ts +29 -0
  69. package/packages/cli/tsconfig.build.json +11 -0
  70. package/packages/cli/tsconfig.json +10 -0
  71. package/packages/client-web/dist/control-room.d.ts +102 -0
  72. package/packages/client-web/dist/control-room.d.ts.map +1 -0
  73. package/packages/client-web/dist/control-room.js +12 -0
  74. package/packages/client-web/dist/control-room.js.map +1 -0
  75. package/packages/client-web/dist/design-contract.d.ts +85 -0
  76. package/packages/client-web/dist/design-contract.d.ts.map +1 -0
  77. package/packages/client-web/dist/design-contract.js +99 -0
  78. package/packages/client-web/dist/design-contract.js.map +1 -0
  79. package/packages/client-web/dist/index.d.ts +17 -0
  80. package/packages/client-web/dist/index.d.ts.map +1 -0
  81. package/packages/client-web/dist/index.js +19 -0
  82. package/packages/client-web/dist/index.js.map +1 -0
  83. package/packages/client-web/dist/react-room.d.ts +6 -0
  84. package/packages/client-web/dist/react-room.d.ts.map +1 -0
  85. package/packages/client-web/dist/react-room.js +103 -0
  86. package/packages/client-web/dist/react-room.js.map +1 -0
  87. package/packages/client-web/package.json +29 -0
  88. package/packages/client-web/src/control-room.ts +10 -0
  89. package/packages/client-web/src/design-contract.ts +112 -0
  90. package/packages/client-web/src/index.ts +21 -0
  91. package/packages/client-web/src/react-room.tsx +78 -0
  92. package/packages/client-web/test/design-contract.test.ts +24 -0
  93. package/packages/client-web/tsconfig.build.json +1 -0
  94. package/packages/client-web/tsconfig.json +1 -0
  95. package/packages/core/dist/boot.d.ts +13 -0
  96. package/packages/core/dist/boot.d.ts.map +1 -0
  97. package/packages/core/dist/boot.js +96 -0
  98. package/packages/core/dist/boot.js.map +1 -0
  99. package/packages/core/dist/context.d.ts +3 -0
  100. package/packages/core/dist/context.d.ts.map +1 -0
  101. package/packages/core/dist/context.js +2 -0
  102. package/packages/core/dist/context.js.map +1 -0
  103. package/packages/core/dist/index.d.ts +7 -0
  104. package/packages/core/dist/index.d.ts.map +1 -0
  105. package/packages/core/dist/index.js +6 -0
  106. package/packages/core/dist/index.js.map +1 -0
  107. package/packages/core/dist/plugins/model.d.ts +8 -0
  108. package/packages/core/dist/plugins/model.d.ts.map +1 -0
  109. package/packages/core/dist/plugins/model.js +12 -0
  110. package/packages/core/dist/plugins/model.js.map +1 -0
  111. package/packages/core/dist/plugins/models.d.ts +16 -0
  112. package/packages/core/dist/plugins/models.d.ts.map +1 -0
  113. package/packages/core/dist/plugins/models.js +24 -0
  114. package/packages/core/dist/plugins/models.js.map +1 -0
  115. package/packages/core/dist/plugins/resources.d.ts +18 -0
  116. package/packages/core/dist/plugins/resources.d.ts.map +1 -0
  117. package/packages/core/dist/plugins/resources.js +48 -0
  118. package/packages/core/dist/plugins/resources.js.map +1 -0
  119. package/packages/core/dist/plugins/runtime.d.ts +14 -0
  120. package/packages/core/dist/plugins/runtime.d.ts.map +1 -0
  121. package/packages/core/dist/plugins/runtime.js +68 -0
  122. package/packages/core/dist/plugins/runtime.js.map +1 -0
  123. package/packages/core/dist/plugins/session.d.ts +15 -0
  124. package/packages/core/dist/plugins/session.d.ts.map +1 -0
  125. package/packages/core/dist/plugins/session.js +20 -0
  126. package/packages/core/dist/plugins/session.js.map +1 -0
  127. package/packages/core/dist/plugins/stdio.d.ts +8 -0
  128. package/packages/core/dist/plugins/stdio.d.ts.map +1 -0
  129. package/packages/core/dist/plugins/stdio.js +20 -0
  130. package/packages/core/dist/plugins/stdio.js.map +1 -0
  131. package/packages/core/dist/plugins/tools.d.ts +13 -0
  132. package/packages/core/dist/plugins/tools.d.ts.map +1 -0
  133. package/packages/core/dist/plugins/tools.js +17 -0
  134. package/packages/core/dist/plugins/tools.js.map +1 -0
  135. package/packages/core/dist/profile.d.ts +8 -0
  136. package/packages/core/dist/profile.d.ts.map +1 -0
  137. package/packages/core/dist/profile.js +28 -0
  138. package/packages/core/dist/profile.js.map +1 -0
  139. package/packages/core/dist/runtime.d.ts +16 -0
  140. package/packages/core/dist/runtime.d.ts.map +1 -0
  141. package/packages/core/dist/runtime.js +33 -0
  142. package/packages/core/dist/runtime.js.map +1 -0
  143. package/packages/core/dist/services.d.ts +63 -0
  144. package/packages/core/dist/services.d.ts.map +1 -0
  145. package/packages/core/dist/services.js +39 -0
  146. package/packages/core/dist/services.js.map +1 -0
  147. package/packages/core/dist/stdio.d.ts +25 -0
  148. package/packages/core/dist/stdio.d.ts.map +1 -0
  149. package/packages/core/dist/stdio.js +74 -0
  150. package/packages/core/dist/stdio.js.map +1 -0
  151. package/packages/core/package.json +44 -0
  152. package/packages/core/profiles/default/cordis.yml +35 -0
  153. package/packages/core/profiles/development/cordis.yml +47 -0
  154. package/packages/core/src/boot.ts +103 -0
  155. package/packages/core/src/context.ts +3 -0
  156. package/packages/core/src/index.ts +6 -0
  157. package/packages/core/src/plugins/model.ts +12 -0
  158. package/packages/core/src/plugins/models.ts +32 -0
  159. package/packages/core/src/plugins/resources.ts +57 -0
  160. package/packages/core/src/plugins/runtime.ts +73 -0
  161. package/packages/core/src/plugins/session.ts +27 -0
  162. package/packages/core/src/plugins/stdio.ts +20 -0
  163. package/packages/core/src/plugins/tools.ts +23 -0
  164. package/packages/core/src/profile.ts +31 -0
  165. package/packages/core/src/runtime.ts +39 -0
  166. package/packages/core/src/services.ts +105 -0
  167. package/packages/core/src/stdio.ts +88 -0
  168. package/packages/core/test/boot.test.ts +86 -0
  169. package/packages/core/test/profile.test.ts +39 -0
  170. package/packages/core/test/profiles.integration.test.ts +93 -0
  171. package/packages/core/test/runtime-fixture.ts +31 -0
  172. package/packages/core/test/runtime.test.ts +54 -0
  173. package/packages/core/test/services.test.ts +131 -0
  174. package/packages/core/test/stdio.test.ts +87 -0
  175. package/packages/core/tsconfig.build.json +10 -0
  176. package/packages/core/tsconfig.json +10 -0
  177. package/packages/host-webserver/dist/index.d.ts +29 -0
  178. package/packages/host-webserver/dist/index.d.ts.map +1 -0
  179. package/packages/host-webserver/dist/index.js +73 -0
  180. package/packages/host-webserver/dist/index.js.map +1 -0
  181. package/packages/host-webserver/package.json +18 -0
  182. package/packages/host-webserver/src/index.ts +97 -0
  183. package/packages/host-webserver/test/index.test.ts +43 -0
  184. package/packages/host-webserver/tsconfig.build.json +1 -0
  185. package/packages/host-webserver/tsconfig.json +1 -0
package/README.md ADDED
@@ -0,0 +1,152 @@
1
+ # Pi Harness
2
+
3
+ Pi Harness is a plugin-first web host for [Pi](https://github.com/earendil-works/pi) built on the published DeepSeek Cordis stack. The browser console, HTTP API, static asset server, models, resources, sessions, tools, runtime, logging, timers, and HMR are Cordis plugins. A CLI surface remains available for scripted and terminal workflows.
4
+
5
+ ## Requirements
6
+
7
+ - Node.js 22.19 or newer
8
+ - npm 10 or newer
9
+ - Provider credentials supported by Pi for real model requests
10
+
11
+ ## Run from source
12
+
13
+ ```sh
14
+ npm ci
15
+ npm run build
16
+ node packages/cli/dist/bin.js --help
17
+ node packages/cli/dist/bin.js "Explain this repository"
18
+ ```
19
+
20
+ ## Run the web console
21
+
22
+ ```sh
23
+ npm ci
24
+ npm run web
25
+ ```
26
+
27
+ The web launcher builds the Vite browser bundle, starts the Cordis host, and prints a local URL (by default `http://127.0.0.1:3080`). Set `PI_HARNESS_HOST`, `PI_HARNESS_PORT`, and `PI_AGENT_DIR` to change the bind address, port, or Pi state directory. The browser surface is served by the `@pi-harness/web-app` plugin and talks to `@pi-harness/api-gateway` over `/api/status`, `/api/session`, `/api/sessions`, `/api/session/new`, `/api/session/open`, `/api/models`, `/api/model`, `/api/files`, `/api/prompt`, `/api/abort`, and the `/api/events` Server-Sent Events stream. The launcher refuses non-loopback hosts unless `PI_HARNESS_ALLOW_REMOTE=1` is explicitly set on a trusted network; the API is intended for local use and has no user authentication layer.
28
+
29
+ The default profile selects `deepseek/deepseek-v4-flash`, stores JSONL sessions under `$PI_AGENT_DIR/sessions`, and loads Pi resources from the current project and agent directory. `PI_AGENT_DIR` defaults to `~/.pi/agent`.
30
+
31
+ ## Architecture
32
+
33
+ ```text
34
+ web launcher / CLI launcher
35
+ └── Cordis Context
36
+ ├── Loader
37
+ └── Include(profile YAML)
38
+ └── Group
39
+ ├── models -> piModelRuntime
40
+ ├── resources -> piResources + extension providers
41
+ ├── model -> piModels
42
+ ├── session -> piSession
43
+ ├── tools -> piTools
44
+ ├── runtime -> piRuntime
45
+ ├── webserver -> webServer
46
+ ├── api -> HTTP JSON routes
47
+ ├── web-app -> static Vite bundle + SPA fallback
48
+ └── stdio -> piApplication
49
+ ```
50
+
51
+ Cordis owns module loading, configuration validation, dependency injection, activation ordering, lifecycle effects, rollback, grouping, and development HMR. Pi owns model discovery, project resources, session persistence, tool execution, provider calls, and agent events. There is no parallel plugin registry or lifecycle abstraction.
52
+
53
+ ## CLI
54
+
55
+ ```sh
56
+ # Built-in production profile
57
+ pih --profile default "Summarize the current directory"
58
+
59
+ # Built-in development profile with logger, timer, and HMR
60
+ pih --profile development "Summarize the current directory"
61
+
62
+ # Project-owned Cordis entry tree
63
+ pih --config ./cordis.yml "Summarize the current directory"
64
+
65
+ # Inspect a profile without importing plugins
66
+ pih --profile default --dump-config
67
+ ```
68
+
69
+ Launcher options are `--profile`, `--config`, `--dump-config`, `--help`, and `--version`. Remaining arguments are passed unchanged to the active application plugin. The bundled stdio application accepts `--prompt <text>`, a positional prompt, or piped stdin.
70
+
71
+ The built-in development profile watches the invocation working directory and the launcher automatically supervises a child process with Node's `--expose-internals` flag, which Cordis HMR requires. Cordis performs partial plugin reloads in place and requests a supervised process restart when a framework module changes. Production does not expose Node internals. A custom profile that mounts `@deepseek-ai/cordis-plugin-hmr` must start the CLI entry with `node --expose-internals`.
72
+
73
+ ## Profiles
74
+
75
+ Profiles are YAML arrays of Cordis Loader entries. Every entry needs a stable `id`, a module `name`, and optional `config`, `inject`, `group`, or `disabled` fields. IDs must be unique across the complete entry tree because Cordis groups share their owning tree's entry store.
76
+
77
+ Bare module specifiers resolve from the directory containing the profile. Keep project profiles in a package that installs every referenced plugin. Relative specifiers resolve from the same directory.
78
+
79
+ Pi Harness reads and hot-refreshes profile files but does not persist Loader mutations back into them. This prevents an activation rollback from rewriting a source profile; edit the YAML directly to make changes.
80
+
81
+ ## Author a plugin
82
+
83
+ [`examples/plugin-hello`](./examples/plugin-hello) is a complete external Cordis plugin. It contributes a native Pi `ToolDefinition`, registers cleanup with `ctx.effect()`, and provides a readiness marker after registration:
84
+
85
+ ```ts
86
+ export default {
87
+ name: "pi-hello",
88
+ inject: ["piTools"],
89
+ apply(ctx: Context) {
90
+ ctx.effect(() => ctx.piTools.register(helloTool));
91
+ ctx.provide("piHelloTool", helloTool);
92
+ },
93
+ };
94
+ ```
95
+
96
+ Custom tools are a startup contract. The runtime leases an immutable tool snapshot while its Pi session exists, so a profile must make runtime activation depend on every tool plugin's marker:
97
+
98
+ ```yaml
99
+ - id: tools
100
+ name: "@pi-harness/core/plugins/tools"
101
+ config:
102
+ names: [read, bash, edit, write]
103
+ - id: hello
104
+ name: "@pi-harness/plugin-hello"
105
+ config: {}
106
+ - id: runtime
107
+ name: "@pi-harness/core/plugins/runtime"
108
+ inject:
109
+ - piHelloTool
110
+ config:
111
+ thinkingLevel: medium
112
+ ```
113
+
114
+ This uses Cordis injection for deterministic ordering. A late contribution fails startup instead of being silently omitted from the active AgentSession. When HMR unloads a tool marker, Cordis first disposes the dependent runtime and releases its snapshot; the reloaded tool plugin can then register against the same lifecycle-owned registry.
115
+
116
+ ## Failure and security boundaries
117
+
118
+ - A profile can load arbitrary Node.js modules. Treat profile files and plugin packages as executable code.
119
+ - Missing modules, invalid configuration, unresolved injections, model lookup failures, and plugin activation failures abort startup and dispose the partial tree.
120
+ - The runtime does not fall back to a different model or storage backend.
121
+ - Signals cancel startup or abort the active Pi run before the Cordis tree is disposed. Runtime abort and root disposal have a five-second deadline, after which the executable forces the signal-compatible exit code.
122
+ - The production profile excludes HMR. Development HMR grants access to Node internal ESM loader APIs only in the relaunched development process.
123
+ - Existing Pi resources and extensions under `PI_AGENT_DIR` participate in startup and shutdown. Use an isolated agent directory for deterministic tests.
124
+
125
+ ## Development
126
+
127
+ ```sh
128
+ npm test
129
+ npm run typecheck
130
+ npm run lint
131
+ npm run build
132
+ ```
133
+
134
+ `npm test` builds every workspace before running Vitest, so Loader integration tests resolve the same package exports shipped to users. Tests use real Cordis contexts and real Pi sessions; deterministic provider fixtures avoid paid network requests.
135
+
136
+ ## Release
137
+
138
+ Publishing is triggered by a push to `main` (including a merged pull request), or manually with `workflow_dispatch`. The `Release packages` workflow runs the complete test, lint, and diff gate, publishes the root `pi-harness-workspace` package and six public workspaces to npm with provenance, skips package versions that already exist, and creates a matching GitHub Release tag. The web app and example plugin workspaces are private and are never published.
139
+
140
+ Before the first release, add the npm automation token as the GitHub Actions secret `NPM_TOKEN`. The workflow passes the secret through `NODE_AUTH_TOKEN` and publishes to npm without provenance because this repository is private and npm rejects provenance attestations from private GitHub sources. The token must be allowed to publish the seven package names and, if npm two-factor authentication is enabled, use an automation-compatible publish policy. Bump all published workspace versions together and update their internal `@pi-harness/*` dependency versions before merging to `main`; the merge then publishes and creates the matching GitHub Release automatically.
141
+
142
+ ## Workspace layout
143
+
144
+ - `packages/core`: Cordis boot host, typed Pi services, runtime plugins, and built-in profiles
145
+ - `packages/cli`: launcher argument, process, stdio, signal, and development re-exec handling
146
+ - `packages/host-webserver`: Cordis-owned HTTP server and route lifecycle
147
+ - `packages/api-gateway`: Cordis API plugin for status, live sessions, model selection, workspace files, prompts, abort, and SSE events
148
+ - `packages/client-web`: browser-side Cordis plugin tree and console surface
149
+ - `packages/bundle-web-app`: static frontend and SPA fallback plugin
150
+ - `apps/web`: Vite entrypoint and production web launcher
151
+ - `examples/plugin-hello`: lifecycle-safe external Pi tool plugin
152
+ - `docs/plans`: accepted architecture and implementation plan