@treeseed/sdk 0.1.2 → 0.3.1
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/README.md +97 -506
- package/dist/{src/cli-tools.d.ts → cli-tools.d.ts} +1 -1
- package/dist/cli-tools.js +5 -3
- package/dist/{src/content-store.d.ts → content-store.d.ts} +3 -2
- package/dist/content-store.js +52 -20
- package/dist/{src/d1-store.d.ts → d1-store.d.ts} +62 -1
- package/dist/d1-store.js +625 -65
- package/dist/field-aliases.d.ts +11 -0
- package/dist/field-aliases.js +41 -0
- package/dist/graph/build.d.ts +19 -0
- package/dist/graph/build.js +949 -0
- package/dist/graph/dsl.d.ts +2 -0
- package/dist/graph/dsl.js +243 -0
- package/dist/graph/query.d.ts +47 -0
- package/dist/graph/query.js +447 -0
- package/dist/graph/ranking.d.ts +3 -0
- package/dist/graph/ranking.js +483 -0
- package/dist/graph/schema.d.ts +142 -0
- package/dist/graph/schema.js +133 -0
- package/dist/graph.d.ts +52 -0
- package/dist/graph.js +133 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +91 -2
- package/dist/model-registry.d.ts +8 -0
- package/dist/model-registry.js +351 -25
- package/dist/operations/providers/default.d.ts +10 -0
- package/dist/operations/providers/default.js +514 -0
- package/dist/operations/runtime.d.ts +7 -0
- package/dist/operations/runtime.js +60 -0
- package/dist/operations/services/config-runtime.d.ts +269 -0
- package/dist/operations/services/config-runtime.js +1397 -0
- package/dist/operations/services/d1-migration.d.ts +6 -0
- package/dist/operations/services/d1-migration.js +89 -0
- package/dist/operations/services/deploy.d.ts +371 -0
- package/dist/operations/services/deploy.js +981 -0
- package/dist/operations/services/git-workflow.d.ts +49 -0
- package/dist/operations/services/git-workflow.js +218 -0
- package/dist/operations/services/github-automation.d.ts +156 -0
- package/dist/operations/services/github-automation.js +256 -0
- package/dist/operations/services/local-dev.d.ts +9 -0
- package/dist/operations/services/local-dev.js +106 -0
- package/dist/operations/services/mailpit-runtime.d.ts +4 -0
- package/dist/operations/services/mailpit-runtime.js +59 -0
- package/dist/operations/services/railway-deploy.d.ts +53 -0
- package/dist/operations/services/railway-deploy.js +123 -0
- package/dist/operations/services/runtime-paths.d.ts +19 -0
- package/dist/operations/services/runtime-paths.js +54 -0
- package/dist/operations/services/runtime-tools.d.ts +117 -0
- package/dist/operations/services/runtime-tools.js +358 -0
- package/dist/operations/services/save-deploy-preflight.d.ts +34 -0
- package/dist/operations/services/save-deploy-preflight.js +76 -0
- package/dist/operations/services/template-registry.d.ts +88 -0
- package/dist/operations/services/template-registry.js +407 -0
- package/dist/operations/services/watch-dev.d.ts +21 -0
- package/dist/operations/services/watch-dev.js +284 -0
- package/dist/operations/services/workspace-preflight.d.ts +40 -0
- package/dist/operations/services/workspace-preflight.js +165 -0
- package/dist/operations/services/workspace-save.d.ts +42 -0
- package/dist/operations/services/workspace-save.js +235 -0
- package/dist/operations/services/workspace-tools.d.ts +16 -0
- package/dist/operations/services/workspace-tools.js +270 -0
- package/dist/operations-registry.d.ts +5 -0
- package/dist/operations-registry.js +68 -0
- package/dist/operations-types.d.ts +71 -0
- package/dist/operations-types.js +17 -0
- package/dist/operations.d.ts +6 -0
- package/dist/operations.js +16 -0
- package/dist/platform/books-data.d.ts +1 -0
- package/dist/platform/books-data.js +1 -0
- package/dist/platform/contracts.d.ts +158 -0
- package/dist/platform/contracts.js +0 -0
- package/dist/platform/deploy/config.d.ts +4 -0
- package/dist/platform/deploy/config.js +222 -0
- package/dist/platform/deploy-config.d.ts +1 -0
- package/dist/platform/deploy-config.js +1 -0
- package/dist/platform/deploy-runtime.d.ts +18 -0
- package/dist/platform/deploy-runtime.js +78 -0
- package/dist/platform/env.yaml +394 -0
- package/dist/platform/environment.d.ts +130 -0
- package/dist/platform/environment.js +331 -0
- package/dist/platform/plugin.d.ts +2 -0
- package/dist/platform/plugin.js +4 -0
- package/dist/platform/plugins/constants.d.ts +22 -0
- package/dist/platform/plugins/constants.js +29 -0
- package/dist/platform/plugins/plugin.d.ts +51 -0
- package/dist/platform/plugins/plugin.js +6 -0
- package/dist/platform/plugins/runtime.d.ts +35 -0
- package/dist/platform/plugins/runtime.js +161 -0
- package/dist/platform/plugins.d.ts +6 -0
- package/dist/platform/plugins.js +38 -0
- package/dist/platform/site-config-schema.js +1 -0
- package/dist/platform/tenant/config.d.ts +9 -0
- package/dist/platform/tenant/config.js +154 -0
- package/dist/platform/tenant/runtime-config.d.ts +4 -0
- package/dist/platform/tenant/runtime-config.js +20 -0
- package/dist/platform/tenant-config.d.ts +1 -0
- package/dist/platform/tenant-config.js +1 -0
- package/dist/platform/utils/books-data.d.ts +29 -0
- package/dist/platform/utils/books-data.js +82 -0
- package/dist/platform/utils/site-config-schema.js +321 -0
- package/dist/remote.d.ts +175 -0
- package/dist/remote.js +202 -0
- package/dist/runtime.js +35 -22
- package/dist/scripts/aggregate-book.js +121 -0
- package/dist/scripts/build-dist.js +54 -13
- package/dist/scripts/build-tenant-worker.js +36 -0
- package/dist/scripts/cleanup-markdown.js +373 -0
- package/dist/scripts/cli-test-fixtures.js +48 -0
- package/dist/scripts/config-treeseed.js +95 -0
- package/dist/scripts/ensure-mailpit.js +29 -0
- package/dist/scripts/local-dev.js +129 -0
- package/dist/scripts/logs-mailpit.js +2 -0
- package/dist/scripts/patch-starlight-content-path.js +172 -0
- package/dist/scripts/release-verify.js +34 -6
- package/dist/scripts/run-fixture-astro-command.js +18 -0
- package/dist/scripts/scaffold-site.js +65 -0
- package/dist/scripts/stop-mailpit.js +5 -0
- package/dist/scripts/sync-dev-vars.js +6 -0
- package/dist/scripts/sync-template.js +20 -0
- package/dist/scripts/template-catalog.test.js +100 -0
- package/dist/scripts/template-command.js +31 -0
- package/dist/scripts/tenant-astro-command.js +3 -0
- package/dist/scripts/tenant-build.js +16 -0
- package/dist/scripts/tenant-check.js +7 -0
- package/dist/scripts/tenant-d1-migrate-local.js +11 -0
- package/dist/scripts/tenant-deploy.js +180 -0
- package/dist/scripts/tenant-destroy.js +104 -0
- package/dist/scripts/tenant-dev.js +171 -0
- package/dist/scripts/tenant-lint.js +4 -0
- package/dist/scripts/tenant-test.js +4 -0
- package/dist/scripts/test-cloudflare-local.js +212 -0
- package/dist/scripts/test-scaffold.js +314 -0
- package/dist/scripts/test-smoke.js +71 -13
- package/dist/scripts/treeseed-assert-release-tag-version.js +21 -0
- package/dist/scripts/treeseed-build-dist.js +134 -0
- package/dist/scripts/treeseed-publish-package.js +19 -0
- package/dist/scripts/treeseed-release-verify.js +131 -0
- package/dist/scripts/treeseed-run-ts.js +45 -0
- package/dist/scripts/validate-templates.js +6 -0
- package/dist/scripts/verify-driver.js +29 -0
- package/dist/scripts/workflow-commands.test.js +39 -0
- package/dist/scripts/workspace-close.js +24 -0
- package/dist/scripts/workspace-command-e2e.js +718 -0
- package/dist/scripts/workspace-lint.js +9 -0
- package/dist/scripts/workspace-preflight.js +22 -0
- package/dist/scripts/workspace-publish-changed-packages.js +16 -0
- package/dist/scripts/workspace-release-verify.js +81 -0
- package/dist/scripts/workspace-release.js +42 -0
- package/dist/scripts/workspace-save.js +124 -0
- package/dist/scripts/workspace-start-warning.js +3 -0
- package/dist/scripts/workspace-start.js +71 -0
- package/dist/scripts/workspace-test-unit.js +4 -0
- package/dist/scripts/workspace-test.js +11 -0
- package/dist/sdk-fields.d.ts +11 -0
- package/dist/sdk-fields.js +169 -0
- package/dist/sdk-filters.d.ts +4 -0
- package/dist/sdk-filters.js +12 -15
- package/dist/sdk-types.d.ts +796 -0
- package/dist/sdk-types.js +7 -1
- package/dist/sdk-version.d.ts +2 -0
- package/dist/sdk-version.js +42 -0
- package/dist/sdk.d.ts +215 -0
- package/dist/sdk.js +235 -11
- package/dist/stores/cursor-store.js +9 -3
- package/dist/stores/lease-store.js +8 -2
- package/dist/{src/stores → stores}/message-store.d.ts +1 -1
- package/dist/stores/message-store.js +27 -3
- package/dist/stores/operational-store.d.ts +24 -0
- package/dist/stores/operational-store.js +279 -0
- package/dist/stores/run-store.js +8 -1
- package/dist/stores/subscription-store.js +7 -5
- package/dist/template-catalog.d.ts +13 -0
- package/dist/template-catalog.js +141 -0
- package/dist/treeseed/services/compose.yml +7 -0
- package/dist/treeseed/template-catalog/catalog.fixture.json +55 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/astro.config.d.ts +2 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/astro.config.ts +3 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/package.json +32 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/config.yaml +40 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/empty/.gitkeep +1 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/knowledge/handbook/index.mdx +11 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/pages/welcome.mdx +11 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content.config.d.ts +1 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content.config.ts +3 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/env.yaml +1 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/manifest.yaml +19 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/treeseed.site.yaml +26 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/tsconfig.json +9 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template.config.json +90 -0
- package/dist/utils/agents/contracts/messages.d.ts +88 -0
- package/dist/utils/agents/contracts/messages.js +138 -0
- package/dist/utils/agents/contracts/run.d.ts +20 -0
- package/dist/utils/agents/contracts/run.js +0 -0
- package/dist/utils/agents/runtime-types.d.ts +117 -0
- package/dist/utils/agents/runtime-types.js +4 -0
- package/dist/verification.d.ts +20 -0
- package/dist/verification.js +98 -0
- package/dist/workflow/operations.d.ts +396 -0
- package/dist/workflow/operations.js +841 -0
- package/dist/workflow-state.d.ts +56 -0
- package/dist/workflow-state.js +195 -0
- package/dist/workflow-support.d.ts +9 -0
- package/dist/workflow-support.js +176 -0
- package/dist/workflow.d.ts +111 -0
- package/dist/workflow.js +97 -0
- package/package.json +111 -5
- package/scripts/verify-driver.mjs +29 -0
- package/dist/scripts/.ts-run-1775630384291-crtqr3izsa.js +0 -22
- package/dist/scripts/.ts-run-1775630388025-vnjle0z75a.js +0 -129
- package/dist/scripts/assert-release-tag-version.d.ts +0 -1
- package/dist/scripts/build-dist.d.ts +0 -1
- package/dist/scripts/fixture-tools.d.ts +0 -5
- package/dist/scripts/package-tools.d.ts +0 -15
- package/dist/scripts/publish-package.d.ts +0 -1
- package/dist/scripts/release-verify.d.ts +0 -1
- package/dist/scripts/test-smoke.d.ts +0 -1
- package/dist/src/index.d.ts +0 -6
- package/dist/src/model-registry.d.ts +0 -4
- package/dist/src/sdk-filters.d.ts +0 -4
- package/dist/src/sdk-types.d.ts +0 -285
- package/dist/src/sdk.d.ts +0 -109
- package/dist/test/test-fixture.d.ts +0 -1
- package/dist/test/utils/envelopes.test.d.ts +0 -1
- package/dist/test/utils/sdk.test.d.ts +0 -1
- package/dist/vitest.config.d.ts +0 -2
- /package/dist/{src/frontmatter.d.ts → frontmatter.d.ts} +0 -0
- /package/dist/{src/git-runtime.d.ts → git-runtime.d.ts} +0 -0
- /package/dist/{src/runtime.d.ts → runtime.d.ts} +0 -0
- /package/dist/{src/stores → stores}/cursor-store.d.ts +0 -0
- /package/dist/{src/stores → stores}/envelopes.d.ts +0 -0
- /package/dist/{src/stores → stores}/helpers.d.ts +0 -0
- /package/dist/{src/stores → stores}/lease-store.d.ts +0 -0
- /package/dist/{src/stores → stores}/run-store.d.ts +0 -0
- /package/dist/{src/stores → stores}/subscription-store.d.ts +0 -0
- /package/dist/{src/types → types}/agents.d.ts +0 -0
- /package/dist/{src/types → types}/cloudflare.d.ts +0 -0
- /package/dist/{src/wrangler-d1.d.ts → wrangler-d1.d.ts} +0 -0
|
@@ -5,7 +5,7 @@ export declare class MessageStore extends SqliteStoreBase {
|
|
|
5
5
|
private usesEnvelopeTable;
|
|
6
6
|
getById(id: number): Promise<SdkMessageEntity | null>;
|
|
7
7
|
search(request: SdkSearchRequest): Promise<SdkMessageEntity[]>;
|
|
8
|
-
claim(request: SdkClaimMessageRequest): Promise<SdkMessageEntity | null>;
|
|
8
|
+
claim(request: SdkClaimMessageRequest, strategy?: 'latest' | 'highest_priority' | 'oldest'): Promise<SdkMessageEntity | null>;
|
|
9
9
|
ack(request: SdkAckMessageRequest): Promise<void>;
|
|
10
10
|
create(request: SdkCreateMessageRequest): Promise<SdkMessageEntity>;
|
|
11
11
|
update(request: SdkUpdateRequest): Promise<SdkMessageEntity | null>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { assertExpectedVersion } from "../sdk-version.js";
|
|
1
2
|
import { SqliteStoreBase, nowIso, toSqlValue } from "./helpers.js";
|
|
2
3
|
import { createMessageEnvelope, messageEntityFromEnvelope, TRESEED_ENVELOPE_SCHEMA_VERSION } from "./envelopes.js";
|
|
3
4
|
function messageFromRow(row) {
|
|
@@ -36,6 +37,17 @@ function buildFilterSql(filters = []) {
|
|
|
36
37
|
function buildOrderSql(sort = []) {
|
|
37
38
|
return sort?.length ? `ORDER BY ${sort.map((entry) => `${entry.field} ${entry.direction === "asc" ? "ASC" : "DESC"}`).join(", ")}` : "";
|
|
38
39
|
}
|
|
40
|
+
function claimOrderSql(strategy) {
|
|
41
|
+
switch (strategy) {
|
|
42
|
+
case "oldest":
|
|
43
|
+
return "ORDER BY available_at ASC, priority DESC";
|
|
44
|
+
case "latest":
|
|
45
|
+
return "ORDER BY available_at DESC, priority DESC";
|
|
46
|
+
case "highest_priority":
|
|
47
|
+
default:
|
|
48
|
+
return "ORDER BY priority DESC, available_at ASC";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
39
51
|
class MessageStore extends SqliteStoreBase {
|
|
40
52
|
async usesEnvelopeTable() {
|
|
41
53
|
return this.tableExists("message_queue");
|
|
@@ -68,11 +80,11 @@ class MessageStore extends SqliteStoreBase {
|
|
|
68
80
|
const rows = await this.selectAll(sql);
|
|
69
81
|
return rows.map(messageFromRow);
|
|
70
82
|
}
|
|
71
|
-
async claim(request) {
|
|
83
|
+
async claim(request, strategy = "highest_priority") {
|
|
72
84
|
if (await this.usesEnvelopeTable()) {
|
|
73
85
|
const typeClause2 = request.messageTypes?.length ? ` AND message_type IN (${request.messageTypes.map(toSqlValue).join(", ")})` : "";
|
|
74
86
|
const row2 = await this.selectFirst(
|
|
75
|
-
`SELECT * FROM message_queue WHERE status IN ('pending', 'failed') AND available_at <= ${toSqlValue(nowIso())}${typeClause2}
|
|
87
|
+
`SELECT * FROM message_queue WHERE status IN ('pending', 'failed') AND available_at <= ${toSqlValue(nowIso())}${typeClause2} ${claimOrderSql(strategy)} LIMIT 1`
|
|
76
88
|
);
|
|
77
89
|
if (!row2) {
|
|
78
90
|
return null;
|
|
@@ -86,7 +98,7 @@ class MessageStore extends SqliteStoreBase {
|
|
|
86
98
|
}
|
|
87
99
|
const typeClause = request.messageTypes?.length ? ` AND type IN (${request.messageTypes.map(toSqlValue).join(", ")})` : "";
|
|
88
100
|
const row = await this.selectFirst(
|
|
89
|
-
`SELECT * FROM messages WHERE status IN ('pending', 'failed') AND available_at <= ${toSqlValue(nowIso())}${typeClause}
|
|
101
|
+
`SELECT * FROM messages WHERE status IN ('pending', 'failed') AND available_at <= ${toSqlValue(nowIso())}${typeClause} ${claimOrderSql(strategy)} LIMIT 1`
|
|
90
102
|
);
|
|
91
103
|
if (!row) {
|
|
92
104
|
return null;
|
|
@@ -136,6 +148,11 @@ class MessageStore extends SqliteStoreBase {
|
|
|
136
148
|
if (!id) {
|
|
137
149
|
throw new Error("Message update requires an id.");
|
|
138
150
|
}
|
|
151
|
+
const existing = await this.getById(id);
|
|
152
|
+
if (!existing) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
assertExpectedVersion(request.expectedVersion, existing, `message ${id}`);
|
|
139
156
|
if (await this.usesEnvelopeTable()) {
|
|
140
157
|
const fields2 = [];
|
|
141
158
|
for (const [key, value] of Object.entries(request.data)) {
|
|
@@ -226,18 +243,25 @@ function messageEnvelopeColumn(field) {
|
|
|
226
243
|
case "type":
|
|
227
244
|
return "message_type";
|
|
228
245
|
case "relatedModel":
|
|
246
|
+
case "related_model":
|
|
229
247
|
return "related_model";
|
|
230
248
|
case "relatedId":
|
|
249
|
+
case "related_id":
|
|
231
250
|
return "related_id";
|
|
232
251
|
case "maxAttempts":
|
|
252
|
+
case "max_attempts":
|
|
233
253
|
return "max_attempts";
|
|
234
254
|
case "availableAt":
|
|
255
|
+
case "available_at":
|
|
235
256
|
return "available_at";
|
|
236
257
|
case "claimedBy":
|
|
258
|
+
case "claimed_by":
|
|
237
259
|
return "claimed_by";
|
|
238
260
|
case "claimedAt":
|
|
261
|
+
case "claimed_at":
|
|
239
262
|
return "claimed_at";
|
|
240
263
|
case "leaseExpiresAt":
|
|
264
|
+
case "lease_expires_at":
|
|
241
265
|
return "lease_expires_at";
|
|
242
266
|
default:
|
|
243
267
|
return field.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { SdkAppendTaskEventRequest, SdkClaimTaskRequest, SdkCloseWorkDayRequest, SdkCompleteTaskRequest, SdkCreateReportRequest, SdkCreateTaskRequest, SdkFailTaskRequest, SdkGraphRunEntity, SdkReportEntity, SdkStartWorkDayRequest, SdkTaskEntity, SdkTaskEventEntity, SdkTaskOutputEntity, SdkTaskProgressRequest, SdkTaskSearchRequest, SdkWorkDayEntity } from '../sdk-types.ts';
|
|
2
|
+
import { SqliteStoreBase } from './helpers.ts';
|
|
3
|
+
export declare class OperationalStore extends SqliteStoreBase {
|
|
4
|
+
getWorkDay(id: string): Promise<SdkWorkDayEntity | null>;
|
|
5
|
+
searchWorkDays(limit?: number): Promise<SdkWorkDayEntity[]>;
|
|
6
|
+
startWorkDay(request: SdkStartWorkDayRequest): Promise<SdkWorkDayEntity | null>;
|
|
7
|
+
closeWorkDay(request: SdkCloseWorkDayRequest): Promise<SdkWorkDayEntity | null>;
|
|
8
|
+
getTask(id: string): Promise<SdkTaskEntity | null>;
|
|
9
|
+
searchTasks(request?: SdkTaskSearchRequest): Promise<SdkTaskEntity[]>;
|
|
10
|
+
createTask(request: SdkCreateTaskRequest): Promise<SdkTaskEntity | null>;
|
|
11
|
+
claimTask(request: SdkClaimTaskRequest): Promise<SdkTaskEntity | null>;
|
|
12
|
+
recordTaskProgress(request: SdkTaskProgressRequest): Promise<SdkTaskEntity | null>;
|
|
13
|
+
completeTask(request: SdkCompleteTaskRequest): Promise<SdkTaskEntity | null>;
|
|
14
|
+
failTask(request: SdkFailTaskRequest): Promise<SdkTaskEntity | null>;
|
|
15
|
+
appendTaskEvent(request: SdkAppendTaskEventRequest): Promise<SdkTaskEventEntity | null>;
|
|
16
|
+
listTaskEvents(taskId: string): Promise<SdkTaskEventEntity[]>;
|
|
17
|
+
listTaskOutputs(taskId: string): Promise<SdkTaskOutputEntity[]>;
|
|
18
|
+
createGraphRun(input: Omit<SdkGraphRunEntity, 'createdAt'> & {
|
|
19
|
+
createdAt?: string;
|
|
20
|
+
}): Promise<SdkGraphRunEntity | null>;
|
|
21
|
+
getLatestGraphRun(workDayId: string): Promise<SdkGraphRunEntity | null>;
|
|
22
|
+
createReport(request: SdkCreateReportRequest): Promise<SdkReportEntity | null>;
|
|
23
|
+
getReport(id: string): Promise<SdkReportEntity | null>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import { SqliteStoreBase, nowIso, toSqlValue } from "./helpers.js";
|
|
3
|
+
function json(value) {
|
|
4
|
+
return JSON.stringify(value ?? {});
|
|
5
|
+
}
|
|
6
|
+
function workDayFromRow(row) {
|
|
7
|
+
return {
|
|
8
|
+
id: String(row.id ?? ""),
|
|
9
|
+
projectId: String(row.project_id ?? row.projectId ?? ""),
|
|
10
|
+
state: String(row.state ?? "active"),
|
|
11
|
+
capacityBudget: Number(row.capacity_budget ?? row.capacityBudget ?? 0),
|
|
12
|
+
capacityUsed: Number(row.capacity_used ?? row.capacityUsed ?? 0),
|
|
13
|
+
graphVersion: row.graph_version !== void 0 && row.graph_version !== null ? String(row.graph_version) : row.graphVersion !== void 0 && row.graphVersion !== null ? String(row.graphVersion) : null,
|
|
14
|
+
summaryJson: row.summary_json !== void 0 && row.summary_json !== null ? String(row.summary_json) : row.summaryJson !== void 0 && row.summaryJson !== null ? String(row.summaryJson) : null,
|
|
15
|
+
startedAt: String(row.started_at ?? row.startedAt ?? nowIso()),
|
|
16
|
+
endedAt: row.ended_at !== void 0 && row.ended_at !== null ? String(row.ended_at) : row.endedAt !== void 0 && row.endedAt !== null ? String(row.endedAt) : null,
|
|
17
|
+
createdAt: String(row.created_at ?? row.createdAt ?? nowIso()),
|
|
18
|
+
updatedAt: String(row.updated_at ?? row.updatedAt ?? nowIso())
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function taskFromRow(row) {
|
|
22
|
+
return {
|
|
23
|
+
id: String(row.id ?? ""),
|
|
24
|
+
workDayId: String(row.work_day_id ?? row.workDayId ?? ""),
|
|
25
|
+
agentId: String(row.agent_id ?? row.agentId ?? ""),
|
|
26
|
+
type: String(row.type ?? ""),
|
|
27
|
+
state: String(row.state ?? "pending"),
|
|
28
|
+
priority: Number(row.priority ?? 0),
|
|
29
|
+
idempotencyKey: String(row.idempotency_key ?? row.idempotencyKey ?? ""),
|
|
30
|
+
payloadJson: String(row.payload_json ?? row.payloadJson ?? "{}"),
|
|
31
|
+
payloadHash: row.payload_hash !== void 0 && row.payload_hash !== null ? String(row.payload_hash) : row.payloadHash !== void 0 && row.payloadHash !== null ? String(row.payloadHash) : null,
|
|
32
|
+
attemptCount: Number(row.attempt_count ?? row.attemptCount ?? 0),
|
|
33
|
+
maxAttempts: Number(row.max_attempts ?? row.maxAttempts ?? 3),
|
|
34
|
+
claimedBy: row.claimed_by !== void 0 && row.claimed_by !== null ? String(row.claimed_by) : row.claimedBy !== void 0 && row.claimedBy !== null ? String(row.claimedBy) : null,
|
|
35
|
+
leaseExpiresAt: row.lease_expires_at !== void 0 && row.lease_expires_at !== null ? String(row.lease_expires_at) : row.leaseExpiresAt !== void 0 && row.leaseExpiresAt !== null ? String(row.leaseExpiresAt) : null,
|
|
36
|
+
availableAt: String(row.available_at ?? row.availableAt ?? nowIso()),
|
|
37
|
+
lastErrorCode: row.last_error_code !== void 0 && row.last_error_code !== null ? String(row.last_error_code) : row.lastErrorCode !== void 0 && row.lastErrorCode !== null ? String(row.lastErrorCode) : null,
|
|
38
|
+
lastErrorMessage: row.last_error_message !== void 0 && row.last_error_message !== null ? String(row.last_error_message) : row.lastErrorMessage !== void 0 && row.lastErrorMessage !== null ? String(row.lastErrorMessage) : null,
|
|
39
|
+
graphVersion: row.graph_version !== void 0 && row.graph_version !== null ? String(row.graph_version) : row.graphVersion !== void 0 && row.graphVersion !== null ? String(row.graphVersion) : null,
|
|
40
|
+
parentTaskId: row.parent_task_id !== void 0 && row.parent_task_id !== null ? String(row.parent_task_id) : row.parentTaskId !== void 0 && row.parentTaskId !== null ? String(row.parentTaskId) : null,
|
|
41
|
+
createdAt: String(row.created_at ?? row.createdAt ?? nowIso()),
|
|
42
|
+
startedAt: row.started_at !== void 0 && row.started_at !== null ? String(row.started_at) : row.startedAt !== void 0 && row.startedAt !== null ? String(row.startedAt) : null,
|
|
43
|
+
completedAt: row.completed_at !== void 0 && row.completed_at !== null ? String(row.completed_at) : row.completedAt !== void 0 && row.completedAt !== null ? String(row.completedAt) : null,
|
|
44
|
+
updatedAt: String(row.updated_at ?? row.updatedAt ?? nowIso())
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function taskEventFromRow(row) {
|
|
48
|
+
return {
|
|
49
|
+
id: String(row.id ?? ""),
|
|
50
|
+
taskId: String(row.task_id ?? row.taskId ?? ""),
|
|
51
|
+
seq: Number(row.seq ?? 0),
|
|
52
|
+
kind: String(row.kind ?? ""),
|
|
53
|
+
dataJson: String(row.data_json ?? row.dataJson ?? "{}"),
|
|
54
|
+
createdAt: String(row.created_at ?? row.createdAt ?? nowIso())
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function taskOutputFromRow(row) {
|
|
58
|
+
return {
|
|
59
|
+
id: String(row.id ?? ""),
|
|
60
|
+
taskId: String(row.task_id ?? row.taskId ?? ""),
|
|
61
|
+
outputJson: String(row.output_json ?? row.outputJson ?? "{}"),
|
|
62
|
+
outputRef: row.output_ref !== void 0 && row.output_ref !== null ? String(row.output_ref) : row.outputRef !== void 0 && row.outputRef !== null ? String(row.outputRef) : null,
|
|
63
|
+
createdAt: String(row.created_at ?? row.createdAt ?? nowIso())
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function graphRunFromRow(row) {
|
|
67
|
+
return {
|
|
68
|
+
id: String(row.id ?? ""),
|
|
69
|
+
workDayId: String(row.work_day_id ?? row.workDayId ?? ""),
|
|
70
|
+
corpusHash: String(row.corpus_hash ?? row.corpusHash ?? ""),
|
|
71
|
+
graphVersion: String(row.graph_version ?? row.graphVersion ?? ""),
|
|
72
|
+
queryJson: row.query_json !== void 0 && row.query_json !== null ? String(row.query_json) : row.queryJson !== void 0 && row.queryJson !== null ? String(row.queryJson) : null,
|
|
73
|
+
seedIdsJson: row.seed_ids_json !== void 0 && row.seed_ids_json !== null ? String(row.seed_ids_json) : row.seedIdsJson !== void 0 && row.seedIdsJson !== null ? String(row.seedIdsJson) : null,
|
|
74
|
+
selectedNodeIdsJson: row.selected_node_ids_json !== void 0 && row.selected_node_ids_json !== null ? String(row.selected_node_ids_json) : row.selectedNodeIdsJson !== void 0 && row.selectedNodeIdsJson !== null ? String(row.selectedNodeIdsJson) : null,
|
|
75
|
+
statsJson: row.stats_json !== void 0 && row.stats_json !== null ? String(row.stats_json) : row.statsJson !== void 0 && row.statsJson !== null ? String(row.statsJson) : null,
|
|
76
|
+
snapshotRef: row.snapshot_ref !== void 0 && row.snapshot_ref !== null ? String(row.snapshot_ref) : row.snapshotRef !== void 0 && row.snapshotRef !== null ? String(row.snapshotRef) : null,
|
|
77
|
+
createdAt: String(row.created_at ?? row.createdAt ?? nowIso())
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function reportFromRow(row) {
|
|
81
|
+
return {
|
|
82
|
+
id: String(row.id ?? ""),
|
|
83
|
+
workDayId: String(row.work_day_id ?? row.workDayId ?? ""),
|
|
84
|
+
kind: String(row.kind ?? ""),
|
|
85
|
+
bodyJson: String(row.body_json ?? row.bodyJson ?? "{}"),
|
|
86
|
+
renderedRef: row.rendered_ref !== void 0 && row.rendered_ref !== null ? String(row.rendered_ref) : row.renderedRef !== void 0 && row.renderedRef !== null ? String(row.renderedRef) : null,
|
|
87
|
+
sentAt: row.sent_at !== void 0 && row.sent_at !== null ? String(row.sent_at) : row.sentAt !== void 0 && row.sentAt !== null ? String(row.sentAt) : null,
|
|
88
|
+
createdAt: String(row.created_at ?? row.createdAt ?? nowIso())
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
class OperationalStore extends SqliteStoreBase {
|
|
92
|
+
async getWorkDay(id) {
|
|
93
|
+
const row = await this.selectFirst(`SELECT * FROM work_days WHERE id = ${toSqlValue(id)} LIMIT 1`);
|
|
94
|
+
return row ? workDayFromRow(row) : null;
|
|
95
|
+
}
|
|
96
|
+
async searchWorkDays(limit = 20) {
|
|
97
|
+
const rows = await this.selectAll(`SELECT * FROM work_days ORDER BY updated_at DESC LIMIT ${limit}`);
|
|
98
|
+
return rows.map(workDayFromRow);
|
|
99
|
+
}
|
|
100
|
+
async startWorkDay(request) {
|
|
101
|
+
const id = request.id ?? crypto.randomUUID();
|
|
102
|
+
const timestamp = nowIso();
|
|
103
|
+
await this.execute(
|
|
104
|
+
`INSERT OR REPLACE INTO work_days (id, project_id, state, capacity_budget, capacity_used, graph_version, summary_json, started_at, ended_at, created_at, updated_at) VALUES (${toSqlValue(id)}, ${toSqlValue(request.projectId)}, 'active', ${Number(request.capacityBudget ?? 0)}, 0, ${toSqlValue(request.graphVersion ?? null)}, ${toSqlValue(json(request.summary ?? null))}, ${toSqlValue(timestamp)}, NULL, COALESCE((SELECT created_at FROM work_days WHERE id = ${toSqlValue(id)}), ${toSqlValue(timestamp)}), ${toSqlValue(timestamp)})`
|
|
105
|
+
);
|
|
106
|
+
return this.getWorkDay(id);
|
|
107
|
+
}
|
|
108
|
+
async closeWorkDay(request) {
|
|
109
|
+
const existing = await this.getWorkDay(request.id);
|
|
110
|
+
if (!existing) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const timestamp = nowIso();
|
|
114
|
+
await this.execute(
|
|
115
|
+
`UPDATE work_days SET state = ${toSqlValue(request.state ?? "completed")}, summary_json = ${toSqlValue(json(request.summary ?? null))}, ended_at = ${toSqlValue(timestamp)}, updated_at = ${toSqlValue(timestamp)} WHERE id = ${toSqlValue(request.id)}`
|
|
116
|
+
);
|
|
117
|
+
return this.getWorkDay(request.id);
|
|
118
|
+
}
|
|
119
|
+
async getTask(id) {
|
|
120
|
+
const row = await this.selectFirst(`SELECT * FROM tasks WHERE id = ${toSqlValue(id)} LIMIT 1`);
|
|
121
|
+
return row ? taskFromRow(row) : null;
|
|
122
|
+
}
|
|
123
|
+
async searchTasks(request = {}) {
|
|
124
|
+
const clauses = [];
|
|
125
|
+
if (request.workDayId) clauses.push(`work_day_id = ${toSqlValue(request.workDayId)}`);
|
|
126
|
+
if (request.agentId) clauses.push(`agent_id = ${toSqlValue(request.agentId)}`);
|
|
127
|
+
if (request.state) {
|
|
128
|
+
const states = Array.isArray(request.state) ? request.state : [request.state];
|
|
129
|
+
clauses.push(`state IN (${states.map((entry) => toSqlValue(entry)).join(", ")})`);
|
|
130
|
+
}
|
|
131
|
+
const sql = [
|
|
132
|
+
"SELECT * FROM tasks",
|
|
133
|
+
clauses.length ? `WHERE ${clauses.join(" AND ")}` : "",
|
|
134
|
+
"ORDER BY priority DESC, available_at ASC, created_at ASC",
|
|
135
|
+
`LIMIT ${request.limit ?? 50}`
|
|
136
|
+
].filter(Boolean).join(" ");
|
|
137
|
+
const rows = await this.selectAll(sql);
|
|
138
|
+
return rows.map(taskFromRow);
|
|
139
|
+
}
|
|
140
|
+
async createTask(request) {
|
|
141
|
+
const id = request.id ?? crypto.randomUUID();
|
|
142
|
+
const timestamp = nowIso();
|
|
143
|
+
await this.execute(
|
|
144
|
+
`INSERT OR REPLACE INTO tasks (id, work_day_id, agent_id, type, state, priority, idempotency_key, payload_json, payload_hash, attempt_count, max_attempts, claimed_by, lease_expires_at, available_at, last_error_code, last_error_message, graph_version, parent_task_id, created_at, started_at, completed_at, updated_at) VALUES (${toSqlValue(id)}, ${toSqlValue(request.workDayId)}, ${toSqlValue(request.agentId)}, ${toSqlValue(request.type)}, ${toSqlValue(request.state ?? "pending")}, ${Number(request.priority ?? 0)}, ${toSqlValue(request.idempotencyKey)}, ${toSqlValue(json(request.payload))}, ${toSqlValue(request.payloadHash ?? null)}, 0, ${Number(request.maxAttempts ?? 3)}, NULL, NULL, ${toSqlValue(request.availableAt ?? timestamp)}, NULL, NULL, ${toSqlValue(request.graphVersion ?? null)}, ${toSqlValue(request.parentTaskId ?? null)}, COALESCE((SELECT created_at FROM tasks WHERE id = ${toSqlValue(id)}), ${toSqlValue(timestamp)}), NULL, NULL, ${toSqlValue(timestamp)})`
|
|
145
|
+
);
|
|
146
|
+
return this.getTask(id);
|
|
147
|
+
}
|
|
148
|
+
async claimTask(request) {
|
|
149
|
+
const existing = await this.getTask(request.id);
|
|
150
|
+
if (!existing) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
const timestamp = nowIso();
|
|
154
|
+
const leaseExpiresAt = new Date(Date.now() + request.leaseSeconds * 1e3).toISOString();
|
|
155
|
+
await this.execute(
|
|
156
|
+
`UPDATE tasks SET state = 'claimed', claimed_by = ${toSqlValue(request.workerId)}, lease_expires_at = ${toSqlValue(leaseExpiresAt)}, attempt_count = attempt_count + 1, started_at = COALESCE(started_at, ${toSqlValue(timestamp)}), updated_at = ${toSqlValue(timestamp)} WHERE id = ${toSqlValue(request.id)}`
|
|
157
|
+
);
|
|
158
|
+
return this.getTask(request.id);
|
|
159
|
+
}
|
|
160
|
+
async recordTaskProgress(request) {
|
|
161
|
+
const existing = await this.getTask(request.id);
|
|
162
|
+
if (!existing) {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
const patch = request.patch ?? {};
|
|
166
|
+
const currentPayload = JSON.parse(existing.payloadJson);
|
|
167
|
+
const nextPayload = { ...currentPayload, ...patch };
|
|
168
|
+
const timestamp = nowIso();
|
|
169
|
+
await this.execute(
|
|
170
|
+
`UPDATE tasks SET state = ${toSqlValue(request.state ?? existing.state)}, payload_json = ${toSqlValue(json(nextPayload))}, claimed_by = ${toSqlValue(request.workerId ?? existing.claimedBy)}, updated_at = ${toSqlValue(timestamp)} WHERE id = ${toSqlValue(request.id)}`
|
|
171
|
+
);
|
|
172
|
+
if (request.appendEvent?.kind) {
|
|
173
|
+
await this.appendTaskEvent({
|
|
174
|
+
taskId: request.id,
|
|
175
|
+
kind: request.appendEvent.kind,
|
|
176
|
+
data: request.appendEvent.data,
|
|
177
|
+
actor: request.actor
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
return this.getTask(request.id);
|
|
181
|
+
}
|
|
182
|
+
async completeTask(request) {
|
|
183
|
+
const existing = await this.getTask(request.id);
|
|
184
|
+
if (!existing) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
const timestamp = nowIso();
|
|
188
|
+
await this.execute(
|
|
189
|
+
`UPDATE tasks SET state = 'completed', completed_at = ${toSqlValue(timestamp)}, lease_expires_at = NULL, updated_at = ${toSqlValue(timestamp)} WHERE id = ${toSqlValue(request.id)}`
|
|
190
|
+
);
|
|
191
|
+
if (request.output) {
|
|
192
|
+
await this.execute(
|
|
193
|
+
`INSERT INTO task_outputs (id, task_id, output_json, output_ref, created_at) VALUES (${toSqlValue(crypto.randomUUID())}, ${toSqlValue(request.id)}, ${toSqlValue(json(request.output))}, ${toSqlValue(request.outputRef ?? null)}, ${toSqlValue(timestamp)})`
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
if (request.summary) {
|
|
197
|
+
await this.appendTaskEvent({
|
|
198
|
+
taskId: request.id,
|
|
199
|
+
kind: "completed",
|
|
200
|
+
data: request.summary,
|
|
201
|
+
actor: request.actor
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
return this.getTask(request.id);
|
|
205
|
+
}
|
|
206
|
+
async failTask(request) {
|
|
207
|
+
const existing = await this.getTask(request.id);
|
|
208
|
+
if (!existing) {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
const timestamp = nowIso();
|
|
212
|
+
const nextState = request.retryable ? "pending" : "failed";
|
|
213
|
+
await this.execute(
|
|
214
|
+
`UPDATE tasks SET state = ${toSqlValue(nextState)}, available_at = ${toSqlValue(request.nextVisibleAt ?? existing.availableAt)}, last_error_code = ${toSqlValue(request.errorCode ?? null)}, last_error_message = ${toSqlValue(request.errorMessage)}, lease_expires_at = NULL, updated_at = ${toSqlValue(timestamp)} WHERE id = ${toSqlValue(request.id)}`
|
|
215
|
+
);
|
|
216
|
+
await this.appendTaskEvent({
|
|
217
|
+
taskId: request.id,
|
|
218
|
+
kind: nextState === "pending" ? "retry_scheduled" : "failed",
|
|
219
|
+
data: { errorCode: request.errorCode ?? null, errorMessage: request.errorMessage },
|
|
220
|
+
actor: request.actor
|
|
221
|
+
});
|
|
222
|
+
return this.getTask(request.id);
|
|
223
|
+
}
|
|
224
|
+
async appendTaskEvent(request) {
|
|
225
|
+
const seqRow = await this.selectFirst(
|
|
226
|
+
`SELECT COALESCE(MAX(seq), 0) + 1 AS next_seq FROM task_events WHERE task_id = ${toSqlValue(request.taskId)}`
|
|
227
|
+
);
|
|
228
|
+
const seq = Number(seqRow?.next_seq ?? 1);
|
|
229
|
+
const id = crypto.randomUUID();
|
|
230
|
+
const timestamp = nowIso();
|
|
231
|
+
await this.execute(
|
|
232
|
+
`INSERT INTO task_events (id, task_id, seq, kind, data_json, created_at) VALUES (${toSqlValue(id)}, ${toSqlValue(request.taskId)}, ${seq}, ${toSqlValue(request.kind)}, ${toSqlValue(json({ ...request.data ?? {}, actor: request.actor }))}, ${toSqlValue(timestamp)})`
|
|
233
|
+
);
|
|
234
|
+
const row = await this.selectFirst(`SELECT * FROM task_events WHERE id = ${toSqlValue(id)} LIMIT 1`);
|
|
235
|
+
return row ? taskEventFromRow(row) : null;
|
|
236
|
+
}
|
|
237
|
+
async listTaskEvents(taskId) {
|
|
238
|
+
const rows = await this.selectAll(
|
|
239
|
+
`SELECT * FROM task_events WHERE task_id = ${toSqlValue(taskId)} ORDER BY seq ASC`
|
|
240
|
+
);
|
|
241
|
+
return rows.map(taskEventFromRow);
|
|
242
|
+
}
|
|
243
|
+
async listTaskOutputs(taskId) {
|
|
244
|
+
const rows = await this.selectAll(
|
|
245
|
+
`SELECT * FROM task_outputs WHERE task_id = ${toSqlValue(taskId)} ORDER BY created_at ASC`
|
|
246
|
+
);
|
|
247
|
+
return rows.map(taskOutputFromRow);
|
|
248
|
+
}
|
|
249
|
+
async createGraphRun(input) {
|
|
250
|
+
const timestamp = input.createdAt ?? nowIso();
|
|
251
|
+
await this.execute(
|
|
252
|
+
`INSERT OR REPLACE INTO graph_runs (id, work_day_id, corpus_hash, graph_version, query_json, seed_ids_json, selected_node_ids_json, stats_json, snapshot_ref, created_at) VALUES (${toSqlValue(input.id)}, ${toSqlValue(input.workDayId)}, ${toSqlValue(input.corpusHash)}, ${toSqlValue(input.graphVersion)}, ${toSqlValue(input.queryJson ?? null)}, ${toSqlValue(input.seedIdsJson ?? null)}, ${toSqlValue(input.selectedNodeIdsJson ?? null)}, ${toSqlValue(input.statsJson ?? null)}, ${toSqlValue(input.snapshotRef ?? null)}, ${toSqlValue(timestamp)})`
|
|
253
|
+
);
|
|
254
|
+
const row = await this.selectFirst(`SELECT * FROM graph_runs WHERE id = ${toSqlValue(input.id)} LIMIT 1`);
|
|
255
|
+
return row ? graphRunFromRow(row) : null;
|
|
256
|
+
}
|
|
257
|
+
async getLatestGraphRun(workDayId) {
|
|
258
|
+
const row = await this.selectFirst(
|
|
259
|
+
`SELECT * FROM graph_runs WHERE work_day_id = ${toSqlValue(workDayId)} ORDER BY created_at DESC LIMIT 1`
|
|
260
|
+
);
|
|
261
|
+
return row ? graphRunFromRow(row) : null;
|
|
262
|
+
}
|
|
263
|
+
async createReport(request) {
|
|
264
|
+
const id = request.id ?? crypto.randomUUID();
|
|
265
|
+
const timestamp = nowIso();
|
|
266
|
+
await this.execute(
|
|
267
|
+
`INSERT OR REPLACE INTO reports (id, work_day_id, kind, body_json, rendered_ref, sent_at, created_at) VALUES (${toSqlValue(id)}, ${toSqlValue(request.workDayId)}, ${toSqlValue(request.kind)}, ${toSqlValue(json(request.body))}, ${toSqlValue(request.renderedRef ?? null)}, ${toSqlValue(request.sentAt ?? null)}, ${toSqlValue(timestamp)})`
|
|
268
|
+
);
|
|
269
|
+
const row = await this.selectFirst(`SELECT * FROM reports WHERE id = ${toSqlValue(id)} LIMIT 1`);
|
|
270
|
+
return row ? reportFromRow(row) : null;
|
|
271
|
+
}
|
|
272
|
+
async getReport(id) {
|
|
273
|
+
const row = await this.selectFirst(`SELECT * FROM reports WHERE id = ${toSqlValue(id)} LIMIT 1`);
|
|
274
|
+
return row ? reportFromRow(row) : null;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
export {
|
|
278
|
+
OperationalStore
|
|
279
|
+
};
|
package/dist/stores/run-store.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { assertExpectedVersion } from "../sdk-version.js";
|
|
1
2
|
import { SqliteStoreBase, nowIso, toSqlValue } from "./helpers.js";
|
|
2
3
|
import { createRunEnvelope, runEntityFromEnvelope, TRESEED_ENVELOPE_SCHEMA_VERSION } from "./envelopes.js";
|
|
3
4
|
function runFromRecord(row) {
|
|
@@ -109,10 +110,16 @@ class RunStore extends SqliteStoreBase {
|
|
|
109
110
|
return run;
|
|
110
111
|
}
|
|
111
112
|
async update(request) {
|
|
113
|
+
const runId = String(request.data.run_id ?? request.data.runId ?? request.id ?? request.key ?? "");
|
|
114
|
+
assertExpectedVersion(
|
|
115
|
+
request.expectedVersion,
|
|
116
|
+
runId ? await this.getByKey(runId) : null,
|
|
117
|
+
`agent_run "${runId}"`
|
|
118
|
+
);
|
|
112
119
|
return this.record({
|
|
113
120
|
run: {
|
|
114
121
|
...request.data,
|
|
115
|
-
runId
|
|
122
|
+
runId
|
|
116
123
|
}
|
|
117
124
|
});
|
|
118
125
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { assertExpectedVersion } from "../sdk-version.js";
|
|
1
2
|
import { SqliteStoreBase, toSqlValue } from "./helpers.js";
|
|
2
3
|
import { createSubscriptionEnvelope, subscriptionEntityFromEnvelope, TRESEED_ENVELOPE_SCHEMA_VERSION } from "./envelopes.js";
|
|
3
4
|
function subscriptionFromRow(row) {
|
|
@@ -72,8 +73,8 @@ class SubscriptionStore extends SqliteStoreBase {
|
|
|
72
73
|
name: data.name !== void 0 && data.name !== null ? String(data.name) : null,
|
|
73
74
|
status: typeof data.status === "string" ? data.status : "active",
|
|
74
75
|
source: typeof data.source === "string" ? data.source : "sdk",
|
|
75
|
-
consentAt: typeof data.consent_at === "string" ? data.consent_at : (/* @__PURE__ */ new Date()).toISOString(),
|
|
76
|
-
ipHash: typeof data.ip_hash === "string" ? data.ip_hash : ""
|
|
76
|
+
consentAt: typeof (data.consent_at ?? data.consentAt) === "string" ? String(data.consent_at ?? data.consentAt) : (/* @__PURE__ */ new Date()).toISOString(),
|
|
77
|
+
ipHash: typeof (data.ip_hash ?? data.ipHash) === "string" ? String(data.ip_hash ?? data.ipHash) : ""
|
|
77
78
|
});
|
|
78
79
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
79
80
|
await this.execute(
|
|
@@ -82,7 +83,7 @@ class SubscriptionStore extends SqliteStoreBase {
|
|
|
82
83
|
return this.getByKey(envelope.payload.email);
|
|
83
84
|
}
|
|
84
85
|
await this.execute(
|
|
85
|
-
`INSERT INTO subscriptions (email, name, status, source, consent_at, created_at, updated_at, ip_hash) VALUES (${toSqlValue(data.email)}, ${toSqlValue(data.name ?? null)}, ${toSqlValue(data.status ?? "active")}, ${toSqlValue(data.source ?? "sdk")}, ${toSqlValue(data.consent_at ?? (/* @__PURE__ */ new Date()).toISOString())}, ${toSqlValue(data.created_at ?? (/* @__PURE__ */ new Date()).toISOString())}, ${toSqlValue(data.updated_at ?? (/* @__PURE__ */ new Date()).toISOString())}, ${toSqlValue(data.ip_hash ?? "")})`
|
|
86
|
+
`INSERT INTO subscriptions (email, name, status, source, consent_at, created_at, updated_at, ip_hash) VALUES (${toSqlValue(data.email)}, ${toSqlValue(data.name ?? null)}, ${toSqlValue(data.status ?? "active")}, ${toSqlValue(data.source ?? "sdk")}, ${toSqlValue(data.consent_at ?? data.consentAt ?? (/* @__PURE__ */ new Date()).toISOString())}, ${toSqlValue(data.created_at ?? data.createdAt ?? (/* @__PURE__ */ new Date()).toISOString())}, ${toSqlValue(data.updated_at ?? data.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString())}, ${toSqlValue(data.ip_hash ?? data.ipHash ?? "")})`
|
|
86
87
|
);
|
|
87
88
|
return this.getByKey(String(data.email));
|
|
88
89
|
}
|
|
@@ -92,6 +93,7 @@ class SubscriptionStore extends SqliteStoreBase {
|
|
|
92
93
|
if (!existing) {
|
|
93
94
|
throw new Error(`No subscription found for "${key}".`);
|
|
94
95
|
}
|
|
96
|
+
assertExpectedVersion(request.expectedVersion, existing, `subscription "${existing.email}"`);
|
|
95
97
|
const next = {
|
|
96
98
|
...existing,
|
|
97
99
|
...request.data,
|
|
@@ -103,8 +105,8 @@ class SubscriptionStore extends SqliteStoreBase {
|
|
|
103
105
|
name: next.name ?? null,
|
|
104
106
|
status: String(next.status ?? "active"),
|
|
105
107
|
source: typeof next.source === "string" ? next.source : "sdk",
|
|
106
|
-
consentAt: typeof next.consent_at === "string" ? next.consent_at : null,
|
|
107
|
-
ipHash: typeof next.ip_hash === "string" ? next.ip_hash : "",
|
|
108
|
+
consentAt: typeof (next.consent_at ?? next.consentAt) === "string" ? String(next.consent_at ?? next.consentAt) : null,
|
|
109
|
+
ipHash: typeof (next.ip_hash ?? next.ipHash) === "string" ? String(next.ip_hash ?? next.ipHash) : "",
|
|
108
110
|
meta: { legacyId: existing.id }
|
|
109
111
|
});
|
|
110
112
|
await this.execute(
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SdkTemplateCatalogEntry, SdkTemplateCatalogResponse } from './sdk-types.ts';
|
|
2
|
+
export interface RemoteTemplateCatalogClientOptions {
|
|
3
|
+
endpoint: string;
|
|
4
|
+
fetchImpl?: typeof fetch;
|
|
5
|
+
}
|
|
6
|
+
export declare function parseTemplateCatalogResponse(payload: unknown): SdkTemplateCatalogResponse;
|
|
7
|
+
export declare class RemoteTemplateCatalogClient {
|
|
8
|
+
private readonly endpoint;
|
|
9
|
+
private readonly fetchImpl;
|
|
10
|
+
constructor(options: RemoteTemplateCatalogClientOptions);
|
|
11
|
+
listTemplates(): Promise<SdkTemplateCatalogResponse>;
|
|
12
|
+
getTemplate(id: string): Promise<SdkTemplateCatalogEntry | null>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
function expectRecord(value, label) {
|
|
4
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
5
|
+
throw new Error(`Invalid template catalog response: expected ${label} to be an object.`);
|
|
6
|
+
}
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
function expectString(value, label) {
|
|
10
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
11
|
+
throw new Error(`Invalid template catalog response: expected ${label} to be a non-empty string.`);
|
|
12
|
+
}
|
|
13
|
+
return value.trim();
|
|
14
|
+
}
|
|
15
|
+
function optionalString(value) {
|
|
16
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
17
|
+
}
|
|
18
|
+
function optionalStringArray(value, label) {
|
|
19
|
+
if (value === void 0) {
|
|
20
|
+
return void 0;
|
|
21
|
+
}
|
|
22
|
+
if (!Array.isArray(value)) {
|
|
23
|
+
throw new Error(`Invalid template catalog response: expected ${label} to be an array.`);
|
|
24
|
+
}
|
|
25
|
+
return value.map((entry, index) => expectString(entry, `${label}[${index}]`));
|
|
26
|
+
}
|
|
27
|
+
function optionalBoolean(value, label) {
|
|
28
|
+
if (value === void 0) {
|
|
29
|
+
return void 0;
|
|
30
|
+
}
|
|
31
|
+
if (typeof value !== "boolean") {
|
|
32
|
+
throw new Error(`Invalid template catalog response: expected ${label} to be a boolean.`);
|
|
33
|
+
}
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
function expectNumber(value, label) {
|
|
37
|
+
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
38
|
+
throw new Error(`Invalid template catalog response: expected ${label} to be a number.`);
|
|
39
|
+
}
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
function normalizeTemplateCatalogEntry(value) {
|
|
43
|
+
const record = expectRecord(value, "template entry");
|
|
44
|
+
const publisher = expectRecord(record.publisher, "publisher");
|
|
45
|
+
const fulfillment = expectRecord(record.fulfillment, "fulfillment");
|
|
46
|
+
const source = expectRecord(fulfillment.source, "fulfillment.source");
|
|
47
|
+
const offer = record.offer === void 0 ? void 0 : expectRecord(record.offer, "offer");
|
|
48
|
+
return {
|
|
49
|
+
id: expectString(record.id ?? record.slug, "id"),
|
|
50
|
+
displayName: expectString(record.displayName ?? record.title, "displayName"),
|
|
51
|
+
description: expectString(record.description, "description"),
|
|
52
|
+
summary: expectString(record.summary, "summary"),
|
|
53
|
+
status: expectString(record.status ?? "draft", "status"),
|
|
54
|
+
featured: optionalBoolean(record.featured, "featured"),
|
|
55
|
+
category: expectString(record.category, "category"),
|
|
56
|
+
audience: optionalStringArray(record.audience, "audience") ?? [],
|
|
57
|
+
tags: optionalStringArray(record.tags, "tags") ?? [],
|
|
58
|
+
publisher: {
|
|
59
|
+
id: expectString(publisher.id, "publisher.id"),
|
|
60
|
+
name: expectString(publisher.name, "publisher.name"),
|
|
61
|
+
url: optionalString(publisher.url)
|
|
62
|
+
},
|
|
63
|
+
publisherVerified: optionalBoolean(record.publisherVerified, "publisherVerified"),
|
|
64
|
+
templateVersion: expectString(record.templateVersion, "templateVersion"),
|
|
65
|
+
templateApiVersion: expectNumber(record.templateApiVersion, "templateApiVersion"),
|
|
66
|
+
minCliVersion: expectString(record.minCliVersion, "minCliVersion"),
|
|
67
|
+
minCoreVersion: optionalString(record.minCoreVersion),
|
|
68
|
+
fulfillment: {
|
|
69
|
+
source: {
|
|
70
|
+
kind: "git",
|
|
71
|
+
repoUrl: expectString(source.repoUrl, "fulfillment.source.repoUrl"),
|
|
72
|
+
directory: expectString(source.directory, "fulfillment.source.directory"),
|
|
73
|
+
ref: expectString(source.ref, "fulfillment.source.ref"),
|
|
74
|
+
integrity: optionalString(source.integrity)
|
|
75
|
+
},
|
|
76
|
+
hooksPolicy: expectString(fulfillment.hooksPolicy ?? "builtin_only", "fulfillment.hooksPolicy"),
|
|
77
|
+
supportsReconcile: typeof fulfillment.supportsReconcile === "boolean" ? fulfillment.supportsReconcile : true
|
|
78
|
+
},
|
|
79
|
+
offer: offer ? {
|
|
80
|
+
priceModel: optionalString(offer.priceModel),
|
|
81
|
+
license: optionalString(offer.license),
|
|
82
|
+
support: optionalString(offer.support)
|
|
83
|
+
} : void 0,
|
|
84
|
+
relatedBooks: optionalStringArray(record.relatedBooks, "relatedBooks") ?? [],
|
|
85
|
+
relatedKnowledge: optionalStringArray(record.relatedKnowledge, "relatedKnowledge") ?? [],
|
|
86
|
+
relatedObjectives: optionalStringArray(record.relatedObjectives, "relatedObjectives") ?? []
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function parseTemplateCatalogResponse(payload) {
|
|
90
|
+
if (Array.isArray(payload)) {
|
|
91
|
+
return {
|
|
92
|
+
items: payload.map((entry) => normalizeTemplateCatalogEntry(entry)),
|
|
93
|
+
meta: {}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const record = expectRecord(payload, "root");
|
|
97
|
+
const envelopePayload = record.payload;
|
|
98
|
+
const items = Array.isArray(record.items) ? record.items : Array.isArray(envelopePayload) ? envelopePayload : Array.isArray(expectRecord(envelopePayload ?? {}, "payload").items) ? expectRecord(envelopePayload ?? {}, "payload").items : null;
|
|
99
|
+
if (!items) {
|
|
100
|
+
throw new Error("Invalid template catalog response: expected an item array.");
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
items: items.map((entry) => normalizeTemplateCatalogEntry(entry)),
|
|
104
|
+
meta: typeof record.meta === "object" && record.meta !== null ? record.meta : {}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
async function loadTemplateCatalogPayload(endpoint, fetchImpl) {
|
|
108
|
+
if (endpoint.startsWith("file:")) {
|
|
109
|
+
const filePath = endpoint.startsWith("file://") ? new URL(endpoint) : resolve(process.cwd(), endpoint.slice("file:".length));
|
|
110
|
+
const raw = readFileSync(filePath, "utf8");
|
|
111
|
+
return JSON.parse(raw);
|
|
112
|
+
}
|
|
113
|
+
const response = await fetchImpl(endpoint, {
|
|
114
|
+
headers: {
|
|
115
|
+
accept: "application/json"
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
if (!response.ok) {
|
|
119
|
+
throw new Error(`Template catalog request failed with ${response.status} ${response.statusText}.`);
|
|
120
|
+
}
|
|
121
|
+
return response.json();
|
|
122
|
+
}
|
|
123
|
+
class RemoteTemplateCatalogClient {
|
|
124
|
+
endpoint;
|
|
125
|
+
fetchImpl;
|
|
126
|
+
constructor(options) {
|
|
127
|
+
this.endpoint = options.endpoint;
|
|
128
|
+
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
129
|
+
}
|
|
130
|
+
async listTemplates() {
|
|
131
|
+
return parseTemplateCatalogResponse(await loadTemplateCatalogPayload(this.endpoint, this.fetchImpl));
|
|
132
|
+
}
|
|
133
|
+
async getTemplate(id) {
|
|
134
|
+
const catalog = await this.listTemplates();
|
|
135
|
+
return catalog.items.find((entry) => entry.id === id) ?? null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
export {
|
|
139
|
+
RemoteTemplateCatalogClient,
|
|
140
|
+
parseTemplateCatalogResponse
|
|
141
|
+
};
|