@pasko70/pibo 1.9.2 → 1.9.4

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 (120) hide show
  1. package/README.md +183 -183
  2. package/context/codex-base-prompt.md +148 -148
  3. package/context/compute-worker.md +23 -23
  4. package/context/pibo-compaction-prompt.md +100 -100
  5. package/context/pibo-native-tooling.md +18 -18
  6. package/context/pibo-system-prompt.md +77 -77
  7. package/dist/apps/chat/agent-store.js +248 -248
  8. package/dist/apps/chat/data/project-service.js +168 -168
  9. package/dist/apps/chat/data/read-state-service.js +18 -18
  10. package/dist/apps/chat/data/session-query-service.js +25 -25
  11. package/dist/apps/chat/data/timeline-query-service.js +14 -14
  12. package/dist/apps/chat/static-assets.js +854 -854
  13. package/dist/apps/chat/workflow-persistence.js +255 -255
  14. package/dist/apps/chat-ui/assets/{dist-CjYtD7ZT.js → dist-9a5adSX0.js} +1 -1
  15. package/dist/apps/chat-ui/assets/{dist-9lsp1UpA.js → dist-BJftG-mN.js} +1 -1
  16. package/dist/apps/chat-ui/assets/{dist-2KdPXbMT.js → dist-BmIDFlGO.js} +1 -1
  17. package/dist/apps/chat-ui/assets/{dist-BWbWIOcD.js → dist-CCNYUBAQ.js} +1 -1
  18. package/dist/apps/chat-ui/assets/{dist-Cge8JklW.js → dist-Cmr0ZAV7.js} +1 -1
  19. package/dist/apps/chat-ui/assets/{dist-DFhhiR8M.js → dist-Crc-B1sZ.js} +1 -1
  20. package/dist/apps/chat-ui/assets/{dist-5GM30SQK.js → dist-DHPwmWcR.js} +1 -1
  21. package/dist/apps/chat-ui/assets/{dist-C-5u2QIS.js → dist-U3lqQ0aI.js} +1 -1
  22. package/dist/apps/chat-ui/assets/{dist-Idz5kzy8.js → dist-_poCjCWK.js} +1 -1
  23. package/dist/apps/chat-ui/assets/{dist-Etxmpyxg.js → dist-ffW7mw39.js} +1 -1
  24. package/dist/apps/chat-ui/assets/{dist-BYKMZlI0.js → dist-w2d_3LSu.js} +1 -1
  25. package/dist/apps/chat-ui/assets/{index-BqD_bm7z.js → index-rXMhSu4U.js} +9 -9
  26. package/dist/apps/chat-ui/index.html +17 -17
  27. package/dist/apps/chat-ui/manifest.webmanifest +25 -25
  28. package/dist/apps/chat-ui/sw.js +47 -47
  29. package/dist/apps/chat-vscode-web/assets/index-BAMxIaI_.js +41 -0
  30. package/dist/apps/chat-vscode-web/index.html +13 -13
  31. package/dist/apps/cli-ui/cliSessionsCommand.js +23 -23
  32. package/dist/apps/context-files-ui/index.html +11 -11
  33. package/dist/cli.js +39 -39
  34. package/dist/compute/cli.js +54 -54
  35. package/dist/core/session-router.js +5 -2
  36. package/dist/cron/cli.js +15 -15
  37. package/dist/cron/store.js +49 -49
  38. package/dist/data/cli.js +23 -23
  39. package/dist/data/event-log.js +23 -23
  40. package/dist/data/message-store.js +20 -20
  41. package/dist/data/navigation-store.js +9 -9
  42. package/dist/data/observation-store.js +4 -4
  43. package/dist/data/payload-store.js +17 -17
  44. package/dist/data/schema.js +431 -431
  45. package/dist/data/session-store.js +4 -4
  46. package/dist/data/telemetry-queries.js +54 -54
  47. package/dist/data/telemetry.js +197 -197
  48. package/dist/debug/events.js +12 -12
  49. package/dist/debug/failures.js +6 -6
  50. package/dist/debug/index.js +227 -227
  51. package/dist/debug/messages.js +6 -6
  52. package/dist/debug/pty.js +124 -124
  53. package/dist/debug/session.js +29 -29
  54. package/dist/debug/tools.js +5 -5
  55. package/dist/debug/web-snapshot-browser-scripts.js +294 -294
  56. package/dist/debug/web-streaming-browser-library.js +925 -925
  57. package/dist/debug/web-streaming-browser-scripts.js +232 -232
  58. package/dist/debug/web-streaming-provider-telemetry.js +4 -4
  59. package/dist/debug/web.js +93 -93
  60. package/dist/gateway/cli.js +19 -19
  61. package/dist/mcp/config-command.js +53 -53
  62. package/dist/mcp/index.js +21 -21
  63. package/dist/mcp/registry.js +11 -11
  64. package/dist/pi-packages/cli.js +11 -11
  65. package/dist/plugins/context-files-store.js +110 -110
  66. package/dist/plugins/context-files.js +4 -4
  67. package/dist/ralph/cli.js +18 -18
  68. package/dist/ralph/templates.js +140 -140
  69. package/dist/reliability/store.js +226 -226
  70. package/dist/session-ui/sessionActivity.js +30 -0
  71. package/dist/sessions/pibo-data-store.js +16 -16
  72. package/dist/sessions/sqlite-store.js +53 -53
  73. package/dist/setup/cli.js +58 -58
  74. package/dist/signals/projector.js +26 -11
  75. package/dist/signals/registry.js +41 -0
  76. package/dist/tools/agent-browser-wrapper.js +80 -80
  77. package/dist/tools/browser-use-cdp.js +12 -12
  78. package/dist/tools/browser-use-wrapper.js +762 -762
  79. package/dist/tools/guides.js +538 -538
  80. package/dist/tools/index.js +99 -99
  81. package/dist/tools/runtime/node-worker-source.js +205 -205
  82. package/dist/tools/runtime/python-worker-source.js +177 -177
  83. package/dist/vscode/cli.js +9 -9
  84. package/dist/web-annotations/cdp.js +900 -900
  85. package/dist/web-annotations/store.js +96 -96
  86. package/docs/README.md +23 -23
  87. package/docs/ops/install-developer-host.md +112 -112
  88. package/docs/ops/install-user-host.md +96 -96
  89. package/docs/ops/upgrade-user-to-developer-host.md +69 -69
  90. package/docs/ops/vscode-extension-release.md +160 -160
  91. package/package.json +95 -95
  92. package/skills/builtin/graphify/SKILL.md +52 -52
  93. package/skills/builtin/pi-agent-harness/SKILL.md +319 -319
  94. package/skills/builtin/pi-agent-harness/agents/openai.yaml +4 -4
  95. package/skills/builtin/pibo-docker-system/SKILL.md +170 -170
  96. package/skills/builtin/pibo-spec-writing/SKILL.md +330 -330
  97. package/skills/builtin/prd/SKILL.md +143 -143
  98. package/skills/builtin/ralph-loop/SKILL.md +359 -359
  99. package/skills/builtin/ralph-prd-json/SKILL.md +123 -123
  100. package/skills/builtin/skill-creator/LICENSE.txt +201 -201
  101. package/skills/builtin/skill-creator/SKILL.md +513 -513
  102. package/skills/builtin/skill-creator/agents/analyzer.md +274 -274
  103. package/skills/builtin/skill-creator/agents/comparator.md +202 -202
  104. package/skills/builtin/skill-creator/agents/grader.md +223 -223
  105. package/skills/builtin/skill-creator/assets/eval_review.html +146 -146
  106. package/skills/builtin/skill-creator/eval-viewer/generate_review.py +471 -471
  107. package/skills/builtin/skill-creator/eval-viewer/viewer.html +1325 -1325
  108. package/skills/builtin/skill-creator/references/schemas.md +430 -430
  109. package/skills/builtin/skill-creator/scripts/aggregate_benchmark.py +401 -401
  110. package/skills/builtin/skill-creator/scripts/generate_report.py +326 -326
  111. package/skills/builtin/skill-creator/scripts/improve_description.py +247 -247
  112. package/skills/builtin/skill-creator/scripts/package_skill.py +136 -136
  113. package/skills/builtin/skill-creator/scripts/quick_validate.py +102 -102
  114. package/skills/builtin/skill-creator/scripts/run_eval.py +310 -310
  115. package/skills/builtin/skill-creator/scripts/run_loop.py +328 -328
  116. package/skills/builtin/skill-creator/scripts/utils.py +47 -47
  117. package/skills/builtin/web-annotations/SKILL.md +93 -93
  118. package/src/mcp/LICENSE.mcp-cli +21 -21
  119. package/dist/apps/chat-vscode-web/assets/index-Cst9OUkC.js +0 -41
  120. package/dist/session-ui/activeTurn.js +0 -126
