@treeseed/sdk 0.8.18 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/d1-store.js CHANGED
@@ -187,6 +187,9 @@ class MemoryAgentDatabase {
187
187
  if (model === "task") {
188
188
  return [...this.tasks.values()];
189
189
  }
190
+ if (model === "task_event") {
191
+ return [...this.taskEvents.values()].flat();
192
+ }
190
193
  if (model === "task_output") {
191
194
  return [...this.taskOutputs.values()].flat();
192
195
  }
@@ -1183,6 +1186,12 @@ class CloudflareD1AgentDatabase {
1183
1186
  if (request.model === "task") {
1184
1187
  return this.operational.getTask(String(request.id ?? request.key ?? request.slug ?? ""));
1185
1188
  }
1189
+ if (request.model === "task_event") {
1190
+ return this.operational.getTaskEvent(String(request.id ?? request.key ?? request.slug ?? ""));
1191
+ }
1192
+ if (request.model === "task_output") {
1193
+ return this.operational.getTaskOutput(String(request.id ?? request.key ?? request.slug ?? ""));
1194
+ }
1186
1195
  if (request.model === "report") {
1187
1196
  return this.operational.getReport(String(request.id ?? request.key ?? request.slug ?? ""));
1188
1197
  }
@@ -1215,9 +1224,24 @@ class CloudflareD1AgentDatabase {
1215
1224
  }
1216
1225
  if (request.model === "task") {
1217
1226
  return this.operational.searchTasks({
1218
- workDayId: request.filters?.find((entry) => entry.field === "workDayId" || entry.field === "work_day_id")?.value,
1219
- agentId: request.filters?.find((entry) => entry.field === "agentId" || entry.field === "agent_id")?.value,
1220
- state: request.filters?.find((entry) => entry.field === "state")?.value,
1227
+ workDayId: normalizedRequest.filters?.find((entry) => entry.field === "work_day_id")?.value,
1228
+ agentId: normalizedRequest.filters?.find((entry) => entry.field === "agent_id")?.value,
1229
+ state: normalizedRequest.filters?.find((entry) => entry.field === "state")?.value,
1230
+ limit: request.limit
1231
+ });
1232
+ }
1233
+ if (request.model === "task_event") {
1234
+ return this.operational.searchTaskEvents({
1235
+ id: normalizedRequest.filters?.find((entry) => entry.field === "id")?.value,
1236
+ taskId: normalizedRequest.filters?.find((entry) => entry.field === "task_id")?.value,
1237
+ kind: normalizedRequest.filters?.find((entry) => entry.field === "kind")?.value,
1238
+ limit: request.limit
1239
+ });
1240
+ }
1241
+ if (request.model === "task_output") {
1242
+ return this.operational.searchTaskOutputs({
1243
+ id: normalizedRequest.filters?.find((entry) => entry.field === "id")?.value,
1244
+ taskId: normalizedRequest.filters?.find((entry) => entry.field === "task_id")?.value,
1221
1245
  limit: request.limit
1222
1246
  });
1223
1247
  }
@@ -1,4 +1,4 @@
1
- import { mkdirSync } from "node:fs";
1
+ import { existsSync, mkdirSync, readdirSync, statSync } from "node:fs";
2
2
  import { dirname, resolve } from "node:path";
3
3
  import { DatabaseSync } from "node:sqlite";
4
4
  import { drizzle } from "drizzle-orm/sqlite-proxy";
@@ -8,7 +8,16 @@ function isDirectoryLike(path) {
8
8
  }
9
9
  function resolveTreeseedSqlitePath(input) {
10
10
  const base = input?.trim() || ".treeseed/generated/environments/local/site-data.sqlite";
11
- return isDirectoryLike(base) ? resolve(base, "site-data.sqlite") : resolve(base);
11
+ if (!isDirectoryLike(base)) return resolve(base);
12
+ const miniflareRoot = resolve(base, "miniflare-D1DatabaseObject");
13
+ if (existsSync(miniflareRoot)) {
14
+ const candidates = readdirSync(miniflareRoot).filter((entry) => /\.sqlite$/u.test(entry) && entry !== "metadata.sqlite").map((entry) => {
15
+ const path = resolve(miniflareRoot, entry);
16
+ return { path, size: statSync(path).size };
17
+ }).sort((left, right) => right.size - left.size || left.path.localeCompare(right.path));
18
+ if (candidates[0]?.path) return candidates[0].path;
19
+ }
20
+ return resolve(base, "site-data.sqlite");
12
21
  }
13
22
  function toD1Result(result, rows = []) {
14
23
  const changes = Number(result?.changes ?? 0);
@@ -336,12 +336,13 @@ function buildBuiltinModelRegistry(repoRoot) {
336
336
  storage: "d1",
337
337
  operations: ["get", "read", "search", "create", "update"],
338
338
  fields: {
339
- project_id: field("project_id", { aliases: ["projectId"], filterable: true, dbColumns: ["project_id"], writeDbColumn: "project_id" }),
339
+ id: field("id", { filterable: true, dbColumns: ["id"], writeDbColumn: "id" }),
340
+ project_id: field("project_id", { aliases: ["projectId"], filterable: true, dbColumns: ["project_id"], payloadPaths: ["projectId"], writeDbColumn: "project_id" }),
340
341
  state: field("state", { filterable: true, dbColumns: ["state"], writeDbColumn: "state" }),
341
- started_at: field("started_at", { aliases: ["startedAt"], filterable: true, sortable: true, comparableAs: "date", dbColumns: ["started_at"], writeDbColumn: "started_at" }),
342
- updated_at: field("updated_at", { aliases: ["updatedAt"], filterable: true, sortable: true, comparableAs: "date", dbColumns: ["updated_at"], writeDbColumn: "updated_at" })
342
+ started_at: field("started_at", { aliases: ["startedAt"], filterable: true, sortable: true, comparableAs: "date", dbColumns: ["started_at"], payloadPaths: ["startedAt"], writeDbColumn: "started_at" }),
343
+ updated_at: field("updated_at", { aliases: ["updatedAt"], filterable: true, sortable: true, comparableAs: "date", dbColumns: ["updated_at"], payloadPaths: ["updatedAt"], writeDbColumn: "updated_at" })
343
344
  },
344
- filterableFields: ["project_id", "state", "started_at", "updated_at"],
345
+ filterableFields: ["id", "project_id", "state", "started_at", "updated_at"],
345
346
  sortableFields: ["started_at", "updated_at"],
346
347
  pickField: "updated_at"
347
348
  },
@@ -351,16 +352,17 @@ function buildBuiltinModelRegistry(repoRoot) {
351
352
  storage: "d1",
352
353
  operations: ["get", "read", "search", "pick", "create", "update"],
353
354
  fields: {
354
- work_day_id: field("work_day_id", { aliases: ["workDayId"], filterable: true, dbColumns: ["work_day_id"], writeDbColumn: "work_day_id" }),
355
- agent_id: field("agent_id", { aliases: ["agentId"], filterable: true, dbColumns: ["agent_id"], writeDbColumn: "agent_id" }),
355
+ id: field("id", { filterable: true, dbColumns: ["id"], writeDbColumn: "id" }),
356
+ work_day_id: field("work_day_id", { aliases: ["workDayId"], filterable: true, dbColumns: ["work_day_id"], payloadPaths: ["workDayId"], writeDbColumn: "work_day_id" }),
357
+ agent_id: field("agent_id", { aliases: ["agentId"], filterable: true, dbColumns: ["agent_id"], payloadPaths: ["agentId"], writeDbColumn: "agent_id" }),
356
358
  type: field("type", { filterable: true, dbColumns: ["type"], writeDbColumn: "type" }),
357
359
  state: field("state", { filterable: true, dbColumns: ["state"], writeDbColumn: "state" }),
358
360
  priority: field("priority", { filterable: true, sortable: true, comparableAs: "number", dbColumns: ["priority"], writeDbColumn: "priority" }),
359
- idempotency_key: field("idempotency_key", { aliases: ["idempotencyKey"], filterable: true, dbColumns: ["idempotency_key"], writeDbColumn: "idempotency_key" }),
360
- available_at: field("available_at", { aliases: ["availableAt"], filterable: true, sortable: true, comparableAs: "date", dbColumns: ["available_at"], writeDbColumn: "available_at" }),
361
- updated_at: field("updated_at", { aliases: ["updatedAt"], filterable: true, sortable: true, comparableAs: "date", dbColumns: ["updated_at"], writeDbColumn: "updated_at" })
361
+ idempotency_key: field("idempotency_key", { aliases: ["idempotencyKey"], filterable: true, dbColumns: ["idempotency_key"], payloadPaths: ["idempotencyKey"], writeDbColumn: "idempotency_key" }),
362
+ available_at: field("available_at", { aliases: ["availableAt"], filterable: true, sortable: true, comparableAs: "date", dbColumns: ["available_at"], payloadPaths: ["availableAt"], writeDbColumn: "available_at" }),
363
+ updated_at: field("updated_at", { aliases: ["updatedAt"], filterable: true, sortable: true, comparableAs: "date", dbColumns: ["updated_at"], payloadPaths: ["updatedAt"], writeDbColumn: "updated_at" })
362
364
  },
363
- filterableFields: ["work_day_id", "agent_id", "type", "state", "priority", "idempotency_key", "available_at", "updated_at"],
365
+ filterableFields: ["id", "work_day_id", "agent_id", "type", "state", "priority", "idempotency_key", "available_at", "updated_at"],
364
366
  sortableFields: ["priority", "available_at", "updated_at"],
365
367
  pickField: "available_at"
366
368
  },
@@ -370,12 +372,13 @@ function buildBuiltinModelRegistry(repoRoot) {
370
372
  storage: "d1",
371
373
  operations: ["get", "read", "search", "create"],
372
374
  fields: {
373
- task_id: field("task_id", { aliases: ["taskId"], filterable: true, dbColumns: ["task_id"], writeDbColumn: "task_id" }),
375
+ id: field("id", { filterable: true, dbColumns: ["id"], writeDbColumn: "id" }),
376
+ task_id: field("task_id", { aliases: ["taskId"], filterable: true, dbColumns: ["task_id"], payloadPaths: ["taskId"], writeDbColumn: "task_id" }),
374
377
  kind: field("kind", { filterable: true, dbColumns: ["kind"], writeDbColumn: "kind" }),
375
378
  seq: field("seq", { filterable: true, sortable: true, comparableAs: "number", dbColumns: ["seq"], writeDbColumn: "seq" }),
376
- created_at: field("created_at", { aliases: ["createdAt"], filterable: true, sortable: true, comparableAs: "date", dbColumns: ["created_at"], writeDbColumn: "created_at" })
379
+ created_at: field("created_at", { aliases: ["createdAt"], filterable: true, sortable: true, comparableAs: "date", dbColumns: ["created_at"], payloadPaths: ["createdAt"], writeDbColumn: "created_at" })
377
380
  },
378
- filterableFields: ["task_id", "kind", "seq", "created_at"],
381
+ filterableFields: ["id", "task_id", "kind", "seq", "created_at"],
379
382
  sortableFields: ["seq", "created_at"],
380
383
  pickField: "created_at"
381
384
  },
@@ -385,10 +388,11 @@ function buildBuiltinModelRegistry(repoRoot) {
385
388
  storage: "d1",
386
389
  operations: ["get", "read", "search", "create"],
387
390
  fields: {
388
- task_id: field("task_id", { aliases: ["taskId"], filterable: true, dbColumns: ["task_id"], writeDbColumn: "task_id" }),
389
- created_at: field("created_at", { aliases: ["createdAt"], filterable: true, sortable: true, comparableAs: "date", dbColumns: ["created_at"], writeDbColumn: "created_at" })
391
+ id: field("id", { filterable: true, dbColumns: ["id"], writeDbColumn: "id" }),
392
+ task_id: field("task_id", { aliases: ["taskId"], filterable: true, dbColumns: ["task_id"], payloadPaths: ["taskId"], writeDbColumn: "task_id" }),
393
+ created_at: field("created_at", { aliases: ["createdAt"], filterable: true, sortable: true, comparableAs: "date", dbColumns: ["created_at"], payloadPaths: ["createdAt"], writeDbColumn: "created_at" })
390
394
  },
391
- filterableFields: ["task_id", "created_at"],
395
+ filterableFields: ["id", "task_id", "created_at"],
392
396
  sortableFields: ["created_at"],
393
397
  pickField: "created_at"
394
398
  },
@@ -398,11 +402,18 @@ function buildBuiltinModelRegistry(repoRoot) {
398
402
  storage: "d1",
399
403
  operations: ["get", "read", "search", "create"],
400
404
  fields: {
401
- work_day_id: field("work_day_id", { aliases: ["workDayId"], filterable: true, dbColumns: ["work_day_id"], writeDbColumn: "work_day_id" }),
402
- graph_version: field("graph_version", { aliases: ["graphVersion"], filterable: true, sortable: true, dbColumns: ["graph_version"], writeDbColumn: "graph_version" }),
403
- created_at: field("created_at", { aliases: ["createdAt"], filterable: true, sortable: true, comparableAs: "date", dbColumns: ["created_at"], writeDbColumn: "created_at" })
405
+ id: field("id", { filterable: true, dbColumns: ["id"], writeDbColumn: "id" }),
406
+ work_day_id: field("work_day_id", { aliases: ["workDayId"], filterable: true, dbColumns: ["work_day_id"], payloadPaths: ["workDayId"], writeDbColumn: "work_day_id" }),
407
+ corpus_hash: field("corpus_hash", { aliases: ["corpusHash"], filterable: true, dbColumns: ["corpus_hash"], payloadPaths: ["corpusHash"], writeDbColumn: "corpus_hash" }),
408
+ graph_version: field("graph_version", { aliases: ["graphVersion"], filterable: true, sortable: true, dbColumns: ["graph_version"], payloadPaths: ["graphVersion"], writeDbColumn: "graph_version" }),
409
+ query_json: field("query_json", { aliases: ["queryJson"], dbColumns: ["query_json"], payloadPaths: ["queryJson"], writeDbColumn: "query_json" }),
410
+ seed_ids_json: field("seed_ids_json", { aliases: ["seedIdsJson"], dbColumns: ["seed_ids_json"], payloadPaths: ["seedIdsJson"], writeDbColumn: "seed_ids_json" }),
411
+ selected_node_ids_json: field("selected_node_ids_json", { aliases: ["selectedNodeIdsJson"], dbColumns: ["selected_node_ids_json"], payloadPaths: ["selectedNodeIdsJson"], writeDbColumn: "selected_node_ids_json" }),
412
+ stats_json: field("stats_json", { aliases: ["statsJson"], dbColumns: ["stats_json"], payloadPaths: ["statsJson"], writeDbColumn: "stats_json" }),
413
+ snapshot_ref: field("snapshot_ref", { aliases: ["snapshotRef"], filterable: true, dbColumns: ["snapshot_ref"], payloadPaths: ["snapshotRef"], writeDbColumn: "snapshot_ref" }),
414
+ created_at: field("created_at", { aliases: ["createdAt"], filterable: true, sortable: true, comparableAs: "date", dbColumns: ["created_at"], payloadPaths: ["createdAt"], writeDbColumn: "created_at" })
404
415
  },
405
- filterableFields: ["work_day_id", "graph_version", "created_at"],
416
+ filterableFields: ["id", "work_day_id", "corpus_hash", "graph_version", "snapshot_ref", "created_at"],
406
417
  sortableFields: ["created_at"],
407
418
  pickField: "created_at"
408
419
  },
@@ -412,12 +423,13 @@ function buildBuiltinModelRegistry(repoRoot) {
412
423
  storage: "d1",
413
424
  operations: ["get", "read", "search", "create", "update"],
414
425
  fields: {
415
- work_day_id: field("work_day_id", { aliases: ["workDayId"], filterable: true, dbColumns: ["work_day_id"], writeDbColumn: "work_day_id" }),
426
+ id: field("id", { filterable: true, dbColumns: ["id"], writeDbColumn: "id" }),
427
+ work_day_id: field("work_day_id", { aliases: ["workDayId"], filterable: true, dbColumns: ["work_day_id"], payloadPaths: ["workDayId"], writeDbColumn: "work_day_id" }),
416
428
  kind: field("kind", { filterable: true, dbColumns: ["kind"], writeDbColumn: "kind" }),
417
- sent_at: field("sent_at", { aliases: ["sentAt"], filterable: true, sortable: true, comparableAs: "date", dbColumns: ["sent_at"], writeDbColumn: "sent_at" }),
418
- created_at: field("created_at", { aliases: ["createdAt"], filterable: true, sortable: true, comparableAs: "date", dbColumns: ["created_at"], writeDbColumn: "created_at" })
429
+ sent_at: field("sent_at", { aliases: ["sentAt"], filterable: true, sortable: true, comparableAs: "date", dbColumns: ["sent_at"], payloadPaths: ["sentAt"], writeDbColumn: "sent_at" }),
430
+ created_at: field("created_at", { aliases: ["createdAt"], filterable: true, sortable: true, comparableAs: "date", dbColumns: ["created_at"], payloadPaths: ["createdAt"], writeDbColumn: "created_at" })
419
431
  },
420
- filterableFields: ["work_day_id", "kind", "sent_at", "created_at"],
432
+ filterableFields: ["id", "work_day_id", "kind", "sent_at", "created_at"],
421
433
  sortableFields: ["sent_at", "created_at"],
422
434
  pickField: "created_at"
423
435
  },
@@ -571,6 +583,25 @@ function buildBuiltinModelRegistry(repoRoot) {
571
583
  filterableFields: ["project_id", "environment", "runner_id", "runner_service_name", "state"],
572
584
  sortableFields: ["runner_id", "available_capacity", "last_heartbeat_at"],
573
585
  pickField: "last_heartbeat_at"
586
+ },
587
+ repository_claim: {
588
+ name: "repository_claim",
589
+ aliases: ["repository_claims"],
590
+ storage: "d1",
591
+ operations: ["get", "read", "search", "create", "update"],
592
+ fields: {
593
+ id: field("id", { filterable: true, dbColumns: ["id"], writeDbColumn: "id" }),
594
+ project_id: field("project_id", { aliases: ["projectId"], filterable: true, dbColumns: ["project_id"], payloadPaths: ["projectId"], writeDbColumn: "project_id" }),
595
+ repository_id: field("repository_id", { aliases: ["repositoryId"], filterable: true, dbColumns: ["repository_id"], payloadPaths: ["repositoryId"], writeDbColumn: "repository_id" }),
596
+ runner_id: field("runner_id", { aliases: ["runnerId"], filterable: true, dbColumns: ["runner_id"], payloadPaths: ["runnerId"], writeDbColumn: "runner_id" }),
597
+ runner_service_name: field("runner_service_name", { aliases: ["runnerServiceName"], filterable: true, dbColumns: ["runner_service_name"], payloadPaths: ["runnerServiceName"], writeDbColumn: "runner_service_name" }),
598
+ volume_identity: field("volume_identity", { aliases: ["volumeIdentity"], filterable: true, dbColumns: ["volume_identity"], payloadPaths: ["volumeIdentity"], writeDbColumn: "volume_identity" }),
599
+ claim_state: field("claim_state", { aliases: ["claimState"], filterable: true, dbColumns: ["claim_state"], payloadPaths: ["claimState"], writeDbColumn: "claim_state" }),
600
+ updated_at: field("updated_at", { aliases: ["updatedAt"], sortable: true, comparableAs: "date", dbColumns: ["updated_at"], payloadPaths: ["updatedAt"], writeDbColumn: "updated_at" })
601
+ },
602
+ filterableFields: ["id", "project_id", "repository_id", "runner_id", "runner_service_name", "volume_identity", "claim_state"],
603
+ sortableFields: ["updated_at"],
604
+ pickField: "updated_at"
574
605
  }
575
606
  };
576
607
  }
@@ -2,6 +2,7 @@ import { existsSync, readdirSync } from "node:fs";
2
2
  import { readFileSync } from "node:fs";
3
3
  import { resolve } from "node:path";
4
4
  import { spawnSync } from "node:child_process";
5
+ import { NodeSqliteD1Database } from "../../db/node-sqlite.js";
5
6
  import { resolveWranglerBin } from "./runtime-tools.js";
6
7
  const DATABASE_BINDING = "SITE_DATA_DB";
7
8
  const WRANGLER_D1_TIMEOUT_MS = 12e4;
@@ -121,6 +122,36 @@ function migrationAlreadySatisfied({ cwd, wranglerConfig, persistTo, filePath })
121
122
  const profileColumns = tableColumns({ cwd, wranglerConfig, persistTo, tableName: "task_estimate_profiles" });
122
123
  return estimateColumns.has("execution_profile_id") && actualColumns.has("execution_profile_id") && profileColumns.has("execution_profile_id") && profileColumns.has("completed_sample_count") && profileColumns.has("interrupted_sample_count") && profileColumns.has("confidence_score");
123
124
  }
