@pasko70/pibo 2.2.5 → 2.4.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 (43) hide show
  1. package/dist/agent-runtime/context-build.js +5 -2
  2. package/dist/agent-runtimes/pi/adapter.js +1 -1
  3. package/dist/agent-runtimes/pi/runtime.js +25 -16
  4. package/dist/apps/chat-ui/assets/{dist-BK7eaoLT.js → dist-Byygd1lH.js} +1 -1
  5. package/dist/apps/chat-ui/assets/{dist-fNgdnmyE.js → dist-C9BrS7sL.js} +1 -1
  6. package/dist/apps/chat-ui/assets/{dist-wq3P0LZj.js → dist-CUcAofmV.js} +1 -1
  7. package/dist/apps/chat-ui/assets/{dist-BCRR_a0Z.js → dist-D4RU6xu3.js} +1 -1
  8. package/dist/apps/chat-ui/assets/{dist-CTUT484B.js → dist-DusFwy0L.js} +1 -1
  9. package/dist/apps/chat-ui/assets/{index-DsFKL_EZ.js → index-Bifi_kjN.js} +90 -90
  10. package/dist/apps/chat-ui/index.html +1 -1
  11. package/dist/apps/chat-vscode-web/assets/{index-R4FTxr78.js → index-WsLm1mo3.js} +5 -5
  12. package/dist/apps/chat-vscode-web/index.html +1 -1
  13. package/dist/apps/vscode-artifacts/latest.vsix +0 -0
  14. package/dist/apps/vscode-artifacts/{pibo-vscode-ext-2.2.5.vsix → pibo-vscode-ext-2.4.0.vsix} +0 -0
  15. package/dist/compute/cli.js +13 -0
  16. package/dist/compute/pool/artifacts.js +116 -0
  17. package/dist/compute/pool/cli.js +156 -0
  18. package/dist/compute/pool/config.js +101 -0
  19. package/dist/compute/pool/docker.js +157 -0
  20. package/dist/compute/pool/seeds.js +201 -0
  21. package/dist/compute/pool/service.js +402 -0
  22. package/dist/compute/pool/store.js +239 -0
  23. package/dist/compute/pool/types.js +1 -0
  24. package/dist/core/codex-compat.js +1 -3
  25. package/dist/core/context-build.js +16 -7
  26. package/dist/core/session-router.js +221 -45
  27. package/dist/data/ingest-service.js +12 -0
  28. package/dist/debug/agents.js +391 -0
  29. package/dist/debug/index.js +7 -0
  30. package/dist/index.js +1 -1
  31. package/dist/resources/lifecycle.js +22 -2
  32. package/dist/resources/reaper.js +1 -0
  33. package/dist/session-ui/delegation.js +4 -2
  34. package/dist/shared/trace-async-agent-runs.js +4 -2
  35. package/dist/shared/trace-event-projection.js +8 -2
  36. package/dist/shared/trace-subagent-links.js +19 -6
  37. package/dist/subagents/observations.js +149 -0
  38. package/dist/subagents/tool.js +177 -46
  39. package/dist/tools/session-service.js +1 -0
  40. package/dist/tools/session-tool-set.js +9 -5
  41. package/dist/web/channel.js +9 -3
  42. package/npm-shrinkwrap.json +2 -2
  43. package/package.json +1 -1
