@piagent/platform 1.7.1 → 1.9.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 (227) hide show
  1. package/AGENTS.md +7 -0
  2. package/CHANGELOG.md +113 -1
  3. package/README.md +45 -70
  4. package/README.vi.md +34 -61
  5. package/architecture/layers.json +16 -3
  6. package/catalog/capabilities.json +14 -7
  7. package/catalog/claude-model-additions.json +42 -0
  8. package/docs/auto-delegation-policy.md +2 -0
  9. package/docs/command-reference-vietnamese.md +69 -91
  10. package/docs/context-window-policy.md +5 -5
  11. package/docs/distribution-standard.md +16 -19
  12. package/docs/en/architecture.md +9 -1
  13. package/docs/herdr-workflow.md +2 -3
  14. package/docs/languages.json +4 -4
  15. package/docs/managed-local-acceptance.md +403 -0
  16. package/docs/mcp-and-tools.md +5 -7
  17. package/docs/memory-policy.md +3 -3
  18. package/docs/model-options.md +22 -17
  19. package/docs/oauth-providers.md +1 -1
  20. package/docs/operator-manual-vietnamese.md +85 -130
  21. package/docs/package-architecture-notes.md +4 -4
  22. package/docs/piagent-core-improvement-plan.md +3 -5
  23. package/docs/piagent-core-plan-checkpoint-2026-09-06.json +2 -13
  24. package/docs/piagent-runtime-benchmark-execution-plan.md +10 -8
  25. package/docs/project-adapters.md +3 -3
  26. package/docs/project-onboarding.md +15 -16
  27. package/docs/publishing-for-teams.md +3 -1
  28. package/docs/quality-benchmark.md +2 -0
  29. package/docs/quickstart-vietnamese.md +24 -25
  30. package/docs/release-install-policy.md +16 -11
  31. package/docs/research/harness-next-evidence-review.md +7 -7
  32. package/docs/runtime-harness-standard.md +2 -0
  33. package/docs/runtime-policy-design.md +2 -0
  34. package/docs/runtime-quality-baseline.md +2 -0
  35. package/docs/subagent-orchestration-capabilities.md +1 -1
  36. package/docs/subagents-and-multiagent.md +10 -8
  37. package/docs/task-implementation-contract.md +2 -0
  38. package/docs/task-lifecycle-vietnamese.md +2 -0
  39. package/docs/team-onboarding.md +33 -64
  40. package/docs/usage-observability.md +2 -2
  41. package/docs/vi/architecture.md +9 -1
  42. package/docs/workflow-recipes.md +6 -10
  43. package/docs-site/architecture.html +4 -3
  44. package/docs-site/assets/docs.css +80 -0
  45. package/docs-site/benchmark.html +7 -1
  46. package/docs-site/commands.html +37 -23
  47. package/docs-site/content/architecture.html +2 -2
  48. package/docs-site/content/benchmark.html +5 -0
  49. package/docs-site/content/commands.html +35 -22
  50. package/docs-site/content/ecosystem.html +144 -0
  51. package/docs-site/content/en/architecture.html +1 -1
  52. package/docs-site/content/en/benchmark.html +5 -0
  53. package/docs-site/content/en/commands.html +30 -13
  54. package/docs-site/content/en/ecosystem.html +144 -0
  55. package/docs-site/content/en/index.html +24 -9
  56. package/docs-site/content/en/quickstart.html +10 -12
  57. package/docs-site/content/en/runtime.html +1 -1
  58. package/docs-site/content/en/security.html +1 -1
  59. package/docs-site/content/en/team.html +2 -2
  60. package/docs-site/content/en/whats-new.html +89 -1
  61. package/docs-site/content/en/workflows.html +29 -31
  62. package/docs-site/content/index.html +24 -9
  63. package/docs-site/content/quickstart.html +10 -12
  64. package/docs-site/content/runtime.html +2 -2
  65. package/docs-site/content/security.html +2 -2
  66. package/docs-site/content/team.html +2 -2
  67. package/docs-site/content/whats-new.html +89 -1
  68. package/docs-site/content/workflows.html +36 -38
  69. package/docs-site/context-engine.html +2 -1
  70. package/docs-site/ecosystem.html +283 -0
  71. package/docs-site/en/architecture.html +3 -2
  72. package/docs-site/en/benchmark.html +7 -1
  73. package/docs-site/en/commands.html +32 -14
  74. package/docs-site/en/context-engine.html +2 -1
  75. package/docs-site/en/ecosystem.html +283 -0
  76. package/docs-site/en/index.html +30 -14
  77. package/docs-site/en/mcp-approval.html +2 -1
  78. package/docs-site/en/mcp-auth.html +2 -1
  79. package/docs-site/en/mcp-servers.html +2 -1
  80. package/docs-site/en/mcp.html +2 -1
  81. package/docs-site/en/permissions.html +2 -1
  82. package/docs-site/en/profiles.html +2 -1
  83. package/docs-site/en/quickstart.html +17 -18
  84. package/docs-site/en/runtime.html +3 -2
  85. package/docs-site/en/scope.html +2 -1
  86. package/docs-site/en/security.html +6 -5
  87. package/docs-site/en/team.html +4 -3
  88. package/docs-site/en/whats-new.html +97 -8
  89. package/docs-site/en/workflows.html +34 -35
  90. package/docs-site/index.html +30 -14
  91. package/docs-site/mcp-approval.html +2 -1
  92. package/docs-site/mcp-auth.html +2 -1
  93. package/docs-site/mcp-servers.html +2 -1
  94. package/docs-site/mcp.html +2 -1
  95. package/docs-site/permissions.html +2 -1
  96. package/docs-site/profiles.html +2 -1
  97. package/docs-site/quickstart.html +17 -18
  98. package/docs-site/runtime.html +4 -3
  99. package/docs-site/scope.html +2 -1
  100. package/docs-site/security.html +7 -6
  101. package/docs-site/team.html +4 -3
  102. package/docs-site/whats-new.html +97 -8
  103. package/docs-site/workflows.html +41 -42
  104. package/evals/fs5-causal-arm.v1.json +2 -2
  105. package/evals/private-holdout-v1/CURRENT_BOUNDARY.md +17 -0
  106. package/evals/private-holdout-v1/public-exposure.v2.json +2 -2
  107. package/package.json +10 -9
  108. package/packages/piagent-core/README.md +15 -23
  109. package/packages/piagent-core/docs/context-efficiency-improvement-plan.md +2 -0
  110. package/packages/piagent-core/extensions/experiment-loop-policy.ts +75 -0
  111. package/packages/piagent-core/extensions/local-state-path.js +15 -0
  112. package/packages/piagent-core/extensions/piagent-guard.ts +108 -960
  113. package/packages/piagent-core/extensions/policy-core.js +2 -2
  114. package/packages/piagent-core/extensions/source-checkout-paths.ts +54 -0
  115. package/packages/piagent-core/managed/broker-client.mjs +49 -0
  116. package/packages/piagent-core/managed/capabilities.mjs +28 -0
  117. package/packages/piagent-core/managed/compaction.mjs +63 -0
  118. package/packages/piagent-core/managed/doctor.mjs +107 -0
  119. package/packages/piagent-core/managed/native-catalog.mjs +42 -0
  120. package/packages/piagent-core/managed/patch-snapshot.mjs +48 -0
  121. package/packages/piagent-core/managed/repository-operation.mjs +84 -0
  122. package/packages/piagent-core/managed/request-stream.mjs +129 -0
  123. package/packages/piagent-core/managed/resource-loader.mjs +42 -0
  124. package/packages/piagent-core/managed/review-snapshot-worker.mjs +27 -0
  125. package/packages/piagent-core/managed/sandbox-diagnostic.mjs +12 -0
  126. package/packages/piagent-core/managed/search-fallback.mjs +93 -0
  127. package/packages/piagent-core/managed/session.mjs +472 -0
  128. package/packages/piagent-core/managed/store.d.mts +3 -0
  129. package/packages/piagent-core/managed/store.mjs +64 -0
  130. package/packages/piagent-core/managed/tool-boundary.mjs +243 -0
  131. package/packages/piagent-core/managed/tool-worker.mjs +36 -0
  132. package/packages/piagent-core/managed/toolchain.mjs +120 -0
  133. package/packages/piagent-core/managed/web-fetch.mjs +105 -0
  134. package/packages/piagent-core/managed/web-search.mjs +96 -0
  135. package/packages/piagent-core/managed/workflow.mjs +299 -0
  136. package/packages/piagent-core/package.json +3 -6
  137. package/packages/piagent-core/policies/base-policy.json +80 -26
  138. package/packages/piagent-core/runtime/hooks/agent-start-hook.ts +3 -3
  139. package/packages/piagent-core/runtime/hooks/input-hook.ts +35 -196
  140. package/packages/piagent-core/runtime/hooks/session-start-hook.ts +2 -0
  141. package/packages/piagent-core/runtime/inspection/approval-broker.ts +9 -1
  142. package/packages/piagent-core/runtime/inspection/same-process-bridge-proof.ts +1 -1
  143. package/packages/piagent-core/runtime/inspection/webui-snapshot.ts +1 -1
  144. package/packages/piagent-core/runtime/managed-failure.d.mts +10 -0
  145. package/packages/piagent-core/runtime/managed-failure.mjs +164 -0
  146. package/packages/piagent-core/runtime/model/model-route-policy.ts +33 -13
  147. package/packages/piagent-core/runtime/model/model-route-types.ts +10 -6
  148. package/packages/piagent-core/runtime/orchestration/minimal-delegation-policy.ts +8 -29
  149. package/packages/piagent-core/runtime/orchestration/owned-work-budget.ts +1 -1
  150. package/packages/piagent-core/runtime/policy/block-remedy.ts +5 -3
  151. package/packages/piagent-core/runtime/registration/context-commands.ts +1 -1
  152. package/packages/piagent-core/runtime/registration/knowledge-tools.ts +7 -7
  153. package/packages/piagent-core/runtime/registration/policy-tools.ts +2 -2
  154. package/packages/piagent-core/runtime/registration/session-commands.ts +11 -26
  155. package/packages/piagent-core/runtime/registration/task-evidence-tools.ts +1 -1
  156. package/packages/piagent-core/runtime/session/system-prompt.ts +6 -7
  157. package/packages/piagent-core/runtime/workflows/webui-runtime-command.ts +6 -6
  158. package/packages/piagent-core/runtime/workflows/webui-workflow.ts +6 -11
  159. package/packages/piagent-core/security/sensitive-text.js +9 -0
  160. package/packages/piagent-core/skills/piagent-ops/SKILL.md +8 -10
  161. package/packages/piagent-core/skills/test-audit/SKILL.md +101 -0
  162. package/packages/piagent-core/subagents/piagent-planner.md +1 -1
  163. package/packages/piagent-webui/dist/client/assets/{MarkdownMessage-DGk34zJT.js → MarkdownMessage-Dd9wPk-v.js} +1 -1
  164. package/packages/piagent-webui/dist/client/assets/index-7I-50Q2U.js +228 -0
  165. package/packages/piagent-webui/dist/client/assets/{index-DVahUVWy.css → index-DgSmcnP8.css} +1 -1
  166. package/packages/piagent-webui/dist/client/index.html +2 -2
  167. package/packages/piagent-webui/extension/piagent-webui.ts +11 -11
  168. package/packages/piagent-webui/extension/session-stream-adapter.ts +3 -1
  169. package/packages/piagent-webui/extension/terminal-session-adapter.ts +6 -1
  170. package/packages/piagent-webui/gateway/company-relay.ts +308 -0
  171. package/packages/piagent-webui/gateway/control-socket.ts +39 -12
  172. package/packages/piagent-webui/gateway/gateway-service.ts +109 -28
  173. package/packages/piagent-webui/gateway/gateway-session-stream.ts +58 -2
  174. package/packages/piagent-webui/gateway/managed-gateway.mjs +41 -0
  175. package/packages/piagent-webui/gateway/managed-launch.ts +145 -0
  176. package/packages/piagent-webui/gateway/managed-projection.ts +20 -0
  177. package/packages/piagent-webui/gateway/pi-host.ts +22 -4
  178. package/packages/piagent-webui/gateway/runtime-session-controls.ts +5 -2
  179. package/packages/piagent-webui/gateway/session-approval-authority.ts +28 -0
  180. package/packages/piagent-webui/gateway/session-catalog.ts +11 -3
  181. package/packages/piagent-webui/gateway/session-command-controller.ts +8 -2
  182. package/packages/piagent-webui/gateway/session-file-facts.ts +25 -0
  183. package/packages/piagent-webui/gateway/session-inspection-registry.ts +42 -12
  184. package/packages/piagent-webui/gateway/session-list-cache.ts +68 -0
  185. package/packages/piagent-webui/gateway/session-runtime-ownership.ts +8 -1
  186. package/packages/piagent-webui/gateway/session-runtime-supervisor.ts +20 -27
  187. package/packages/piagent-webui/ownership/managed-terminal-lease.ts +27 -0
  188. package/packages/piagent-webui/ownership/profile-state.ts +2 -0
  189. package/packages/piagent-webui/ownership/session-lease-store.ts +22 -1
  190. package/packages/piagent-webui/server/approval-projection.ts +9 -0
  191. package/packages/piagent-webui/server/core-inspection-provider.ts +4 -9
  192. package/packages/piagent-webui/server/loopback-server.ts +37 -1
  193. package/packages/piagent-webui/server/message-stop-reason.ts +11 -0
  194. package/packages/piagent-webui/server/tool-call-summary.ts +185 -0
  195. package/packages/piagent-webui/server/transcript-projection.ts +86 -3
  196. package/packs/engineering-base/pack.json +4 -0
  197. package/schemas/piagent-webui/runtime-command-v1.schema.json +1 -2
  198. package/schemas/piagent-webui/session-catalog-v1.schema.json +8 -0
  199. package/schemas/piagent-webui/transcript-v1.schema.json +94 -1
  200. package/scripts/build-docs-site.mjs +23 -12
  201. package/scripts/check-public-wording.mjs +5 -6
  202. package/scripts/check-runtime-advisories.mjs +23 -6
  203. package/scripts/claude-model-additions.mjs +33 -0
  204. package/scripts/configure-model-scope.sh +36 -8
  205. package/scripts/configure-subagents.sh +1 -1
  206. package/scripts/explain-command.mjs +5 -6
  207. package/scripts/install-global.sh +2 -2
  208. package/scripts/model-route-evaluation-core.ts +1 -0
  209. package/scripts/model-scope-prune.mjs +75 -0
  210. package/scripts/phase-tools-evaluation.mjs +9 -4
  211. package/scripts/pi-model-route.mjs +1 -1
  212. package/scripts/piagent-cli.mjs +51 -2
  213. package/scripts/piagent-dashboard.mjs +27 -4
  214. package/scripts/piagent-installations.mjs +26 -0
  215. package/scripts/piagent-studio.mjs +155 -0
  216. package/scripts/runtime-advisory-exceptions.json +29 -0
  217. package/scripts/setup.sh +2 -2
  218. package/scripts/team-doctor.sh +20 -1
  219. package/scripts/typescript-loader.mjs +6 -0
  220. package/scripts/verify-local.sh +5 -5
  221. package/scripts/verify-release-identity.mjs +1 -1
  222. package/templates/global/settings.json +8 -2
  223. package/templates/project/.pi/project-context.md +3 -3
  224. package/templates/project/AGENTS.md +4 -5
  225. package/docs/piagent-core-reasoning-research-2026-09-06.md +0 -225
  226. package/docs/piagent-core-research-sources-2026-09-06.json +0 -416
  227. package/packages/piagent-webui/dist/client/assets/index-DiKRmCEP.js +0 -176