125
+ function ensureLocalSdkRuntimeState({ migrationsRoot, persistTo }) {
126
+ if (!persistTo) {
127
+ return;
128
+ }
129
+ const migrationPath = resolve(migrationsRoot, "0025_agent_runtime_state.sql");
130
+ if (!existsSync(migrationPath)) {
131
+ return;
132
+ }
133
+ const sql = readFileSync(migrationPath, "utf8");
134
+ const targets = /* @__PURE__ */ new Set();
135
+ const sdkDb = new NodeSqliteD1Database(persistTo);
136
+ targets.add(sdkDb.path);
137
+ sdkDb.close();
138
+ const miniflareRoot = resolve(persistTo, "miniflare-D1DatabaseObject");
139
+ if (existsSync(miniflareRoot)) {
140
+ for (const entry of readdirSync(miniflareRoot)) {
141
+ if (entry.endsWith(".sqlite") && entry !== "metadata.sqlite") {
142
+ targets.add(resolve(miniflareRoot, entry));
143
+ }
144
+ }
145
+ }
146
+ for (const target of targets) {
147
+ const db = new NodeSqliteD1Database(target);
148
+ try {
149
+ db.client.exec(sql);
150
+ } finally {
151
+ db.close();
152
+ }
153
+ }
154
+ }
124
155
  function runLocalD1Migrations({ cwd, wranglerConfig, migrationsRoot, persistTo }) {
125
156
  ensureSchemaMigrationsTable({ cwd, wranglerConfig, persistTo });
126
157
  const appliedMigrations = loadAppliedMigrations({ cwd, wranglerConfig, persistTo });
@@ -141,6 +172,7 @@ function runLocalD1Migrations({ cwd, wranglerConfig, migrationsRoot, persistTo }
141
172
  executeSqlFile({ cwd, wranglerConfig, filePath, persistTo });
142
173
  markMigrationApplied({ cwd, wranglerConfig, persistTo, migration });
143
174
  }
175
+ ensureLocalSdkRuntimeState({ migrationsRoot, persistTo });
144
176
  }