@@ -0,0 +1,239 @@
1
+ import { mkdirSync } from "node:fs";
2
+ import { chmodSync } from "node:fs";
3
+ import { dirname, resolve } from "node:path";
4
+ import { DatabaseSync } from "node:sqlite";
5
+ function slotFromRow(row) {
6
+ return {
7
+ id: row.id,
8
+ ordinal: row.ordinal,
9
+ webPort: row.web_port,
10
+ gatewayPort: row.gateway_port,
11
+ publicUrl: row.public_url ?? undefined,
12
+ state: row.state,
13
+ activeLeaseId: row.active_lease_id ?? undefined,
14
+ dirtyReason: row.dirty_reason ?? undefined,
15
+ updatedAt: row.updated_at,
16
+ };
17
+ }
18
+ function leaseFromRow(row) {
19
+ return {
20
+ id: row.id,
21
+ slotId: row.slot_id,
22
+ holder: row.holder,
23
+ seedMode: row.seed_mode,
24
+ artifactSha256: row.artifact_sha256,
25
+ artifactRuntimePath: row.artifact_runtime_path,
26
+ packageVersion: row.package_version ?? undefined,
27
+ commit: row.commit_sha ?? undefined,
28
+ containerName: row.container_name,
29
+ publicUrl: row.public_url ?? undefined,
30
+ status: row.status,
31
+ createdAt: row.created_at,
32
+ expiresAt: row.expires_at,
33
+ renewedAt: row.renewed_at ?? undefined,
34
+ releasedAt: row.released_at ?? undefined,
35
+ failedAt: row.failed_at ?? undefined,
36
+ failureSnapshotPath: row.failure_snapshot_path ?? undefined,
37
+ lastError: row.last_error ?? undefined,
38
+ };
39
+ }
40
+ export class DeploymentPoolStore {
41
+ path;
42
+ db;
43
+ constructor(path, slots) {
44
+ this.path = path === ":memory:" ? path : resolve(path);
45
+ if (this.path !== ":memory:")
46
+ mkdirSync(dirname(this.path), { recursive: true, mode: 0o700 });
47
+ this.db = new DatabaseSync(this.path);
48
+ this.db.exec("PRAGMA busy_timeout = 10000");
49
+ if (this.path !== ":memory:")
50
+ this.db.exec("PRAGMA journal_mode = WAL");
51
+ this.applySchema();
52
+ this.ensureSlots(slots);
53
+ if (this.path !== ":memory:")
54
+ chmodSync(this.path, 0o600);
55
+ }
56
+ applySchema() {
57
+ this.db.exec(`
58
+ CREATE TABLE IF NOT EXISTS deployment_pool_slots (
59
+ id TEXT PRIMARY KEY,
60
+ ordinal INTEGER NOT NULL UNIQUE,
61
+ web_port INTEGER NOT NULL UNIQUE,
62
+ gateway_port INTEGER NOT NULL UNIQUE,
63
+ public_url TEXT,
64
+ state TEXT NOT NULL,
65
+ active_lease_id TEXT,
66
+ dirty_reason TEXT,
67
+ updated_at TEXT NOT NULL
68
+ );
69
+ CREATE TABLE IF NOT EXISTS deployment_pool_leases (
70
+ id TEXT PRIMARY KEY,
71
+ slot_id TEXT NOT NULL,
72
+ holder TEXT NOT NULL,
73
+ seed_mode TEXT NOT NULL,
74
+ artifact_sha256 TEXT NOT NULL,
75
+ artifact_runtime_path TEXT NOT NULL,
76
+ package_version TEXT,
77
+ commit_sha TEXT,
78
+ container_name TEXT NOT NULL,
79
+ public_url TEXT,
80
+ status TEXT NOT NULL,
81
+ created_at TEXT NOT NULL,
82
+ expires_at TEXT NOT NULL,
83
+ renewed_at TEXT,
84
+ released_at TEXT,
85
+ failed_at TEXT,
86
+ failure_snapshot_path TEXT,
87
+ last_error TEXT
88
+ );
89
+ CREATE INDEX IF NOT EXISTS deployment_pool_leases_status_idx
90
+ ON deployment_pool_leases (status, expires_at);
91
+ CREATE INDEX IF NOT EXISTS deployment_pool_leases_slot_idx
92
+ ON deployment_pool_leases (slot_id, created_at DESC);
93
+ `);
94
+ }
95
+ ensureSlots(slots) {
96
+ const now = new Date().toISOString();
97
+ const insert = this.db.prepare(`
98
+ INSERT INTO deployment_pool_slots (id, ordinal, web_port, gateway_port, public_url, state, updated_at)
99
+ VALUES (?, ?, ?, ?, ?, 'free', ?)
100
+ ON CONFLICT(id) DO UPDATE SET
101
+ ordinal=excluded.ordinal,
102
+ web_port=excluded.web_port,
103
+ gateway_port=excluded.gateway_port,
104
+ public_url=excluded.public_url
105
+ `);
106
+ for (const slot of slots)
107
+ insert.run(slot.id, slot.ordinal, slot.webPort, slot.gatewayPort, slot.publicUrl ?? null, now);
108
+ }
109
+ listSlots() {
110
+ return this.db.prepare("SELECT * FROM deployment_pool_slots ORDER BY ordinal").all().map(slotFromRow);
111
+ }
112
+ getSlot(id) {
113
+ const row = this.db.prepare("SELECT * FROM deployment_pool_slots WHERE id = ?").get(id);
114
+ return row ? slotFromRow(row) : undefined;
115
+ }
116
+ listLeases(options = {}) {
117
+ const where = options.includeInactive ? "" : "WHERE status IN ('provisioning', 'ready', 'releasing')";
118
+ return this.db.prepare(`SELECT * FROM deployment_pool_leases ${where} ORDER BY created_at DESC`).all().map(leaseFromRow);
119
+ }
120
+ getLease(id) {
121
+ const row = this.db.prepare("SELECT * FROM deployment_pool_leases WHERE id = ?").get(id);
122
+ return row ? leaseFromRow(row) : undefined;
123
+ }
124
+ reserveLease(input) {
125
+ this.db.exec("BEGIN IMMEDIATE");
126
+ try {
127
+ const active = this.db.prepare("SELECT COUNT(*) AS count FROM deployment_pool_slots WHERE state IN ('provisioning', 'ready', 'releasing')").get();
128
+ if (Number(active.count) >= input.maxActive) {
129
+ const nearest = this.db.prepare(`
130
+ SELECT MIN(l.expires_at) AS nearest_expiry
131
+ FROM deployment_pool_slots s
132
+ JOIN deployment_pool_leases l ON l.id = s.active_lease_id
133
+ WHERE s.state IN ('provisioning', 'ready', 'releasing')
134
+ `).get();
135
+ throw new Error(`Deployment pool capacity reached (${input.maxActive} active)${nearest.nearest_expiry ? `; nearest expiry ${nearest.nearest_expiry}` : ""}`);
136
+ }
137
+ const row = this.db.prepare("SELECT * FROM deployment_pool_slots WHERE state = 'free' ORDER BY ordinal LIMIT 1").get();
138
+ if (!row)
139
+ throw new Error("No free deployment pool slot is available");
140
+ const slot = slotFromRow(row);
141
+ const containerName = `pibo-pool-${slot.id}`;
142
+ this.db.prepare(`
143
+ INSERT INTO deployment_pool_leases (
144
+ id, slot_id, holder, seed_mode, artifact_sha256, artifact_runtime_path,
145
+ package_version, commit_sha, container_name, public_url, status, created_at, expires_at
146
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'provisioning', ?, ?)
147
+ `).run(input.id, slot.id, input.holder, input.seedMode, input.artifactSha256, input.artifactRuntimePath, input.packageVersion ?? null, input.commit ?? null, containerName, slot.publicUrl ?? null, input.createdAt, input.expiresAt);
148
+ this.db.prepare("UPDATE deployment_pool_slots SET state='provisioning', active_lease_id=?, dirty_reason=NULL, updated_at=? WHERE id=?")
149
+ .run(input.id, input.createdAt, slot.id);
150
+ this.db.exec("COMMIT");
151
+ return { slot: this.getSlot(slot.id), lease: this.getLease(input.id) };
152
+ }
153
+ catch (error) {
154
+ this.db.exec("ROLLBACK");
155
+ throw error;
156
+ }
157
+ }
158
+ markReady(leaseId, now = new Date().toISOString()) {
159
+ const lease = this.requireLease(leaseId);
160
+ this.db.exec("BEGIN IMMEDIATE");
161
+ try {
162
+ this.db.prepare("UPDATE deployment_pool_leases SET status='ready', last_error=NULL WHERE id=?").run(leaseId);
163
+ this.db.prepare("UPDATE deployment_pool_slots SET state='ready', dirty_reason=NULL, updated_at=? WHERE id=? AND active_lease_id=?")
164
+ .run(now, lease.slotId, leaseId);
165
+ this.db.exec("COMMIT");
166
+ return this.requireLease(leaseId);
167
+ }
168
+ catch (error) {
169
+ this.db.exec("ROLLBACK");
170
+ throw error;
171
+ }
172
+ }
173
+ markReleasing(leaseId, now = new Date().toISOString()) {
174
+ const lease = this.requireLease(leaseId);
175
+ this.db.prepare("UPDATE deployment_pool_leases SET status='releasing' WHERE id=? AND status IN ('provisioning','ready','releasing')").run(leaseId);
176
+ this.db.prepare("UPDATE deployment_pool_slots SET state='releasing', updated_at=? WHERE id=? AND active_lease_id=?").run(now, lease.slotId, leaseId);
177
+ return this.requireLease(leaseId);
178
+ }
179
+ markReleased(leaseId, status, now = new Date().toISOString()) {
180
+ const lease = this.requireLease(leaseId);
181
+ this.db.exec("BEGIN IMMEDIATE");
182
+ try {
183
+ this.db.prepare("UPDATE deployment_pool_leases SET status=?, released_at=?, last_error=NULL WHERE id=?").run(status, now, leaseId);
184
+ this.db.prepare("UPDATE deployment_pool_slots SET state='free', active_lease_id=NULL, dirty_reason=NULL, updated_at=? WHERE id=? AND active_lease_id=?")
185
+ .run(now, lease.slotId, leaseId);
186
+ this.db.exec("COMMIT");
187
+ return this.requireLease(leaseId);
188
+ }
189
+ catch (error) {
190
+ this.db.exec("ROLLBACK");
191
+ throw error;
192
+ }
193
+ }
194
+ markFailed(leaseId, error, snapshotPath, options = { slotClean: false }) {
195
+ const lease = this.requireLease(leaseId);
196
+ const now = options.now ?? new Date().toISOString();
197
+ this.db.exec("BEGIN IMMEDIATE");
198
+ try {
199
+ this.db.prepare("UPDATE deployment_pool_leases SET status='failed', failed_at=?, failure_snapshot_path=?, last_error=? WHERE id=?")
200
+ .run(now, snapshotPath ?? null, error, leaseId);
201
+ if (options.slotClean) {
202
+ this.db.prepare("UPDATE deployment_pool_slots SET state='free', active_lease_id=NULL, dirty_reason=NULL, updated_at=? WHERE id=? AND active_lease_id=?")
203
+ .run(now, lease.slotId, leaseId);
204
+ }
205
+ else {
206
+ this.db.prepare("UPDATE deployment_pool_slots SET state='dirty', dirty_reason=?, updated_at=? WHERE id=? AND active_lease_id=?")
207
+ .run(error, now, lease.slotId, leaseId);
208
+ }
209
+ this.db.exec("COMMIT");
210
+ return this.requireLease(leaseId);
211
+ }
212
+ catch (caught) {
213
+ this.db.exec("ROLLBACK");
214
+ throw caught;
215
+ }
216
+ }
217
+ renewLease(leaseId, holder, expiresAt, now = new Date().toISOString()) {
218
+ const result = this.db.prepare(`
219
+ UPDATE deployment_pool_leases SET expires_at=?, renewed_at=?
220
+ WHERE id=? AND holder=? AND status='ready'
221
+ `).run(expiresAt, now, leaseId, holder);
222
+ if (Number(result.changes ?? 0) !== 1)
223
+ throw new Error(`Active deployment lease "${leaseId}" for holder "${holder}" was not found`);
224
+ return this.requireLease(leaseId);
225
+ }
226
+ freeDirtySlot(slotId, now = new Date().toISOString()) {
227
+ this.db.prepare("UPDATE deployment_pool_slots SET state='free', active_lease_id=NULL, dirty_reason=NULL, updated_at=? WHERE id=?")
228
+ .run(now, slotId);
229
+ }
230
+ requireLease(id) {
231
+ const lease = this.getLease(id);
232
+ if (!lease)
233
+ throw new Error(`Deployment lease "${id}" was not found`);
234
+ return lease;
235
+ }
236
+ close() {
237
+ this.db.close();
238
+ }
239
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,3 @@
1
- const CODEX_COMPAT_SUBAGENTS = ["default", "explorer", "worker"];
2
1
  function currentDate() {
3
2
  return new Date().toISOString().slice(0, 10);
4
3
  }
@@ -15,7 +14,7 @@ export function buildCodexCompatSystemPrompt(options) {
15
14
  const compatibilityInstructions = [
16
15
  "# Codex-Compatible Runtime",
17
16
  "You are running in Pibo through the codex-compat profile. Match Codex-style tool use where the exposed Pibo tools support it, while staying truthful about implemented behavior.",
18
- "Use Pibo's pibo_run_* tools and generated pibo_subagent_* tools for parallel work, yielded runs, and child-agent lifecycle management.",
17
+ "Use Pibo's pibo_run_* and pibo_agents_* tools for parallel work, yielded runs, and delegated-agent lifecycle management.",
19
18
  "Use direct execution for normal coding tasks. If a structured planning or user-input tool is not present, ask concise questions in normal chat.",
20
19
  "When web_search is selected by the profile, use it for current or externally sourced information.",
21
20
  childInstructions,
@@ -24,7 +23,6 @@ export function buildCodexCompatSystemPrompt(options) {
24
23
  ` <shell>${options.shell}</shell>`,
25
24
  ` <current_date>${options.currentDate ?? currentDate()}</current_date>`,
26
25
  ` <timezone>${options.timezone ?? currentTimezone()}</timezone>`,
27
- ` <subagents>${CODEX_COMPAT_SUBAGENTS.join(", ")}</subagents>`,
28
26
  "</environment_context>",
29
27
  options.baseSystemPrompt,
30
28
  ];
@@ -139,11 +139,20 @@ function sanitizeNode(input, parentId, order = 0) {
139
139
  function countNodes(nodes) {
140
140
  return nodes.reduce((count, node) => count + 1 + countNodes(node.children ?? []), 0);
141
141
  }
142
- function inspectionSubagentRunner() {
142
+ function inspectionAgentsController() {
143
+ const fail = () => {
144
+ throw new Error("Context build inspection cannot execute delegated-agent tools");
145
+ };
143
146
  return {
144
- async runSubagent() {
145
- throw new Error("Context build inspection cannot execute subagents");
146
- },
147
+ sendMessage: fail,
148
+ listAgents: () => [],
149
+ observe: (input) => ({
150
+ filters: input,
151
+ observations: [],
152
+ nextAfterSequence: input.afterSequence ?? 0,
153
+ truncated: false,
154
+ }),
155
+ killAgent: fail,
147
156
  };
148
157
  }
149
158
  function inspectionRunToolController() {
@@ -196,8 +205,8 @@ function toolDefinitionSchema(definition, toolInfo) {
196
205
  function generatedOriginForTool(name, profile) {
197
206
  if (name === "runtime")
198
207
  return "Generated Pibo runtime tool selected by the profile.";
199
- if (name.startsWith("pibo_subagent_"))
200
- return "Generated subagent tool from the profile's subagent list.";
208
+ if (name.startsWith("pibo_agents_"))
209
+ return "Generated shared agent-management tool from the profile's delegated-agent list.";
201
210
  if (name.startsWith("pibo_run_"))
202
211
  return "Generated run-control tool from the pibo-run-control capability package.";
203
212
  if (PIBO_GOAL_TOOL_NAMES.includes(name))
@@ -298,7 +307,7 @@ export async function inspectPiboContextBuild(options = {}) {
298
307
  profile: inspectionProfile,
299
308
  activeModel: undefined,
300
309
  persistSession: false,
301
- subagentRunner: options.subagentRunner ?? (hasEnabledSubagents ? inspectionSubagentRunner() : undefined),
310
+ agentsController: options.agentsController ?? (hasEnabledSubagents ? inspectionAgentsController() : undefined),
302
311
  runToolController: options.runToolController ?? (hasYieldableTools ? inspectionRunToolController() : undefined),
303
312
  });
304
313
  try {