@@ -10,6 +10,7 @@ import { installedPiHostRoot } from "../packages/piagent-webui/gateway/pi-host.t
10
10
  import { gatewayProfileState, profileRef, readGatewayDescriptor, readOrCreateCatalogKey,
11
11
  removeGatewayDescriptor } from "../packages/piagent-webui/gateway/profile-state.ts";
12
12
  import { startPiagentGateway } from "../packages/piagent-webui/gateway/gateway-service.ts";
13
+ import { agentWatchCompanyConnector } from "../packages/piagent-webui/gateway/managed-launch.ts";
13
14
 
14
15
  const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
15
16
  const packageJson = JSON.parse(fs.readFileSync(path.join(packageRoot, "package.json"), "utf8"));
@@ -111,9 +112,9 @@ async function control(action, timeoutMs = 1_500) {
111
112
  return await requestGatewayControl(state.controlSocket, { action }, timeoutMs);
112
113
  }
113
114
 
114
- async function currentLaunchUrl() {
115
+ async function currentLaunchUrl(timeoutMs) {
115
116
  try {
116
- const response = await control("issue-launch-url");
117
+ const response = await control("issue-launch-url", timeoutMs);
117
118
  if (response.ok && response.value && typeof response.value === "object"
118
119
  && typeof response.value.launchUrl === "string") return response.value.launchUrl;
119
120
  } catch {
@@ -122,6 +123,26 @@ async function currentLaunchUrl() {
122
123
  return null;
123
124
  }
124
125
 
126
+ // A Gateway that is alive but busy answers late. Starting another one beside
127
+ // it left two Gateways on the same conversations, the first unreachable and
128
+ // still serving its pages, so the running one is waited for instead.
129
+ async function waitForRunningGateway(timeoutMs = 30_000) {
130
+ const running = readGatewayDescriptor(gatewayProfileState(agentDir));
131
+ if (!running || !processAlive(running.pid)) return null;
132
+ const deadline = Date.now() + timeoutMs;
133
+ while (Date.now() < deadline && processAlive(running.pid)) {
134
+ try {
135
+ const response = await control("issue-launch-url", 5_000);
136
+ if (response.ok && typeof response.value?.launchUrl === "string") return response.value.launchUrl;
137
+ } catch (error) {
138
+ // Nothing listens on its socket: the process is not a Gateway anymore.
139
+ if (!(error instanceof Error) || error.message !== "gateway-control-timeout") return null;
140
+ }
141
+ }
142
+ if (!processAlive(running.pid)) return null;
143
+ throw new Error("gateway-busy\nThe Gateway is running but did not answer within 30s. Try again, or run `piagent dashboard restart`.");
144
+ }
145
+
125
146
  async function waitForGatewayStopped(previous, timeoutMs = 8_000) {
126
147
  const deadline = Date.now() + timeoutMs;
127
148
  while (Date.now() < deadline) {
@@ -134,7 +155,7 @@ async function waitForGatewayStopped(previous, timeoutMs = 8_000) {
134
155
  }
135
156
 
136
157
  async function ensureStarted() {
137
- const existing = await currentLaunchUrl();
158
+ const existing = await currentLaunchUrl() ?? await waitForRunningGateway();
138
159
  if (existing) return existing;
139
160
  const effectiveAgentDir = path.resolve(agentDir ?? process.env.PI_CODING_AGENT_DIR ?? path.join(os.homedir(), ".pi", "agent"));
140
161
  const state = gatewayProfileState(effectiveAgentDir);
@@ -168,7 +189,9 @@ async function ensureStarted() {
168
189
  }
169
190
 
170
191
  async function serve() {
171
- const gateway = await startPiagentGateway({ packageRoot, expectedPiVersion, agentDir });
192
+ // Company sessions come from the Agent Watch binding in this Pi folder.
193
+ const piAgentDir = path.resolve(agentDir ?? process.env.PI_CODING_AGENT_DIR ?? path.join(os.homedir(), ".pi", "agent"));
194
+ const gateway = await startPiagentGateway({ packageRoot, expectedPiVersion, agentDir, company: agentWatchCompanyConnector(piAgentDir) });
172
195
  const shutdown = () => { void gateway.close(); };
173
196
  process.once("SIGINT", shutdown);
174
197
  process.once("SIGTERM", shutdown);
@@ -0,0 +1,26 @@
1
+ import fs from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import {createHash} from 'node:crypto';
5
+
6
+ // Read metadata only: never execute an old launcher (its Node/PATH may fail).
7
+ export function piagentInstallations({home=os.homedir(), searchPath=process.env.PATH??'', systemRoots=['/opt/homebrew','/usr/local']}={}) {
8
+ const bins=new Set([...searchPath.split(path.delimiter).filter(Boolean),path.join(home,'.local/bin'),path.join(home,'.pi/npm-global/bin'),...systemRoots.map(root=>path.join(root,'bin'))]);
9
+ const found=new Map();
10
+ for(const bin of bins) {
11
+ try {
12
+ const launcher=fs.realpathSync(path.join(bin,'piagent'));
13
+ let root=path.dirname(launcher);
14
+ for(let depth=0;depth<5;depth++,root=path.dirname(root)) {
15
+ const manifest=path.join(root,'package.json');
16
+ if(!fs.existsSync(manifest))continue;
17
+ const pkg=JSON.parse(fs.readFileSync(manifest,'utf8'));
18
+ if(pkg.name!=='@piagent/platform')continue;
19
+ const managed=path.join(root,'scripts/piagent-studio.mjs');
20
+ const info=found.get(root)??{root,version:String(pkg.version),managed:fs.existsSync(managed),fingerprint:createHash('sha256').update(fs.readFileSync(fs.existsSync(managed)?managed:launcher)).digest('hex').slice(0,12),launchers:[]};
21
+ info.launchers.push(path.join(bin,'piagent'));found.set(root,info);break;
22
+ }
23
+ } catch { /* Missing/broken installation is not executed. */ }
24
+ }
25
+ return [...found.values()];
26
+ }
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { createHash } from 'node:crypto';
6
+ import { fileURLToPath, pathToFileURL } from 'node:url';
7
+ import { ManagedBrokerClient } from '../packages/piagent-core/managed/broker-client.mjs';
8
+ import { ManagedSession } from '../packages/piagent-core/managed/session.mjs';
9
+ import { resolveStore, storedSlot } from '../packages/piagent-core/managed/store.mjs';
10
+
11
+ const digest = file => createHash('sha256').update(fs.readFileSync(file)).digest('hex');
12
+ // Node's experimental-feature notices (type stripping, SQLite) are not
13
+ // actionable for members and bury the launch messages in Terminal.
14
+ process.removeAllListeners('warning');
15
+ process.on('warning', warning => { if (warning.name !== 'ExperimentalWarning') process.stderr.write(`${warning.name}: ${warning.message}\n`); });
16
+ const args = process.argv.slice(2), flags = new Map();
17
+ if (args.includes('--help')) { console.log('piagent studio [--web [--no-open] | --serve | --check | --doctor | --prompt <text>] [--config <Agent Watch configuration>] [--project <folder>]\nDefaults: the configuration imported into ~/.pi/agent and the current project. Personal sessions remain under pi / piagent dashboard.'); process.exit(0); }
18
+ for (let i = 0; i < args.length; i++) {
19
+ if (['--check', '--doctor', '--web', '--serve', '--no-open'].includes(args[i])) { flags.set(args[i], true); continue; }
20
+ if (!['--config', '--project', '--prompt'].includes(args[i]) || flags.has(args[i]) || !args[i + 1]) throw Error('managed-launch-arguments');
21
+ flags.set(args[i], args[++i]);
22
+ }
23
+ const home = os.homedir();
24
+ // Do this before importing the SDK: it must not discover personal keys, Node
25
+ // preload hooks, proxy overrides or provider endpoints from an ambient shell.
26
+ const clean = { PATH: '/usr/bin:/bin', HOME: home, LANG: 'en_US.UTF-8', TERM: process.env.TERM || 'xterm-256color' };
27
+ for (const key of Object.keys(process.env)) delete process.env[key];
28
+ Object.assign(process.env, clean);
29
+ let broker, current, gateway, hold;
30
+ try {
31
+ const configPath = fs.realpathSync(flags.get('--config') ?? path.join(home,'.pi/agent/agent-watch-managed.json'));
32
+ if (!fs.statSync(configPath).isFile() || fs.statSync(configPath).size > 16384) throw Error('managed-config-invalid');
33
+ const config = JSON.parse(fs.readFileSync(configPath));
34
+ // Agent Watch rewrites this when the key or its harness changes.
35
+ const bindingRevision = () => { try { return String(JSON.parse(fs.readFileSync(configPath, 'utf8')).configuration_revision ?? '') || null; } catch { return null; } };
36
+ // --serve backs the personal dashboard: no browser, no project of its own.
37
+ // Its startup probe runs in an empty private folder that is never listed.
38
+ const serve = flags.has('--serve');
39
+ if (serve && (flags.has('--project') || flags.has('--web') || flags.has('--check') || flags.has('--prompt'))) throw Error('managed-launch-arguments');
40
+ if (config.schema_version !== 1 || config.model !== 'agent-watch-auto' || !/^[a-f0-9]{64}$/.test(config.profile_id)
41
+ || config.entrypoint !== fs.realpathSync(fileURLToPath(import.meta.url)) || config.node !== fs.realpathSync(process.execPath)
42
+ || digest(config.entrypoint) !== config.entrypoint_sha256 || digest(config.node) !== config.node_sha256
43
+ || digest(config.broker) !== config.broker_sha256) throw Error('managed-launch-binding-changed');
44
+ // What company sessions need on this machine, checked with the real sandbox
45
+ // and broker; no conversation, no model request.
46
+ if (flags.has('--doctor')) {
47
+ const { runDoctor, doctorReport } = await import('../packages/piagent-core/managed/doctor.mjs');
48
+ const asked = new ManagedBrokerClient({ executable: config.broker, profileID: config.profile_id });
49
+ let report;
50
+ try { report = doctorReport(await runDoctor({ sdkRoot: config.sdk_root, origin: config.origin, broker: asked })); }
51
+ finally { await asked.dispose(); }
52
+ console.log(report.text); process.exit(report.ok ? 0 : 1);
53
+ }
54
+ // Conversations live in one store per member on this machine, whichever key
55
+ // Agent Watch holds: a key's slot learns its member once, then points there.
56
+ const root = path.join(home, 'Library/Application Support/AgentWatch/ManagedSessions');
57
+ let store = storedSlot(root, config.profile_id);
58
+ if (!store) {
59
+ const asked = new ManagedBrokerClient({ executable: config.broker, profileID: config.profile_id });
60
+ try { store = resolveStore(root, config.profile_id, { origin: config.origin, userId: (await asked.request('config'))?.user?.id }); }
61
+ finally { await asked.dispose(); }
62
+ }
63
+ const agentDir = path.join(root, store);
64
+ const cwd = serve ? path.join(agentDir, 'probe') : fs.realpathSync(flags.get('--project') || process.cwd());
65
+ if (configPath.startsWith(cwd + path.sep)) throw Error('managed-launch-binding-changed');
66
+ fs.mkdirSync(agentDir, { recursive: true, mode: 0o700 }); fs.chmodSync(agentDir, 0o700);
67
+ if (serve) { fs.mkdirSync(cwd, { recursive: true, mode: 0o700 }); fs.chmodSync(cwd, 0o700); }
68
+ await import('./register-typescript-loader.mjs');
69
+ if (flags.has('--web') || serve) {
70
+ if (flags.has('--check') || flags.has('--prompt')) throw Error('managed-launch-arguments');
71
+ const packageRoot=path.dirname(path.dirname(fileURLToPath(import.meta.url)));
72
+ const {requestGatewayControl}=await import('../packages/piagent-webui/gateway/control-socket.ts');
73
+ const {gatewayProfileState}=await import('../packages/piagent-webui/ownership/profile-state.ts');
74
+ const control=gatewayProfileState(agentDir).controlSocket;
75
+ const release=JSON.parse(fs.readFileSync(path.join(packageRoot,'package.json'),'utf8')).version;
76
+ const health=async()=>{ try { const reply=await requestGatewayControl(control,{action:'health'}); return reply.ok ? reply.value ?? {} : null; } catch { return null; } };
77
+ // This key's company Gateway may already run: the dashboard starts one and
78
+ // an earlier WebUI launch may still be open. Reuse it when it is this
79
+ // release (a new browser session on this project); replace an older one.
80
+ let running=await health();
81
+ for(const started=Date.now();running && !running.packageVersion && running.state==='starting' && Date.now()-started<45000;running=await health()) await new Promise(r=>setTimeout(r,250));
82
+ if(running && running.packageVersion!==release){
83
+ try { await requestGatewayControl(control,{action:'stop'}); } catch {}
84
+ for(const started=Date.now();await health();) { if(Date.now()-started>15000) throw Error('managed-launch-stale-runtime'); await new Promise(r=>setTimeout(r,250)); }
85
+ running=null;
86
+ }
87
+ if(!running){
88
+ const {startManagedGateway}=await import('../packages/piagent-webui/gateway/managed-gateway.mjs');
89
+ gateway=await startManagedGateway({config,configPath,cwd,agentDir,registerProject:!serve,packageRoot});
90
+ }
91
+ if (serve) process.stdout.write('Agent Watch Auto: ready\n');
92
+ else {
93
+ // Register (idempotent) to learn the project's ref: the page opens a new
94
+ // conversation for the project chosen in Agent Watch.
95
+ const registered=await requestGatewayControl(control,{action:'project.register',cwd});
96
+ if(!registered.ok || typeof registered.value?.projectRef!=='string') throw Error('managed-web-launch-failed');
97
+ const result=await requestGatewayControl(control,{action:'issue-launch-url'});
98
+ if(!result.ok || !result.value?.launchUrl) throw Error('managed-web-launch-failed');
99
+ result.value.launchUrl+=`&project=${encodeURIComponent(registered.value.projectRef)}`;
100
+ process.stdout.write(`Agent Watch Auto: ${result.value.launchUrl}\n`);
101
+ if(!flags.has('--no-open')){ const {spawn}=await import('node:child_process'); spawn('/usr/bin/open',[result.value.launchUrl],{stdio:'ignore',env:clean}).unref(); }
102
+ }
103
+ if(gateway){
104
+ process.once('SIGINT',()=>void gateway.close());process.once('SIGTERM',()=>void gateway.close());
105
+ await gateway.wait();
106
+ } else if(!serve) process.stdout.write('Agent Watch Auto: opened in the running company session service; closing this window does not stop it.\n');
107
+ } else {
108
+ // The key Agent Watch holds now: a conversation that enrolls again follows it.
109
+ const slot = () => { try { const now = JSON.parse(fs.readFileSync(configPath, 'utf8')); return /^[a-f0-9]{64}$/.test(now.profile_id) && now.broker === config.broker ? now.profile_id : config.profile_id; } catch { return config.profile_id; } };
110
+ const newBroker = () => new ManagedBrokerClient({ executable: config.broker, profileID: slot() });
111
+ broker = newBroker();
112
+ const api = await import(pathToFileURL(path.join(config.sdk_root, 'dist/index.js')));
113
+ // The conversation this process writes is held in the same lease the
114
+ // company Gateway uses: the WebUI shows it running here and never runs it
115
+ // at the same time. One the WebUI is running is refused.
116
+ const { holdManagedSession } = await import('../packages/piagent-webui/ownership/managed-terminal-lease.ts');
117
+ const factory = async ({ cwd, sessionManager }) => {
118
+ let next;
119
+ try { next = holdManagedSession(agentDir, sessionManager.getSessionFile()); }
120
+ catch (error) { throw Error(String(error?.message) === 'session-owner-conflict' ? 'managed-session-open-elsewhere' : 'managed-session-lease-unavailable'); }
121
+ hold?.release(); hold = next;
122
+ // A conversation that enrolled again (key or harness changed) holds the live broker.
123
+ if (current) { broker = current.broker; await current.session.abort(); await Promise.allSettled([...current.helpers.values()]); await broker.request('close'); current.session.dispose(); await current.boundary.dispose(); }
124
+ current = await ManagedSession.create({ sdkRoot: config.sdk_root, cwd, origin: config.origin, broker, agentDir, sessionManager,
125
+ protectedRoots: [configPath, agentDir], renewBroker: newBroker, bindingRevision });
126
+ return { session: current.session, extensionsResult: current.extensionsResult, services: current.services, diagnostics: [] };
127
+ };
128
+ const host = await api.createAgentSessionRuntime(factory, { cwd, agentDir, sessionManager: api.SessionManager.create(cwd, path.join(agentDir, 'sessions')) });
129
+ if (flags.get('--check')) console.log('agent-watch-auto: connected; native context; isolated tools; no inference sent.');
130
+ else if (flags.has('--prompt')) {
131
+ current.session.subscribe(event => {
132
+ if (event.type === 'message_update' && event.assistantMessageEvent.type === 'text_delta') process.stdout.write(event.assistantMessageEvent.delta);
133
+ if (event.type === 'message_end' && ['agent-watch-helper-receipt','agent-watch-review-status'].includes(event.message?.customType)) process.stderr.write(String(event.message.content) + '\n');
134
+ });
135
+ await current.session.prompt(flags.get('--prompt')); process.stdout.write('\n');
136
+ const last=current.session.messages.filter(message=>message.role==='assistant').at(-1);
137
+ if (last?.stopReason === 'error') {
138
+ // Already says who failed and why, ending in its stable [code].
139
+ process.stderr.write(`${String(last.errorMessage??'Agent Watch: the request failed [managed-request-failed]')}\n`);process.exitCode = 1;
140
+ }
141
+ } else {
142
+ // The company terminal runs the pinned Pi release: no "Run pi update" notice
143
+ // (updating Pi breaks the Agent Watch import), no package-update, catalog or
144
+ // install-telemetry calls. Search tools were provisioned above.
145
+ process.env.PI_OFFLINE = '1'; process.env.PI_SKIP_VERSION_CHECK = '1';
146
+ await new api.InteractiveMode(host, { verbose: false }).run();
147
+ }
148
+ }
149
+ } catch (error) {
150
+ // Never print JSON payloads or startup objects that can contain role tokens.
151
+ const code = error instanceof Error && /^managed-[a-z:_-]+$/.test(error.message) ? error.message : 'managed-launch-failed';
152
+ const hint = code === 'managed-session-open-elsewhere' ? 'This conversation is running in the Piagent WebUI; continue it there, or start a new one here.'
153
+ : 'Refresh the Studio import or check Keychain access.';
154
+ process.stderr.write(`Agent Watch: ${code}. ${hint}\n`); process.exitCode = 1;
155
+ } finally { await gateway?.close(); if (current) await current.dispose(); else await broker?.dispose(); hold?.release(); }
@@ -0,0 +1,29 @@
1
+ {
2
+ "version": 1,
3
+ "exceptions": [
4
+ {
5
+ "id": "GHSA-q2hr-2g5m-vwhr",
6
+ "package": "brace-expansion",
7
+ "node": "node_modules/@earendil-works/pi-coding-agent/node_modules/brace-expansion",
8
+ "decided": "2026-10-02",
9
+ "until": "2026-10-31",
10
+ "reason": "Denial of service (CPU) through a crafted brace pattern in a glob; no data exposure. brace-expansion 5.0.9 is pinned by the npm-shrinkwrap of every published Pi host (0.87.1 to 1.0.0), so no Piagent change can update it; 5.0.12 fixes it. Remove when a Pi host carries brace-expansion >= 5.0.12."
11
+ },
12
+ {
13
+ "id": "GHSA-qhr7-859c-m2p7",
14
+ "package": "brace-expansion",
15
+ "node": "node_modules/@earendil-works/pi-coding-agent/node_modules/brace-expansion",
16
+ "decided": "2026-10-02",
17
+ "until": "2026-10-31",
18
+ "reason": "Denial of service (stack exhaustion) through nested brace groups in a glob; no data exposure. Pinned by the Pi host's npm-shrinkwrap as above; fixed in 5.0.11."
19
+ },
20
+ {
21
+ "id": "GHSA-6j4f-fj2g-mc7p",
22
+ "package": "brace-expansion",
23
+ "node": "node_modules/@earendil-works/pi-coding-agent/node_modules/brace-expansion",
24
+ "decided": "2026-10-02",
25
+ "until": "2026-10-31",
26
+ "reason": "Denial of service (stack exhaustion) in parseCommaParts; no data exposure. Pinned by the Pi host's npm-shrinkwrap as above; fixed in 5.0.10."
27
+ }
28
+ ]
29
+ }
package/scripts/setup.sh CHANGED
@@ -36,7 +36,7 @@ Options:
36
36
  --model-scope <full|codex|claude> model families to enable
37
37
  Configure Pi enabledModels for selector/cycling (default: full)
38
38
  --default-model <provider/model[:thinking]>
39
- Configure default provider/model/thinking (default: openai-codex/gpt-5.6-sol:high)
39
+ Configure default provider/model/thinking (default: openai-codex/gpt-6-sol:high)
40
40
  --no-model-scope Skip global model-scope configuration
41
41
  --install-pi / --no-install-pi Install/skip Pi CLI with npm if `pi` is missing (default: install)
42
42
  --force-profile Replace existing project .pi/piagent-profile.json
@@ -78,7 +78,7 @@ WITH_WEB_ACCESS=true
78
78
  WITH_HERDR=true
79
79
  CONFIGURE_MODEL_SCOPE=true
80
80
  MODEL_SCOPE_PRESET="full"
81
- DEFAULT_MODEL="openai-codex/gpt-5.6-sol:high"
81
+ DEFAULT_MODEL="openai-codex/gpt-6-sol:high"
82
82
  AUTO_INSTALL_PI=true
83
83
  FORCE_PROFILE=false
84
84
  FORCE_SETTINGS=false
@@ -67,6 +67,9 @@ const strictShare = strictShareRaw === "true";
67
67
  const offline = offlineRaw === "true";
68
68
  const errors = [];
69
69
  const warnings = [];
70
+ const { piagentInstallations } = await import(pathToFileURL(path.join(platformRoot, "scripts/piagent-installations.mjs")).href);
71
+ const installations = piagentInstallations();
72
+ if(installations.length>1) warnings.push("Multiple Piagent installations detected. Use the pinned Watch launcher; other PATHs may run an older build: "+installations.map(i=>`${i.version} [${i.fingerprint}] ${i.root}`).join("; "));
70
73
  const { verifyCapabilityLock } = await import(pathToFileURL(path.join(platformRoot, "packages", "piagent-core", "capabilities", "capability-core.js")).href);
71
74
 
72
75
  function exists(rel) {
@@ -185,7 +188,7 @@ for (const rel of [
185
188
  const rootPackage = readJson(path.join(platformRoot, "package.json"));
186
189
  if (!rootPackage.pi?.extensions?.length) errors.push("root package.json missing pi.extensions");
187
190
  if (!rootPackage.pi?.skills?.length) errors.push("root package.json missing pi.skills");
188
- if (!rootPackage.pi?.prompts?.length) errors.push("root package.json missing pi.prompts");
191
+ // Prompt templates are optional: freeform chat does not require workflow prompts.
189
192
  if (!rootPackage.pi?.subagents?.agents?.length) errors.push("root package.json missing pi.subagents.agents");
190
193
 
191
194
  if (!commandExists("pi")) warnings.push("pi is not on PATH");
@@ -297,6 +300,20 @@ try {
297
300
  warnings.push(`MCP readiness check could not run: ${error instanceof Error ? error.message : String(error)}`);
298
301
  }
299
302
 
303
+ // A pattern in enabledModels that matches no model Pi knows makes Pi print a
304
+ // warning on every start; it never matches again by itself.
305
+ try {
306
+ const prune = await import(pathToFileURL(path.join(platformRoot, "scripts", "model-scope-prune.mjs")).href);
307
+ const agentDir = process.env.PI_CODING_AGENT_DIR || path.join(process.env.HOME || "", ".pi", "agent");
308
+ const settings = readJsonIfPresent(path.join(agentDir, "settings.json"));
309
+ const patterns = Array.isArray(settings?.enabledModels) ? settings.enabledModels.filter((item) => typeof item === "string") : [];
310
+ const piRoot = patterns.length ? prune.piPackageRoot() : null;
311
+ const stale = piRoot ? await prune.stalePatterns(patterns, await prune.knownModels(piRoot, agentDir), piRoot) : [];
312
+ if (stale.length) warnings.push(`Pi enabledModels has ${stale.length} pattern(s) that match no model Pi knows (${stale.join(", ")}); Pi warns about them on every start. Run \`piagent-model-scope --prune\` to remove only these`);
313
+ } catch (error) {
314
+ warnings.push(`model scope check could not run: ${error instanceof Error ? error.message : String(error)}`);
315
+ }
316
+
300
317
  const subagentConfigPath = path.join(process.env.PI_CODING_AGENT_DIR || path.join(process.env.HOME || "", ".pi", "agent"), "extensions", "subagent", "config.json");
301
318
  const subagentConfig = readJsonIfPresent(subagentConfigPath);
302
319
  if (piHasSubagents && !subagentConfig) {
@@ -541,6 +558,8 @@ const report = {
541
558
  },
542
559
  rootPiManifest: rootPackage.pi,
543
560
  warnings,
561
+ installations,
562
+ nodeExecutable: process.execPath,
544
563
  errors
545
564
  };
546
565
 
@@ -5,6 +5,12 @@ import { stripTypeScriptTypes } from "node:module";
5
5
  import path from "node:path";
6
6
  import { fileURLToPath, pathToFileURL } from "node:url";
7
7
 
8
+ // This runs on Node's loader thread, where a launcher's warning filter does
9
+ // not apply: hide only the experimental notice for type stripping, which
10
+ // members cannot act on (`piagent studio` from Agent Watch runs plain node).
11
+ process.removeAllListeners("warning");
12
+ process.on("warning", (warning) => { if (warning.name !== "ExperimentalWarning") process.stderr.write(`${warning.name}: ${warning.message}\n`); });
13
+
8
14
  const BENCHMARK_BOOTSTRAP_METADATA = "PIAGENT_BENCHMARK_BOOTSTRAP_METADATA";
9
15
  const RUNTIME_DEPENDENCY_KEYS = [
10
16
  "schemaVersion", "node", "platform", "packages", "resolutionRoot", "resolutionTree", "isolation", "digest"
@@ -634,15 +634,15 @@ for (const rel of jsonFiles) {
634
634
  }
635
635
 
636
636
  const rootPkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8"));
637
- if (!rootPkg.pi || !rootPkg.pi.extensions || !rootPkg.pi.prompts || !rootPkg.pi.skills) {
637
+ if (!rootPkg.pi || !rootPkg.pi.extensions || !rootPkg.pi.skills) {
638
638
  throw new Error("root package.json missing pi manifest");
639
639
  }
640
640
  if (!rootPkg.pi.subagents?.agents?.length) {
641
641
  throw new Error("root package.json missing pi.subagents.agents");
642
642
  }
643
643
  const expectedPeers = {
644
- "@earendil-works/pi-ai": "0.86.1",
645
- "@earendil-works/pi-coding-agent": "0.86.1",
644
+ "@earendil-works/pi-ai": "0.87.1",
645
+ "@earendil-works/pi-coding-agent": "0.87.1",
646
646
  typebox: "1.3.27"
647
647
  };
648
648
  for (const [name, version] of Object.entries(expectedPeers)) {
@@ -651,7 +651,7 @@ for (const [name, version] of Object.entries(expectedPeers)) {
651
651
  }
652
652
 
653
653
  const pkg = JSON.parse(fs.readFileSync(path.join(root, "packages/piagent-core/package.json"), "utf8"));
654
- if (!pkg.pi || !pkg.pi.extensions || !pkg.pi.prompts || !pkg.pi.skills) {
654
+ if (!pkg.pi || !pkg.pi.extensions || !pkg.pi.skills) {
655
655
  throw new Error("packages/piagent-core/package.json missing pi manifest");
656
656
  }
657
657
  if (!pkg.pi.subagents?.agents?.length) {
@@ -945,7 +945,7 @@ if [[ "$OFFLINE" == true || "${PIAGENT_VERIFY_OFFLINE:-}" == "1" || "${CI:-}" ==
945
945
  else
946
946
  bash "$ROOT/scripts/pi-model-catalog.sh" --json >/dev/null
947
947
  fi
948
- bash "$ROOT/scripts/configure-model-scope.sh" --dry-run --preset full --default-model openai-codex/gpt-5.6-sol:high >/dev/null
948
+ bash "$ROOT/scripts/configure-model-scope.sh" --dry-run --preset full --default-model openai-codex/gpt-6-sol:high >/dev/null
949
949
  node "$ROOT/scripts/mcp-manage.mjs" --list >/dev/null
950
950
  node "$ROOT/scripts/mcp-manage.mjs" --dry-run --preset popular --scope project --project "$ROOT" >/dev/null
951
951
  node --input-type=module - "$ROOT" <<'NODE'
@@ -58,7 +58,7 @@ const packageLock = readJson("package-lock.json");
58
58
  const capabilityLock = readJson(".pi/piagent-profile.lock.json");
59
59
  const version = rootPackage.version;
60
60
  const expectedTag = `v${version}`;
61
- const supportedPiHost = "0.86.1";
61
+ const supportedPiHost = "0.87.1";
62
62
 
63
63
  // The package is published now, so the old private-forever rule is gone. What
64
64
  // still has to hold is that a scoped package cannot reach the registry as
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "defaultProjectTrust": "ask",
3
3
  "defaultProvider": "openai-codex",
4
- "defaultModel": "gpt-5.6-sol",
4
+ "defaultModel": "gpt-6-sol",
5
5
  "defaultThinkingLevel": "high",
6
6
  "showCacheMissNotices": true,
7
7
  "enabledModels": [
@@ -12,6 +12,10 @@
12
12
  "openai-codex/gpt-5.6-luna:medium",
13
13
  "openai-codex/gpt-5.6-terra:high",
14
14
  "openai-codex/gpt-5.6-sol:high",
15
+ "openai-codex/gpt-6-luna:medium",
16
+ "openai-codex/gpt-6-sol:medium",
17
+ "openai-codex/gpt-6-sol:high",
18
+ "openai-codex/gpt-6-astra:xhigh",
15
19
  "openai-codex/*",
16
20
  "anthropic/claude-haiku-4-5:low",
17
21
  "anthropic/claude-sonnet-4-5:high",
@@ -21,7 +25,9 @@
21
25
  "anthropic/claude-opus-4-6:max",
22
26
  "anthropic/claude-opus-4-7:xhigh",
23
27
  "anthropic/claude-opus-4-8:xhigh",
24
- "anthropic/claude-fable-5:xhigh"
28
+ "anthropic/claude-fable-5:xhigh",
29
+ "anthropic/claude-sonnet-5-5:high",
30
+ "anthropic/claude-opus-5-5:high"
25
31
  ],
26
32
  "compaction": {
27
33
  "enabled": true,
@@ -4,7 +4,7 @@
4
4
 
5
5
  - Generated: not yet
6
6
  - Profile: see `.pi/piagent-profile.json`
7
- - Model/pass: run `/onboard run` after Pi login and model selection
7
+ - Model/pass: ask the agent to onboard the project after Pi login and model selection
8
8
  - Scope: pending
9
9
 
10
10
  ## Purpose
@@ -16,13 +16,13 @@ Before the first real implementation task in this project:
16
16
  1. Open Pi in the project.
17
17
  2. Run `/login` if needed.
18
18
  3. Select the intended provider/model.
19
- 4. Run `/onboard run`.
19
+ 4. Ask the agent: "Inspect this project read-only and record its project context."
20
20
 
21
21
  The selected model should inspect the project read-only, then replace this file with a concise project map, required context, verification matrix, and high-risk areas.
22
22
 
23
23
  ## Update triggers
24
24
 
25
- Regenerate with `/onboard run` when:
25
+ Ask the agent to refresh it when:
26
26
 
27
27
  - source layout changes;
28
28
  - architecture or domain ownership changes;
@@ -7,12 +7,11 @@ This project uses Pi Agent Platform.
7
7
 
8
8
  For an ordinary source task:
9
9
 
10
- 1. Runtime binds bounded source work to this Pi session before the model starts. If intake pauses for broad/high-risk/ambiguous scope, call `piagent_task_start` exactly once with project-relative path/glob scope and reuse the contract.
11
- 2. Read the narrow target and nearest test. Use ordinary read/search/edit/bash tools and one writer.
12
- 3. Complete intended source and focused regression-test edits, then run each exact runtime verifier. Rerun only after another mutation.
13
- 4. Do not call Piagent management/diagnostic tools unless runtime or the operator asks. Report changed files, verification, and residual risk concisely.
10
+ 1. Read the narrow target and nearest test. Use ordinary read/search/edit/bash tools and one writer.
11
+ 2. Make the change, then run the project's checks. Rerun only after another change.
12
+ 3. Do not call Piagent management/diagnostic tools unless runtime or the operator asks. Report changed files, verification, and residual risk concisely.
14
13
 
15
- Runtime enforces protected paths, permissions, external/destructive confirmation, scope, current-tree evidence, and the final gate. Current source is authoritative; generated context is advisory. Use subagents only for independent read-only lanes.
14
+ Runtime enforces protected paths, permissions, read-only paths, and external/destructive confirmation. Current source is authoritative; generated context is advisory. Use subagents only for independent read-only lanes.
16
15
  <!-- piagent-managed:end -->
17
16
 
18
17
  ## Review