145
177
  export {
146
178
  runLocalD1Migrations
@@ -358,9 +358,12 @@ function buildLocalRuntimeVars(deployConfig, state, target, env) {
358
358
  if (target.kind !== "persistent" || target.scope !== "local") {
359
359
  return {};
360
360
  }
361
+ const localDevAuthTtlSeconds = String(365 * 24 * 60 * 60);
361
362
  return {
362
363
  ...localAuthRuntimeVars(env),
363
364
  TREESEED_LOCAL_DEV_MODE: envValue(env, "TREESEED_LOCAL_DEV_MODE") ?? "cloudflare",
365
+ TREESEED_API_ACCESS_TOKEN_TTL: envValue(env, "TREESEED_API_ACCESS_TOKEN_TTL") ?? localDevAuthTtlSeconds,
366
+ TREESEED_API_REFRESH_TOKEN_TTL: envValue(env, "TREESEED_API_REFRESH_TOKEN_TTL") ?? localDevAuthTtlSeconds,
364
367
  TREESEED_FORM_TOKEN_SECRET: envValue(env, "TREESEED_FORM_TOKEN_SECRET") ?? state.generatedSecrets?.TREESEED_FORM_TOKEN_SECRET ?? "treeseed-local-form-token-secret",
365
368
  TREESEED_BETTER_AUTH_SECRET: envValue(env, "TREESEED_BETTER_AUTH_SECRET") ?? state.generatedSecrets?.TREESEED_BETTER_AUTH_SECRET ?? state.generatedSecrets?.TREESEED_FORM_TOKEN_SECRET ?? "treeseed-local-better-auth-secret-minimum-32-characters",
366
369
  TREESEED_EDITORIAL_PREVIEW_SECRET: envValue(env, "TREESEED_EDITORIAL_PREVIEW_SECRET") ?? state.generatedSecrets?.TREESEED_EDITORIAL_PREVIEW_SECRET ?? "treeseed-local-editorial-preview-secret",
@@ -316,7 +316,7 @@ function applyManagedProjectDefaults(projectRoot, input) {
316
316
  railway: {
317
317
  serviceName: `${slug}-api`,
318
318
  buildCommand: "npm run build:api",
319
- startCommand: "npm run build:api && node ./src/api/server.js",
319
+ startCommand: "node ./packages/agent/dist/scripts/treeseed-processing.js api",
320
320
  healthcheckTimeoutSeconds: 120
321
321
  },
322
322
  environments: {
@@ -332,7 +332,7 @@ function applyManagedProjectDefaults(projectRoot, input) {
332
332
  serviceName: `${slug}-workday-manager`,
333
333
  rootDir: ".",
334
334
  buildCommand: "npm run build:api",
335
- startCommand: "npm run build:api && node ./packages/agent/dist/services/workday-manager.js",
335
+ startCommand: "node ./packages/agent/dist/scripts/treeseed-processing.js manager",
336
336
  schedule: "0 9 * * 1-5"
337
337
  }
338
338
  },
@@ -342,7 +342,7 @@ function applyManagedProjectDefaults(projectRoot, input) {
342
342
  railway: {
343
343
  rootDir: ".",
344
344
  buildCommand: "npm run build:api",
345
- startCommand: "npm run build:api && node ./packages/agent/dist/services/worker.js"
345
+ startCommand: "node ./packages/agent/dist/scripts/treeseed-processing.js worker"
346
346
  }
347
347
  },
348
348
  ...config.services ?? {}
@@ -212,6 +212,23 @@ export declare function deployProjectPlatform(options: ProjectPlatformActionOpti
212
212
  reason: string;
213
213
  };
214
214
  readiness: any;
215
+ apiMonitor: {
216
+ ok: boolean;
217
+ processingAgentApi: boolean;
218
+ endpoints: {
219
+ apiHealth: null;
220
+ apiReady: null;
221
+ d1Health: null;
222
+ agentHealth: null;
223
+ processingAgentApi: boolean;
224
+ } | {
225
+ apiHealth: string;
226
+ apiReady: string;
227
+ d1Health: string | null;
228
+ agentHealth: string;
229
+ processingAgentApi: boolean;
230
+ };
231
+ };
215
232
  };
216
233
  };
217
234
  hostingRepair: {
@@ -394,6 +411,23 @@ export declare function monitorProjectPlatform(options: ProjectPlatformActionOpt
394
411
  reason: string;
395
412
  };
396
413
  readiness: any;
414
+ apiMonitor: {
415
+ ok: boolean;
416
+ processingAgentApi: boolean;
417
+ endpoints: {
418
+ apiHealth: null;
419
+ apiReady: null;
420
+ d1Health: null;
421
+ agentHealth: null;
422
+ processingAgentApi: boolean;
423
+ } | {
424
+ apiHealth: string;
425
+ apiReady: string;
426
+ d1Health: string | null;
427
+ agentHealth: string;
428
+ processingAgentApi: boolean;
429
+ };
430
+ };
397
431
  };
398
432
  }>;
399
433
  export declare function syncControlPlaneState(options: ProjectPlatformActionOptions): Promise<void>;
@@ -528,6 +562,23 @@ export declare function runProjectPlatformAction(action: ProjectPlatformAction,
528
562
  reason: string;
529
563
  };
530
564
  readiness: any;
565
+ apiMonitor: {
566
+ ok: boolean;
567
+ processingAgentApi: boolean;
568
+ endpoints: {
569
+ apiHealth: null;
570
+ apiReady: null;
571
+ d1Health: null;
572
+ agentHealth: null;
573
+ processingAgentApi: boolean;
574
+ } | {
575
+ apiHealth: string;
576
+ apiReady: string;
577
+ d1Health: string | null;
578
+ agentHealth: string;
579
+ processingAgentApi: boolean;
580
+ };
581
+ };
531
582
  };
