@pstdio/pocketcoder-cli 0.7.2 → 0.7.3

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 (2) hide show
  1. package/dist/index.js +82 -23
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5214,7 +5214,7 @@ function isYargsInstance(y) {
5214
5214
  var Yargs = YargsFactory(esm_default);
5215
5215
  var yargs_default = Yargs;
5216
5216
  // package.json
5217
- var version = "0.7.2";
5217
+ var version = "0.7.3";
5218
5218
 
5219
5219
  // src/command/cli-context.ts
5220
5220
  import { existsSync as existsSync3, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
@@ -21248,6 +21248,17 @@ function sqlValues(values) {
21248
21248
  }
21249
21249
  var timestamptz = (name2) => timestamp2(name2, { withTimezone: true, mode: "date" });
21250
21250
 
21251
+ // ../db/src/schema/structured-json.ts
21252
+ var structuredJson = customType2({
21253
+ dataType: () => "jsonb",
21254
+ codec: "jsonb",
21255
+ fromDriver: (value) => typeof value === "string" ? JSON.parse(value) : value
21256
+ });
21257
+ function structuredJsonValue(column) {
21258
+ return sql`CASE WHEN jsonb_typeof(${column}) = 'string'
21259
+ THEN (${column} #>> '{}')::jsonb ELSE ${column} END`;
21260
+ }
21261
+
21251
21262
  // ../db/src/schema/access.ts
21252
21263
  function createAccessTables(table2 = pgTable) {
21253
21264
  const templates2 = table2("templates", {
@@ -21256,7 +21267,7 @@ function createAccessTables(table2 = pgTable) {
21256
21267
  version: text2("version").notNull(),
21257
21268
  digest: text2("digest").notNull().unique(),
21258
21269
  description: text2("description"),
21259
- spec: jsonb("spec").$type().notNull(),
21270
+ spec: structuredJson("spec").$type().notNull(),
21260
21271
  status: text2("status").$type().notNull(),
21261
21272
  createdAt: timestamptz("created_at").notNull(),
21262
21273
  retiredAt: timestamptz("retired_at")
@@ -37314,7 +37325,7 @@ function createActivityTables(table2 = pgTable, { workspaces: workspaces2 }) {
37314
37325
  role: text2("role").$type().notNull(),
37315
37326
  content: text2("content").notNull(),
37316
37327
  occurredAt: timestamptz("occurred_at").notNull(),
37317
- metadata: jsonb("metadata").$type().notNull().default({}),
37328
+ metadata: structuredJson("metadata").$type().notNull().default({}),
37318
37329
  createdAt: timestamptz("created_at").notNull()
37319
37330
  }, (table3) => [
37320
37331
  primaryKey({ columns: [table3.workspaceId, table3.seq] }),
@@ -37368,9 +37379,9 @@ function createPersistenceTables(table2 = pgTable, { principals }, { workspaces:
37368
37379
  workspaceId: uuid("workspace_id").notNull().references(() => workspaces2.id),
37369
37380
  principalId: uuid("principal_id").notNull().references(() => principals.id),
37370
37381
  providerKind: text2("provider_kind").notNull(),
37371
- providerRef: jsonb("provider_ref").$type().notNull(),
37382
+ providerRef: structuredJson("provider_ref").$type().notNull(),
37372
37383
  state: text2("state").$type().notNull(),
37373
- mountManifest: jsonb("mount_manifest").$type().notNull(),
37384
+ mountManifest: structuredJson("mount_manifest").$type().notNull(),
37374
37385
  logicalBytes: bigint2("logical_bytes", { mode: "number" }),
37375
37386
  fileCount: bigint2("file_count", { mode: "number" }),
37376
37387
  retainedUntil: timestamptz("retained_until"),
@@ -37393,11 +37404,11 @@ function createPersistenceTables(table2 = pgTable, { principals }, { workspaces:
37393
37404
  state: text2("state").$type().notNull(),
37394
37405
  reasonCode: text2("reason_code").$type(),
37395
37406
  providerKind: text2("provider_kind").notNull(),
37396
- providerRef: jsonb("provider_ref").$type(),
37397
- templateSnapshot: jsonb("template_snapshot").$type().notNull(),
37407
+ providerRef: structuredJson("provider_ref").$type(),
37408
+ templateSnapshot: structuredJson("template_snapshot").$type().notNull(),
37398
37409
  templateDigest: text2("template_digest").notNull(),
37399
- sourceProvenance: jsonb("source_provenance").$type(),
37400
- manifest: jsonb("manifest").$type(),
37410
+ sourceProvenance: structuredJson("source_provenance").$type(),
37411
+ manifest: structuredJson("manifest").$type(),
37401
37412
  manifestDigest: text2("manifest_digest"),
37402
37413
  logicalBytes: bigint2("logical_bytes", { mode: "number" }),
37403
37414
  storedBytes: bigint2("stored_bytes", { mode: "number" }),
@@ -37452,7 +37463,7 @@ function createWorkspaceTables(table2 = pgTable, { principals, machineKeys, temp
37452
37463
  templateName: text2("template_name").notNull(),
37453
37464
  templateVersion: text2("template_version").notNull(),
37454
37465
  templateDigest: text2("template_digest").notNull(),
37455
- templateSnapshot: jsonb("template_snapshot").$type().notNull(),
37466
+ templateSnapshot: structuredJson("template_snapshot").$type().notNull(),
37456
37467
  state: text2("state").$type().notNull(),
37457
37468
  reasonCode: text2("reason_code").$type(),
37458
37469
  agentState: text2("agent_state").$type().notNull().default("unknown"),
@@ -37463,9 +37474,9 @@ function createWorkspaceTables(table2 = pgTable, { principals, machineKeys, temp
37463
37474
  failureLogTailTruncated: boolean2("failure_log_tail_truncated").notNull().default(false),
37464
37475
  failureLastLogSeq: bigint2("failure_last_log_seq", { mode: "number" }),
37465
37476
  terminalIntent: text2("terminal_intent").$type(),
37466
- launchInput: jsonb("launch_input").$type(),
37477
+ launchInput: structuredJson("launch_input").$type(),
37467
37478
  providerKind: text2("provider_kind"),
37468
- providerRef: jsonb("provider_ref").$type(),
37479
+ providerRef: structuredJson("provider_ref").$type(),
37469
37480
  provisioningMode: text2("provisioning_mode").$type(),
37470
37481
  registrationDigest: bytea2("registration_digest").$type(),
37471
37482
  registrationExpiresAt: timestamptz("registration_expires_at"),
@@ -37476,20 +37487,20 @@ function createWorkspaceTables(table2 = pgTable, { principals, machineKeys, temp
37476
37487
  readyAt: timestamptz("ready_at"),
37477
37488
  lastActivityAt: timestamptz("last_activity_at"),
37478
37489
  launchAttempts: integer("launch_attempts").notNull().default(0),
37479
- health: jsonb("health").$type().notNull().default({}),
37480
- metadata: jsonb("metadata").$type().notNull().default({}),
37490
+ health: structuredJson("health").$type().notNull().default({}),
37491
+ metadata: structuredJson("metadata").$type().notNull().default({}),
37481
37492
  deadlineAt: timestamptz("deadline_at").notNull(),
37482
37493
  createdAt: timestamptz("created_at").notNull(),
37483
37494
  updatedAt: timestamptz("updated_at").notNull(),
37484
37495
  terminalAt: timestamptz("terminal_at"),
37485
37496
  originWorkspaceId: uuid("origin_workspace_id"),
37486
37497
  restoredFromCheckpointId: uuid("restored_from_checkpoint_id"),
37487
- sourceDescriptor: jsonb("source_descriptor").$type(),
37488
- resolvedSource: jsonb("resolved_source").$type(),
37498
+ sourceDescriptor: structuredJson("source_descriptor").$type(),
37499
+ resolvedSource: structuredJson("resolved_source").$type(),
37489
37500
  persistenceCapability: text2("persistence_capability").$type().notNull().default("filesystem_only"),
37490
37501
  latestCheckpointId: uuid("latest_checkpoint_id"),
37491
37502
  launchMode: text2("launch_mode").$type().notNull().default("create"),
37492
- outputs: jsonb("outputs").$type().notNull().default({})
37503
+ outputs: structuredJson("outputs").$type().notNull().default({})
37493
37504
  }, (table3) => [
37494
37505
  check("workspaces_state_check", sql`${table3.state} IN ${sqlValues(WORKSPACE_STATES)}`),
37495
37506
  check("workspaces_reason_code_check", sql`${table3.reasonCode} IS NULL OR ${table3.reasonCode} IN ${sqlValues(REASON_CODES)}`),
@@ -37552,7 +37563,7 @@ function createWorkspaceTables(table2 = pgTable, { principals, machineKeys, temp
37552
37563
  driverKind: text2("driver_kind").notNull(),
37553
37564
  eligibilityFingerprint: text2("eligibility_fingerprint").notNull(),
37554
37565
  state: text2("state").$type().notNull(),
37555
- providerRef: jsonb("provider_ref").$type(),
37566
+ providerRef: structuredJson("provider_ref").$type(),
37556
37567
  enrollmentDigest: bytea2("enrollment_digest").$type(),
37557
37568
  enrollmentExpiresAt: timestamptz("enrollment_expires_at"),
37558
37569
  workspaceId: uuid("workspace_id").references(() => workspaces2.id),
@@ -37944,7 +37955,7 @@ function createOutputs({ db, tables: { workspaceOutputs: outputs2, workspaces: w
37944
37955
  const row = { ...input, seq: requiredRow(latest).seq + 1 };
37945
37956
  await tx.insert(outputs2).values({ ...row, value: row.value === null ? sql`'null'::jsonb` : row.value });
37946
37957
  await tx.update(workspaces3).set({
37947
- outputs: sql`${workspaces3.outputs} || jsonb_build_object(${input.name}::text, ${sql.param(input.value, outputs2.value)}::jsonb)`,
37958
+ outputs: sql`${structuredJsonValue(workspaces3.outputs)} || jsonb_build_object(${input.name}::text, ${sql.param(input.value, outputs2.value)}::jsonb)`,
37948
37959
  updatedAt: input.occurredAt
37949
37960
  }).where(eq(workspaces3.id, input.workspaceId));
37950
37961
  return row;
@@ -39664,7 +39675,7 @@ function createWorkspaces(context) {
39664
39675
  const cursor = db.select({ createdAt: workspaces3.createdAt, id: workspaces3.id }).from(workspaces3).where(and(eq(workspaces3.id, filter.cursor), eq(workspaces3.principalId, principalId)));
39665
39676
  cursorFilter = sql`(${workspaces3.createdAt}, ${workspaces3.id}) < (${cursor})`;
39666
39677
  }
39667
- const rows = await db.select().from(workspaces3).where(and(eq(workspaces3.principalId, principalId), filter.externalId ? eq(workspaces3.externalId, filter.externalId) : undefined, filter.state ? eq(workspaces3.state, filter.state) : undefined, filter.template ? eq(workspaces3.templateName, filter.template) : undefined, filter.metadata ? sql`${workspaces3.metadata} @> ${sql.param(filter.metadata, workspaces3.metadata)}::jsonb` : undefined, filter.createdAfter ? gte(workspaces3.createdAt, filter.createdAfter) : undefined, filter.createdBefore ? lt(workspaces3.createdAt, filter.createdBefore) : undefined, cursorFilter)).orderBy(desc2(workspaces3.createdAt), desc2(workspaces3.id)).limit(filter.limit);
39678
+ const rows = await db.select().from(workspaces3).where(and(eq(workspaces3.principalId, principalId), filter.externalId ? eq(workspaces3.externalId, filter.externalId) : undefined, filter.state ? eq(workspaces3.state, filter.state) : undefined, filter.template ? eq(workspaces3.templateName, filter.template) : undefined, filter.metadata ? sql`${structuredJsonValue(workspaces3.metadata)} @> ${sql.param(filter.metadata, workspaces3.metadata)}::jsonb` : undefined, filter.createdAfter ? gte(workspaces3.createdAt, filter.createdAfter) : undefined, filter.createdBefore ? lt(workspaces3.createdAt, filter.createdBefore) : undefined, cursorFilter)).orderBy(desc2(workspaces3.createdAt), desc2(workspaces3.id)).limit(filter.limit);
39668
39679
  return rows.map(workspaceFromRow);
39669
39680
  }
39670
39681
  };
@@ -41480,6 +41491,43 @@ class PersistenceCheckpointService {
41480
41491
 
41481
41492
  // ../server/src/persistence/persistence-maintenance.ts
41482
41493
  import { randomUUID as randomUUID13 } from "crypto";
41494
+
41495
+ // ../server/src/persistence/persistence-cleanup.ts
41496
+ async function cleanupPreservedStorage(context, storageId) {
41497
+ const { store, driver } = context.deps;
41498
+ const storage = await store.getStorage(storageId);
41499
+ if (storage?.state !== "retained")
41500
+ return;
41501
+ if (storage.lastErrorCode && storage.lastErrorCode !== "storage_cleanup_failed")
41502
+ return;
41503
+ const workspace = await store.getWorkspace(storage.workspaceId);
41504
+ if (workspace?.state !== "preserved" || !workspace.terminalAt)
41505
+ return;
41506
+ const checkpoints = (await store.listCheckpoints(storage.principalId)).filter((checkpoint) => checkpoint.storageId === storage.id);
41507
+ if (checkpoints.length === 0 || checkpoints.some((checkpoint) => checkpoint.state !== "deleted"))
41508
+ return;
41509
+ const checkpointIds = new Set(checkpoints.map((checkpoint) => checkpoint.id));
41510
+ const operations = await store.listIncompleteOperations();
41511
+ if (operations.some((operation) => operation.workspaceId === workspace.id || operation.resultWorkspaceId === workspace.id || operation.checkpointId !== null && checkpointIds.has(operation.checkpointId)))
41512
+ return;
41513
+ try {
41514
+ if ((await driver.list()).some((provider) => provider.workspaceId === workspace.id))
41515
+ return;
41516
+ await context.storageDriver().deleteStorage(storage.providerRef);
41517
+ const now = context.now();
41518
+ await store.updateWorkspaceStorage(storage.id, {
41519
+ state: "deleted",
41520
+ deletedAt: now,
41521
+ retainedUntil: null,
41522
+ lastErrorCode: null
41523
+ }, now);
41524
+ } catch (error51) {
41525
+ await store.updateWorkspaceStorage(storage.id, { lastErrorCode: "storage_cleanup_failed" }, context.now());
41526
+ context.deps.log?.(`storage cleanup ${storage.id}: ${error51 instanceof Error ? error51.message : String(error51)}`);
41527
+ }
41528
+ }
41529
+
41530
+ // ../server/src/persistence/persistence-maintenance.ts
41483
41531
  class PersistenceMaintenanceService {
41484
41532
  context;
41485
41533
  constructor(context) {
@@ -41531,6 +41579,10 @@ class PersistenceMaintenanceService {
41531
41579
  this.context.deps.log?.(`retention ${checkpoint.id}: ${error51 instanceof Error ? error51.message : String(error51)}`);
41532
41580
  }
41533
41581
  }
41582
+ const deletedCheckpoints = await this.context.deps.store.listCheckpoints(principal.id, { state: "deleted" });
41583
+ for (const storageId of new Set(deletedCheckpoints.map((checkpoint) => checkpoint.storageId))) {
41584
+ await cleanupPreservedStorage(this.context, storageId);
41585
+ }
41534
41586
  }
41535
41587
  return { deleted, skipped, transcriptsDeleted };
41536
41588
  }
@@ -41557,8 +41609,14 @@ class PersistenceMaintenanceService {
41557
41609
  async delete(principal, checkpointId, idempotencyKey) {
41558
41610
  const requestDigest = digestOf({ checkpoint_id: checkpointId });
41559
41611
  const replay = await this.context.replayedOperation(principal.id, "delete", idempotencyKey, requestDigest, "Changed delete request.");
41560
- if (replay)
41612
+ if (replay) {
41613
+ if (replay.state === "succeeded") {
41614
+ const checkpoint2 = await this.context.deps.store.getCheckpoint(checkpointId);
41615
+ if (checkpoint2)
41616
+ await cleanupPreservedStorage(this.context, checkpoint2.storageId);
41617
+ }
41561
41618
  return replay;
41619
+ }
41562
41620
  const checkpoint = await this.context.getCheckpointOwned(principal, checkpointId);
41563
41621
  const activeRestore = (await this.context.deps.store.listIncompleteOperations()).some((operation) => operation.kind === "restore" && operation.checkpointId === checkpoint.id);
41564
41622
  if (activeRestore) {
@@ -41602,6 +41660,7 @@ class PersistenceMaintenanceService {
41602
41660
  } catch {
41603
41661
  await this.context.failOperation(inserted.operation.id, "checkpoint_failed");
41604
41662
  }
41663
+ await cleanupPreservedStorage(this.context, checkpoint.storageId);
41605
41664
  return await this.context.deps.store.getOperation(inserted.operation.id) ?? inserted.operation;
41606
41665
  }
41607
41666
  }
@@ -52024,8 +52083,7 @@ async function startPocketCoderServer(config2 = loadConfig(), options = {}) {
52024
52083
  const url2 = `http://${healthHost}:${server.port}`;
52025
52084
  log(`listening on http://${config2.listenHost}:${server.port}`);
52026
52085
  log(`workspaces reach this server at ${config2.workspaceServerUrl}`);
52027
- if (warmPool)
52028
- warmPool.reconcile().catch((error51) => log(`warm pool initial reconcile failed: ${String(error51)}`));
52086
+ const initialWarmPool = warmPool?.reconcile().catch((error51) => log(`warm pool initial reconcile failed: ${String(error51)}`));
52029
52087
  let stopPromise = null;
52030
52088
  return {
52031
52089
  config: config2,
@@ -52041,6 +52099,7 @@ async function startPocketCoderServer(config2 = loadConfig(), options = {}) {
52041
52099
  if (warmPoolTimer)
52042
52100
  clearInterval(warmPoolTimer);
52043
52101
  await server.stop(true);
52102
+ await initialWarmPool;
52044
52103
  await store.close();
52045
52104
  })();
52046
52105
  return stopPromise;
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "type:app"
7
7
  ]
8
8
  },
9
- "version": "0.7.2",
9
+ "version": "0.7.3",
10
10
  "private": false,
11
11
  "description": "Operator and diagnostics CLI for PocketCoder.",
12
12
  "type": "module",