@pasko70/pibo 1.9.11 → 1.9.13

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 (111) 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 +25 -14
  12. package/dist/apps/chat/static-assets.js +854 -854
  13. package/dist/apps/chat/trace.js +2 -0
  14. package/dist/apps/chat/web-app.js +7 -0
  15. package/dist/apps/chat/workflow-persistence.js +255 -255
  16. package/dist/apps/chat-ui/index.html +16 -16
  17. package/dist/apps/chat-ui/manifest.webmanifest +25 -25
  18. package/dist/apps/chat-ui/sw.js +47 -47
  19. package/dist/apps/chat-vscode-web/index.html +12 -12
  20. package/dist/apps/cli-ui/cliSessionsCommand.js +23 -23
  21. package/dist/apps/context-files-ui/index.html +11 -11
  22. package/dist/apps/vscode-artifacts/latest.vsix +0 -0
  23. package/dist/apps/vscode-artifacts/pibo-vscode-ext-1.9.13.vsix +0 -0
  24. package/dist/cli.js +39 -39
  25. package/dist/compute/cli.js +54 -54
  26. package/dist/cron/cli.js +15 -15
  27. package/dist/cron/store.js +49 -49
  28. package/dist/data/cli.js +23 -23
  29. package/dist/data/event-log.js +23 -23
  30. package/dist/data/ingest-service.js +7 -0
  31. package/dist/data/message-store.js +31 -20
  32. package/dist/data/navigation-store.js +9 -9
  33. package/dist/data/observation-store.js +4 -4
  34. package/dist/data/payload-store.js +17 -17
  35. package/dist/data/schema.js +433 -431
  36. package/dist/data/session-store.js +4 -4
  37. package/dist/data/telemetry-queries.js +54 -54
  38. package/dist/data/telemetry.js +197 -197
  39. package/dist/debug/events.js +12 -12
  40. package/dist/debug/failures.js +6 -6
  41. package/dist/debug/index.js +227 -227
  42. package/dist/debug/messages.js +6 -6
  43. package/dist/debug/pty.js +124 -124
  44. package/dist/debug/session.js +29 -29
  45. package/dist/debug/tools.js +5 -5
  46. package/dist/debug/web-snapshot-browser-scripts.js +294 -294
  47. package/dist/debug/web-streaming-browser-library.js +925 -925
  48. package/dist/debug/web-streaming-browser-scripts.js +232 -232
  49. package/dist/debug/web-streaming-provider-telemetry.js +4 -4
  50. package/dist/debug/web.js +93 -93
  51. package/dist/gateway/cli.js +19 -19
  52. package/dist/mcp/config-command.js +53 -53
  53. package/dist/mcp/index.js +21 -21
  54. package/dist/mcp/registry.js +11 -11
  55. package/dist/pi-packages/cli.js +11 -11
  56. package/dist/plugins/context-files-store.js +110 -110
  57. package/dist/plugins/context-files.js +4 -4
  58. package/dist/ralph/cli.js +18 -18
  59. package/dist/ralph/templates.js +140 -140
  60. package/dist/reliability/store.js +226 -226
  61. package/dist/resources/lifecycle.js +4 -6
  62. package/dist/resources/reaper-state.js +30 -3
  63. package/dist/resources/reaper.js +43 -15
  64. package/dist/sessions/pibo-data-store.js +16 -16
  65. package/dist/sessions/sqlite-store.js +53 -53
  66. package/dist/setup/cli.js +58 -58
  67. package/dist/shared/trace-engine.js +3 -2
  68. package/dist/shared/trace-event-projection.js +26 -0
  69. package/dist/tools/agent-browser-wrapper.js +80 -80
  70. package/dist/tools/browser-use-cdp.js +12 -12
  71. package/dist/tools/browser-use-wrapper.js +762 -762
  72. package/dist/tools/guides.js +538 -538
  73. package/dist/tools/index.js +99 -99
  74. package/dist/tools/runtime/node-worker-source.js +205 -205
  75. package/dist/tools/runtime/python-worker-source.js +177 -177
  76. package/dist/vscode/cli.js +9 -9
  77. package/dist/web-annotations/cdp.js +900 -900
  78. package/dist/web-annotations/store.js +96 -96
  79. package/docs/README.md +23 -23
  80. package/docs/ops/install-developer-host.md +112 -112
  81. package/docs/ops/install-user-host.md +96 -96
  82. package/docs/ops/upgrade-user-to-developer-host.md +69 -69
  83. package/docs/ops/vscode-extension-release.md +160 -160
  84. package/package.json +95 -95
  85. package/skills/builtin/graphify/SKILL.md +52 -52
  86. package/skills/builtin/pi-agent-harness/SKILL.md +319 -319
  87. package/skills/builtin/pi-agent-harness/agents/openai.yaml +4 -4
  88. package/skills/builtin/pibo-docker-system/SKILL.md +170 -170
  89. package/skills/builtin/pibo-spec-writing/SKILL.md +330 -330
  90. package/skills/builtin/prd/SKILL.md +143 -143
  91. package/skills/builtin/ralph-loop/SKILL.md +359 -359
  92. package/skills/builtin/ralph-prd-json/SKILL.md +123 -123
  93. package/skills/builtin/skill-creator/LICENSE.txt +201 -201
  94. package/skills/builtin/skill-creator/SKILL.md +513 -513
  95. package/skills/builtin/skill-creator/agents/analyzer.md +274 -274
  96. package/skills/builtin/skill-creator/agents/comparator.md +202 -202
  97. package/skills/builtin/skill-creator/agents/grader.md +223 -223
  98. package/skills/builtin/skill-creator/assets/eval_review.html +146 -146
  99. package/skills/builtin/skill-creator/eval-viewer/generate_review.py +471 -471
  100. package/skills/builtin/skill-creator/eval-viewer/viewer.html +1325 -1325
  101. package/skills/builtin/skill-creator/references/schemas.md +430 -430
  102. package/skills/builtin/skill-creator/scripts/aggregate_benchmark.py +401 -401
  103. package/skills/builtin/skill-creator/scripts/generate_report.py +326 -326
  104. package/skills/builtin/skill-creator/scripts/improve_description.py +247 -247
  105. package/skills/builtin/skill-creator/scripts/package_skill.py +136 -136
  106. package/skills/builtin/skill-creator/scripts/quick_validate.py +102 -102
  107. package/skills/builtin/skill-creator/scripts/run_eval.py +310 -310
  108. package/skills/builtin/skill-creator/scripts/run_loop.py +328 -328
  109. package/skills/builtin/skill-creator/scripts/utils.py +47 -47
  110. package/skills/builtin/web-annotations/SKILL.md +93 -93
  111. package/src/mcp/LICENSE.mcp-cli +21 -21