@@ -18,31 +18,31 @@ export class SqlitePiboSessionStore {
18
18
  this.ensureActiveModelColumn();
19
19
  }
20
20
  applySchema() {
21
- this.db.exec(`
22
- CREATE TABLE IF NOT EXISTS pibo_sessions (
23
- id TEXT PRIMARY KEY,
24
- pi_session_id TEXT NOT NULL UNIQUE,
25
- channel TEXT NOT NULL,
26
- kind TEXT NOT NULL,
27
- profile TEXT NOT NULL,
28
- parent_id TEXT,
29
- origin_id TEXT,
30
- workspace TEXT,
31
- title TEXT,
32
- metadata_json TEXT,
33
- active_model_json TEXT,
34
- created_at TEXT NOT NULL,
35
- updated_at TEXT NOT NULL,
36
- FOREIGN KEY(parent_id) REFERENCES pibo_sessions(id),
37
- FOREIGN KEY(origin_id) REFERENCES pibo_sessions(id)
38
- );
39
-
40
- CREATE INDEX IF NOT EXISTS idx_pibo_sessions_parent
41
- ON pibo_sessions(parent_id, updated_at);
42
- CREATE INDEX IF NOT EXISTS idx_pibo_sessions_origin
43
- ON pibo_sessions(origin_id, updated_at);
44
- CREATE INDEX IF NOT EXISTS idx_pibo_sessions_channel_kind
45
- ON pibo_sessions(channel, kind, updated_at);
21
+ this.db.exec(`
22
+ CREATE TABLE IF NOT EXISTS pibo_sessions (
23
+ id TEXT PRIMARY KEY,
24
+ pi_session_id TEXT NOT NULL UNIQUE,
25
+ channel TEXT NOT NULL,
26
+ kind TEXT NOT NULL,
27
+ profile TEXT NOT NULL,
28
+ parent_id TEXT,
29
+ origin_id TEXT,
30
+ workspace TEXT,
31
+ title TEXT,
32
+ metadata_json TEXT,
33
+ active_model_json TEXT,
34
+ created_at TEXT NOT NULL,
35
+ updated_at TEXT NOT NULL,
36
+ FOREIGN KEY(parent_id) REFERENCES pibo_sessions(id),
37
+ FOREIGN KEY(origin_id) REFERENCES pibo_sessions(id)
38
+ );
39
+
40
+ CREATE INDEX IF NOT EXISTS idx_pibo_sessions_parent
41
+ ON pibo_sessions(parent_id, updated_at);
42
+ CREATE INDEX IF NOT EXISTS idx_pibo_sessions_origin
43
+ ON pibo_sessions(origin_id, updated_at);
44
+ CREATE INDEX IF NOT EXISTS idx_pibo_sessions_channel_kind
45
+ ON pibo_sessions(channel, kind, updated_at);
46
46
  `);
47
47
  }
48
48
  ensureActiveModelColumn() {
@@ -60,22 +60,22 @@ export class SqlitePiboSessionStore {
60
60
  create(input) {
61
61
  const session = createPiboSession(input);
62
62
  this.db
63
- .prepare(`
64
- INSERT INTO pibo_sessions (
65
- id,
66
- pi_session_id,
67
- channel,
68
- kind,
69
- profile,
70
- parent_id,
71
- origin_id,
72
- workspace,
73
- title,
74
- metadata_json,
75
- active_model_json,
76
- created_at,
77
- updated_at
78
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
63
+ .prepare(`
64
+ INSERT INTO pibo_sessions (
65
+ id,
66
+ pi_session_id,
67
+ channel,
68
+ kind,
69
+ profile,
70
+ parent_id,
71
+ origin_id,
72
+ workspace,
73
+ title,
74
+ metadata_json,
75
+ active_model_json,
76
+ created_at,
77
+ updated_at
78
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
79
79
  `)
80
80
  .run(session.id, session.piSessionId, session.channel, session.kind, session.profile, session.parentId ?? null, session.originId ?? null, session.workspace ?? null, session.title ?? null, JSON.stringify(session.metadata ?? {}), session.activeModel ? JSON.stringify(session.activeModel) : null, session.createdAt, session.updatedAt);
81
81
  const created = this.get(session.id);
@@ -100,18 +100,18 @@ export class SqlitePiboSessionStore {
100
100
  updatedAt: new Date().toISOString(),
101
101
  };
102
102
  this.db
103
- .prepare(`
104
- UPDATE pibo_sessions SET
105
- pi_session_id = ?,
106
- profile = ?,
107
- parent_id = ?,
108
- origin_id = ?,
109
- workspace = ?,
110
- title = ?,
111
- metadata_json = ?,
112
- active_model_json = ?,
113
- updated_at = ?
114
- WHERE id = ?
103
+ .prepare(`
104
+ UPDATE pibo_sessions SET
105
+ pi_session_id = ?,
106
+ profile = ?,
107
+ parent_id = ?,
108
+ origin_id = ?,
109
+ workspace = ?,
110
+ title = ?,
111
+ metadata_json = ?,
112
+ active_model_json = ?,
113
+ updated_at = ?
114
+ WHERE id = ?
115
115
  `)
116
116
  .run(updated.piSessionId, updated.profile, updated.parentId ?? null, updated.originId ?? null, updated.workspace ?? null, updated.title ?? null, JSON.stringify(updated.metadata ?? {}), updated.activeModel ? JSON.stringify(updated.activeModel) : null, updated.updatedAt, id);
117
117
  return this.get(id);
package/dist/setup/cli.js CHANGED
@@ -23,89 +23,89 @@ function shellQuote(value) {
23
23
  }
24
24
  function serviceUnit(options) {
25
25
  const gatewayPortEnv = options.serviceKind === "dev" ? `Environment=PIBO_GATEWAY_DEV_PORT=${options.webPort}\n` : `Environment=PIBO_GATEWAY_WEB_PORT=${options.webPort}\n`;
26
- return `[Unit]
27
- Description=${options.description}
28
- After=network-online.target
29
- Wants=network-online.target
30
-
31
- [Service]
32
- Type=simple
33
- WorkingDirectory=${options.workingDirectory}
34
- Environment=HOME=/root
35
- Environment=PIBO_HOME=${options.piboHome}
36
- Environment=NODE_ENV=production
37
- ${gatewayPortEnv}ExecStart=${options.execStart}
38
- Restart=always
39
- RestartSec=5
40
- KillSignal=SIGTERM
41
- TimeoutStopSec=30
42
-
43
- [Install]
44
- WantedBy=multi-user.target
26
+ return `[Unit]
27
+ Description=${options.description}
28
+ After=network-online.target
29
+ Wants=network-online.target
30
+
31
+ [Service]
32
+ Type=simple
33
+ WorkingDirectory=${options.workingDirectory}
34
+ Environment=HOME=/root
35
+ Environment=PIBO_HOME=${options.piboHome}
36
+ Environment=NODE_ENV=production
37
+ ${gatewayPortEnv}ExecStart=${options.execStart}
38
+ Restart=always
39
+ RestartSec=5
40
+ KillSignal=SIGTERM
41
+ TimeoutStopSec=30
42
+
43
+ [Install]
44
+ WantedBy=multi-user.target
45
45
  `;
46
46
  }
47
47
  function devStartWrapper(options) {
48
- return `#!/usr/bin/env node
49
- import { runWebGatewayServer } from ${JSON.stringify(`${options.repoDir}/dist/gateway/web.js`)};
50
-
51
- await runWebGatewayServer({
52
- host: "127.0.0.1",
53
- port: ${options.gatewayPort},
54
- web: {
55
- host: "127.0.0.1",
56
- port: ${options.webPort},
57
- },
58
- });
48
+ return `#!/usr/bin/env node
49
+ import { runWebGatewayServer } from ${JSON.stringify(`${options.repoDir}/dist/gateway/web.js`)};
50
+
51
+ await runWebGatewayServer({
52
+ host: "127.0.0.1",
53
+ port: ${options.gatewayPort},
54
+ web: {
55
+ host: "127.0.0.1",
56
+ port: ${options.webPort},
57
+ },
58
+ });
59
59
  `;
60
60
  }
61
61
  function caddyfile(options) {
62
62
  const blocks = [];
63
63
  if (options.prodDomain) {
64
- blocks.push(`${options.prodDomain} {
65
- encode zstd gzip
66
- reverse_proxy 127.0.0.1:${options.prodPort}
64
+ blocks.push(`${options.prodDomain} {
65
+ encode zstd gzip
66
+ reverse_proxy 127.0.0.1:${options.prodPort}
67
67
  }`);
68
68
  }
69
69
  if (options.prodWwwDomain && options.prodDomain) {
70
- blocks.push(`${options.prodWwwDomain} {
71
- redir https://${options.prodDomain}{uri} permanent
70
+ blocks.push(`${options.prodWwwDomain} {
71
+ redir https://${options.prodDomain}{uri} permanent
72
72
  }`);
73
73
  }
74
74
  if (options.devDomain && options.devPort) {
75
- blocks.push(`${options.devDomain} {
76
- encode zstd gzip
77
- reverse_proxy 127.0.0.1:${options.devPort}
75
+ blocks.push(`${options.devDomain} {
76
+ encode zstd gzip
77
+ reverse_proxy 127.0.0.1:${options.devPort}
78
78
  }`);
79
79
  }
80
80
  if (options.devWwwDomain && options.devDomain) {
81
- blocks.push(`${options.devWwwDomain} {
82
- redir https://${options.devDomain}{uri} permanent
81
+ blocks.push(`${options.devWwwDomain} {
82
+ redir https://${options.devDomain}{uri} permanent
83
83
  }`);
84
84
  }
85
85
  return `${blocks.join("\n\n")}\n`;
86
86
  }
87
87
  function userEnvTemplate(options) {
88
- return `# Pibo user-host setup
89
- PIBO_HOME=${options.piboHome}
90
- PIBO_AUTH_BASE_URL=${options.domain ? `https://${options.domain}` : "https://pibo.example.com"}
91
- # Set through \`pibo config set\` or your secret manager:
92
- # PIBO_AUTH_SECRET=<at-least-32-characters>
93
- # PIBO_GOOGLE_CLIENT_ID=<google-client-id>
94
- # PIBO_GOOGLE_CLIENT_SECRET=<google-client-secret>
95
- # PIBO_ALLOWED_EMAILS=you@example.com
88
+ return `# Pibo user-host setup
89
+ PIBO_HOME=${options.piboHome}
90
+ PIBO_AUTH_BASE_URL=${options.domain ? `https://${options.domain}` : "https://pibo.example.com"}
91
+ # Set through \`pibo config set\` or your secret manager:
92
+ # PIBO_AUTH_SECRET=<at-least-32-characters>
93
+ # PIBO_GOOGLE_CLIENT_ID=<google-client-id>
94
+ # PIBO_GOOGLE_CLIENT_SECRET=<google-client-secret>
95
+ # PIBO_ALLOWED_EMAILS=you@example.com
96
96
  `;
97
97
  }
98
98
  function developerEnvTemplate(options) {
99
- return `# Pibo developer-host setup
100
- PIBO_ORIGIN=${options.origin ?? "git@github.com:<your-fork>/pibo.git"}
101
- PIBO_UPSTREAM=${options.upstream ?? "git@github.com:Pascapone/pibo.git"}
102
- PIBO_REPO_DIR=${options.repoDir}
103
- PIBO_PROD_HOME=${options.prodHome}
104
- PIBO_DEV_HOME=${options.devHome}
105
- PIBO_PROD_BASE_URL=${options.prodDomain ? `https://${options.prodDomain}` : "https://pibo.example.com"}
106
- PIBO_DEV_BASE_URL=${options.devDomain ? `https://${options.devDomain}` : "https://dev.pibo.example.com"}
107
- # Optional: override the dev deploy reachability probe. If omitted, deploy uses PIBO_DEV_BASE_URL/apps/chat.
108
- # PIBO_DEV_PUBLIC_URL=${options.devDomain ? `https://${options.devDomain}/apps/chat` : "https://dev.pibo.example.com/apps/chat"}
99
+ return `# Pibo developer-host setup
100
+ PIBO_ORIGIN=${options.origin ?? "git@github.com:<your-fork>/pibo.git"}
101
+ PIBO_UPSTREAM=${options.upstream ?? "git@github.com:Pascapone/pibo.git"}
102
+ PIBO_REPO_DIR=${options.repoDir}
103
+ PIBO_PROD_HOME=${options.prodHome}
104
+ PIBO_DEV_HOME=${options.devHome}
105
+ PIBO_PROD_BASE_URL=${options.prodDomain ? `https://${options.prodDomain}` : "https://pibo.example.com"}
106
+ PIBO_DEV_BASE_URL=${options.devDomain ? `https://${options.devDomain}` : "https://dev.pibo.example.com"}
107
+ # Optional: override the dev deploy reachability probe. If omitted, deploy uses PIBO_DEV_BASE_URL/apps/chat.
108
+ # PIBO_DEV_PUBLIC_URL=${options.devDomain ? `https://${options.devDomain}/apps/chat` : "https://dev.pibo.example.com/apps/chat"}
109
109
  `;
110
110
  }
111
111
  export function createUserHostSetupPlan(options = {}) {
@@ -16,10 +16,14 @@ function runStatus(status) {
16
16
  return "error";
17
17
  return status;
18
18
  }
19
- function settleActiveSessionNodes(piboSessionId, context) {
19
+ function settleActiveSessionNodes(piboSessionId, context, status, terminalSource) {
20
20
  return context.getSessionNodes(piboSessionId)
21
21
  .filter((node) => node.kind !== "session" && node.kind !== "yielded_run" && isActiveSignalStatus(node.status))
22
- .map((node) => ({ type: "patch_node", nodeId: node.id, patch: { status: "done", completedAt: context.now() } }));
22
+ .map((node) => ({
23
+ type: "patch_node",
24
+ nodeId: node.id,
25
+ patch: { status, completedAt: context.now(), metadata: { ...node.metadata, terminalSource } },
26
+ }));
23
27
  }
24
28
  export const sessionLifecycleSignalProducer = {
25
29
  name: "session-lifecycle",
@@ -40,18 +44,24 @@ export const sessionLifecycleSignalProducer = {
40
44
  }, context) }];
41
45
  }
42
46
  if (data.type === "session_disposed") {
43
- return [{ type: "patch_node", nodeId: `session:${data.piboSessionId}`, patch: { status: "disposed", completedAt: context.now(), metadata: { reason: data.reason } } }];
47
+ return [
48
+ ...settleActiveSessionNodes(data.piboSessionId, context, "cancelled", "session_disposed"),
49
+ { type: "patch_node", nodeId: `session:${data.piboSessionId}`, patch: { status: "disposed", completedAt: context.now(), metadata: { reason: data.reason } } },
50
+ ];
44
51
  }
45
52
  if (data.type === "session_interrupted") {
46
- return [{ type: "patch_node", nodeId: `session:${data.piboSessionId}`, patch: { status: "interrupted", completedAt: context.now(), metadata: { reason: data.reason } } }];
53
+ return [
54
+ ...settleActiveSessionNodes(data.piboSessionId, context, "interrupted", "session_interrupted"),
55
+ { type: "patch_node", nodeId: `session:${data.piboSessionId}`, patch: { status: "interrupted", completedAt: context.now(), metadata: { reason: data.reason } } },
56
+ ];
47
57
  }
48
58
  if (data.type === "session_processing_changed") {
49
59
  const existing = context.getNode(`session:${data.piboSessionId}`);
50
- const status = data.processing ? "running" : existing && isTerminalSignalStatus(existing.status) ? existing.status : "idle";
60
+ const status = existing && isTerminalSignalStatus(existing.status) ? existing.status : data.processing ? "running" : "idle";
51
61
  return [
52
62
  { type: "patch_node", nodeId: `session:${data.piboSessionId}`, patch: { status } },
53
63
  { type: "set_session_queue", piboSessionId: data.piboSessionId, queuedMessages: data.queuedMessages },
54
- ...(data.processing ? [] : settleActiveSessionNodes(data.piboSessionId, context)),
64
+ ...(data.processing ? [] : settleActiveSessionNodes(data.piboSessionId, context, "interrupted", "processing_stopped")),
55
65
  ];
56
66
  }
57
67
  if (data.type === "queue_changed") {
@@ -79,6 +89,11 @@ export const outputSignalProducer = {
79
89
  const event = data.event;
80
90
  const piboSessionId = event.piboSessionId;
81
91
  const mutations = [];
92
+ const eventTurn = event.eventId ? context.getNode(`turn:${piboSessionId}:${event.eventId}`) : undefined;
93
+ const explicitTerminalAfterFallback = eventTurn?.metadata?.terminalSource === "processing_stopped"
94
+ && (event.type === "message_finished" || event.type === "session_error");
95
+ if (eventTurn && isTerminalSignalStatus(eventTurn.status) && !explicitTerminalAfterFallback)
96
+ return [];
82
97
  if (event.type === "message_queued") {
83
98
  mutations.push({ type: "set_session_queue", piboSessionId, queuedMessages: event.queuedMessages });
84
99
  mutations.push({ type: "upsert_node", node: node({ id: `message:${piboSessionId}:${event.eventId ?? context.now()}`, kind: "message", status: "queued", piboSessionId, metadata: { source: event.source } }, context) });
@@ -87,7 +102,7 @@ export const outputSignalProducer = {
87
102
  mutations.push({ type: "patch_node", nodeId: `session:${piboSessionId}`, patch: { status: "running" } });
88
103
  if (event.eventId) {
89
104
  mutations.push({ type: "patch_node", nodeId: `message:${piboSessionId}:${event.eventId}`, patch: { status: "done", completedAt: context.now() } });
90
- mutations.push({ type: "upsert_node", node: node({ id: `turn:${piboSessionId}:${event.eventId}`, kind: "turn", status: "running", piboSessionId, startedAt: context.now(), metadata: { source: event.source } }, context) });
105
+ mutations.push({ type: "upsert_node", node: node({ id: `turn:${piboSessionId}:${event.eventId}`, kind: "turn", status: "running", piboSessionId, startedAt: eventTurn?.startedAt ?? context.now(), metadata: { eventId: event.eventId, source: event.source } }, context) });
91
106
  }
92
107
  }
93
108
  if (event.type === "assistant_delta") {
@@ -124,17 +139,17 @@ export const outputSignalProducer = {
124
139
  }
125
140
  if (event.eventId) {
126
141
  mutations.push({ type: "patch_node", nodeId: `message:${piboSessionId}:${event.eventId}`, patch: { status: "done", completedAt: context.now() } });
127
- mutations.push({ type: "patch_node", nodeId: `turn:${piboSessionId}:${event.eventId}`, patch: { status: "done", completedAt: context.now() } });
142
+ mutations.push({ type: "patch_node", nodeId: `turn:${piboSessionId}:${event.eventId}`, patch: { status: "done", completedAt: context.now(), metadata: { ...eventTurn?.metadata, terminalSource: "message_finished" } } });
128
143
  }
129
- mutations.push(...settleActiveSessionNodes(piboSessionId, context));
144
+ mutations.push(...settleActiveSessionNodes(piboSessionId, context, "done", "message_finished"));
130
145
  }
131
146
  if (event.type === "session_error") {
132
147
  mutations.push({ type: "set_session_queue", piboSessionId, queuedMessages: 0 });
133
- mutations.push(...settleActiveSessionNodes(piboSessionId, context));
148
+ mutations.push(...settleActiveSessionNodes(piboSessionId, context, "error", "session_error"));
134
149
  mutations.push({ type: "patch_node", nodeId: `session:${piboSessionId}`, patch: { status: "error", completedAt: context.now(), error: { message: event.error, source: "pi" } } });
135
150
  if (event.eventId) {
136
151
  mutations.push({ type: "patch_node", nodeId: `message:${piboSessionId}:${event.eventId}`, patch: { status: "error", completedAt: context.now(), error: { message: event.error, source: "pi" } } });
137
- mutations.push({ type: "patch_node", nodeId: `turn:${piboSessionId}:${event.eventId}`, patch: { status: "error", completedAt: context.now(), error: { message: event.error, source: "pi" } } });
152
+ mutations.push({ type: "patch_node", nodeId: `turn:${piboSessionId}:${event.eventId}`, patch: { status: "error", completedAt: context.now(), error: { message: event.error, source: "pi" }, metadata: { ...eventTurn?.metadata, terminalSource: "session_error" } } });
138
153
  }
139
154
  }
140
155
  return mutations;
@@ -106,6 +106,44 @@ function telemetryTurnIdFromNode(node, piboSessionId) {
106
106
  }
107
107
  return `turn_${node.id.slice(prefix.length)}`;
108
108
  }
109
+ function latestTurnSummary(nodes, piboSessionId) {
110
+ const turn = nodes
111
+ .filter((node) => node.kind === "turn" && node.startedAt)
112
+ .sort((left, right) => Date.parse(left.startedAt ?? left.createdAt) - Date.parse(right.startedAt ?? right.createdAt))
113
+ .at(-1);
114
+ if (!turn?.startedAt)
115
+ return undefined;
116
+ const state = turnSignalState(turn.status);
117
+ if (!state)
118
+ return undefined;
119
+ const prefix = `turn:${piboSessionId}:`;
120
+ const eventId = typeof turn.metadata?.eventId === "string"
121
+ ? turn.metadata.eventId
122
+ : turn.id.startsWith(prefix)
123
+ ? turn.id.slice(prefix.length)
124
+ : turn.id;
125
+ return {
126
+ nodeId: turn.id,
127
+ eventId,
128
+ state,
129
+ startedAt: turn.startedAt,
130
+ updatedAt: turn.updatedAt,
131
+ completedAt: turn.completedAt,
132
+ };
133
+ }
134
+ function turnSignalState(status) {
135
+ if (isActiveSignalStatus(status))
136
+ return "running";
137
+ if (status === "done")
138
+ return "completed";
139
+ if (status === "error")
140
+ return "failed";
141
+ if (status === "cancelled" || status === "disposed")
142
+ return "cancelled";
143
+ if (status === "interrupted")
144
+ return "interrupted";
145
+ return undefined;
146
+ }
109
147
  function signalNodeEqual(a, b) {
110
148
  if (!a)
111
149
  return false;
@@ -162,6 +200,7 @@ function sessionSnapshotSemanticallyEqual(a, b) {
162
200
  && a.queuedMessages === b.queuedMessages
163
201
  && a.currentMessageId === b.currentMessageId
164
202
  && a.currentTurnId === b.currentTurnId
203
+ && jsonValueEqual(a.latestTurn, b.latestTurn)
165
204
  && a.isLocalActive === b.isLocalActive
166
205
  && a.hasActiveDescendant === b.hasActiveDescendant
167
206
  && a.isTreeActive === b.isTreeActive
@@ -463,6 +502,7 @@ export class InMemoryPiboSignalRegistry {
463
502
  const activeRuns = nodes.filter((node) => node.kind === "yielded_run" && isActiveSignalStatus(node.status)).map((node) => ({ nodeId: node.id, runId: String(node.metadata?.runId ?? node.id.replace(/^run:/, "")), toolName: typeof node.metadata?.toolName === "string" ? node.metadata.toolName : undefined, status: node.status, completionPolicy: typeof node.metadata?.completionPolicy === "string" ? node.metadata.completionPolicy : undefined, consumed: typeof node.metadata?.consumed === "boolean" ? node.metadata.consumed : undefined, startedAt: node.startedAt, updatedAt: node.updatedAt }));
464
503
  const activeChildren = childSnapshots.filter((snapshot) => snapshot.isTreeActive).map((snapshot) => ({ nodeId: `session:${snapshot.piboSessionId}`, piboSessionId: snapshot.piboSessionId, status: snapshot.aggregateStatus, isTreeActive: snapshot.isTreeActive, hasError: snapshot.hasError || snapshot.hasErrorDescendant, updatedAt: snapshot.updatedAt }));
465
504
  const activeTelemetry = activeTelemetryHint(piboSessionId, activeLocalNodes, queuedMessages, now());
505
+ const latestTurn = latestTurnSummary(nodes, piboSessionId);
466
506
  const localErrors = nodes.flatMap((node) => {
467
507
  if (node.kind === "tool_call" || node.kind === "yielded_run")
468
508
  return [];
@@ -484,6 +524,7 @@ export class InMemoryPiboSignalRegistry {
484
524
  queuedMessages,
485
525
  currentMessageId: activeLocalNodes.find((node) => node.kind === "message")?.id,
486
526
  currentTurnId: activeLocalNodes.find((node) => node.kind === "turn")?.id,
527
+ latestTurn,
487
528
  isLocalActive,
488
529
  hasActiveDescendant,
489
530
  isTreeActive: isLocalActive || hasActiveDescendant,
@@ -6,86 +6,86 @@ function shellQuote(value) {
6
6
  return `'${value.replaceAll("'", "'\\''")}'`;
7
7
  }
8
8
  function createAgentBrowserWrapper(realExecutablePath, defaultHomeDir) {
9
- return `#!/usr/bin/env bash
10
- set -euo pipefail
11
-
12
- real_agent_browser=${shellQuote(realExecutablePath)}
13
- default_home=${shellQuote(defaultHomeDir)}
14
- fresh_flag=${shellQuote(AGENT_BROWSER_FRESH_PROFILE_FLAG)}
15
-
16
- if [ -z "\${AGENT_BROWSER_HOME:-}" ]; then
17
- export AGENT_BROWSER_HOME="$default_home"
18
- fi
19
- mkdir -p "$AGENT_BROWSER_HOME" "$AGENT_BROWSER_HOME/profiles"
20
-
21
- # agent-browser@0.27.0 uses HOME for ~/.agent-browser state. Redirect it by
22
- # default so doctor, config, sockets, and auth vault files stay inside Pibo's
23
- # tool home. Operators can opt out for upstream debugging.
24
- if [ "\${PIBO_AGENT_BROWSER_PRESERVE_HOME:-0}" != "1" ]; then
25
- export HOME="$AGENT_BROWSER_HOME"
26
- fi
27
-
28
- explicit_runtime=0
29
- fresh_profile=0
30
- show_help=0
31
- starts_browser=0
32
- args=()
33
-
34
- print_wrapper_help() {
35
- cat <<'HELP'
36
- Pibo agent-browser wrapper
37
- - keeps Agent Browser state under AGENT_BROWSER_HOME by default
38
- - prepends a persistent Pibo profile for browser-launching commands
39
- - pass --fresh-profile to disable Pibo profile injection
40
- - explicit --profile, --state, --cdp, --auto-connect, --provider, --engine,
41
- --executable-path, or --config flags override Pibo defaults
42
- HELP
43
- }
44
-
45
- while [ "$#" -gt 0 ]; do
46
- case "$1" in
47
- --help|-h)
48
- show_help=1
49
- args+=("$1")
50
- ;;
51
- --fresh-profile)
52
- fresh_profile=1
53
- ;;
54
- --profile|--state|--cdp|--auto-connect|--provider|--engine|--executable-path|--config)
55
- explicit_runtime=1
56
- args+=("$1")
57
- if [ "$#" -gt 1 ]; then
58
- shift
59
- args+=("$1")
60
- fi
61
- ;;
62
- --profile=*|--state=*|--cdp=*|--auto-connect=*|--provider=*|--engine=*|--executable-path=*|--config=*)
63
- explicit_runtime=1
64
- args+=("$1")
65
- ;;
66
- open|launch|new|goto)
67
- starts_browser=1
68
- args+=("$1")
69
- ;;
70
- *)
71
- args+=("$1")
72
- ;;
73
- esac
74
- shift
75
- done
76
-
77
- if [ "$show_help" -eq 1 ]; then
78
- print_wrapper_help
79
- exec "$real_agent_browser" "\${args[@]}"
80
- fi
81
-
82
- if [ "$starts_browser" -eq 1 ] && [ "$fresh_profile" -eq 0 ] && [ "$explicit_runtime" -eq 0 ]; then
83
- profile_dir=\${AGENT_BROWSER_PROFILE:-$AGENT_BROWSER_HOME/profiles/${AGENT_BROWSER_DEFAULT_PROFILE}}
84
- mkdir -p "$profile_dir"
85
- exec "$real_agent_browser" --profile "$profile_dir" "\${args[@]}"
86
- fi
87
-
88
- exec "$real_agent_browser" "\${args[@]}"
9
+ return `#!/usr/bin/env bash
10
+ set -euo pipefail
11
+
12
+ real_agent_browser=${shellQuote(realExecutablePath)}
13
+ default_home=${shellQuote(defaultHomeDir)}
14
+ fresh_flag=${shellQuote(AGENT_BROWSER_FRESH_PROFILE_FLAG)}
15
+
16
+ if [ -z "\${AGENT_BROWSER_HOME:-}" ]; then
17
+ export AGENT_BROWSER_HOME="$default_home"
18
+ fi
19
+ mkdir -p "$AGENT_BROWSER_HOME" "$AGENT_BROWSER_HOME/profiles"
20
+
21
+ # agent-browser@0.27.0 uses HOME for ~/.agent-browser state. Redirect it by
22
+ # default so doctor, config, sockets, and auth vault files stay inside Pibo's
23
+ # tool home. Operators can opt out for upstream debugging.
24
+ if [ "\${PIBO_AGENT_BROWSER_PRESERVE_HOME:-0}" != "1" ]; then
25
+ export HOME="$AGENT_BROWSER_HOME"
26
+ fi
27
+
28
+ explicit_runtime=0
29
+ fresh_profile=0
30
+ show_help=0
31
+ starts_browser=0
32
+ args=()
33
+
34
+ print_wrapper_help() {
35
+ cat <<'HELP'
36
+ Pibo agent-browser wrapper
37
+ - keeps Agent Browser state under AGENT_BROWSER_HOME by default
38
+ - prepends a persistent Pibo profile for browser-launching commands
39
+ - pass --fresh-profile to disable Pibo profile injection
40
+ - explicit --profile, --state, --cdp, --auto-connect, --provider, --engine,
41
+ --executable-path, or --config flags override Pibo defaults
42
+ HELP
43
+ }
44
+
45
+ while [ "$#" -gt 0 ]; do
46
+ case "$1" in
47
+ --help|-h)
48
+ show_help=1
49
+ args+=("$1")
50
+ ;;
51
+ --fresh-profile)
52
+ fresh_profile=1
53
+ ;;
54
+ --profile|--state|--cdp|--auto-connect|--provider|--engine|--executable-path|--config)
55
+ explicit_runtime=1
56
+ args+=("$1")
57
+ if [ "$#" -gt 1 ]; then
58
+ shift
59
+ args+=("$1")
60
+ fi
61
+ ;;
62
+ --profile=*|--state=*|--cdp=*|--auto-connect=*|--provider=*|--engine=*|--executable-path=*|--config=*)
63
+ explicit_runtime=1
64
+ args+=("$1")
65
+ ;;
66
+ open|launch|new|goto)
67
+ starts_browser=1
68
+ args+=("$1")
69
+ ;;
70
+ *)
71
+ args+=("$1")
72
+ ;;
73
+ esac
74
+ shift
75
+ done
76
+
77
+ if [ "$show_help" -eq 1 ]; then
78
+ print_wrapper_help
79
+ exec "$real_agent_browser" "\${args[@]}"
80
+ fi
81
+
82
+ if [ "$starts_browser" -eq 1 ] && [ "$fresh_profile" -eq 0 ] && [ "$explicit_runtime" -eq 0 ]; then
83
+ profile_dir=\${AGENT_BROWSER_PROFILE:-$AGENT_BROWSER_HOME/profiles/${AGENT_BROWSER_DEFAULT_PROFILE}}
84
+ mkdir -p "$profile_dir"
85
+ exec "$real_agent_browser" --profile "$profile_dir" "\${args[@]}"
86
+ fi
87
+
88
+ exec "$real_agent_browser" "\${args[@]}"
89
89
  `;
90
90
  }
91
91
  export function ensureAgentBrowserWrapper(status) {
@@ -47,18 +47,18 @@ async function discoverCdpUrl() {
47
47
  }
48
48
  import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
49
49
  import { join } from 'node:path';
50
- const CHAT_TARGET_PROBE = `(() => {
51
- const text = String(document.body?.innerText || "");
52
- const textareas = [...document.querySelectorAll("textarea")].map((textarea) => ({
53
- placeholder: textarea.placeholder || "",
54
- disabled: Boolean(textarea.disabled),
55
- value: textarea.value || "",
56
- }));
57
- return {
58
- title: document.title || "",
59
- text: text.slice(0, 3000),
60
- textareas,
61
- };
50
+ const CHAT_TARGET_PROBE = `(() => {
51
+ const text = String(document.body?.innerText || "");
52
+ const textareas = [...document.querySelectorAll("textarea")].map((textarea) => ({
53
+ placeholder: textarea.placeholder || "",
54
+ disabled: Boolean(textarea.disabled),
55
+ value: textarea.value || "",
56
+ }));
57
+ return {
58
+ title: document.title || "",
59
+ text: text.slice(0, 3000),
60
+ textareas,
61
+ };
62
62
  })()`;
63
63
  export async function listBrowserUseCdpTargets(options = {}) {
64
64
  const cdpUrl = await normalizeCdpUrl(options.cdpUrl);