@avocadostudio-ai/orchestrator-core 0.1.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 +201 -0
- package/dist/agent/agent-context.d.ts +19 -0
- package/dist/agent/agent-context.js +67 -0
- package/dist/agent/agent-logger.d.ts +5 -0
- package/dist/agent/agent-logger.js +22 -0
- package/dist/agent/agent-loop-openai.d.ts +8 -0
- package/dist/agent/agent-loop-openai.js +172 -0
- package/dist/agent/agent-loop.d.ts +56 -0
- package/dist/agent/agent-loop.js +167 -0
- package/dist/agent/agent-provider.d.ts +28 -0
- package/dist/agent/agent-provider.js +63 -0
- package/dist/agent/agent-tools.d.ts +28 -0
- package/dist/agent/agent-tools.js +899 -0
- package/dist/agent/context/editing-guidelines.md +46 -0
- package/dist/agent/context/role.md +39 -0
- package/dist/agent/integration-prompt.d.ts +9 -0
- package/dist/agent/integration-prompt.js +154 -0
- package/dist/agent/sites-agent-context.d.ts +12 -0
- package/dist/agent/sites-agent-context.js +316 -0
- package/dist/agent/sites-agent-shared.d.ts +161 -0
- package/dist/agent/sites-agent-shared.js +1101 -0
- package/dist/agent/sites-agent-tools.d.ts +18 -0
- package/dist/agent/sites-agent-tools.js +1227 -0
- package/dist/chat/anthropic-cache.d.ts +20 -0
- package/dist/chat/anthropic-cache.js +54 -0
- package/dist/chat/anthropic-planner.d.ts +98 -0
- package/dist/chat/anthropic-planner.js +1012 -0
- package/dist/chat/changelog-coverage-validator.d.ts +37 -0
- package/dist/chat/changelog-coverage-validator.js +215 -0
- package/dist/chat/chat-pipeline-context.d.ts +211 -0
- package/dist/chat/chat-pipeline-context.js +249 -0
- package/dist/chat/chat-pipeline-deterministic.d.ts +61 -0
- package/dist/chat/chat-pipeline-deterministic.js +407 -0
- package/dist/chat/chat-pipeline-image.d.ts +86 -0
- package/dist/chat/chat-pipeline-image.js +897 -0
- package/dist/chat/chat-pipeline-shared.d.ts +69 -0
- package/dist/chat/chat-pipeline-shared.js +212 -0
- package/dist/chat/chat-pipeline-translation.d.ts +27 -0
- package/dist/chat/chat-pipeline-translation.js +417 -0
- package/dist/chat/chat-pipeline-ui.d.ts +14 -0
- package/dist/chat/chat-pipeline-ui.js +244 -0
- package/dist/chat/chat-pipeline.d.ts +99 -0
- package/dist/chat/chat-pipeline.js +3999 -0
- package/dist/chat/decomposer.d.ts +21 -0
- package/dist/chat/decomposer.js +65 -0
- package/dist/chat/gemini-planner.d.ts +70 -0
- package/dist/chat/gemini-planner.js +541 -0
- package/dist/chat/hallucination-validator.d.ts +36 -0
- package/dist/chat/hallucination-validator.js +110 -0
- package/dist/chat/locale-strings.d.ts +47 -0
- package/dist/chat/locale-strings.js +100 -0
- package/dist/chat/plan-json-schema.d.ts +133 -0
- package/dist/chat/plan-json-schema.js +112 -0
- package/dist/chat/planner-types.d.ts +120 -0
- package/dist/chat/planner-types.js +66 -0
- package/dist/chat/planner.d.ts +148 -0
- package/dist/chat/planner.js +1361 -0
- package/dist/chat/prompts.d.ts +67 -0
- package/dist/chat/prompts.js +356 -0
- package/dist/chat/provider-routing.d.ts +14 -0
- package/dist/chat/provider-routing.js +27 -0
- package/dist/chat/variation-pipeline.d.ts +135 -0
- package/dist/chat/variation-pipeline.js +837 -0
- package/dist/chat/vision-alt-generator.d.ts +35 -0
- package/dist/chat/vision-alt-generator.js +152 -0
- package/dist/cms/adapter.d.ts +62 -0
- package/dist/cms/adapter.js +1 -0
- package/dist/cms/bootstrap.d.ts +17 -0
- package/dist/cms/bootstrap.js +85 -0
- package/dist/cms/editor-api-adapter.d.ts +23 -0
- package/dist/cms/editor-api-adapter.js +71 -0
- package/dist/cms/index.d.ts +4 -0
- package/dist/cms/index.js +3 -0
- package/dist/cms/json-file-adapter.d.ts +11 -0
- package/dist/cms/json-file-adapter.js +62 -0
- package/dist/demo-mode.d.ts +59 -0
- package/dist/demo-mode.js +201 -0
- package/dist/errors.d.ts +67 -0
- package/dist/errors.js +129 -0
- package/dist/http/chat-stream-resumable.d.ts +108 -0
- package/dist/http/chat-stream-resumable.js +290 -0
- package/dist/http/chat-stream.d.ts +99 -0
- package/dist/http/chat-stream.js +92 -0
- package/dist/image/gdrive-client.d.ts +22 -0
- package/dist/image/gdrive-client.js +215 -0
- package/dist/image/image-helpers.d.ts +95 -0
- package/dist/image/image-helpers.js +488 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/jira/jira-approval.d.ts +22 -0
- package/dist/jira/jira-approval.js +51 -0
- package/dist/jira/jira-client.d.ts +44 -0
- package/dist/jira/jira-client.js +313 -0
- package/dist/jira/jira-poller.d.ts +46 -0
- package/dist/jira/jira-poller.js +184 -0
- package/dist/jira/jira-processor.d.ts +103 -0
- package/dist/jira/jira-processor.js +1085 -0
- package/dist/jira/jira-types.d.ts +117 -0
- package/dist/jira/jira-types.js +38 -0
- package/dist/logger.d.ts +12 -0
- package/dist/logger.js +28 -0
- package/dist/migration/mcp-server-stdio.d.ts +8 -0
- package/dist/migration/mcp-server-stdio.js +672 -0
- package/dist/migration/migration-prompt.d.ts +7 -0
- package/dist/migration/migration-prompt.js +197 -0
- package/dist/migration/migration-tools.d.ts +17 -0
- package/dist/migration/migration-tools.js +159 -0
- package/dist/migration/scrape-cache.d.ts +9 -0
- package/dist/migration/scrape-cache.js +19 -0
- package/dist/nlp/deterministic-planner-context.d.ts +141 -0
- package/dist/nlp/deterministic-planner-context.js +362 -0
- package/dist/nlp/deterministic-planner-pages.d.ts +26 -0
- package/dist/nlp/deterministic-planner-pages.js +170 -0
- package/dist/nlp/deterministic-planner-patches.d.ts +80 -0
- package/dist/nlp/deterministic-planner-patches.js +508 -0
- package/dist/nlp/deterministic-planner-refs.d.ts +33 -0
- package/dist/nlp/deterministic-planner-refs.js +164 -0
- package/dist/nlp/deterministic-planner-suggestions.d.ts +49 -0
- package/dist/nlp/deterministic-planner-suggestions.js +579 -0
- package/dist/nlp/deterministic-planner.d.ts +85 -0
- package/dist/nlp/deterministic-planner.js +1631 -0
- package/dist/nlp/intent-detection.d.ts +309 -0
- package/dist/nlp/intent-detection.js +730 -0
- package/dist/nlp/intent-helpers.d.ts +15 -0
- package/dist/nlp/intent-helpers.js +243 -0
- package/dist/nlp/intent-patterns.d.ts +40 -0
- package/dist/nlp/intent-patterns.js +223 -0
- package/dist/nlp/plan-normalizer.d.ts +41 -0
- package/dist/nlp/plan-normalizer.js +1537 -0
- package/dist/ops/destructive-action-gate.d.ts +44 -0
- package/dist/ops/destructive-action-gate.js +90 -0
- package/dist/ops/ops-engine.d.ts +151 -0
- package/dist/ops/ops-engine.js +1394 -0
- package/dist/publish/diff-engine.d.ts +18 -0
- package/dist/publish/diff-engine.js +305 -0
- package/dist/publish/publish-helpers.d.ts +87 -0
- package/dist/publish/publish-helpers.js +521 -0
- package/dist/publish/publish-target-registry.d.ts +7 -0
- package/dist/publish/publish-target-registry.js +61 -0
- package/dist/publish/publish-target.d.ts +81 -0
- package/dist/publish/publish-target.js +1 -0
- package/dist/publish/targets/deploy-hook.d.ts +13 -0
- package/dist/publish/targets/deploy-hook.js +123 -0
- package/dist/publish/targets/git.d.ts +13 -0
- package/dist/publish/targets/git.js +55 -0
- package/dist/publish/targets/site-contract.d.ts +19 -0
- package/dist/publish/targets/site-contract.js +124 -0
- package/dist/state/content-source.d.ts +17 -0
- package/dist/state/content-source.js +1 -0
- package/dist/state/in-memory-content-source.d.ts +27 -0
- package/dist/state/in-memory-content-source.js +51 -0
- package/dist/state/session-lock.d.ts +13 -0
- package/dist/state/session-lock.js +29 -0
- package/dist/state/session-state.d.ts +310 -0
- package/dist/state/session-state.js +1083 -0
- package/dist/state/sqlite-store-singleton.d.ts +31 -0
- package/dist/state/sqlite-store-singleton.js +170 -0
- package/dist/state/sqlite-store.d.ts +135 -0
- package/dist/state/sqlite-store.js +421 -0
- package/dist/telemetry/chat-telemetry.d.ts +105 -0
- package/dist/telemetry/chat-telemetry.js +247 -0
- package/dist/telemetry/eval-candidate-store.d.ts +50 -0
- package/dist/telemetry/eval-candidate-store.js +120 -0
- package/dist/telemetry/feedback-store.d.ts +34 -0
- package/dist/telemetry/feedback-store.js +76 -0
- package/dist/telemetry/jira-telemetry.d.ts +57 -0
- package/dist/telemetry/jira-telemetry.js +68 -0
- package/dist/telemetry/migration-telemetry.d.ts +35 -0
- package/dist/telemetry/migration-telemetry.js +40 -0
- package/dist/telemetry/usage.d.ts +24 -0
- package/dist/telemetry/usage.js +80 -0
- package/dist/tools/builtin-registrations.d.ts +12 -0
- package/dist/tools/builtin-registrations.js +33 -0
- package/dist/tools/builtins/gdrive-browse.d.ts +3 -0
- package/dist/tools/builtins/gdrive-browse.js +68 -0
- package/dist/tools/builtins/image-generate.d.ts +3 -0
- package/dist/tools/builtins/image-generate.js +211 -0
- package/dist/tools/builtins/unsplash-get-by-id.d.ts +23 -0
- package/dist/tools/builtins/unsplash-get-by-id.js +119 -0
- package/dist/tools/builtins/unsplash-search.d.ts +3 -0
- package/dist/tools/builtins/unsplash-search.js +74 -0
- package/dist/tools/executor.d.ts +23 -0
- package/dist/tools/executor.js +169 -0
- package/dist/tools/index.d.ts +5 -0
- package/dist/tools/index.js +5 -0
- package/dist/tools/registry.d.ts +21 -0
- package/dist/tools/registry.js +75 -0
- package/dist/tools/runtime.d.ts +27 -0
- package/dist/tools/runtime.js +48 -0
- package/dist/tools/schema-validator.d.ts +24 -0
- package/dist/tools/schema-validator.js +88 -0
- package/dist/tools/types.d.ts +86 -0
- package/dist/tools/types.js +1 -0
- package/dist/variation-images.d.ts +19 -0
- package/dist/variation-images.js +12 -0
- package/package.json +78 -0
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
import { mkdirSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import Database from "better-sqlite3";
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Caps (mirrors limits used by in-memory state)
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
export const HISTORY_DEPTH_CAP = 50;
|
|
8
|
+
export const VERSION_LOG_CAP = 100;
|
|
9
|
+
export const RECENT_EDITS_CAP = 10;
|
|
10
|
+
export const CHAT_HISTORY_CAP = 6;
|
|
11
|
+
export const PUBLISH_LOG_CAP = 200;
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Schema
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
const SCHEMA = `
|
|
16
|
+
CREATE TABLE IF NOT EXISTS meta (
|
|
17
|
+
key TEXT PRIMARY KEY,
|
|
18
|
+
value TEXT NOT NULL
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
22
|
+
session TEXT PRIMARY KEY,
|
|
23
|
+
version INTEGER NOT NULL DEFAULT 0
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
CREATE TABLE IF NOT EXISTS pages (
|
|
27
|
+
session TEXT NOT NULL,
|
|
28
|
+
slug TEXT NOT NULL,
|
|
29
|
+
kind TEXT NOT NULL CHECK (kind IN ('draft','published')),
|
|
30
|
+
doc TEXT NOT NULL,
|
|
31
|
+
PRIMARY KEY (session, slug, kind)
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
CREATE TABLE IF NOT EXISTS history (
|
|
35
|
+
session TEXT NOT NULL,
|
|
36
|
+
slug TEXT NOT NULL,
|
|
37
|
+
direction TEXT NOT NULL CHECK (direction IN ('undo','redo')),
|
|
38
|
+
seq INTEGER NOT NULL,
|
|
39
|
+
snapshot TEXT,
|
|
40
|
+
PRIMARY KEY (session, slug, direction, seq)
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
CREATE TABLE IF NOT EXISTS version_log (
|
|
44
|
+
session TEXT NOT NULL,
|
|
45
|
+
seq INTEGER NOT NULL,
|
|
46
|
+
entry TEXT NOT NULL,
|
|
47
|
+
PRIMARY KEY (session, seq)
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
CREATE TABLE IF NOT EXISTS recent_edits (
|
|
51
|
+
session TEXT NOT NULL,
|
|
52
|
+
seq INTEGER NOT NULL,
|
|
53
|
+
entry TEXT NOT NULL,
|
|
54
|
+
PRIMARY KEY (session, seq)
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
CREATE TABLE IF NOT EXISTS chat_history (
|
|
58
|
+
session TEXT NOT NULL,
|
|
59
|
+
seq INTEGER NOT NULL,
|
|
60
|
+
role TEXT NOT NULL CHECK (role IN ('user','assistant')),
|
|
61
|
+
content TEXT NOT NULL,
|
|
62
|
+
PRIMARY KEY (session, seq)
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
CREATE TABLE IF NOT EXISTS site_configs (
|
|
66
|
+
session TEXT PRIMARY KEY,
|
|
67
|
+
config TEXT NOT NULL
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
CREATE TABLE IF NOT EXISTS issue_touched (
|
|
71
|
+
issue_key TEXT PRIMARY KEY,
|
|
72
|
+
slugs TEXT NOT NULL,
|
|
73
|
+
updated_at TEXT NOT NULL
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
CREATE TABLE IF NOT EXISTS publish_log (
|
|
77
|
+
session TEXT NOT NULL,
|
|
78
|
+
seq INTEGER NOT NULL,
|
|
79
|
+
id TEXT NOT NULL,
|
|
80
|
+
site_id TEXT NOT NULL,
|
|
81
|
+
target TEXT NOT NULL,
|
|
82
|
+
status TEXT NOT NULL CHECK (status IN ('triggered','success','failed')),
|
|
83
|
+
at TEXT NOT NULL,
|
|
84
|
+
updated_at TEXT NOT NULL,
|
|
85
|
+
entry TEXT NOT NULL,
|
|
86
|
+
PRIMARY KEY (session, seq)
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
CREATE INDEX IF NOT EXISTS publish_log_by_id ON publish_log(id);
|
|
90
|
+
CREATE INDEX IF NOT EXISTS publish_log_by_session_at ON publish_log(session, at DESC);
|
|
91
|
+
`;
|
|
92
|
+
const SCHEMA_VERSION = 1;
|
|
93
|
+
export class SqliteStore {
|
|
94
|
+
db;
|
|
95
|
+
stmt;
|
|
96
|
+
constructor(options) {
|
|
97
|
+
const { file } = options;
|
|
98
|
+
const useWal = options.wal ?? (file !== ":memory:");
|
|
99
|
+
if (file !== ":memory:") {
|
|
100
|
+
mkdirSync(dirname(resolve(file)), { recursive: true });
|
|
101
|
+
}
|
|
102
|
+
this.db = new Database(file);
|
|
103
|
+
this.db.pragma("foreign_keys = ON");
|
|
104
|
+
if (useWal) {
|
|
105
|
+
this.db.pragma("journal_mode = WAL");
|
|
106
|
+
this.db.pragma("synchronous = NORMAL");
|
|
107
|
+
}
|
|
108
|
+
this.db.exec(SCHEMA);
|
|
109
|
+
this.ensureSchemaVersion();
|
|
110
|
+
this.stmt = this.prepareAll();
|
|
111
|
+
options.onLog?.(`SqliteStore opened: ${file}`);
|
|
112
|
+
}
|
|
113
|
+
ensureSchemaVersion() {
|
|
114
|
+
const row = this.db
|
|
115
|
+
.prepare("SELECT value FROM meta WHERE key = 'schema_version'")
|
|
116
|
+
.get();
|
|
117
|
+
if (!row) {
|
|
118
|
+
this.db
|
|
119
|
+
.prepare("INSERT INTO meta(key, value) VALUES ('schema_version', ?)")
|
|
120
|
+
.run(String(SCHEMA_VERSION));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
prepareAll() {
|
|
124
|
+
const db = this.db;
|
|
125
|
+
return {
|
|
126
|
+
upsertPage: db.prepare(`INSERT INTO pages(session, slug, kind, doc) VALUES (?, ?, ?, ?)
|
|
127
|
+
ON CONFLICT(session, slug, kind) DO UPDATE SET doc = excluded.doc`),
|
|
128
|
+
deletePage: db.prepare(`DELETE FROM pages WHERE session = ? AND slug = ? AND kind = ?`),
|
|
129
|
+
selectPage: db.prepare(`SELECT doc FROM pages WHERE session = ? AND slug = ? AND kind = ?`),
|
|
130
|
+
listPagesBySessionKind: db.prepare(`SELECT slug, doc FROM pages WHERE session = ? AND kind = ? ORDER BY slug`),
|
|
131
|
+
listAllDraftSessions: db.prepare(`SELECT DISTINCT session FROM pages WHERE kind = 'draft' ORDER BY session`),
|
|
132
|
+
insertHistory: db.prepare(`INSERT INTO history(session, slug, direction, seq, snapshot) VALUES (?, ?, ?, ?, ?)`),
|
|
133
|
+
popHistoryTop: db.prepare(`SELECT seq, snapshot FROM history
|
|
134
|
+
WHERE session = ? AND slug = ? AND direction = ?
|
|
135
|
+
ORDER BY seq DESC LIMIT 1`),
|
|
136
|
+
deleteHistoryRow: db.prepare(`DELETE FROM history WHERE session = ? AND slug = ? AND direction = ? AND seq = ?`),
|
|
137
|
+
clearHistoryDirection: db.prepare(`DELETE FROM history WHERE session = ? AND slug = ? AND direction = ?`),
|
|
138
|
+
listHistory: db.prepare(`SELECT seq, snapshot FROM history
|
|
139
|
+
WHERE session = ? AND slug = ? AND direction = ?
|
|
140
|
+
ORDER BY seq ASC`),
|
|
141
|
+
trimHistory: db.prepare(`DELETE FROM history
|
|
142
|
+
WHERE session = ? AND slug = ? AND direction = ?
|
|
143
|
+
AND seq NOT IN (
|
|
144
|
+
SELECT seq FROM history
|
|
145
|
+
WHERE session = ? AND slug = ? AND direction = ?
|
|
146
|
+
ORDER BY seq DESC LIMIT ?
|
|
147
|
+
)`),
|
|
148
|
+
nextHistorySeq: db.prepare(`SELECT COALESCE(MAX(seq), 0) + 1 AS next FROM history
|
|
149
|
+
WHERE session = ? AND slug = ? AND direction = ?`),
|
|
150
|
+
upsertSession: db.prepare(`INSERT INTO sessions(session, version) VALUES (?, ?)
|
|
151
|
+
ON CONFLICT(session) DO UPDATE SET version = excluded.version`),
|
|
152
|
+
selectSessionVersion: db.prepare(`SELECT version FROM sessions WHERE session = ?`),
|
|
153
|
+
bumpSessionVersion: db.prepare(`INSERT INTO sessions(session, version) VALUES (?, 1)
|
|
154
|
+
ON CONFLICT(session) DO UPDATE SET version = version + 1
|
|
155
|
+
RETURNING version`),
|
|
156
|
+
insertVersionLog: db.prepare(`INSERT INTO version_log(session, seq, entry) VALUES (?, ?, ?)`),
|
|
157
|
+
listVersionLog: db.prepare(`SELECT entry FROM version_log WHERE session = ? ORDER BY seq ASC`),
|
|
158
|
+
listVersionLogForSlug: db.prepare(`SELECT entry FROM version_log
|
|
159
|
+
WHERE session = ? AND json_extract(entry, '$.slug') = ?
|
|
160
|
+
ORDER BY seq ASC`),
|
|
161
|
+
trimVersionLog: db.prepare(`DELETE FROM version_log
|
|
162
|
+
WHERE session = ?
|
|
163
|
+
AND seq NOT IN (
|
|
164
|
+
SELECT seq FROM version_log
|
|
165
|
+
WHERE session = ?
|
|
166
|
+
ORDER BY seq DESC LIMIT ?
|
|
167
|
+
)`),
|
|
168
|
+
nextVersionLogSeq: db.prepare(`SELECT COALESCE(MAX(seq), 0) + 1 AS next FROM version_log WHERE session = ?`),
|
|
169
|
+
insertRecentEdit: db.prepare(`INSERT INTO recent_edits(session, seq, entry) VALUES (?, ?, ?)`),
|
|
170
|
+
listRecentEdits: db.prepare(`SELECT entry FROM recent_edits WHERE session = ? ORDER BY seq ASC`),
|
|
171
|
+
trimRecentEdits: db.prepare(`DELETE FROM recent_edits
|
|
172
|
+
WHERE session = ?
|
|
173
|
+
AND seq NOT IN (
|
|
174
|
+
SELECT seq FROM recent_edits
|
|
175
|
+
WHERE session = ?
|
|
176
|
+
ORDER BY seq DESC LIMIT ?
|
|
177
|
+
)`),
|
|
178
|
+
nextRecentEditSeq: db.prepare(`SELECT COALESCE(MAX(seq), 0) + 1 AS next FROM recent_edits WHERE session = ?`),
|
|
179
|
+
insertChatMessage: db.prepare(`INSERT INTO chat_history(session, seq, role, content) VALUES (?, ?, ?, ?)`),
|
|
180
|
+
listChatHistory: db.prepare(`SELECT role, content FROM chat_history WHERE session = ? ORDER BY seq ASC`),
|
|
181
|
+
trimChatHistory: db.prepare(`DELETE FROM chat_history
|
|
182
|
+
WHERE session = ?
|
|
183
|
+
AND seq NOT IN (
|
|
184
|
+
SELECT seq FROM chat_history
|
|
185
|
+
WHERE session = ?
|
|
186
|
+
ORDER BY seq DESC LIMIT ?
|
|
187
|
+
)`),
|
|
188
|
+
nextChatSeq: db.prepare(`SELECT COALESCE(MAX(seq), 0) + 1 AS next FROM chat_history WHERE session = ?`),
|
|
189
|
+
upsertSiteConfig: db.prepare(`INSERT INTO site_configs(session, config) VALUES (?, ?)
|
|
190
|
+
ON CONFLICT(session) DO UPDATE SET config = excluded.config`),
|
|
191
|
+
selectSiteConfig: db.prepare(`SELECT config FROM site_configs WHERE session = ?`),
|
|
192
|
+
listSiteConfigs: db.prepare(`SELECT session, config FROM site_configs`),
|
|
193
|
+
upsertIssueTouched: db.prepare(`INSERT INTO issue_touched(issue_key, slugs, updated_at) VALUES (?, ?, ?)
|
|
194
|
+
ON CONFLICT(issue_key) DO UPDATE SET
|
|
195
|
+
slugs = excluded.slugs,
|
|
196
|
+
updated_at = excluded.updated_at`),
|
|
197
|
+
selectIssueTouched: db.prepare(`SELECT slugs, updated_at FROM issue_touched WHERE issue_key = ?`),
|
|
198
|
+
listIssueTouched: db.prepare(`SELECT issue_key, slugs, updated_at FROM issue_touched ORDER BY updated_at ASC`),
|
|
199
|
+
trimIssueTouched: db.prepare(`DELETE FROM issue_touched
|
|
200
|
+
WHERE issue_key NOT IN (
|
|
201
|
+
SELECT issue_key FROM issue_touched
|
|
202
|
+
ORDER BY updated_at DESC LIMIT ?
|
|
203
|
+
)`),
|
|
204
|
+
insertPublishLog: db.prepare(`INSERT INTO publish_log(session, seq, id, site_id, target, status, at, updated_at, entry)
|
|
205
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`),
|
|
206
|
+
updatePublishLogById: db.prepare(`UPDATE publish_log
|
|
207
|
+
SET status = ?, updated_at = ?, entry = ?
|
|
208
|
+
WHERE id = ?`),
|
|
209
|
+
selectPublishLogById: db.prepare(`SELECT entry FROM publish_log WHERE id = ?`),
|
|
210
|
+
selectPublishLogByDeploymentId: db.prepare(`SELECT entry FROM publish_log
|
|
211
|
+
WHERE session = ?
|
|
212
|
+
AND json_extract(entry, '$.deploymentId') = ?
|
|
213
|
+
ORDER BY seq DESC LIMIT 1`),
|
|
214
|
+
selectPublishLogByMostRecentTriggered: db.prepare(`SELECT entry FROM publish_log
|
|
215
|
+
WHERE session = ? AND status = 'triggered'
|
|
216
|
+
ORDER BY seq DESC LIMIT 1`),
|
|
217
|
+
listPublishLog: db.prepare(`SELECT entry FROM publish_log
|
|
218
|
+
WHERE session = ?
|
|
219
|
+
ORDER BY seq ASC`),
|
|
220
|
+
listAllPublishLogSessions: db.prepare(`SELECT DISTINCT session FROM publish_log`),
|
|
221
|
+
trimPublishLog: db.prepare(`DELETE FROM publish_log
|
|
222
|
+
WHERE session = ?
|
|
223
|
+
AND seq NOT IN (
|
|
224
|
+
SELECT seq FROM publish_log
|
|
225
|
+
WHERE session = ?
|
|
226
|
+
ORDER BY seq DESC LIMIT ?
|
|
227
|
+
)`),
|
|
228
|
+
nextPublishLogSeq: db.prepare(`SELECT COALESCE(MAX(seq), 0) + 1 AS next FROM publish_log WHERE session = ?`),
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
// -------------------------------------------------------------------------
|
|
232
|
+
// Pages
|
|
233
|
+
// -------------------------------------------------------------------------
|
|
234
|
+
setPage(session, page, kind = "draft") {
|
|
235
|
+
this.stmt.upsertPage.run(session, page.slug, kind, JSON.stringify(page));
|
|
236
|
+
}
|
|
237
|
+
getPage(session, slug, kind = "draft") {
|
|
238
|
+
const row = this.stmt.selectPage.get(session, slug, kind);
|
|
239
|
+
return row ? JSON.parse(row.doc) : null;
|
|
240
|
+
}
|
|
241
|
+
removePage(session, slug, kind = "draft") {
|
|
242
|
+
this.stmt.deletePage.run(session, slug, kind);
|
|
243
|
+
}
|
|
244
|
+
listPages(session, kind = "draft") {
|
|
245
|
+
const rows = this.stmt.listPagesBySessionKind.all(session, kind);
|
|
246
|
+
return rows.map((r) => JSON.parse(r.doc));
|
|
247
|
+
}
|
|
248
|
+
listDraftSessions() {
|
|
249
|
+
const rows = this.stmt.listAllDraftSessions.all();
|
|
250
|
+
return rows.map((r) => r.session);
|
|
251
|
+
}
|
|
252
|
+
// -------------------------------------------------------------------------
|
|
253
|
+
// History (undo/redo) — capped at HISTORY_DEPTH_CAP per (session,slug,direction)
|
|
254
|
+
// -------------------------------------------------------------------------
|
|
255
|
+
pushHistory(session, slug, direction, snapshot) {
|
|
256
|
+
const nextRow = this.stmt.nextHistorySeq.get(session, slug, direction);
|
|
257
|
+
const payload = snapshot === null ? null : JSON.stringify(snapshot);
|
|
258
|
+
this.stmt.insertHistory.run(session, slug, direction, nextRow.next, payload);
|
|
259
|
+
this.stmt.trimHistory.run(session, slug, direction, session, slug, direction, HISTORY_DEPTH_CAP);
|
|
260
|
+
}
|
|
261
|
+
popHistory(session, slug, direction) {
|
|
262
|
+
const row = this.stmt.popHistoryTop.get(session, slug, direction);
|
|
263
|
+
if (!row)
|
|
264
|
+
return undefined;
|
|
265
|
+
this.stmt.deleteHistoryRow.run(session, slug, direction, row.seq);
|
|
266
|
+
return row.snapshot === null ? null : JSON.parse(row.snapshot);
|
|
267
|
+
}
|
|
268
|
+
clearHistory(session, slug, direction) {
|
|
269
|
+
this.stmt.clearHistoryDirection.run(session, slug, direction);
|
|
270
|
+
}
|
|
271
|
+
listHistory(session, slug, direction) {
|
|
272
|
+
const rows = this.stmt.listHistory.all(session, slug, direction);
|
|
273
|
+
return rows.map((r) => (r.snapshot === null ? null : JSON.parse(r.snapshot)));
|
|
274
|
+
}
|
|
275
|
+
// -------------------------------------------------------------------------
|
|
276
|
+
// Version counter
|
|
277
|
+
// -------------------------------------------------------------------------
|
|
278
|
+
getVersion(session) {
|
|
279
|
+
const row = this.stmt.selectSessionVersion.get(session);
|
|
280
|
+
return row?.version ?? 0;
|
|
281
|
+
}
|
|
282
|
+
setVersion(session, version) {
|
|
283
|
+
this.stmt.upsertSession.run(session, version);
|
|
284
|
+
}
|
|
285
|
+
bumpVersion(session) {
|
|
286
|
+
const row = this.stmt.bumpSessionVersion.get(session);
|
|
287
|
+
return row.version;
|
|
288
|
+
}
|
|
289
|
+
// -------------------------------------------------------------------------
|
|
290
|
+
// Version log — capped at VERSION_LOG_CAP per session
|
|
291
|
+
// -------------------------------------------------------------------------
|
|
292
|
+
pushVersionLog(session, entry) {
|
|
293
|
+
const next = this.stmt.nextVersionLogSeq.get(session);
|
|
294
|
+
this.stmt.insertVersionLog.run(session, next.next, JSON.stringify(entry));
|
|
295
|
+
this.stmt.trimVersionLog.run(session, session, VERSION_LOG_CAP);
|
|
296
|
+
}
|
|
297
|
+
listVersionLog(session, slug, limit = 50) {
|
|
298
|
+
const rows = (slug
|
|
299
|
+
? this.stmt.listVersionLogForSlug.all(session, slug)
|
|
300
|
+
: this.stmt.listVersionLog.all(session));
|
|
301
|
+
const parsed = rows.map((r) => JSON.parse(r.entry));
|
|
302
|
+
return parsed.slice(-limit);
|
|
303
|
+
}
|
|
304
|
+
// -------------------------------------------------------------------------
|
|
305
|
+
// Recent edits — capped at RECENT_EDITS_CAP per session
|
|
306
|
+
// -------------------------------------------------------------------------
|
|
307
|
+
pushRecentEdit(session, entry) {
|
|
308
|
+
const next = this.stmt.nextRecentEditSeq.get(session);
|
|
309
|
+
this.stmt.insertRecentEdit.run(session, next.next, JSON.stringify(entry));
|
|
310
|
+
this.stmt.trimRecentEdits.run(session, session, RECENT_EDITS_CAP);
|
|
311
|
+
}
|
|
312
|
+
listRecentEdits(session) {
|
|
313
|
+
const rows = this.stmt.listRecentEdits.all(session);
|
|
314
|
+
return rows.map((r) => JSON.parse(r.entry));
|
|
315
|
+
}
|
|
316
|
+
// -------------------------------------------------------------------------
|
|
317
|
+
// Chat history — capped at CHAT_HISTORY_CAP messages per session
|
|
318
|
+
// -------------------------------------------------------------------------
|
|
319
|
+
pushChatMessage(session, role, content) {
|
|
320
|
+
const next = this.stmt.nextChatSeq.get(session);
|
|
321
|
+
this.stmt.insertChatMessage.run(session, next.next, role, content);
|
|
322
|
+
this.stmt.trimChatHistory.run(session, session, CHAT_HISTORY_CAP);
|
|
323
|
+
}
|
|
324
|
+
listChatHistory(session) {
|
|
325
|
+
const rows = this.stmt.listChatHistory.all(session);
|
|
326
|
+
return rows.map((r) => ({ role: r.role, content: r.content }));
|
|
327
|
+
}
|
|
328
|
+
// -------------------------------------------------------------------------
|
|
329
|
+
// Site configs
|
|
330
|
+
// -------------------------------------------------------------------------
|
|
331
|
+
setSiteConfig(session, config) {
|
|
332
|
+
this.stmt.upsertSiteConfig.run(session, JSON.stringify(config));
|
|
333
|
+
}
|
|
334
|
+
getSiteConfig(session) {
|
|
335
|
+
const row = this.stmt.selectSiteConfig.get(session);
|
|
336
|
+
return row ? JSON.parse(row.config) : null;
|
|
337
|
+
}
|
|
338
|
+
listSiteConfigs() {
|
|
339
|
+
const rows = this.stmt.listSiteConfigs.all();
|
|
340
|
+
return rows.map((r) => ({ session: r.session, config: JSON.parse(r.config) }));
|
|
341
|
+
}
|
|
342
|
+
// -------------------------------------------------------------------------
|
|
343
|
+
// Issue-touched slugs
|
|
344
|
+
// -------------------------------------------------------------------------
|
|
345
|
+
setIssueTouched(issueKey, row, cap = 200) {
|
|
346
|
+
this.stmt.upsertIssueTouched.run(issueKey, JSON.stringify(row.slugs), row.updatedAt);
|
|
347
|
+
this.stmt.trimIssueTouched.run(cap);
|
|
348
|
+
}
|
|
349
|
+
getIssueTouched(issueKey) {
|
|
350
|
+
const row = this.stmt.selectIssueTouched.get(issueKey);
|
|
351
|
+
if (!row)
|
|
352
|
+
return null;
|
|
353
|
+
return { slugs: JSON.parse(row.slugs), updatedAt: row.updated_at };
|
|
354
|
+
}
|
|
355
|
+
listIssueTouched() {
|
|
356
|
+
const rows = this.stmt.listIssueTouched.all();
|
|
357
|
+
return rows.map((r) => ({
|
|
358
|
+
issueKey: r.issue_key,
|
|
359
|
+
row: { slugs: JSON.parse(r.slugs), updatedAt: r.updated_at },
|
|
360
|
+
}));
|
|
361
|
+
}
|
|
362
|
+
// -------------------------------------------------------------------------
|
|
363
|
+
// Publish log — capped at PUBLISH_LOG_CAP per session.
|
|
364
|
+
// Append-only with per-id UPDATE for async deploy-status transitions.
|
|
365
|
+
// -------------------------------------------------------------------------
|
|
366
|
+
pushPublishLog(entry) {
|
|
367
|
+
const next = this.stmt.nextPublishLogSeq.get(entry.session);
|
|
368
|
+
this.stmt.insertPublishLog.run(entry.session, next.next, entry.id, entry.siteId, entry.target, entry.status, entry.at, entry.updatedAt, JSON.stringify(entry));
|
|
369
|
+
this.stmt.trimPublishLog.run(entry.session, entry.session, PUBLISH_LOG_CAP);
|
|
370
|
+
}
|
|
371
|
+
getPublishLogById(id) {
|
|
372
|
+
const row = this.stmt.selectPublishLogById.get(id);
|
|
373
|
+
return row ? JSON.parse(row.entry) : null;
|
|
374
|
+
}
|
|
375
|
+
getPublishLogByDeploymentId(session, deploymentId) {
|
|
376
|
+
const row = this.stmt.selectPublishLogByDeploymentId.get(session, deploymentId);
|
|
377
|
+
return row ? JSON.parse(row.entry) : null;
|
|
378
|
+
}
|
|
379
|
+
getMostRecentTriggeredPublishLog(session) {
|
|
380
|
+
const row = this.stmt.selectPublishLogByMostRecentTriggered.get(session);
|
|
381
|
+
return row ? JSON.parse(row.entry) : null;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Patch an existing publish-log row. Merges `patch` into the stored JSON,
|
|
385
|
+
* bumps `updatedAt`, and updates the hoisted `status` column. Returns the
|
|
386
|
+
* full updated entry, or null if the id was not found.
|
|
387
|
+
*/
|
|
388
|
+
updatePublishLogById(id, patch) {
|
|
389
|
+
const existing = this.getPublishLogById(id);
|
|
390
|
+
if (!existing)
|
|
391
|
+
return null;
|
|
392
|
+
const next = {
|
|
393
|
+
...existing,
|
|
394
|
+
...patch,
|
|
395
|
+
id: existing.id,
|
|
396
|
+
session: existing.session,
|
|
397
|
+
at: existing.at,
|
|
398
|
+
updatedAt: new Date().toISOString(),
|
|
399
|
+
};
|
|
400
|
+
this.stmt.updatePublishLogById.run(next.status, next.updatedAt, JSON.stringify(next), id);
|
|
401
|
+
return next;
|
|
402
|
+
}
|
|
403
|
+
listPublishLog(session, limit = 50) {
|
|
404
|
+
const rows = this.stmt.listPublishLog.all(session);
|
|
405
|
+
const parsed = rows.map((r) => JSON.parse(r.entry));
|
|
406
|
+
return parsed.slice(-limit);
|
|
407
|
+
}
|
|
408
|
+
listPublishLogSessions() {
|
|
409
|
+
const rows = this.stmt.listAllPublishLogSessions.all();
|
|
410
|
+
return rows.map((r) => r.session);
|
|
411
|
+
}
|
|
412
|
+
// -------------------------------------------------------------------------
|
|
413
|
+
// Transactions — per-request boundary. Nested calls reuse the outer txn.
|
|
414
|
+
// -------------------------------------------------------------------------
|
|
415
|
+
transaction(fn) {
|
|
416
|
+
return this.db.transaction(fn)();
|
|
417
|
+
}
|
|
418
|
+
close() {
|
|
419
|
+
this.db.close();
|
|
420
|
+
}
|
|
421
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
export type ChatTelemetryPhase = "received" | "milestone" | "forced_plan" | "deterministic_plan_generated" | "plan_attempt_failed" | "plan_generated" | "plan_apply_failed" | "repair_attempt" | "repair_generated" | "tool_call" | "result";
|
|
2
|
+
export type ChatTelemetryEntry = {
|
|
3
|
+
id: string;
|
|
4
|
+
at: string;
|
|
5
|
+
phase: ChatTelemetryPhase;
|
|
6
|
+
session: string;
|
|
7
|
+
requestedSlug: string;
|
|
8
|
+
effectiveSlug: string;
|
|
9
|
+
plannerSource: "openai" | "anthropic" | "gemini" | "demo";
|
|
10
|
+
modelKey: string;
|
|
11
|
+
modelUsed: string;
|
|
12
|
+
promptHash: string;
|
|
13
|
+
promptExcerpt: string;
|
|
14
|
+
promptLength: number;
|
|
15
|
+
outcome?: string;
|
|
16
|
+
timelineStage?: "request_received" | "first_token" | "first_structured_progress" | "plan_ready" | "first_op_applied" | "done";
|
|
17
|
+
reason?: string;
|
|
18
|
+
reasonCategory?: string;
|
|
19
|
+
opCount?: number;
|
|
20
|
+
opTypes?: string[];
|
|
21
|
+
skippedOpCount?: number;
|
|
22
|
+
intent?: string;
|
|
23
|
+
inputTokens?: number;
|
|
24
|
+
outputTokens?: number;
|
|
25
|
+
totalTokens?: number;
|
|
26
|
+
cacheCreationInputTokens?: number;
|
|
27
|
+
cacheReadInputTokens?: number;
|
|
28
|
+
estimatedUsd?: number | null;
|
|
29
|
+
totalDurationMs?: number;
|
|
30
|
+
planningDurationMs?: number;
|
|
31
|
+
firstPlanningTokenMs?: number;
|
|
32
|
+
applyDurationMs?: number;
|
|
33
|
+
imageResolutionDurationMs?: number;
|
|
34
|
+
planningAttempts?: number;
|
|
35
|
+
contextPackBytes?: number;
|
|
36
|
+
contractMode?: "minimal" | "targeted" | "full";
|
|
37
|
+
contractBytes?: number;
|
|
38
|
+
contractBlockCount?: number;
|
|
39
|
+
strictJsonEnabled?: boolean;
|
|
40
|
+
schemaRetryUsed?: boolean;
|
|
41
|
+
plannerRefusal?: boolean;
|
|
42
|
+
plannerIncomplete?: boolean;
|
|
43
|
+
compactContextEnabled?: boolean;
|
|
44
|
+
minimalContextEnabled?: boolean;
|
|
45
|
+
plannerTier?: "forced_deterministic" | "deterministic" | "llm_intent_router" | "full_llm" | "demo";
|
|
46
|
+
toolName?: string;
|
|
47
|
+
toolOk?: boolean;
|
|
48
|
+
toolLatencyMs?: number;
|
|
49
|
+
toolAttempts?: number;
|
|
50
|
+
toolErrorCode?: string;
|
|
51
|
+
correlationId?: string;
|
|
52
|
+
};
|
|
53
|
+
type Logger = {
|
|
54
|
+
info: (payload: Record<string, unknown>, message?: string) => void;
|
|
55
|
+
error: (payload: Record<string, unknown>, message?: string) => void;
|
|
56
|
+
};
|
|
57
|
+
type CreateChatTelemetryStoreArgs = {
|
|
58
|
+
filePath: string;
|
|
59
|
+
limit: number;
|
|
60
|
+
persistEnabled: boolean;
|
|
61
|
+
logger: Logger;
|
|
62
|
+
onPush?: (entry: ChatTelemetryEntry) => void;
|
|
63
|
+
};
|
|
64
|
+
export declare function createChatTelemetryStore(args: CreateChatTelemetryStoreArgs): {
|
|
65
|
+
promptExcerpt: (message: string) => string;
|
|
66
|
+
promptHash: (message: string) => string;
|
|
67
|
+
push: (entry: ChatTelemetryEntry) => void;
|
|
68
|
+
loadFromDisk: () => Promise<void>;
|
|
69
|
+
list: (args: {
|
|
70
|
+
limit?: number;
|
|
71
|
+
outcome?: string;
|
|
72
|
+
phase?: string;
|
|
73
|
+
session?: string;
|
|
74
|
+
}) => {
|
|
75
|
+
totalBuffered: number;
|
|
76
|
+
returned: number;
|
|
77
|
+
byOutcome: Record<string, number>;
|
|
78
|
+
byReasonCategory: Record<string, number>;
|
|
79
|
+
rows: ChatTelemetryEntry[];
|
|
80
|
+
};
|
|
81
|
+
review: (args: {
|
|
82
|
+
limit?: number;
|
|
83
|
+
session?: string;
|
|
84
|
+
}) => {
|
|
85
|
+
analyzed: number;
|
|
86
|
+
appliedCount: number;
|
|
87
|
+
failedCount: number;
|
|
88
|
+
failureRate: number;
|
|
89
|
+
plannerRefusalCount: number;
|
|
90
|
+
plannerIncompleteCount: number;
|
|
91
|
+
failureByOutcome: Record<string, number>;
|
|
92
|
+
failureByReasonCategory: Record<string, number>;
|
|
93
|
+
topFailedPrompts: {
|
|
94
|
+
promptExcerpt: string;
|
|
95
|
+
count: number;
|
|
96
|
+
outcomes: Record<string, number>;
|
|
97
|
+
reasonCategories: Record<string, number>;
|
|
98
|
+
lastAt: string;
|
|
99
|
+
promptHash: string;
|
|
100
|
+
}[];
|
|
101
|
+
recommendations: string[];
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
export type ChatTelemetryStore = ReturnType<typeof createChatTelemetryStore>;
|
|
105
|
+
export {};
|