@@ -9,6 +9,7 @@ export class ResourceReaperService {
9
9
  plan;
10
10
  apply;
11
11
  now;
12
+ writeState;
12
13
  timer;
13
14
  running = false;
14
15
  stopped = true;
@@ -23,6 +24,7 @@ export class ResourceReaperService {
23
24
  this.plan = options.plan ?? planResourceReap;
24
25
  this.apply = options.apply ?? applyResourceReapPlan;
25
26
  this.now = options.clock ?? (() => new Date());
27
+ this.writeState = options.writeState ?? writeResourceReaperState;
26
28
  }
27
29
  async start() {
28
30
  if (!this.stopped)
@@ -47,19 +49,24 @@ export class ResourceReaperService {
47
49
  if (this.timer)
48
50
  clearTimeout(this.timer);
49
51
  this.timer = undefined;
50
- if (this.state && this.ownsTimer) {
51
- this.state = { ...this.state, status: "stopped", nextRunAt: undefined };
52
- await this.persist();
52
+ try {
53
+ if (this.state && this.ownsTimer) {
54
+ this.state = { ...this.state, status: "stopped", nextRunAt: undefined };
55
+ await this.persist();
56
+ }
57
+ }
58
+ finally {
59
+ if (this.ownsTimer)
60
+ await releaseResourceReaperOwnership(this.lockPath);
61
+ this.ownsTimer = false;
53
62
  }
54
- if (this.ownsTimer)
55
- await releaseResourceReaperOwnership(this.lockPath);
56
- this.ownsTimer = false;
57
63
  }
58
64
  async runNow() {
59
65
  if (!this.ownsTimer || this.running)
60
66
  return undefined;
61
67
  this.running = true;
62
68
  const runAt = this.now();
69
+ let result;
63
70
  try {
64
71
  const plan = await this.plan({
65
72
  includeDev: this.options.includeDev,
@@ -71,7 +78,7 @@ export class ResourceReaperService {
71
78
  exemptBrowserPids: this.options.exemptBrowserPids,
72
79
  now: runAt,
73
80
  });
74
- const result = await this.apply(plan);
81
+ result = await this.apply(plan);
75
82
  this.state = {
76
83
  ...(this.state ?? {
77
84
  status: "running",
@@ -91,8 +98,6 @@ export class ResourceReaperService {
91
98
  lastError: undefined,
92
99
  };
93
100
  console.error(JSON.stringify({ event: "resource_reaper_finished", at: runAt.toISOString(), ...this.state.lastResult }));
94
- await this.persist();
95
- return result;
96
101
  }
97
102
  catch (error) {
98
103
  const message = error instanceof Error ? error.message : String(error);
@@ -109,12 +114,16 @@ export class ResourceReaperService {
109
114
  lastError: message,
110
115
  };
111
116
  console.error(JSON.stringify({ event: "resource_reaper_failed", at: runAt.toISOString(), error: message }));
112
- await this.persist();
113
- return undefined;
114
117
  }
115
118
  finally {
116
- this.running = false;
119
+ try {
120
+ await this.persist();
121
+ }
122
+ finally {
123
+ this.running = false;
124
+ }
117
125
  }
126
+ return result;
118
127
  }
119
128
  arm(delayMs) {
120
129
  if (this.stopped)
@@ -122,13 +131,32 @@ export class ResourceReaperService {
122
131
  if (this.timer)
123
132
  clearTimeout(this.timer);
124
133
  this.timer = setTimeout(() => {
125
- void this.runNow().finally(() => this.arm(this.intervalMs));
134
+ void this.runNow()
135
+ .catch((error) => {
136
+ console.error(JSON.stringify({
137
+ event: "resource_reaper_timer_failed",
138
+ at: new Date().toISOString(),
139
+ error: error instanceof Error ? error.message : String(error),
140
+ }));
141
+ })
142
+ .finally(() => this.arm(this.intervalMs));
126
143
  }, delayMs);
127
144
  this.timer.unref?.();
128
145
  }
129
146
  async persist() {
130
- if (this.state)
131
- await writeResourceReaperState(this.statePath, this.state);
147
+ if (!this.state)
148
+ return;
149
+ try {
150
+ await this.writeState(this.statePath, this.state);
151
+ }
152
+ catch (error) {
153
+ console.error(JSON.stringify({
154
+ event: "resource_reaper_state_persist_failed",
155
+ at: new Date().toISOString(),
156
+ path: this.statePath,
157
+ error: error instanceof Error ? error.message : String(error),
158
+ }));
159
+ }
132
160
  }
133
161
  }
134
162
  function readPositiveInteger(value) {
@@ -53,20 +53,20 @@ export class PiboDataSessionStore {
53
53
  activeModel: input.activeModel === null ? undefined : input.activeModel ? { ...input.activeModel } : existing.activeModel,
54
54
  updatedAt: new Date().toISOString(),
55
55
  };
56
- this.db.prepare(`
57
- UPDATE sessions SET
58
- pi_session_id = ?,
59
- root_session_id = ?,
60
- parent_id = ?,
61
- origin_id = ?,
62
- profile = ?,
63
- active_model_json = ?,
64
- workspace = ?,
65
- title = ?,
66
- metadata_json = ?,
67
- updated_at = ?,
68
- last_activity_at = MAX(last_activity_at, ?)
69
- WHERE id = ? AND deleted_at IS NULL
56
+ this.db.prepare(`
57
+ UPDATE sessions SET
58
+ pi_session_id = ?,
59
+ root_session_id = ?,
60
+ parent_id = ?,
61
+ origin_id = ?,
62
+ profile = ?,
63
+ active_model_json = ?,
64
+ workspace = ?,
65
+ title = ?,
66
+ metadata_json = ?,
67
+ updated_at = ?,
68
+ last_activity_at = MAX(last_activity_at, ?)
69
+ WHERE id = ? AND deleted_at IS NULL
70
70
  `).run(updated.piSessionId, rootSessionId(updated), updated.parentId ?? null, updated.originId ?? null, updated.profile, updated.activeModel ? JSON.stringify(updated.activeModel) : null, updated.workspace ?? null, updated.title ?? "Untitled Session", JSON.stringify(updated.metadata ?? {}), updated.updatedAt, updated.updatedAt, id);
71
71
  return this.get(id);
72
72
  }
@@ -129,8 +129,8 @@ export class PiboDataSessionStore {
129
129
  "channel", "kind", "profile", "active_model_json", "workspace", "title", "first_message_preview",
130
130
  "status", "metadata_json", "created_at", "updated_at", "last_activity_at",
131
131
  ];
132
- this.db.prepare(`
133
- INSERT INTO sessions (${columns.join(", ")}) VALUES (${columns.map(() => "?").join(", ")})
132
+ this.db.prepare(`
133
+ INSERT INTO sessions (${columns.join(", ")}) VALUES (${columns.map(() => "?").join(", ")})
134
134
  `).run(session.id, session.piSessionId, roomIdFromMetadata(session.metadata), rootSessionId(session), session.parentId ?? null, session.originId ?? null, session.channel, session.kind, session.profile, session.activeModel ? JSON.stringify(session.activeModel) : null, session.workspace ?? null, session.title ?? "Untitled Session", previewText(session.title ?? "") ?? null, "idle", JSON.stringify(session.metadata ?? {}), session.createdAt, session.updatedAt, session.updatedAt);
135
135
  }
136
136
  }
@@ -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 = {}) {
@@ -1,5 +1,5 @@
1
1
  import { reconcileAsyncAgentRunStatuses } from "./trace-async-agent-runs.js";
2
- import { applySingleEventToNodes, contentDeltaPatchNodeId, dedupeTraceEvents, eventsCanAffectAsyncAgentRunStatus, findOpenTranscriptEventIds, isConfirmedUserMessageEcho, latestTraceStreamId, messageTurnTimingsFromEvents, reconcileTranscriptUserMessageTimestamps, traceEventDedupeKey, } from "./trace-event-projection.js";
2
+ import { applySingleEventToNodes, contentDeltaPatchNodeId, dedupeTraceEvents, eventsCanAffectAsyncAgentRunStatus, findOpenTranscriptEventIds, isConfirmedUserMessageEcho, latestTraceStreamId, mergeMessageTurnTimings, messageTurnTimingsFromEvents, reconcileTranscriptUserMessageTimestamps, traceEventDedupeKey, } from "./trace-event-projection.js";
3
3
  import { flattenTraceNodes, mapTraceNodesById, nestTraceNodes } from "./trace-nodes.js";
4
4
  import { nestMutableCopiedTraceNodes, shareUnchangedTraceNodes } from "./trace-patch-nodes.js";
5
5
  import { mapTraceChildSessionsByParent, mapTraceSubagentSessionLinks, } from "./trace-subagent-links.js";
@@ -14,7 +14,8 @@ export function buildTraceViewFromEvents(input) {
14
14
  const allEntries = input.transcriptEntries ?? [];
15
15
  const openTranscriptEventIds = findOpenTranscriptEventIds(events, sessionStatus);
16
16
  const entries = projectTranscriptEntries(allEntries, sessionStatus, openTranscriptEventIds);
17
- const nodes = traceNodesFromEntries(input.session.id, entries, messageTurnTimingsFromEvents(events));
17
+ const turnTimings = mergeMessageTurnTimings(input.turnTimings ?? [], messageTurnTimingsFromEvents(events));
18
+ const nodes = traceNodesFromEntries(input.session.id, entries, turnTimings);
18
19
  reconcileTranscriptUserMessageTimestamps(nodes, events);
19
20
  const byId = mapTraceNodesById(nodes);
20
21
  const childByParent = mapTraceChildSessionsByParent(input.sessions ?? []);
@@ -531,6 +531,32 @@ function shouldKeepTranscriptEchoEvent(event, openTranscriptEventIds) {
531
531
  function isStaleToolCallEchoEvent(event, sessionStatus) {
532
532
  return sessionStatus !== "running" && event.type === "tool_call";
533
533
  }
534
+ export function mergeMessageTurnTimings(...groups) {
535
+ const byEventId = new Map();
536
+ for (const timing of groups.flat()) {
537
+ const existing = byEventId.get(timing.eventId);
538
+ if (!existing) {
539
+ byEventId.set(timing.eventId, timing);
540
+ continue;
541
+ }
542
+ const merged = {
543
+ eventId: timing.eventId,
544
+ userText: timing.userText ?? existing.userText,
545
+ startedAt: timing.startedAt ?? existing.startedAt,
546
+ completedAt: timing.completedAt ?? existing.completedAt,
547
+ durationMs: timing.durationMs ?? existing.durationMs,
548
+ };
549
+ if (merged.durationMs === undefined) {
550
+ const startedAtMs = parseTimestamp(merged.startedAt);
551
+ const completedAtMs = parseTimestamp(merged.completedAt);
552
+ if (startedAtMs !== undefined && completedAtMs !== undefined) {
553
+ merged.durationMs = Math.max(0, completedAtMs - startedAtMs);
554
+ }
555
+ }
556
+ byEventId.set(timing.eventId, merged);
557
+ }
558
+ return [...byEventId.values()];
559
+ }
534
560
  export function messageTurnTimingsFromEvents(events) {
535
561
  const timings = new Map();
536
562
  const completedEventIds = [];
@@ -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) {