532
583
  } | {
533
584
  ok: boolean;
@@ -655,6 +706,23 @@ export declare function runProjectPlatformAction(action: ProjectPlatformAction,
655
706
  reason: string;
656
707
  };
657
708
  readiness: any;
709
+ apiMonitor: {
710
+ ok: boolean;
711
+ processingAgentApi: boolean;
712
+ endpoints: {
713
+ apiHealth: null;
714
+ apiReady: null;
715
+ d1Health: null;
716
+ agentHealth: null;
717
+ processingAgentApi: boolean;
718
+ } | {
719
+ apiHealth: string;
720
+ apiReady: string;
721
+ d1Health: string | null;
722
+ agentHealth: string;
723
+ processingAgentApi: boolean;
724
+ };
725
+ };
658
726
  };
659
727
  };
660
728
  hostingRepair: {
@@ -633,6 +633,30 @@ function resolveImmediateApiProbeUrl(siteConfig, state, target) {
633
633
  }
634
634
  return null;
635
635
  }
636
+ function isProcessingAgentApiService(siteConfig) {
637
+ const startCommand = String(siteConfig.services?.api?.railway?.startCommand ?? siteConfig.services?.api?.startCommand ?? "");
638
+ return /\btreeseed-processing(?:\.js)?\s+api\b/u.test(startCommand) || /treeseed-processing\.js\s+api\b/u.test(startCommand);
639
+ }
640
+ function resolveApiMonitorEndpoints(siteConfig, apiBaseUrl) {
641
+ if (!apiBaseUrl) {
642
+ return {
643
+ apiHealth: null,
644
+ apiReady: null,
645
+ d1Health: null,
646
+ agentHealth: null,
647
+ processingAgentApi: isProcessingAgentApiService(siteConfig)
648
+ };
649
+ }
650
+ const baseUrl = String(apiBaseUrl).replace(/\/+$/u, "");
651
+ const processingAgentApi = isProcessingAgentApiService(siteConfig);
652
+ return {
653
+ apiHealth: `${baseUrl}/healthz`,
654
+ apiReady: `${baseUrl}/readyz`,
655
+ d1Health: processingAgentApi ? null : `${baseUrl}/healthz/deep`,
656
+ agentHealth: processingAgentApi ? `${baseUrl}/agent/healthz` : `${baseUrl}/internal/core/agent/healthz`,
657
+ processingAgentApi
658
+ };
659
+ }
636
660
  async function probeQueue(siteConfig, state) {
637
661
  const config = queueClientConfig(siteConfig, state);
638
662
  if (!config) {
@@ -1326,6 +1350,7 @@ async function monitorProjectPlatform(options) {
1326
1350
  const state = loadDeployState(options.tenantRoot, siteConfig, { target });
1327
1351
  const webProbeUrl = resolveImmediatePagesProbeUrl(siteConfig, state, target);
1328
1352
  const apiBaseUrl = resolveImmediateApiProbeUrl(siteConfig, state, target);
1353
+ const apiMonitorEndpoints = resolveApiMonitorEndpoints(siteConfig, apiBaseUrl);
1329
1354
  const railwayResources = options.scope === "local" || !apiSelected && !agentsSelected ? { ok: true, skipped: true, reason: options.scope === "local" ? "local_scope" : "railway_not_selected" } : await verifyRailwayManagedResources(options.tenantRoot, options.scope, {
1330
1355
  env,
1331
1356
  settleDeployments: true,
@@ -1333,17 +1358,23 @@ async function monitorProjectPlatform(options) {
1333
1358
  });
1334
1359
  const skippedApiCheck = apiSelected ? { ok: false, skipped: true, reason: "api_url_unconfigured" } : { ok: true, skipped: true, reason: "api_not_selected" };
1335
1360
  const skippedAgentCheck = agentsSelected ? { ok: false, skipped: true, reason: "api_url_unconfigured" } : { ok: true, skipped: true, reason: "agents_not_selected" };
1361
+ const skippedD1Check = apiMonitorEndpoints.processingAgentApi ? { ok: true, skipped: true, reason: "processing_agent_api" } : skippedApiCheck;
1336
1362
  const checks = {
1337
1363
  pages: await probeHttp(webProbeUrl, { attempts: 3, delayMs: 5e3 }),
1338
- apiHealth: apiSelected && apiBaseUrl ? await probeHttp(`${String(apiBaseUrl).replace(/\/+$/u, "")}/healthz`, { attempts: 8, delayMs: 1e4 }) : skippedApiCheck,
1339
- apiReady: apiSelected && apiBaseUrl ? await probeHttp(`${String(apiBaseUrl).replace(/\/+$/u, "")}/readyz`, { attempts: 8, delayMs: 1e4 }) : skippedApiCheck,
1340
- d1Health: apiSelected && apiBaseUrl ? await probeHttp(`${String(apiBaseUrl).replace(/\/+$/u, "")}/healthz/deep`, { attempts: 8, delayMs: 1e4 }) : skippedApiCheck,
1341
- agentHealth: agentsSelected && apiBaseUrl ? await probeHttp(`${String(apiBaseUrl).replace(/\/+$/u, "")}/internal/core/agent/healthz`, { attempts: 8, delayMs: 1e4 }) : skippedAgentCheck,
1364
+ apiHealth: apiSelected && apiMonitorEndpoints.apiHealth ? await probeHttp(apiMonitorEndpoints.apiHealth, { attempts: 8, delayMs: 1e4 }) : skippedApiCheck,
1365
+ apiReady: apiSelected && apiMonitorEndpoints.apiReady ? await probeHttp(apiMonitorEndpoints.apiReady, { attempts: 8, delayMs: 1e4 }) : skippedApiCheck,
1366
+ d1Health: apiSelected && apiMonitorEndpoints.d1Health ? await probeHttp(apiMonitorEndpoints.d1Health, { attempts: 8, delayMs: 1e4 }) : skippedD1Check,
1367
+ agentHealth: agentsSelected && apiMonitorEndpoints.agentHealth ? await probeHttp(apiMonitorEndpoints.agentHealth, { attempts: 8, delayMs: 1e4 }) : skippedAgentCheck,
1342
1368
  r2: options.dryRun ? { ok: true, skipped: true, reason: "dry_run" } : probeR2(options.tenantRoot, siteConfig, state, target),
1343
1369
  queue: options.dryRun ? Promise.resolve({ ok: true, skipped: true, reason: "dry_run" }) : probeQueue(siteConfig, state),
1344
1370
  scaleProbe: probeScaleConfiguration(siteConfig, state),
1345
1371
  railwayResources,
1346
- readiness: state.readiness
1372
+ readiness: state.readiness,
1373
+ apiMonitor: {
1374
+ ok: true,
1375
+ processingAgentApi: apiMonitorEndpoints.processingAgentApi,
1376
+ endpoints: apiMonitorEndpoints
1377
+ }
1347
1378
  };
1348
1379
  const resolvedChecks = {
1349
1380
  ...checks,
@@ -322,6 +322,14 @@ function packageVersionAtHead(node) {
322
322
  function packageVersionEligibleForBranch(node, version, options) {
323
323
  return node.branchMode === "package-release-main" ? isStableSemverVersion(version) : isDevVersionForBranch(version, node.branch || options.branch);
324
324
  }
325
+ function packageVersionTagConflictsWithHead(node, options) {
326
+ if (node.kind !== "package") return false;
327
+ const version = typeof node.packageJson?.version === "string" ? node.packageJson.version : null;
328
+ if (!version || !packageVersionEligibleForBranch(node, version, options)) return false;
329
+ const head = headCommit(node.path);
330
+ const state = tagState(node.path, version);
331
+ return state.localCommit != null && state.localCommit !== head || state.remoteCommit != null && state.remoteCommit !== head;
332
+ }
325
333
  function selectPackageVersion(node, options) {
326
334
  const current = String(node.packageJson?.version ?? "0.0.0");
327
335
  if (node.branchMode === "package-dev-save" && isDevVersionForBranch(current, node.branch || options.branch) && !tagExists(node.path, current)) {
@@ -1294,7 +1302,8 @@ async function saveOneRepository(node, options, state) {
1294
1302
  const gitDependencyRefreshSpecs = dependencyUpdates.map((update) => state.finalizedReferences.get(update.packageName)).filter((reference) => Boolean(reference) && reference.mode === "dev-git-tag").map((reference) => `${reference.packageName}@${reference.installSpec ?? reference.spec}`);
1295
1303
  const submodulePointers = collectSubmodulePointerChanges(node, state.finalizedCommits);
1296
1304
  const submodulesChanged = submodulePointers.length > 0;
1297
- const packageNeedsVersion = node.kind === "package" && (hasMeaningfulChanges(node.path) || dependencyChanged || submodulesChanged);
1305
+ const packageHasMeaningfulChanges = hasMeaningfulChanges(node.path);
1306
+ const packageNeedsVersion = node.kind === "package" && (packageHasMeaningfulChanges || dependencyChanged || submodulesChanged || packageVersionTagConflictsWithHead(node, options));
1298
1307
  let plannedVersion = null;
1299
1308
  if (packageNeedsVersion) {
1300
1309
  const selection = selectPackageVersion(node, options);
@@ -1,5 +1,5 @@
1
1
  import type { TreeseedFieldAliasBinding } from './field-aliases.ts';
2
- export declare const SDK_MODEL_NAMES: readonly ["page", "note", "question", "proposal", "decision", "book", "knowledge", "objective", "person", "subscription", "message", "agent", "agent_run", "agent_cursor", "content_lease", "work_day", "task", "task_event", "task_output", "graph_run", "report", "approval_request", "team_inbox_item", "workday_manager_lease", "worker_runner"];
2
+ export declare const SDK_MODEL_NAMES: readonly ["page", "note", "question", "proposal", "decision", "book", "knowledge", "objective", "person", "subscription", "message", "agent", "agent_run", "agent_cursor", "content_lease", "work_day", "task", "task_event", "task_output", "graph_run", "report", "approval_request", "team_inbox_item", "workday_manager_lease", "worker_runner", "repository_claim"];
3
3
  export declare const SDK_OPERATIONS: readonly ["get", "read", "search", "follow", "pick", "create", "update"];
4
4
  export declare const SDK_STORAGE_BACKENDS: readonly ["content", "d1"];
5
5
  export declare const SDK_PICK_STRATEGIES: readonly ["latest", "highest_priority", "oldest"];
package/dist/sdk-types.js CHANGED
@@ -23,7 +23,8 @@ const SDK_MODEL_NAMES = [
23
23
  "approval_request",
24
24
  "team_inbox_item",
25
25
  "workday_manager_lease",
26
- "worker_runner"
26
+ "worker_runner",
27
+ "repository_claim"
27
28
  ];
28
29
  const SDK_OPERATIONS = ["get", "read", "search", "follow", "pick", "create", "update"];
29
30
  const SDK_STORAGE_BACKENDS = ["content", "d1"];
@@ -19,7 +19,20 @@ export declare class OperationalStore extends SqliteStoreBase {
19
19
  failTask(request: SdkFailTaskRequest): Promise<SdkTaskEntity | null>;
20
20
  appendTaskEvent(request: SdkAppendTaskEventRequest): Promise<SdkTaskEventEntity | null>;
21
21
  listTaskEvents(taskId: string): Promise<SdkTaskEventEntity[]>;
22
+ getTaskEvent(id: string): Promise<SdkTaskEventEntity | null>;
23
+ searchTaskEvents(request?: {
24
+ id?: string | string[];
25
+ taskId?: string | string[];
26
+ kind?: string | string[];
27
+ limit?: number;
28
+ }): Promise<SdkTaskEventEntity[]>;
22
29
  listTaskOutputs(taskId: string): Promise<SdkTaskOutputEntity[]>;
30
+ getTaskOutput(id: string): Promise<SdkTaskOutputEntity | null>;
31
+ searchTaskOutputs(request?: {
32
+ id?: string | string[];
33
+ taskId?: string | string[];
34
+ limit?: number;
35
+ }): Promise<SdkTaskOutputEntity[]>;
23
36
  createGraphRun(input: Omit<SdkGraphRunEntity, 'createdAt'> & {
24
37
  createdAt?: string;
25
38
  }): Promise<SdkGraphRunEntity | null>;
@@ -530,12 +530,62 @@ class OperationalStore extends SqliteStoreBase {
530
530
  );
531
531
  return rows.map(taskEventFromRow);
532
532
  }
533
+ async getTaskEvent(id) {
534
+ const row = await this.selectFirst(`SELECT * FROM task_events WHERE id = ${toSqlValue(id)} LIMIT 1`);
535
+ return row ? taskEventFromRow(row) : null;
536
+ }
537
+ async searchTaskEvents(request = {}) {
538
+ const clauses = [];
539
+ if (request.id) {
540
+ const ids = Array.isArray(request.id) ? request.id : [request.id];
541
+ clauses.push(`id IN (${ids.map((entry) => toSqlValue(entry)).join(", ")})`);
542
+ }
543
+ if (request.taskId) {
544
+ const taskIds = Array.isArray(request.taskId) ? request.taskId : [request.taskId];
545
+ clauses.push(`task_id IN (${taskIds.map((entry) => toSqlValue(entry)).join(", ")})`);
546
+ }
547
+ if (request.kind) {
548
+ const kinds = Array.isArray(request.kind) ? request.kind : [request.kind];
549
+ clauses.push(`kind IN (${kinds.map((entry) => toSqlValue(entry)).join(", ")})`);
550
+ }
551
+ const sql = [
552
+ "SELECT * FROM task_events",
553
+ clauses.length ? `WHERE ${clauses.join(" AND ")}` : "",
554
+ "ORDER BY created_at DESC, seq DESC",
555
+ `LIMIT ${request.limit ?? 50}`
556
+ ].filter(Boolean).join(" ");
557
+ const rows = await this.selectAll(sql);
558
+ return rows.map(taskEventFromRow);
559
+ }
533
560
  async listTaskOutputs(taskId) {
534
561
  const rows = await this.selectAll(
535
562
  `SELECT * FROM task_outputs WHERE task_id = ${toSqlValue(taskId)} ORDER BY created_at ASC`
536
563
  );
537
564
  return rows.map(taskOutputFromRow);
538
565
  }
566
+ async getTaskOutput(id) {
567
+ const row = await this.selectFirst(`SELECT * FROM task_outputs WHERE id = ${toSqlValue(id)} LIMIT 1`);
568
+ return row ? taskOutputFromRow(row) : null;
569
+ }
570
+ async searchTaskOutputs(request = {}) {
571
+ const clauses = [];
572
+ if (request.id) {
573
+ const ids = Array.isArray(request.id) ? request.id : [request.id];
574
+ clauses.push(`id IN (${ids.map((entry) => toSqlValue(entry)).join(", ")})`);
575
+ }
576
+ if (request.taskId) {
577
+ const taskIds = Array.isArray(request.taskId) ? request.taskId : [request.taskId];
578
+ clauses.push(`task_id IN (${taskIds.map((entry) => toSqlValue(entry)).join(", ")})`);
579
+ }
580
+ const sql = [
581
+ "SELECT * FROM task_outputs",
582
+ clauses.length ? `WHERE ${clauses.join(" AND ")}` : "",
583
+ "ORDER BY created_at DESC",
584
+ `LIMIT ${request.limit ?? 50}`
585
+ ].filter(Boolean).join(" ");
586
+ const rows = await this.selectAll(sql);
587
+ return rows.map(taskOutputFromRow);
588
+ }
539
589
  async createGraphRun(input) {
540
590
  const timestamp = input.createdAt ?? nowIso();
541
591
  await this.execute(
@@ -46,7 +46,7 @@ services:
46
46
  railway:
47
47
  serviceName: __SITE_SLUG__-api
48
48
  buildCommand: npm run build:api
49
- startCommand: npm run build:api && node ./src/api/server.js
49
+ startCommand: node ./packages/agent/dist/scripts/treeseed-processing.js api
50
50
  healthcheckTimeoutSeconds: 120
51
51
  environments:
52
52
  local:
@@ -58,7 +58,7 @@ services:
58
58
  serviceName: __SITE_SLUG__-workday-manager
59
59
  rootDir: .
60
60
  buildCommand: npm run build:api
61
- startCommand: npm run build:api && node ./packages/agent/dist/services/workday-manager.js
61
+ startCommand: node ./packages/agent/dist/scripts/treeseed-processing.js manager
62
62
  schedule: '0 9 * * 1-5'
63
63
  workerRunner:
64
64
  enabled: true
@@ -66,7 +66,7 @@ services:
66
66
  railway:
67
67
  rootDir: .
68
68
  buildCommand: npm run build:api
69
- startCommand: npm run build:api && node ./packages/agent/dist/services/worker.js
69
+ startCommand: node ./packages/agent/dist/scripts/treeseed-processing.js worker
70
70
  plugins:
71
71
  - package: '@treeseed/core/plugin-default'
72
72
  providers:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treeseed/sdk",
3
- "version": "0.8.18",
3
+ "version": "0.9.0",
4
4
  "description": "Shared Treeseed SDK for content-backed and D1-backed object models.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {