@cat-factory/worker 1.0.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/LICENSE +21 -0
- package/migrations/0001_init.sql +57 -0
- package/migrations/0002_execution_workflow.sql +13 -0
- package/migrations/0003_token_usage.sql +20 -0
- package/migrations/0004_github_projections.sql +141 -0
- package/migrations/0005_block_fragments.sql +4 -0
- package/migrations/0005_confluence.sql +48 -0
- package/migrations/0006_storage_retention.sql +10 -0
- package/migrations/0007_block_model.sql +5 -0
- package/migrations/0008_environments.sql +59 -0
- package/migrations/0009_block_test_target.sql +6 -0
- package/migrations/0010_block_pull_request.sql +5 -0
- package/migrations/0010_bootstrap.sql +44 -0
- package/migrations/0011_repo_blueprints.sql +28 -0
- package/migrations/0012_document_sources.sql +62 -0
- package/migrations/0013_runner_pools.sql +32 -0
- package/migrations/0014_task_sources.sql +49 -0
- package/migrations/0015_bootstrap_freeform.sql +32 -0
- package/migrations/0016_workspace_owner.sql +14 -0
- package/migrations/0017_accounts.sql +52 -0
- package/migrations/0017_bootstrap_board.sql +16 -0
- package/migrations/0018_bootstrap_failure.sql +14 -0
- package/migrations/0019_agent_runs.sql +52 -0
- package/migrations/0019_github_installation_app.sql +7 -0
- package/migrations/0020_drop_executions.sql +5 -0
- package/migrations/0020_prompt_fragments.sql +57 -0
- package/migrations/0021_requirement_reviews.sql +25 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Igor Savin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
-- Initial schema for the Agent Architecture Board.
|
|
2
|
+
--
|
|
3
|
+
-- Every aggregate is scoped by `workspace_id` and keyed by a composite primary
|
|
4
|
+
-- key (workspace_id, id), so the stable seed ids can be reused across boards.
|
|
5
|
+
-- JSON-shaped fields (dependsOn, features, pipeline agentKinds, execution steps)
|
|
6
|
+
-- are stored as TEXT and (de)serialised in the repository mappers.
|
|
7
|
+
|
|
8
|
+
CREATE TABLE workspaces (
|
|
9
|
+
id TEXT NOT NULL PRIMARY KEY,
|
|
10
|
+
name TEXT NOT NULL,
|
|
11
|
+
created_at INTEGER NOT NULL
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
CREATE TABLE blocks (
|
|
15
|
+
workspace_id TEXT NOT NULL,
|
|
16
|
+
id TEXT NOT NULL,
|
|
17
|
+
title TEXT NOT NULL,
|
|
18
|
+
type TEXT NOT NULL,
|
|
19
|
+
description TEXT NOT NULL DEFAULT '',
|
|
20
|
+
pos_x REAL NOT NULL DEFAULT 0,
|
|
21
|
+
pos_y REAL NOT NULL DEFAULT 0,
|
|
22
|
+
status TEXT NOT NULL,
|
|
23
|
+
progress REAL NOT NULL DEFAULT 0,
|
|
24
|
+
depends_on TEXT NOT NULL DEFAULT '[]',
|
|
25
|
+
execution_id TEXT,
|
|
26
|
+
level TEXT NOT NULL DEFAULT 'frame',
|
|
27
|
+
parent_id TEXT,
|
|
28
|
+
confidence REAL,
|
|
29
|
+
confidence_threshold REAL,
|
|
30
|
+
module_name TEXT,
|
|
31
|
+
features TEXT,
|
|
32
|
+
PRIMARY KEY (workspace_id, id)
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
CREATE INDEX idx_blocks_parent ON blocks (workspace_id, parent_id);
|
|
36
|
+
|
|
37
|
+
CREATE TABLE pipelines (
|
|
38
|
+
workspace_id TEXT NOT NULL,
|
|
39
|
+
id TEXT NOT NULL,
|
|
40
|
+
name TEXT NOT NULL,
|
|
41
|
+
agent_kinds TEXT NOT NULL DEFAULT '[]',
|
|
42
|
+
PRIMARY KEY (workspace_id, id)
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
CREATE TABLE executions (
|
|
46
|
+
workspace_id TEXT NOT NULL,
|
|
47
|
+
id TEXT NOT NULL,
|
|
48
|
+
block_id TEXT NOT NULL,
|
|
49
|
+
pipeline_id TEXT NOT NULL,
|
|
50
|
+
pipeline_name TEXT NOT NULL,
|
|
51
|
+
steps TEXT NOT NULL DEFAULT '[]',
|
|
52
|
+
current_step INTEGER NOT NULL DEFAULT 0,
|
|
53
|
+
status TEXT NOT NULL,
|
|
54
|
+
PRIMARY KEY (workspace_id, id)
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
CREATE UNIQUE INDEX idx_executions_block ON executions (workspace_id, block_id);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
-- Durable execution support. `updated_at` is a lease the cron sweeper uses to
|
|
2
|
+
-- find runs that are still `running` but whose Workflows instance has died;
|
|
3
|
+
-- `error` records an agent failure that survived the per-step retries;
|
|
4
|
+
-- `workflow_instance_id` records the durable instance driving the run (equal to
|
|
5
|
+
-- the execution id today, stored explicitly so that can change without a schema
|
|
6
|
+
-- change). Existing rows default safely so tick-mode is unaffected.
|
|
7
|
+
|
|
8
|
+
ALTER TABLE executions ADD COLUMN updated_at INTEGER NOT NULL DEFAULT 0;
|
|
9
|
+
ALTER TABLE executions ADD COLUMN error TEXT;
|
|
10
|
+
ALTER TABLE executions ADD COLUMN workflow_instance_id TEXT;
|
|
11
|
+
|
|
12
|
+
-- Supports the sweeper's "running + stale lease" scan.
|
|
13
|
+
CREATE INDEX idx_executions_running_lease ON executions (status, updated_at);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-- Spend safeguard ledger. One row per metered LLM call: the token counts and a
|
|
2
|
+
-- cost estimate priced at record time (so historical rows stay stable even if
|
|
3
|
+
-- pricing config changes). The budget is org-wide, so usage is summed across all
|
|
4
|
+
-- workspaces for the current billing period via the created_at index.
|
|
5
|
+
|
|
6
|
+
CREATE TABLE token_usage (
|
|
7
|
+
id TEXT NOT NULL PRIMARY KEY,
|
|
8
|
+
workspace_id TEXT NOT NULL,
|
|
9
|
+
execution_id TEXT,
|
|
10
|
+
agent_kind TEXT NOT NULL,
|
|
11
|
+
provider TEXT NOT NULL,
|
|
12
|
+
model TEXT NOT NULL,
|
|
13
|
+
input_tokens INTEGER NOT NULL DEFAULT 0,
|
|
14
|
+
output_tokens INTEGER NOT NULL DEFAULT 0,
|
|
15
|
+
cost_estimate REAL NOT NULL DEFAULT 0,
|
|
16
|
+
created_at INTEGER NOT NULL
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
-- Supports the "sum usage since the start of this period" budget query.
|
|
20
|
+
CREATE INDEX idx_token_usage_created ON token_usage (created_at);
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
-- GitHub integration: local projections of the GitHub data cat-factory reads
|
|
2
|
+
-- often, so the UI/agents don't hit the API on every read and aren't blocked by
|
|
3
|
+
-- rate limits. Projections are kept fresh by webhook-driven incremental syncs,
|
|
4
|
+
-- on-demand resyncs, and a periodic cron reconciliation pass.
|
|
5
|
+
--
|
|
6
|
+
-- Conventions follow the existing schema (0001/0003): aggregates are scoped by
|
|
7
|
+
-- workspace via composite primary keys, timestamps are INTEGER epoch-ms, JSON is
|
|
8
|
+
-- stored as TEXT, there are no foreign keys, and rows that disappear upstream are
|
|
9
|
+
-- soft-deleted via a `deleted_at` tombstone (so a webhook delete and a later full
|
|
10
|
+
-- reconciliation converge without losing audit history).
|
|
11
|
+
|
|
12
|
+
-- One GitHub App installation per workspace. Also caches the short-lived (~1h)
|
|
13
|
+
-- installation access token + its expiry so we don't re-mint on every call; a
|
|
14
|
+
-- lost cache is harmless (the token is cheaply re-derivable from the app JWT).
|
|
15
|
+
CREATE TABLE github_installations (
|
|
16
|
+
installation_id INTEGER NOT NULL PRIMARY KEY,
|
|
17
|
+
workspace_id TEXT NOT NULL,
|
|
18
|
+
account_login TEXT NOT NULL,
|
|
19
|
+
target_type TEXT NOT NULL,
|
|
20
|
+
cached_token TEXT,
|
|
21
|
+
token_expires_at INTEGER,
|
|
22
|
+
created_at INTEGER NOT NULL,
|
|
23
|
+
deleted_at INTEGER
|
|
24
|
+
);
|
|
25
|
+
-- A workspace connects to at most one *live* installation. Partial so a
|
|
26
|
+
-- tombstoned binding doesn't block reconnecting the workspace to a new one.
|
|
27
|
+
CREATE UNIQUE INDEX idx_gh_install_workspace
|
|
28
|
+
ON github_installations (workspace_id)
|
|
29
|
+
WHERE deleted_at IS NULL;
|
|
30
|
+
|
|
31
|
+
CREATE TABLE github_repos (
|
|
32
|
+
workspace_id TEXT NOT NULL,
|
|
33
|
+
github_id INTEGER NOT NULL,
|
|
34
|
+
installation_id INTEGER NOT NULL,
|
|
35
|
+
owner TEXT NOT NULL,
|
|
36
|
+
name TEXT NOT NULL,
|
|
37
|
+
default_branch TEXT,
|
|
38
|
+
private INTEGER NOT NULL DEFAULT 0,
|
|
39
|
+
block_id TEXT, -- optional link to a board block
|
|
40
|
+
etag TEXT,
|
|
41
|
+
synced_at INTEGER NOT NULL,
|
|
42
|
+
deleted_at INTEGER,
|
|
43
|
+
PRIMARY KEY (workspace_id, github_id)
|
|
44
|
+
);
|
|
45
|
+
CREATE INDEX idx_gh_repos_install ON github_repos (installation_id);
|
|
46
|
+
|
|
47
|
+
CREATE TABLE github_branches (
|
|
48
|
+
workspace_id TEXT NOT NULL,
|
|
49
|
+
repo_github_id INTEGER NOT NULL,
|
|
50
|
+
name TEXT NOT NULL,
|
|
51
|
+
head_sha TEXT NOT NULL,
|
|
52
|
+
protected INTEGER NOT NULL DEFAULT 0,
|
|
53
|
+
synced_at INTEGER NOT NULL,
|
|
54
|
+
deleted_at INTEGER,
|
|
55
|
+
PRIMARY KEY (workspace_id, repo_github_id, name)
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
CREATE TABLE github_pull_requests (
|
|
59
|
+
workspace_id TEXT NOT NULL,
|
|
60
|
+
repo_github_id INTEGER NOT NULL,
|
|
61
|
+
number INTEGER NOT NULL,
|
|
62
|
+
github_id INTEGER NOT NULL,
|
|
63
|
+
title TEXT NOT NULL,
|
|
64
|
+
state TEXT NOT NULL,
|
|
65
|
+
head_ref TEXT,
|
|
66
|
+
base_ref TEXT,
|
|
67
|
+
head_sha TEXT,
|
|
68
|
+
merged INTEGER NOT NULL DEFAULT 0,
|
|
69
|
+
author TEXT,
|
|
70
|
+
gh_updated_at INTEGER,
|
|
71
|
+
synced_at INTEGER NOT NULL,
|
|
72
|
+
deleted_at INTEGER,
|
|
73
|
+
PRIMARY KEY (workspace_id, repo_github_id, number)
|
|
74
|
+
);
|
|
75
|
+
-- Supports the board's "open PRs for this workspace" reads.
|
|
76
|
+
CREATE INDEX idx_gh_pr_state ON github_pull_requests (workspace_id, state);
|
|
77
|
+
|
|
78
|
+
CREATE TABLE github_issues (
|
|
79
|
+
workspace_id TEXT NOT NULL,
|
|
80
|
+
repo_github_id INTEGER NOT NULL,
|
|
81
|
+
number INTEGER NOT NULL,
|
|
82
|
+
github_id INTEGER NOT NULL,
|
|
83
|
+
title TEXT NOT NULL,
|
|
84
|
+
state TEXT NOT NULL,
|
|
85
|
+
author TEXT,
|
|
86
|
+
labels TEXT NOT NULL DEFAULT '[]',
|
|
87
|
+
gh_updated_at INTEGER,
|
|
88
|
+
synced_at INTEGER NOT NULL,
|
|
89
|
+
deleted_at INTEGER,
|
|
90
|
+
PRIMARY KEY (workspace_id, repo_github_id, number)
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
CREATE TABLE github_commits (
|
|
94
|
+
workspace_id TEXT NOT NULL,
|
|
95
|
+
repo_github_id INTEGER NOT NULL,
|
|
96
|
+
sha TEXT NOT NULL,
|
|
97
|
+
message TEXT NOT NULL,
|
|
98
|
+
author TEXT,
|
|
99
|
+
authored_at INTEGER,
|
|
100
|
+
synced_at INTEGER NOT NULL,
|
|
101
|
+
PRIMARY KEY (workspace_id, repo_github_id, sha)
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
CREATE TABLE github_check_runs (
|
|
105
|
+
workspace_id TEXT NOT NULL,
|
|
106
|
+
repo_github_id INTEGER NOT NULL,
|
|
107
|
+
github_id INTEGER NOT NULL,
|
|
108
|
+
head_sha TEXT NOT NULL,
|
|
109
|
+
name TEXT NOT NULL,
|
|
110
|
+
status TEXT NOT NULL,
|
|
111
|
+
conclusion TEXT,
|
|
112
|
+
synced_at INTEGER NOT NULL,
|
|
113
|
+
PRIMARY KEY (workspace_id, repo_github_id, github_id)
|
|
114
|
+
);
|
|
115
|
+
-- Supports "what is the CI status for this commit?" gating reads.
|
|
116
|
+
CREATE INDEX idx_gh_checks_sha ON github_check_runs (workspace_id, repo_github_id, head_sha);
|
|
117
|
+
|
|
118
|
+
-- Incremental sync bookkeeping per (repo, entity kind): the ETag for
|
|
119
|
+
-- conditional GETs and/or the `since` timestamp for delta listing.
|
|
120
|
+
CREATE TABLE github_sync_cursors (
|
|
121
|
+
workspace_id TEXT NOT NULL,
|
|
122
|
+
repo_github_id INTEGER NOT NULL,
|
|
123
|
+
kind TEXT NOT NULL,
|
|
124
|
+
etag TEXT,
|
|
125
|
+
last_synced_at INTEGER,
|
|
126
|
+
since_iso TEXT,
|
|
127
|
+
PRIMARY KEY (workspace_id, repo_github_id, kind)
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
-- Rate-limit ledger: one row per observed `x-ratelimit-*` snapshot, imitating
|
|
131
|
+
-- the token_usage spend ledger. Lets us track headroom and back off proactively.
|
|
132
|
+
CREATE TABLE github_rate_limits (
|
|
133
|
+
id TEXT NOT NULL PRIMARY KEY,
|
|
134
|
+
installation_id INTEGER NOT NULL,
|
|
135
|
+
resource TEXT NOT NULL,
|
|
136
|
+
limit_total INTEGER,
|
|
137
|
+
remaining INTEGER,
|
|
138
|
+
reset_at INTEGER,
|
|
139
|
+
observed_at INTEGER NOT NULL
|
|
140
|
+
);
|
|
141
|
+
CREATE INDEX idx_gh_ratelimit_observed ON github_rate_limits (observed_at);
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
-- Per-block selection of best-practice prompt fragments. Stored as a JSON array
|
|
2
|
+
-- of fragment ids (TEXT), mirroring the existing `features` column; (de)serialised
|
|
3
|
+
-- in the repository mappers. Nullable: existing blocks have no selection.
|
|
4
|
+
ALTER TABLE blocks ADD COLUMN fragment_ids TEXT;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
-- Confluence integration: a workspace's connection to a Confluence Cloud site,
|
|
2
|
+
-- and local projections of the requirement/RFC/PRD pages it has imported. The
|
|
3
|
+
-- cached page body backs both the doc → board planner and the agent-context
|
|
4
|
+
-- injection, so neither path re-fetches the page on every read.
|
|
5
|
+
--
|
|
6
|
+
-- Conventions follow the existing schema (0001/0004): aggregates are scoped by
|
|
7
|
+
-- workspace, timestamps are INTEGER epoch-ms, there are no foreign keys, and a
|
|
8
|
+
-- soft-delete `deleted_at` tombstone with a partial unique index lets a workspace
|
|
9
|
+
-- disconnect and reconnect without the binding colliding.
|
|
10
|
+
|
|
11
|
+
-- At most one *live* Confluence connection per workspace. The API token is stored
|
|
12
|
+
-- as plaintext-at-rest (like github_installations.cached_token) and is never sent
|
|
13
|
+
-- on the wire; it is read only by the import path to authenticate to the site.
|
|
14
|
+
CREATE TABLE confluence_connections (
|
|
15
|
+
workspace_id TEXT NOT NULL,
|
|
16
|
+
base_url TEXT NOT NULL,
|
|
17
|
+
account_email TEXT NOT NULL,
|
|
18
|
+
api_token TEXT NOT NULL,
|
|
19
|
+
created_at INTEGER NOT NULL,
|
|
20
|
+
deleted_at INTEGER,
|
|
21
|
+
PRIMARY KEY (workspace_id, account_email)
|
|
22
|
+
);
|
|
23
|
+
-- A workspace connects to at most one live site. Partial so a tombstoned binding
|
|
24
|
+
-- doesn't block reconnecting the workspace to a new account.
|
|
25
|
+
CREATE UNIQUE INDEX idx_confluence_conn_workspace
|
|
26
|
+
ON confluence_connections (workspace_id)
|
|
27
|
+
WHERE deleted_at IS NULL;
|
|
28
|
+
|
|
29
|
+
-- One row per imported Confluence page. `body` holds the full storage-format
|
|
30
|
+
-- XHTML (consumed by the planner); `excerpt` is a short plain-text preview.
|
|
31
|
+
-- `linked_block_id` attaches the page to a board block as agent context.
|
|
32
|
+
CREATE TABLE confluence_documents (
|
|
33
|
+
workspace_id TEXT NOT NULL,
|
|
34
|
+
page_id TEXT NOT NULL,
|
|
35
|
+
space_key TEXT NOT NULL,
|
|
36
|
+
title TEXT NOT NULL,
|
|
37
|
+
url TEXT NOT NULL,
|
|
38
|
+
version INTEGER NOT NULL DEFAULT 0,
|
|
39
|
+
excerpt TEXT NOT NULL DEFAULT '',
|
|
40
|
+
body TEXT NOT NULL DEFAULT '',
|
|
41
|
+
linked_block_id TEXT,
|
|
42
|
+
synced_at INTEGER NOT NULL,
|
|
43
|
+
deleted_at INTEGER,
|
|
44
|
+
PRIMARY KEY (workspace_id, page_id)
|
|
45
|
+
);
|
|
46
|
+
-- Supports the execution engine's "documents linked to this block" lookup.
|
|
47
|
+
CREATE INDEX idx_confluence_docs_block
|
|
48
|
+
ON confluence_documents (workspace_id, linked_block_id);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
-- Storage & data-retention follow-ups (see docs/storage-and-retention.md).
|
|
2
|
+
--
|
|
3
|
+
-- The unbounded ledgers already have the indexes their retention sweeps need:
|
|
4
|
+
-- token_usage.idx_token_usage_created (created_at) and
|
|
5
|
+
-- github_rate_limits.idx_gh_ratelimit_observed (observed_at). github_commits is
|
|
6
|
+
-- the one append-only projection without a column the retention pass can scan, so
|
|
7
|
+
-- add an index on authored_at to keep the periodic `DELETE … WHERE authored_at <
|
|
8
|
+
-- horizon` cheap (and bounded by the rows actually being reclaimed).
|
|
9
|
+
|
|
10
|
+
CREATE INDEX idx_gh_commits_authored ON github_commits (authored_at);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
-- Per-block selection of the LLM model to run its agents with. Stored as the
|
|
2
|
+
-- catalog model id (TEXT); resolved to a concrete provider/model at run time
|
|
3
|
+
-- (see MODEL_CATALOG in @cat-factory/core). Nullable: existing blocks have no
|
|
4
|
+
-- selection and fall back to the agent routing's default model.
|
|
5
|
+
ALTER TABLE blocks ADD COLUMN model_id TEXT;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
-- Ephemeral environment provider integration: a workspace's binding to its own
|
|
2
|
+
-- self-rolled environment management API (described by a declarative manifest),
|
|
3
|
+
-- and the registry of environments that have been provisioned from it.
|
|
4
|
+
--
|
|
5
|
+
-- Conventions follow the existing schema (0001/0004/0005): aggregates are scoped
|
|
6
|
+
-- by workspace, timestamps are INTEGER epoch-ms, there are no foreign keys, and a
|
|
7
|
+
-- soft-delete `deleted_at` tombstone with a partial unique index lets a workspace
|
|
8
|
+
-- re-register without the binding colliding.
|
|
9
|
+
--
|
|
10
|
+
-- Credentials are stored as opaque ciphertext (AES-256-GCM via SecretCipher),
|
|
11
|
+
-- never plaintext: `secrets_cipher` holds the per-tenant management-API secret
|
|
12
|
+
-- bundle; `access_cipher` holds a provisioned env's own access creds; and
|
|
13
|
+
-- `provision_fields_cipher` holds the fields captured at provision time that
|
|
14
|
+
-- status/teardown calls interpolate.
|
|
15
|
+
|
|
16
|
+
-- At most one *live* environment provider per workspace.
|
|
17
|
+
CREATE TABLE environment_connections (
|
|
18
|
+
workspace_id TEXT NOT NULL,
|
|
19
|
+
provider_id TEXT NOT NULL,
|
|
20
|
+
label TEXT NOT NULL,
|
|
21
|
+
base_url TEXT NOT NULL,
|
|
22
|
+
manifest_json TEXT NOT NULL,
|
|
23
|
+
secrets_cipher TEXT NOT NULL,
|
|
24
|
+
created_at INTEGER NOT NULL,
|
|
25
|
+
deleted_at INTEGER,
|
|
26
|
+
PRIMARY KEY (workspace_id, provider_id)
|
|
27
|
+
);
|
|
28
|
+
-- A workspace registers at most one live provider. Partial so a tombstoned
|
|
29
|
+
-- binding doesn't block re-registering the workspace with a new provider.
|
|
30
|
+
CREATE UNIQUE INDEX idx_environment_conn_workspace
|
|
31
|
+
ON environment_connections (workspace_id)
|
|
32
|
+
WHERE deleted_at IS NULL;
|
|
33
|
+
|
|
34
|
+
-- One row per provisioned environment.
|
|
35
|
+
CREATE TABLE environments (
|
|
36
|
+
id TEXT NOT NULL PRIMARY KEY,
|
|
37
|
+
workspace_id TEXT NOT NULL,
|
|
38
|
+
block_id TEXT,
|
|
39
|
+
execution_id TEXT,
|
|
40
|
+
provider_id TEXT NOT NULL,
|
|
41
|
+
external_id TEXT,
|
|
42
|
+
url TEXT,
|
|
43
|
+
status TEXT NOT NULL,
|
|
44
|
+
access_cipher TEXT,
|
|
45
|
+
provision_fields_cipher TEXT,
|
|
46
|
+
created_at INTEGER NOT NULL,
|
|
47
|
+
expires_at INTEGER,
|
|
48
|
+
last_error TEXT,
|
|
49
|
+
deleted_at INTEGER
|
|
50
|
+
);
|
|
51
|
+
-- Discovery: the live environment provisioned for a board block (consumed by the
|
|
52
|
+
-- execution engine to enrich downstream tester context).
|
|
53
|
+
CREATE INDEX idx_environments_block
|
|
54
|
+
ON environments (workspace_id, block_id)
|
|
55
|
+
WHERE deleted_at IS NULL;
|
|
56
|
+
-- TTL sweep: the cron tears down environments whose expiry has elapsed.
|
|
57
|
+
CREATE INDEX idx_environments_expiry
|
|
58
|
+
ON environments (expires_at)
|
|
59
|
+
WHERE deleted_at IS NULL AND expires_at IS NOT NULL;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
-- Per-block choice of where acceptance / Playwright tests run: 'github_actions'
|
|
2
|
+
-- (project CI, against a service spun up in the same run) or 'ephemeral_env'
|
|
3
|
+
-- (the provisioned ephemeral environment for the run). Stored as TEXT; the
|
|
4
|
+
-- acceptance-testing agents fold it into their prompt. Nullable: existing blocks
|
|
5
|
+
-- have no preference recorded.
|
|
6
|
+
ALTER TABLE blocks ADD COLUMN test_target TEXT;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
-- The pull request a block's implementation ("implementer") agent opened for its
|
|
2
|
+
-- work: a small JSON ref ({ url, number?, branch? }) recorded on a task once its
|
|
3
|
+
-- container agent pushes a branch and opens a PR. Stored as TEXT and
|
|
4
|
+
-- (de)serialised in the repository mappers. Nullable: blocks with no PR yet.
|
|
5
|
+
ALTER TABLE blocks ADD COLUMN pull_request TEXT;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
-- Repo-bootstrap feature: a workspace-scoped, CRUD-managed list of "reference
|
|
2
|
+
-- architectures" (base/golden-template repos new repositories are bootstrapped
|
|
3
|
+
-- from) and a log of "bootstrap repo" jobs, one row per run with its outcome.
|
|
4
|
+
--
|
|
5
|
+
-- Conventions follow the existing schema (0001/0004/0005/0008): aggregates are
|
|
6
|
+
-- scoped by workspace, timestamps are INTEGER epoch-ms, there are no foreign
|
|
7
|
+
-- keys, and reference architectures carry a soft-delete `deleted_at` tombstone.
|
|
8
|
+
-- Bootstrap jobs are an append-mostly log (no soft delete): they are inserted as
|
|
9
|
+
-- `running` and updated in place to their terminal `succeeded`/`failed` state.
|
|
10
|
+
|
|
11
|
+
-- The managed reference architecture list.
|
|
12
|
+
CREATE TABLE reference_architectures (
|
|
13
|
+
id TEXT NOT NULL PRIMARY KEY,
|
|
14
|
+
workspace_id TEXT NOT NULL,
|
|
15
|
+
name TEXT NOT NULL,
|
|
16
|
+
description TEXT NOT NULL DEFAULT '',
|
|
17
|
+
repo_owner TEXT NOT NULL,
|
|
18
|
+
repo_name TEXT NOT NULL,
|
|
19
|
+
default_instructions TEXT NOT NULL DEFAULT '',
|
|
20
|
+
created_at INTEGER NOT NULL,
|
|
21
|
+
updated_at INTEGER NOT NULL,
|
|
22
|
+
deleted_at INTEGER
|
|
23
|
+
);
|
|
24
|
+
CREATE INDEX idx_reference_architectures_workspace
|
|
25
|
+
ON reference_architectures (workspace_id)
|
|
26
|
+
WHERE deleted_at IS NULL;
|
|
27
|
+
|
|
28
|
+
-- One row per "bootstrap repo" run.
|
|
29
|
+
CREATE TABLE bootstrap_jobs (
|
|
30
|
+
id TEXT NOT NULL PRIMARY KEY,
|
|
31
|
+
workspace_id TEXT NOT NULL,
|
|
32
|
+
reference_architecture_id TEXT NOT NULL,
|
|
33
|
+
reference_architecture_name TEXT NOT NULL,
|
|
34
|
+
repo_name TEXT NOT NULL,
|
|
35
|
+
repo_owner TEXT,
|
|
36
|
+
repo_url TEXT,
|
|
37
|
+
instructions TEXT NOT NULL DEFAULT '',
|
|
38
|
+
status TEXT NOT NULL,
|
|
39
|
+
error TEXT,
|
|
40
|
+
created_at INTEGER NOT NULL,
|
|
41
|
+
updated_at INTEGER NOT NULL
|
|
42
|
+
);
|
|
43
|
+
CREATE INDEX idx_bootstrap_jobs_workspace
|
|
44
|
+
ON bootstrap_jobs (workspace_id, created_at);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
-- Board-scan feature: the persisted "repository blueprint" — a decomposition of
|
|
2
|
+
-- one repository into the canonical service → modules → features tree, anchored
|
|
3
|
+
-- to codebase paths. Exactly one blueprint is kept per (workspace, repo): a
|
|
4
|
+
-- re-scan replaces it in place, so the row is the single current map rather than
|
|
5
|
+
-- an append-only log.
|
|
6
|
+
--
|
|
7
|
+
-- Conventions follow the existing schema (0001/0004/0010): aggregates are scoped
|
|
8
|
+
-- by workspace, timestamps are INTEGER epoch-ms, and there are no foreign keys.
|
|
9
|
+
-- The tree is stored as a JSON blob in `service_json` (read/written whole), like
|
|
10
|
+
-- other structured-but-opaque payloads in the projections.
|
|
11
|
+
|
|
12
|
+
CREATE TABLE repo_blueprints (
|
|
13
|
+
id TEXT NOT NULL PRIMARY KEY,
|
|
14
|
+
workspace_id TEXT NOT NULL,
|
|
15
|
+
repo_owner TEXT NOT NULL,
|
|
16
|
+
repo_name TEXT NOT NULL,
|
|
17
|
+
source TEXT NOT NULL,
|
|
18
|
+
service_json TEXT NOT NULL,
|
|
19
|
+
created_at INTEGER NOT NULL,
|
|
20
|
+
updated_at INTEGER NOT NULL
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
-- One blueprint per repository within a workspace (enforces the upsert key).
|
|
24
|
+
CREATE UNIQUE INDEX idx_repo_blueprints_repo
|
|
25
|
+
ON repo_blueprints (workspace_id, repo_owner, repo_name);
|
|
26
|
+
|
|
27
|
+
CREATE INDEX idx_repo_blueprints_workspace
|
|
28
|
+
ON repo_blueprints (workspace_id, updated_at);
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
-- Document-source integration: a workspace's connections to external document
|
|
2
|
+
-- sources (Confluence, Notion, …) and local projections of the requirement /
|
|
3
|
+
-- RFC / PRD pages it has imported from them. Supersedes the Confluence-specific
|
|
4
|
+
-- tables (migration 0005): a `source` discriminator tags every row, so one pair
|
|
5
|
+
-- of tables serves every provider. The cached page body (normalized to Markdown)
|
|
6
|
+
-- backs both the doc → board planner and the agent-context injection.
|
|
7
|
+
--
|
|
8
|
+
-- Conventions follow the existing schema: aggregates are scoped by workspace,
|
|
9
|
+
-- timestamps are INTEGER epoch-ms, there are no foreign keys, and a soft-delete
|
|
10
|
+
-- `deleted_at` tombstone lets a workspace disconnect and reconnect.
|
|
11
|
+
|
|
12
|
+
-- At most one live connection per (workspace, source). The credential bag is a
|
|
13
|
+
-- JSON object of string→string, stored plaintext-at-rest (like the cached GitHub
|
|
14
|
+
-- installation token) and never sent on the wire; it is read only by the import
|
|
15
|
+
-- path to authenticate to the source.
|
|
16
|
+
CREATE TABLE document_connections (
|
|
17
|
+
workspace_id TEXT NOT NULL,
|
|
18
|
+
source TEXT NOT NULL,
|
|
19
|
+
credentials TEXT NOT NULL,
|
|
20
|
+
label TEXT NOT NULL DEFAULT '',
|
|
21
|
+
created_at INTEGER NOT NULL,
|
|
22
|
+
deleted_at INTEGER,
|
|
23
|
+
PRIMARY KEY (workspace_id, source)
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
-- One row per imported page. `body` holds the normalized Markdown (consumed by
|
|
27
|
+
-- the planner); `excerpt` is a short plain-text preview. `linked_block_id`
|
|
28
|
+
-- attaches the page to a board block as agent context.
|
|
29
|
+
CREATE TABLE documents (
|
|
30
|
+
workspace_id TEXT NOT NULL,
|
|
31
|
+
source TEXT NOT NULL,
|
|
32
|
+
external_id TEXT NOT NULL,
|
|
33
|
+
title TEXT NOT NULL,
|
|
34
|
+
url TEXT NOT NULL,
|
|
35
|
+
excerpt TEXT NOT NULL DEFAULT '',
|
|
36
|
+
body TEXT NOT NULL DEFAULT '',
|
|
37
|
+
linked_block_id TEXT,
|
|
38
|
+
synced_at INTEGER NOT NULL,
|
|
39
|
+
deleted_at INTEGER,
|
|
40
|
+
PRIMARY KEY (workspace_id, source, external_id)
|
|
41
|
+
);
|
|
42
|
+
-- Supports the execution engine's "documents linked to this block" lookup.
|
|
43
|
+
CREATE INDEX idx_documents_block
|
|
44
|
+
ON documents (workspace_id, linked_block_id);
|
|
45
|
+
|
|
46
|
+
-- Carry over any live Confluence connections/documents from migration 0005, then
|
|
47
|
+
-- drop the superseded tables. Only live rows are migrated (the new schema keys
|
|
48
|
+
-- connections by (workspace_id, source), so historical tombstones can't collide).
|
|
49
|
+
INSERT INTO document_connections (workspace_id, source, credentials, label, created_at, deleted_at)
|
|
50
|
+
SELECT workspace_id, 'confluence',
|
|
51
|
+
json_object('baseUrl', base_url, 'accountEmail', account_email, 'apiToken', api_token),
|
|
52
|
+
base_url, created_at, NULL
|
|
53
|
+
FROM confluence_connections
|
|
54
|
+
WHERE deleted_at IS NULL;
|
|
55
|
+
|
|
56
|
+
INSERT INTO documents (workspace_id, source, external_id, title, url, excerpt, body, linked_block_id, synced_at, deleted_at)
|
|
57
|
+
SELECT workspace_id, 'confluence', page_id, title, url, excerpt, body, linked_block_id, synced_at, NULL
|
|
58
|
+
FROM confluence_documents
|
|
59
|
+
WHERE deleted_at IS NULL;
|
|
60
|
+
|
|
61
|
+
DROP TABLE confluence_documents;
|
|
62
|
+
DROP TABLE confluence_connections;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
-- Self-hosted runner-pool integration ("bring your own infra"): a workspace's
|
|
2
|
+
-- binding to its own container runner pool's scheduler API (described by a
|
|
3
|
+
-- declarative manifest), used instead of per-run Cloudflare Containers for the
|
|
4
|
+
-- repo-operating coding jobs.
|
|
5
|
+
--
|
|
6
|
+
-- Conventions follow the existing schema (esp. 0008_environments): aggregates are
|
|
7
|
+
-- scoped by workspace, timestamps are INTEGER epoch-ms, there are no foreign keys,
|
|
8
|
+
-- and a soft-delete `deleted_at` tombstone with a partial unique index lets a
|
|
9
|
+
-- workspace re-register without the binding colliding.
|
|
10
|
+
--
|
|
11
|
+
-- The per-tenant scheduler-API secret bundle is stored as opaque ciphertext
|
|
12
|
+
-- (AES-256-GCM via SecretCipher), never plaintext, in `secrets_cipher`. There is
|
|
13
|
+
-- no per-job table: the execution engine already tracks each job durably and the
|
|
14
|
+
-- pool is addressed by the cat-factory job id, so poll/release need no extra row.
|
|
15
|
+
|
|
16
|
+
-- At most one *live* runner pool per workspace.
|
|
17
|
+
CREATE TABLE runner_pool_connections (
|
|
18
|
+
workspace_id TEXT NOT NULL,
|
|
19
|
+
provider_id TEXT NOT NULL,
|
|
20
|
+
label TEXT NOT NULL,
|
|
21
|
+
base_url TEXT NOT NULL,
|
|
22
|
+
manifest_json TEXT NOT NULL,
|
|
23
|
+
secrets_cipher TEXT NOT NULL,
|
|
24
|
+
created_at INTEGER NOT NULL,
|
|
25
|
+
deleted_at INTEGER,
|
|
26
|
+
PRIMARY KEY (workspace_id, provider_id)
|
|
27
|
+
);
|
|
28
|
+
-- A workspace registers at most one live pool. Partial so a tombstoned binding
|
|
29
|
+
-- doesn't block re-registering the workspace with a new pool.
|
|
30
|
+
CREATE UNIQUE INDEX idx_runner_pool_conn_workspace
|
|
31
|
+
ON runner_pool_connections (workspace_id)
|
|
32
|
+
WHERE deleted_at IS NULL;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
-- Task-source integration: a workspace's connections to external task/issue
|
|
2
|
+
-- trackers (Jira, …) and local projections of the individual issues it has
|
|
3
|
+
-- imported from them. A sibling of the document-source tables (migration 0012),
|
|
4
|
+
-- but task-shaped: an issue is a structured record (status/type/assignee/…) used
|
|
5
|
+
-- as extra agent context, not a page body expanded into board structure.
|
|
6
|
+
--
|
|
7
|
+
-- Conventions follow the existing schema: aggregates are scoped by workspace,
|
|
8
|
+
-- timestamps are INTEGER epoch-ms, there are no foreign keys, and a soft-delete
|
|
9
|
+
-- `deleted_at` tombstone lets a workspace disconnect and reconnect.
|
|
10
|
+
|
|
11
|
+
-- At most one live connection per (workspace, source). The credential bag is a
|
|
12
|
+
-- JSON object of string→string, encrypted at rest (AES-256-GCM envelope) and
|
|
13
|
+
-- never sent on the wire; it is read only by the import path to authenticate.
|
|
14
|
+
CREATE TABLE task_connections (
|
|
15
|
+
workspace_id TEXT NOT NULL,
|
|
16
|
+
source TEXT NOT NULL,
|
|
17
|
+
credentials TEXT NOT NULL,
|
|
18
|
+
label TEXT NOT NULL DEFAULT '',
|
|
19
|
+
created_at INTEGER NOT NULL,
|
|
20
|
+
deleted_at INTEGER,
|
|
21
|
+
PRIMARY KEY (workspace_id, source)
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
-- One row per imported issue. The structured fields back the agent-context
|
|
25
|
+
-- injection; `labels` and `comments` are JSON; `description` is normalized
|
|
26
|
+
-- Markdown; `excerpt` is a short plain-text preview. `linked_block_id` attaches
|
|
27
|
+
-- the issue to a board block as agent context.
|
|
28
|
+
CREATE TABLE tasks (
|
|
29
|
+
workspace_id TEXT NOT NULL,
|
|
30
|
+
source TEXT NOT NULL,
|
|
31
|
+
external_id TEXT NOT NULL, -- issue key, e.g. PROJ-123
|
|
32
|
+
title TEXT NOT NULL,
|
|
33
|
+
url TEXT NOT NULL,
|
|
34
|
+
status TEXT NOT NULL DEFAULT '',
|
|
35
|
+
type TEXT NOT NULL DEFAULT '',
|
|
36
|
+
assignee TEXT,
|
|
37
|
+
priority TEXT,
|
|
38
|
+
labels TEXT NOT NULL DEFAULT '[]', -- JSON array of strings
|
|
39
|
+
description TEXT NOT NULL DEFAULT '',
|
|
40
|
+
comments TEXT NOT NULL DEFAULT '[]', -- JSON array of {author,createdAt,body}
|
|
41
|
+
excerpt TEXT NOT NULL DEFAULT '',
|
|
42
|
+
linked_block_id TEXT,
|
|
43
|
+
synced_at INTEGER NOT NULL,
|
|
44
|
+
deleted_at INTEGER,
|
|
45
|
+
PRIMARY KEY (workspace_id, source, external_id)
|
|
46
|
+
);
|
|
47
|
+
-- Supports the execution engine's "issues linked to this block" lookup.
|
|
48
|
+
CREATE INDEX idx_tasks_block
|
|
49
|
+
ON tasks (workspace_id, linked_block_id);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
-- Allow "bootstrap repo" runs with no reference architecture (freeform prompt).
|
|
2
|
+
-- The original 0010 schema declared `reference_architecture_id` and
|
|
3
|
+
-- `reference_architecture_name` NOT NULL; from-scratch runs leave them null, so
|
|
4
|
+
-- relax both columns. SQLite can't drop a NOT NULL constraint in place, so we
|
|
5
|
+
-- rebuild the table (12-step pattern: create new, copy, drop, rename, re-index).
|
|
6
|
+
|
|
7
|
+
CREATE TABLE bootstrap_jobs_new (
|
|
8
|
+
id TEXT NOT NULL PRIMARY KEY,
|
|
9
|
+
workspace_id TEXT NOT NULL,
|
|
10
|
+
reference_architecture_id TEXT,
|
|
11
|
+
reference_architecture_name TEXT,
|
|
12
|
+
repo_name TEXT NOT NULL,
|
|
13
|
+
repo_owner TEXT,
|
|
14
|
+
repo_url TEXT,
|
|
15
|
+
instructions TEXT NOT NULL DEFAULT '',
|
|
16
|
+
status TEXT NOT NULL,
|
|
17
|
+
error TEXT,
|
|
18
|
+
created_at INTEGER NOT NULL,
|
|
19
|
+
updated_at INTEGER NOT NULL
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
INSERT INTO bootstrap_jobs_new
|
|
23
|
+
SELECT id, workspace_id, reference_architecture_id, reference_architecture_name,
|
|
24
|
+
repo_name, repo_owner, repo_url, instructions, status, error,
|
|
25
|
+
created_at, updated_at
|
|
26
|
+
FROM bootstrap_jobs;
|
|
27
|
+
|
|
28
|
+
DROP TABLE bootstrap_jobs;
|
|
29
|
+
ALTER TABLE bootstrap_jobs_new RENAME TO bootstrap_jobs;
|
|
30
|
+
|
|
31
|
+
CREATE INDEX idx_bootstrap_jobs_workspace
|
|
32
|
+
ON bootstrap_jobs (workspace_id, created_at);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
-- Workspace ownership. Until now every authenticated user could read and mutate
|
|
2
|
+
-- EVERY workspace (the table had no owner column, and no route checked one) — a
|
|
3
|
+
-- cross-tenant access-control hole. We add the owning GitHub user id so the API
|
|
4
|
+
-- can scope list/read/write to the owner.
|
|
5
|
+
--
|
|
6
|
+
-- The column is nullable so the migration is additive. Rows created before this
|
|
7
|
+
-- migration have NULL owner and are therefore NOT accessible once auth is
|
|
8
|
+
-- enabled (NULL never equals a signed-in user's id) — the fail-closed choice.
|
|
9
|
+
-- Such legacy boards must be re-created (or claimed by a manual UPDATE) by an
|
|
10
|
+
-- operator. When auth is disabled (local dev / AUTH_DEV_OPEN), ownership is not
|
|
11
|
+
-- enforced and all boards remain visible.
|
|
12
|
+
ALTER TABLE workspaces ADD COLUMN owner_user_id INTEGER;
|
|
13
|
+
|
|
14
|
+
CREATE INDEX idx_workspaces_owner ON workspaces (owner_user_id);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
-- Multi-tenant accounts. Until now a workspace was owned by a single GitHub user
|
|
2
|
+
-- (migration 0016) and a GitHub App installation was bound exclusively to one
|
|
3
|
+
-- workspace (migration 0004) — so a team of engineers could not share boards, and
|
|
4
|
+
-- one GitHub account could not back several boards. This migration introduces an
|
|
5
|
+
-- account tenancy layer:
|
|
6
|
+
--
|
|
7
|
+
-- * an `account` (a personal account-of-one, or an org) owns workspaces;
|
|
8
|
+
-- * `memberships` map GitHub users to accounts with a role, so many engineers
|
|
9
|
+
-- can see and use the same org's workspaces;
|
|
10
|
+
-- * a GitHub App installation is bound to an account, so every workspace in that
|
|
11
|
+
-- account can link the account's repos (repos are still linked *explicitly*
|
|
12
|
+
-- per workspace via the github_repos projection).
|
|
13
|
+
--
|
|
14
|
+
-- The columns are additive and nullable so the migration is safe and so the
|
|
15
|
+
-- auth-disabled / local-dev path (account_id NULL, no signed-in user) behaves
|
|
16
|
+
-- exactly as before: no scoping is enforced and every board stays visible.
|
|
17
|
+
|
|
18
|
+
CREATE TABLE accounts (
|
|
19
|
+
id TEXT NOT NULL PRIMARY KEY,
|
|
20
|
+
type TEXT NOT NULL, -- 'personal' | 'org'
|
|
21
|
+
name TEXT NOT NULL,
|
|
22
|
+
github_account_login TEXT, -- the GitHub org/user login, when known
|
|
23
|
+
created_at INTEGER NOT NULL
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
-- One personal account per GitHub login, so ensuring it on sign-in is idempotent.
|
|
27
|
+
CREATE UNIQUE INDEX idx_accounts_personal
|
|
28
|
+
ON accounts (github_account_login)
|
|
29
|
+
WHERE type = 'personal';
|
|
30
|
+
|
|
31
|
+
CREATE TABLE memberships (
|
|
32
|
+
account_id TEXT NOT NULL,
|
|
33
|
+
user_id INTEGER NOT NULL, -- GitHub user id (stable across renames)
|
|
34
|
+
role TEXT NOT NULL DEFAULT 'member', -- 'owner' | 'member'
|
|
35
|
+
created_at INTEGER NOT NULL,
|
|
36
|
+
PRIMARY KEY (account_id, user_id)
|
|
37
|
+
);
|
|
38
|
+
CREATE INDEX idx_memberships_user ON memberships (user_id);
|
|
39
|
+
|
|
40
|
+
-- Workspaces gain an owning account. NULL means "unscoped" (legacy rows and the
|
|
41
|
+
-- auth-disabled dev path); a signed-in user only sees workspaces whose account is
|
|
42
|
+
-- one they are a member of.
|
|
43
|
+
ALTER TABLE workspaces ADD COLUMN account_id TEXT;
|
|
44
|
+
CREATE INDEX idx_workspaces_account ON workspaces (account_id);
|
|
45
|
+
|
|
46
|
+
-- A GitHub App installation is now bound to an account (not a single workspace).
|
|
47
|
+
-- The workspace_id column from 0004 is retained as the *connector* workspace (and
|
|
48
|
+
-- as the binding key for the auth-disabled path, where account_id is NULL).
|
|
49
|
+
ALTER TABLE github_installations ADD COLUMN account_id TEXT;
|
|
50
|
+
CREATE INDEX idx_gh_install_account
|
|
51
|
+
ON github_installations (account_id)
|
|
52
|
+
WHERE deleted_at IS NULL;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
-- Make a "bootstrap repo" run observable and board-integrated. Two new columns
|
|
2
|
+
-- on bootstrap_jobs (conventions per 0010): the board service frame the run
|
|
3
|
+
-- materialises, and the live subtask progress the bootstrapper agent reports
|
|
4
|
+
-- while the container works.
|
|
5
|
+
--
|
|
6
|
+
-- block_id — the service frame this run creates up front (in `running` state)
|
|
7
|
+
-- so the bootstrap shows on the board immediately as a provisional
|
|
8
|
+
-- "bootstrapping…" card; on success the frame is linked to the new
|
|
9
|
+
-- repo and becomes a normal, droppable service. NULL for older rows
|
|
10
|
+
-- recorded before this column existed.
|
|
11
|
+
-- subtasks — JSON {completed,inProgress,total} mirrored from the agent's todo
|
|
12
|
+
-- list, surfaced as an "N/M done" progress bar. NULL until the agent
|
|
13
|
+
-- first reports (or for older rows).
|
|
14
|
+
|
|
15
|
+
ALTER TABLE bootstrap_jobs ADD COLUMN block_id TEXT;
|
|
16
|
+
ALTER TABLE bootstrap_jobs ADD COLUMN subtasks TEXT;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
-- Capture structured failure diagnostics for a "bootstrap repo" run, so a crash
|
|
2
|
+
-- is recorded as more than a one-line `error` and the board can classify it (and
|
|
3
|
+
-- decide whether a retry is likely to help). Conventions per 0010/0017.
|
|
4
|
+
--
|
|
5
|
+
-- failure — JSON-encoded BootstrapFailure {kind, message, detail, hint,
|
|
6
|
+
-- occurredAt, lastSubtasks} written when a run faults. `kind` is one
|
|
7
|
+
-- of preflight | dispatch | evicted | timeout | agent | unknown. The
|
|
8
|
+
-- container's stdout/stderr can't be folded in (an evicted container
|
|
9
|
+
-- is gone), so for `evicted`/`timeout` the `hint` points at the
|
|
10
|
+
-- Cloudflare container logs. NULL while running/succeeded, and for
|
|
11
|
+
-- older failed rows recorded before this column existed (their
|
|
12
|
+
-- one-line `error` still renders).
|
|
13
|
+
|
|
14
|
+
ALTER TABLE bootstrap_jobs ADD COLUMN failure TEXT;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
-- Unify the two container-backed agent flows — "bootstrap repo" runs and task
|
|
2
|
+
-- pipeline "execution" runs — onto a single `agent_runs` table that is the source
|
|
3
|
+
-- of truth for run lifecycle, live subtask progress, structured failure and
|
|
4
|
+
-- retry. This is the cross-cutting concern both flows duplicated; folding them
|
|
5
|
+
-- into one table lets the board surface failure + retry uniformly and lets one
|
|
6
|
+
-- cron sweeper re-drive any stale run (fixing the previously-missing bootstrap
|
|
7
|
+
-- sweeper). Conventions per 0001/0010: workspace-scoped, INTEGER epoch-ms
|
|
8
|
+
-- timestamps, no foreign keys.
|
|
9
|
+
--
|
|
10
|
+
-- Clean break (dev DB): the old `bootstrap_jobs` table is dropped here and the
|
|
11
|
+
-- old `executions` table in 0020 (no data is migrated). `reference_architectures`
|
|
12
|
+
-- is unaffected.
|
|
13
|
+
--
|
|
14
|
+
-- kind — 'bootstrap' | 'execution'; every query is scoped by it so the two
|
|
15
|
+
-- flows share storage without colliding.
|
|
16
|
+
-- block_id — the board block this run is attached to. Nullable: a bootstrap run
|
|
17
|
+
-- is inserted before its provisional service frame exists; an
|
|
18
|
+
-- execution run always has its task block.
|
|
19
|
+
-- status — fine-grained run status (running | blocked | paused | succeeded |
|
|
20
|
+
-- done | failed). Kept top-level (not buried in `detail`) because the
|
|
21
|
+
-- sweeper scans `status='running'` and must NOT re-drive blocked
|
|
22
|
+
-- (awaiting decision) or paused (spend gate) runs.
|
|
23
|
+
-- detail — kind-specific structural JSON nothing queries on:
|
|
24
|
+
-- execution {pipelineId, pipelineName, steps, currentStep}
|
|
25
|
+
-- bootstrap {referenceArchitectureId, referenceArchitectureName,
|
|
26
|
+
-- repoName, repoOwner, repoUrl, instructions}
|
|
27
|
+
-- subtasks — JSON {completed,inProgress,total} run-level progress (bootstrap's
|
|
28
|
+
-- todo counts). Execution keeps per-step counts inside detail.steps.
|
|
29
|
+
-- failure — JSON-encoded AgentFailure {kind,message,detail,hint,occurredAt,
|
|
30
|
+
-- lastSubtasks} when a run faults; NULL otherwise.
|
|
31
|
+
-- updated_at— refreshed on every write; doubles as the sweeper's lease.
|
|
32
|
+
|
|
33
|
+
CREATE TABLE agent_runs (
|
|
34
|
+
workspace_id TEXT NOT NULL,
|
|
35
|
+
id TEXT NOT NULL,
|
|
36
|
+
kind TEXT NOT NULL,
|
|
37
|
+
block_id TEXT,
|
|
38
|
+
status TEXT NOT NULL,
|
|
39
|
+
detail TEXT NOT NULL DEFAULT '{}',
|
|
40
|
+
subtasks TEXT,
|
|
41
|
+
error TEXT,
|
|
42
|
+
failure TEXT,
|
|
43
|
+
workflow_instance_id TEXT,
|
|
44
|
+
created_at INTEGER NOT NULL,
|
|
45
|
+
updated_at INTEGER NOT NULL,
|
|
46
|
+
PRIMARY KEY (workspace_id, id)
|
|
47
|
+
);
|
|
48
|
+
CREATE INDEX idx_agent_runs_workspace ON agent_runs (workspace_id, created_at);
|
|
49
|
+
CREATE INDEX idx_agent_runs_status_lease ON agent_runs (status, updated_at);
|
|
50
|
+
CREATE INDEX idx_agent_runs_block ON agent_runs (workspace_id, block_id);
|
|
51
|
+
|
|
52
|
+
DROP TABLE IF EXISTS bootstrap_jobs;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
-- Two-App tiering for repository provisioning (ADR 0005). A workspace may now be
|
|
2
|
+
-- connected via either the default (restricted) GitHub App or a privileged App
|
|
3
|
+
-- that carries `Administration: write`. Since an installation id belongs to
|
|
4
|
+
-- exactly one App, record which App owns each installation so token minting routes
|
|
5
|
+
-- to the right key. Existing rows predate the tier and were created via the
|
|
6
|
+
-- default App, so a NULL `app_id` is interpreted as "the default App".
|
|
7
|
+
ALTER TABLE github_installations ADD COLUMN app_id TEXT;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
-- Prompt-fragment library (ADR 0006). Promotes the best-practice fragment
|
|
2
|
+
-- catalog from build-static code to a managed, tenant-scoped projection. A
|
|
3
|
+
-- resolved catalog for a workspace is the merge of three tiers — the built-in
|
|
4
|
+
-- @cat-factory/prompt-fragments collections (never written here), account-owned
|
|
5
|
+
-- fragments, and workspace-owned ones — later tiers overriding earlier by the
|
|
6
|
+
-- stable fragment id, with a tombstone (deleted_at) suppressing an inherited or
|
|
7
|
+
-- removed-upstream fragment.
|
|
8
|
+
--
|
|
9
|
+
-- Rows are scoped by an (owner_kind, owner_id) pair so the one table backs both
|
|
10
|
+
-- tiers, mirroring how the GitHub installation/repo linkage inherits account →
|
|
11
|
+
-- workspace. Provenance columns remember the repo source a fragment came from so
|
|
12
|
+
-- a resync is a cheap sha comparison. Additive + opt-in: untouched when the
|
|
13
|
+
-- PROMPT_LIBRARY_ENABLED gate is off.
|
|
14
|
+
|
|
15
|
+
CREATE TABLE prompt_fragments (
|
|
16
|
+
fragment_id TEXT NOT NULL, -- stable id (slug, or src:<sourceId>:<path>)
|
|
17
|
+
owner_kind TEXT NOT NULL, -- 'account' | 'workspace'
|
|
18
|
+
owner_id TEXT NOT NULL, -- account id or workspace id
|
|
19
|
+
version TEXT NOT NULL,
|
|
20
|
+
title TEXT NOT NULL,
|
|
21
|
+
category TEXT,
|
|
22
|
+
summary TEXT NOT NULL, -- fed to the relevance selector
|
|
23
|
+
body TEXT NOT NULL, -- folded into the system prompt
|
|
24
|
+
applies_to TEXT, -- JSON { blockTypes?, agentKinds? }
|
|
25
|
+
tags TEXT, -- JSON string[]
|
|
26
|
+
source_id TEXT, -- → fragment_sources.id (null = hand-authored)
|
|
27
|
+
source_path TEXT, -- file path within the source repo
|
|
28
|
+
source_sha TEXT, -- blob sha last synced; powers "changed?"
|
|
29
|
+
created_at INTEGER NOT NULL,
|
|
30
|
+
updated_at INTEGER NOT NULL,
|
|
31
|
+
deleted_at INTEGER, -- tombstone (suppress / removed upstream)
|
|
32
|
+
PRIMARY KEY (owner_kind, owner_id, fragment_id)
|
|
33
|
+
);
|
|
34
|
+
CREATE INDEX idx_prompt_fragments_owner
|
|
35
|
+
ON prompt_fragments (owner_kind, owner_id) WHERE deleted_at IS NULL;
|
|
36
|
+
CREATE INDEX idx_prompt_fragments_source
|
|
37
|
+
ON prompt_fragments (source_id) WHERE deleted_at IS NULL;
|
|
38
|
+
|
|
39
|
+
-- A repo directory linked as a source of Markdown guideline files. Linkable at
|
|
40
|
+
-- either tier; reads reuse the account's existing GitHub installation. The
|
|
41
|
+
-- last-synced digest makes "check for changes" a cheap comparison, not a re-read.
|
|
42
|
+
CREATE TABLE fragment_sources (
|
|
43
|
+
id TEXT NOT NULL PRIMARY KEY,
|
|
44
|
+
owner_kind TEXT NOT NULL, -- 'account' | 'workspace'
|
|
45
|
+
owner_id TEXT NOT NULL,
|
|
46
|
+
repo_owner TEXT NOT NULL, -- GitHub owner/login
|
|
47
|
+
repo_name TEXT NOT NULL,
|
|
48
|
+
git_ref TEXT NOT NULL DEFAULT 'HEAD',
|
|
49
|
+
dir_path TEXT NOT NULL DEFAULT '',
|
|
50
|
+
last_synced_sha TEXT, -- tree digest at last successful sync
|
|
51
|
+
last_synced_at INTEGER,
|
|
52
|
+
created_at INTEGER NOT NULL,
|
|
53
|
+
deleted_at INTEGER,
|
|
54
|
+
UNIQUE (owner_kind, owner_id, repo_owner, repo_name, git_ref, dir_path)
|
|
55
|
+
);
|
|
56
|
+
CREATE INDEX idx_fragment_sources_owner
|
|
57
|
+
ON fragment_sources (owner_kind, owner_id) WHERE deleted_at IS NULL;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
-- Requirements-review feature: a stateless reviewer agent raises questions /
|
|
2
|
+
-- gaps / clarifications about a board block's collected requirements, humans
|
|
3
|
+
-- answer or dismiss each, and the agent folds the answers back into the block's
|
|
4
|
+
-- description. Unlike executions/bootstraps this flow is synchronous and has no
|
|
5
|
+
-- durable driver, so it gets its own small table rather than a row in agent_runs.
|
|
6
|
+
--
|
|
7
|
+
-- At most one *live* review per block: the service deletes the block's prior
|
|
8
|
+
-- review before inserting a fresh one, so `block_id` effectively identifies the
|
|
9
|
+
-- current review. `items` holds the JSON-serialized array of review items
|
|
10
|
+
-- (id/category/severity/title/detail/status/reply/timestamps).
|
|
11
|
+
|
|
12
|
+
CREATE TABLE requirement_reviews (
|
|
13
|
+
workspace_id TEXT NOT NULL,
|
|
14
|
+
id TEXT NOT NULL,
|
|
15
|
+
block_id TEXT NOT NULL,
|
|
16
|
+
status TEXT NOT NULL, -- 'ready' | 'incorporated'
|
|
17
|
+
items TEXT NOT NULL DEFAULT '[]', -- JSON array of review items
|
|
18
|
+
model TEXT, -- 'provider:model' that produced it
|
|
19
|
+
incorporated_requirements TEXT, -- revised requirements after incorporation
|
|
20
|
+
created_at INTEGER NOT NULL,
|
|
21
|
+
updated_at INTEGER NOT NULL,
|
|
22
|
+
PRIMARY KEY (workspace_id, id)
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
CREATE INDEX idx_requirement_reviews_block ON requirement_reviews (workspace_id, block_id);
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cat-factory/worker",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Reusable Cloudflare Worker library (Hono + D1) exposing the Agent Architecture Board core: the `createApp()` Hono factory, the default fetch/scheduled/queue handler, and the Durable Object + Workflow classes. Deployments (see deploy/backend) supply the wrangler.toml + config and re-export these.",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist",
|
|
7
|
+
"migrations"
|
|
8
|
+
],
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./app": {
|
|
18
|
+
"types": "./dist/app.d.ts",
|
|
19
|
+
"default": "./dist/app.js"
|
|
20
|
+
},
|
|
21
|
+
"./package.json": "./package.json"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@ai-sdk/anthropic": "^3.0.0",
|
|
28
|
+
"@ai-sdk/openai": "^3.0.0",
|
|
29
|
+
"@ai-sdk/openai-compatible": "^2.0.0",
|
|
30
|
+
"@cloudflare/containers": "^0.3.7",
|
|
31
|
+
"@hono/valibot-validator": "^0.5.2",
|
|
32
|
+
"ai": "^6.0.0",
|
|
33
|
+
"hono": "^4.6.0",
|
|
34
|
+
"pino": "^9.5.0",
|
|
35
|
+
"valibot": "^1.0.0",
|
|
36
|
+
"workers-ai-provider": "^3.2.0",
|
|
37
|
+
"@cat-factory/contracts": "1.0.0",
|
|
38
|
+
"@cat-factory/prompt-fragments": "1.0.0",
|
|
39
|
+
"@cat-factory/core": "1.0.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@cloudflare/vitest-pool-workers": "^0.16.15",
|
|
43
|
+
"@cloudflare/workers-types": "^4.20250620.0",
|
|
44
|
+
"typescript": "^5.6.0",
|
|
45
|
+
"vitest": "^4.1.8",
|
|
46
|
+
"wrangler": "^4.100.0"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "tsc -p tsconfig.build.json",
|
|
50
|
+
"dev": "wrangler dev",
|
|
51
|
+
"typecheck": "tsc -p tsconfig.build.json --noEmit",
|
|
52
|
+
"test": "vitest",
|
|
53
|
+
"test:run": "vitest run",
|
|
54
|
+
"db:migrate:local": "wrangler d1 migrations apply cat_factory --local"
|
|
55
|
+
}
|
|
56
|
+
}
|