wyrm-mcp 7.2.0 → 7.2.2
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 +26 -667
- package/NOTICE +14 -33
- package/dist/activation.d.ts.map +1 -1
- package/dist/activation.js +1 -44
- package/dist/activation.js.map +1 -1
- package/dist/agent-daemon.js +4 -281
- package/dist/agent-loop.js +7 -332
- package/dist/analytics.js +13 -236
- package/dist/attribution.js +1 -49
- package/dist/audit.js +2 -457
- package/dist/auto-capture.js +3 -138
- package/dist/auto-orchestrator.js +1 -325
- package/dist/autoconfig.js +39 -840
- package/dist/buddy-runner.js +1 -109
- package/dist/buddy.js +14 -564
- package/dist/build-flags.js +1 -17
- package/dist/capabilities.js +3 -183
- package/dist/capture.js +1 -56
- package/dist/causality.js +6 -107
- package/dist/cli.js +20 -281
- package/dist/cloud/cli.js +5 -541
- package/dist/cloud/client.js +1 -221
- package/dist/cloud/crypto.js +1 -85
- package/dist/cloud/machine-id.js +2 -113
- package/dist/cloud/recovery.js +1 -60
- package/dist/cloud/sync-engine.js +7 -543
- package/dist/cloud-backup.js +5 -579
- package/dist/cloud-profile.js +1 -138
- package/dist/cloud-sync-entrypoint.js +1 -47
- package/dist/cloud-sync.js +2 -309
- package/dist/constellation.js +12 -168
- package/dist/context-build-budgeted.js +4 -144
- package/dist/context-ranking.js +1 -69
- package/dist/crypto.js +1 -179
- package/dist/daemon-write-endpoint.js +1 -290
- package/dist/daemon-writer.js +2 -406
- package/dist/database.js +43 -1110
- package/dist/deprecations.js +2 -162
- package/dist/design.js +13 -141
- package/dist/event-replication.js +1 -112
- package/dist/events-sse.js +7 -43
- package/dist/events.js +6 -238
- package/dist/failure-patterns.js +42 -659
- package/dist/federation.js +12 -236
- package/dist/goals.js +13 -101
- package/dist/golden.js +3 -355
- package/dist/handlers/agent.js +4 -165
- package/dist/handlers/alias-adapters.js +1 -129
- package/dist/handlers/aliases.js +1 -171
- package/dist/handlers/audit.js +1 -87
- package/dist/handlers/boundary.js +1 -221
- package/dist/handlers/capture.js +73 -1109
- package/dist/handlers/causality.js +7 -114
- package/dist/handlers/cloud.js +85 -382
- package/dist/handlers/companion.js +28 -459
- package/dist/handlers/datalake.js +7 -187
- package/dist/handlers/dispatch-context.js +0 -22
- package/dist/handlers/entity.js +25 -256
- package/dist/handlers/events.js +16 -335
- package/dist/handlers/failure.js +13 -340
- package/dist/handlers/goals.js +4 -296
- package/dist/handlers/intelligence.js +126 -674
- package/dist/handlers/invoicing.js +1 -70
- package/dist/handlers/mcpclient.js +6 -137
- package/dist/handlers/orchestration.js +40 -125
- package/dist/handlers/output-schemas.js +1 -24
- package/dist/handlers/presence.js +3 -99
- package/dist/handlers/project.js +28 -182
- package/dist/handlers/prompts.js +6 -157
- package/dist/handlers/quest.js +4 -224
- package/dist/handlers/recall.js +11 -218
- package/dist/handlers/registry.js +1 -167
- package/dist/handlers/resources.js +1 -288
- package/dist/handlers/review.js +11 -74
- package/dist/handlers/run.js +17 -487
- package/dist/handlers/search.js +15 -326
- package/dist/handlers/session.js +28 -615
- package/dist/handlers/share.js +8 -184
- package/dist/handlers/shims.js +1 -464
- package/dist/handlers/skill.js +67 -449
- package/dist/handlers/survivors.js +1 -120
- package/dist/handlers/symbols.js +8 -109
- package/dist/handlers/syncops.js +4 -302
- package/dist/handlers/types.js +1 -27
- package/dist/harvest.js +5 -191
- package/dist/hours.js +7 -156
- package/dist/http-auth.js +3 -321
- package/dist/http-fast.js +21 -1137
- package/dist/icons.js +1 -47
- package/dist/index.js +2 -924
- package/dist/indexer.js +4 -145
- package/dist/intelligence.js +31 -261
- package/dist/internal-dispatch.js +3 -212
- package/dist/keyset.js +1 -110
- package/dist/knowledge-graph.js +12 -176
- package/dist/license.d.ts +11 -0
- package/dist/license.d.ts.map +1 -1
- package/dist/license.js +2 -414
- package/dist/license.js.map +1 -1
- package/dist/logger.js +2 -199
- package/dist/maintenance.js +2 -148
- package/dist/mcp-client.js +6 -262
- package/dist/memory-artifacts.js +30 -449
- package/dist/migrate-prompt.js +2 -124
- package/dist/migrations.js +40 -655
- package/dist/performance.js +1 -228
- package/dist/presence.js +11 -140
- package/dist/priority-embed.js +5 -164
- package/dist/providers/embedding-provider.js +1 -196
- package/dist/readonly-gate.js +1 -29
- package/dist/rehydration.js +9 -157
- package/dist/reindex.js +1 -88
- package/dist/render-target.js +21 -514
- package/dist/render.js +4 -280
- package/dist/repl-guard.js +1 -173
- package/dist/replication-daemon-entrypoint.js +1 -31
- package/dist/replication-daemon.js +2 -262
- package/dist/resilience.js +1 -591
- package/dist/reverse-bridge.js +5 -360
- package/dist/security.js +1 -244
- package/dist/session-seen.js +3 -51
- package/dist/setup.js +1 -260
- package/dist/skill-author.js +5 -168
- package/dist/spec-kit.js +1 -191
- package/dist/sqlite-busy.js +1 -154
- package/dist/statusline.js +11 -315
- package/dist/sub-agent.js +13 -262
- package/dist/summarizer.js +13 -139
- package/dist/symbols.js +7 -283
- package/dist/sync.js +5 -359
- package/dist/tasks-dispatch.js +1 -84
- package/dist/tasks.js +1 -282
- package/dist/token-budget.js +1 -143
- package/dist/tool-analytics.js +7 -129
- package/dist/tool-annotations.js +1 -365
- package/dist/tool-manifest-v2.json +1 -1
- package/dist/tool-manifest.json +1 -1
- package/dist/tool-profiles.js +1 -75
- package/dist/trace-harvest.js +6 -244
- package/dist/types.js +1 -30
- package/dist/ui-dashboard.js +41 -50
- package/dist/ulid.js +1 -81
- package/dist/validate.js +1 -129
- package/dist/vault.js +1 -534
- package/dist/vectors.js +3 -184
- package/dist/version-check.js +4 -136
- package/dist/visibility.js +19 -155
- package/dist/wyrm-cli.js +98 -2451
- package/dist/wyrm-cli.js.map +1 -1
- package/dist/wyrm-guard.js +14 -424
- package/dist/wyrm-loop.js +3 -150
- package/dist/wyrm-manifest.json +1 -1
- package/dist/wyrm-statusline-daemon.js +1 -11
- package/dist/wyrm-statusline.js +4 -56
- package/dist/wyrm-ui.js +9 -77
- package/package.json +4 -2
|
@@ -1,290 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Daemon-as-writer endpoint logic (v7 F2, T012) — the `POST /write` op surface.
|
|
3
|
-
*
|
|
4
|
-
* When a client process runs with WYRM_DAEMON_WRITES=1 (src/daemon-writer.ts),
|
|
5
|
-
* its CANONICAL WRITES are routed over loopback HTTP to the running daemon
|
|
6
|
-
* (http-fast), which executes them here against ITS database connection —
|
|
7
|
-
* funneling a fleet's writes through one process instead of N contending ones.
|
|
8
|
-
* Reads always stay local to the client.
|
|
9
|
-
*
|
|
10
|
-
* Extracted from http-fast.ts in the readonly-gate.ts style: DB-parameterized
|
|
11
|
-
* and side-effect-free at module load, so the op surface is unit-testable
|
|
12
|
-
* without booting the HTTP server.
|
|
13
|
-
*
|
|
14
|
-
* Article VII — minimal request surface, validated at the boundary:
|
|
15
|
-
* - ONE endpoint, a CLOSED op allowlist (DAEMON_WRITE_OPS). Unknown ops are
|
|
16
|
-
* rejected; there is deliberately no generic "run this SQL/method" escape.
|
|
17
|
-
* - Each op calls the SAME domain method the client's direct path would call
|
|
18
|
-
* (db.insertData / failures.record / truths.set / artifacts.add /
|
|
19
|
-
* db.addQuest), so row shapes are identical in both modes.
|
|
20
|
-
* - `project_id` is a plain integer id: client and daemon share the same
|
|
21
|
-
* database file, so ids are stable across the loopback hop. Project-path
|
|
22
|
-
* resolution (a read) happens client-side.
|
|
23
|
-
* - Enum-ish fields (scope/severity/kind/...) are NOT re-validated here beyond
|
|
24
|
-
* type checks: the domain methods + the schema CHECK constraints are the
|
|
25
|
-
* single source of truth for value validation in BOTH modes — re-implementing
|
|
26
|
-
* the lists here would let the two paths drift. A CHECK/FK violation comes
|
|
27
|
-
* back to the client as the rejected `{e}` shape (see handleDaemonWrite's
|
|
28
|
-
* error mapping), never a generic 500 the client would have to treat as
|
|
29
|
-
* commit-state-unknown.
|
|
30
|
-
*
|
|
31
|
-
* Attribution (v7 F2 review fix): the caller's FULL envelope rides in the
|
|
32
|
-
* request body as `actor: {agent_id, run_id}` — the `Wyrm-Actor` header
|
|
33
|
-
* grammar (`agent_id[;run_id]`) cannot express a run-only envelope, so a
|
|
34
|
-
* header-only hop silently dropped run attribution and let the DAEMON's own
|
|
35
|
-
* env (http-fast's env-level resolution) stamp the caller's row — flipping
|
|
36
|
-
* the T014 quarantine tier (a run-quarantined failure could land
|
|
37
|
-
* project-wide, or an unattributed write could be quarantined to an
|
|
38
|
-
* unrelated run). When the body carries `actor`, it is AUTHORITATIVE: the
|
|
39
|
-
* write runs inside that exact envelope ('param' level), and both-null is an
|
|
40
|
-
* EXPLICIT legacy envelope (columns stay NULL) — the daemon's env can never
|
|
41
|
-
* bleed in. Bodies without `actor` (pre-fix clients) keep the ambient
|
|
42
|
-
* header/env semantics.
|
|
43
|
-
*
|
|
44
|
-
* Idempotency (v7 F2 review fix): the client mints a ULID `write_id` per
|
|
45
|
-
* logical write. Committed write_ids are remembered in an in-memory ledger
|
|
46
|
-
* with TIME-BASED retention (DEDUP_TTL_MS — sized to the realistic caller
|
|
47
|
-
* retry horizon: the instructed retry round-trips through an LLM agent whose
|
|
48
|
-
* next turn is seconds to minutes away, NOT a protocol-bounded window); a
|
|
49
|
-
* duplicate write_id inside the horizon REPLAYS the committed result instead
|
|
50
|
-
* of re-executing — so the client's timeout re-send / instructed retry cannot
|
|
51
|
-
* land a second row (the at-least-once duplicate the adversarial review
|
|
52
|
-
* confirmed). The count cap (DEDUP_CAP) is a memory backstop only — under a
|
|
53
|
-
* sustained fleet burst it, not time, may evict first. Documented residual
|
|
54
|
-
* at-least-once windows: a daemon RESTART loses the ledger, and a retry
|
|
55
|
-
* arriving past the retention horizon (TTL or backstop eviction) re-executes
|
|
56
|
-
* — a VISIBLE fresh execution, never a silent stale replay.
|
|
57
|
-
*
|
|
58
|
-
* Privacy: ops write through the normal domain methods, so the Live Memory
|
|
59
|
-
* surface is unchanged — failure events stay reference-only (is_shared=0).
|
|
60
|
-
*
|
|
61
|
-
* @copyright 2026 Ghost Protocol (Pvt) Ltd.
|
|
62
|
-
* @license AGPL-3.0-or-later — dual-licensed; commercial terms: ghosts.lk@proton.me. See LICENSE.
|
|
63
|
-
*/
|
|
64
|
-
import { isSqliteConstraintError } from './sqlite-busy.js';
|
|
65
|
-
import { LEGACY_ENVELOPE, runWithActor, sanitizeActorId, } from './handlers/boundary.js';
|
|
66
|
-
/**
|
|
67
|
-
* The closed op allowlist — the four canonical write paths of spec FR-1
|
|
68
|
-
* (data-lake insert, failure_record, truth_set, capture), where `capture`
|
|
69
|
-
* decomposes into the three writes wyrm_capture can perform (quest_add /
|
|
70
|
-
* truth_set / artifact_add). Anything else stays on the client's direct path.
|
|
71
|
-
*/
|
|
72
|
-
export const DAEMON_WRITE_OPS = [
|
|
73
|
-
'data_insert',
|
|
74
|
-
'failure_record',
|
|
75
|
-
'truth_set',
|
|
76
|
-
'artifact_add',
|
|
77
|
-
'quest_add',
|
|
78
|
-
];
|
|
79
|
-
export function isDaemonWriteOp(value) {
|
|
80
|
-
return typeof value === 'string' && DAEMON_WRITE_OPS.includes(value);
|
|
81
|
-
}
|
|
82
|
-
/** Boundary check: a finite positive integer id (project ids are rowids). */
|
|
83
|
-
function asProjectId(value) {
|
|
84
|
-
return typeof value === 'number' && Number.isInteger(value) && value > 0 ? value : null;
|
|
85
|
-
}
|
|
86
|
-
function asString(value) {
|
|
87
|
-
return typeof value === 'string' && value.length > 0 ? value : null;
|
|
88
|
-
}
|
|
89
|
-
// ── idempotency ledger (v7 F2 review fix) ───────────────────────────────────
|
|
90
|
-
// write_id → the committed result, replayed on duplicate delivery. Retention
|
|
91
|
-
// is TIME-based: the caller-level instructed retry round-trips through an LLM
|
|
92
|
-
// agent (seconds to minutes — retry_after_ms is advice, not a bound), so a
|
|
93
|
-
// count-FIFO sized to "seconds-scale" gets evicted from under a live retry by
|
|
94
|
-
// any >cap fleet burst in that gap — re-executing a committed write_id, a
|
|
95
|
-
// duplicate with no daemon crash. Entries live DEDUP_TTL_MS; expired entries
|
|
96
|
-
// are swept on insert (insertion order is commit order, so they cluster at
|
|
97
|
-
// the front). DEDUP_CAP remains only as a memory backstop ({ulid, small row}
|
|
98
|
-
// entries are tiny). Only SUCCESSFUL (committed) results are remembered — a
|
|
99
|
-
// rejected/thrown write left nothing behind, so re-executing it is correct.
|
|
100
|
-
export const DEDUP_TTL_MS = 10 * 60_000;
|
|
101
|
-
const DEDUP_CAP = 4096;
|
|
102
|
-
const committedWrites = new Map();
|
|
103
|
-
/** Test hook: clear the idempotency ledger between cases. */
|
|
104
|
-
export function _resetDaemonWriteDedupForTests() {
|
|
105
|
-
committedWrites.clear();
|
|
106
|
-
}
|
|
107
|
-
/** Test hook: age every ledger entry by `ms` (drives TTL eviction without a clock). */
|
|
108
|
-
export function _ageDaemonWriteDedupForTests(ms) {
|
|
109
|
-
for (const entry of committedWrites.values())
|
|
110
|
-
entry.committedAt -= ms;
|
|
111
|
-
}
|
|
112
|
-
function rememberCommitted(writeId, result) {
|
|
113
|
-
const now = Date.now();
|
|
114
|
-
// Age sweep first: retention is the TTL; the count cap below is only the
|
|
115
|
-
// memory backstop. committedAt is non-decreasing in insertion order, so the
|
|
116
|
-
// sweep stops at the first fresh entry.
|
|
117
|
-
for (const [id, entry] of committedWrites) {
|
|
118
|
-
if (now - entry.committedAt < DEDUP_TTL_MS)
|
|
119
|
-
break;
|
|
120
|
-
committedWrites.delete(id);
|
|
121
|
-
}
|
|
122
|
-
if (!committedWrites.has(writeId) && committedWrites.size >= DEDUP_CAP) {
|
|
123
|
-
const oldest = committedWrites.keys().next().value;
|
|
124
|
-
if (oldest !== undefined)
|
|
125
|
-
committedWrites.delete(oldest);
|
|
126
|
-
}
|
|
127
|
-
committedWrites.set(writeId, { result, committedAt: now });
|
|
128
|
-
}
|
|
129
|
-
/** Boundary check for the client-minted idempotency key (a 26-char ULID; the
|
|
130
|
-
* bound mirrors sanitizeActorId's 64-char ceiling). Absent/invalid → no dedup
|
|
131
|
-
* (the pre-fix client shape). */
|
|
132
|
-
function asWriteId(value) {
|
|
133
|
-
return typeof value === 'string' && value.length > 0 && value.length <= 64 ? value : null;
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* Execute one allowlisted write op. Returns the written row on success or a
|
|
137
|
-
* compact `{ e }` error (the house wire format for http-fast routes).
|
|
138
|
-
*
|
|
139
|
-
* Error mapping by what the throw PROVES about the commit:
|
|
140
|
-
* - SQLITE_CONSTRAINT family (CHECK/FK/UNIQUE/NOT NULL) → the rejected `{e}`
|
|
141
|
-
* shape carrying the real constraint message. Every op is a single
|
|
142
|
-
* statement or one IMMEDIATE transaction, so a constraint throw proves the
|
|
143
|
-
* rollback — the client safely fails direct and the local path surfaces
|
|
144
|
-
* the same deterministic error to the caller. Without this, a generic 500
|
|
145
|
-
* reads as commit-state-unknown and the same inputs re-violate forever.
|
|
146
|
-
* - Everything else (SQLITE_BUSY → http-fast's structured 503; SQLITE_FULL,
|
|
147
|
-
* a post-commit throw, ...) propagates — the dispatcher catch owns
|
|
148
|
-
* transport mapping, and a non-constraint throw does NOT prove no commit,
|
|
149
|
-
* so it must never claim the rejected shape.
|
|
150
|
-
*/
|
|
151
|
-
export function handleDaemonWrite(deps, args) {
|
|
152
|
-
const op = args.op;
|
|
153
|
-
if (!isDaemonWriteOp(op))
|
|
154
|
-
return { e: 'unknown op' };
|
|
155
|
-
const input = (args.input ?? {});
|
|
156
|
-
const projectId = asProjectId(args.project_id);
|
|
157
|
-
// Idempotent replay: this write_id already committed — the response was
|
|
158
|
-
// lost in flight. Hand back the SAME row; never execute twice. No age check
|
|
159
|
-
// on read: an old committed result is still the truth (the TTL governs
|
|
160
|
-
// memory retention, not correctness).
|
|
161
|
-
const writeId = asWriteId(args.write_id);
|
|
162
|
-
if (writeId !== null) {
|
|
163
|
-
const replay = committedWrites.get(writeId);
|
|
164
|
-
if (replay !== undefined)
|
|
165
|
-
return replay.result;
|
|
166
|
-
}
|
|
167
|
-
// Body-supplied attribution is authoritative for the forwarded write (see
|
|
168
|
-
// the module header): sanitize at the boundary, run the op inside that
|
|
169
|
-
// exact envelope. Both-null → the EXPLICIT legacy envelope (NULL columns) —
|
|
170
|
-
// never the daemon's own env. No `actor` field at all → pre-fix client:
|
|
171
|
-
// keep the ambient (header/env) semantics unchanged.
|
|
172
|
-
let result;
|
|
173
|
-
try {
|
|
174
|
-
const actorRaw = args.actor;
|
|
175
|
-
if (actorRaw !== undefined && actorRaw !== null && typeof actorRaw === 'object') {
|
|
176
|
-
const a = actorRaw;
|
|
177
|
-
const agent = sanitizeActorId(a.agent_id);
|
|
178
|
-
const run = sanitizeActorId(a.run_id);
|
|
179
|
-
const envelope = agent === null && run === null
|
|
180
|
-
? LEGACY_ENVELOPE
|
|
181
|
-
: { agent_id: agent, run_id: run, source: 'param' };
|
|
182
|
-
result = runWithActor(envelope, () => executeDaemonOp(deps, op, projectId, args.project_id, input));
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
result = executeDaemonOp(deps, op, projectId, args.project_id, input);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
catch (err) {
|
|
189
|
-
// Deterministic domain rejection — provably rolled back (see the function
|
|
190
|
-
// doc). Carry the real message so the caller's direct-path retry of the
|
|
191
|
-
// same inputs reproduces a NAMED error, not a mystery 500.
|
|
192
|
-
if (isSqliteConstraintError(err)) {
|
|
193
|
-
return { e: err instanceof Error ? err.message : String(err) };
|
|
194
|
-
}
|
|
195
|
-
// BUSY (the structured 503 contract) and anything that might have
|
|
196
|
-
// committed stay on the throw path — never claim "no commit" for them.
|
|
197
|
-
throw err;
|
|
198
|
-
}
|
|
199
|
-
// Remember only COMMITTED outcomes (post-commit by construction: the domain
|
|
200
|
-
// method returned synchronously above).
|
|
201
|
-
if (writeId !== null && 'ok' in result && result.ok === true) {
|
|
202
|
-
rememberCommitted(writeId, result);
|
|
203
|
-
}
|
|
204
|
-
return result;
|
|
205
|
-
}
|
|
206
|
-
function executeDaemonOp(deps, op, projectId, rawProjectId, input) {
|
|
207
|
-
switch (op) {
|
|
208
|
-
case 'data_insert': {
|
|
209
|
-
if (projectId === null)
|
|
210
|
-
return { e: 'project_id required' };
|
|
211
|
-
const category = asString(input.category);
|
|
212
|
-
const key = asString(input.key);
|
|
213
|
-
const value = asString(input.value);
|
|
214
|
-
if (!category || !key || !value)
|
|
215
|
-
return { e: 'category, key, value required' };
|
|
216
|
-
// value arrives client-prepared (sanitized + maybeEncrypt'ed): the
|
|
217
|
-
// encryption key stays in the CLIENT process (Article VII — the daemon
|
|
218
|
-
// never needs WYRM_ENCRYPTION_KEY to serve writes).
|
|
219
|
-
const row = deps.db.insertData(projectId, category, key, value, input.metadata);
|
|
220
|
-
return { ok: true, op, row };
|
|
221
|
-
}
|
|
222
|
-
case 'failure_record': {
|
|
223
|
-
// project_id may be null here: global (cross-project) failures are legal.
|
|
224
|
-
if (rawProjectId != null && projectId === null)
|
|
225
|
-
return { e: 'project_id must be an integer' };
|
|
226
|
-
const target = asString(input.target);
|
|
227
|
-
const description = asString(input.description);
|
|
228
|
-
const scope = asString(input.scope);
|
|
229
|
-
if (!scope || !target || !description)
|
|
230
|
-
return { e: 'scope, target, description required' };
|
|
231
|
-
const row = deps.failures.record({
|
|
232
|
-
project_id: projectId,
|
|
233
|
-
scope: scope,
|
|
234
|
-
target,
|
|
235
|
-
description,
|
|
236
|
-
why_failed: typeof input.why_failed === 'string' ? input.why_failed : undefined,
|
|
237
|
-
severity: typeof input.severity === 'string' ? input.severity : undefined,
|
|
238
|
-
});
|
|
239
|
-
return { ok: true, op, row };
|
|
240
|
-
}
|
|
241
|
-
case 'truth_set': {
|
|
242
|
-
if (projectId === null)
|
|
243
|
-
return { e: 'project_id required' };
|
|
244
|
-
const category = asString(input.category);
|
|
245
|
-
const key = asString(input.key);
|
|
246
|
-
const value = asString(input.value);
|
|
247
|
-
if (!category || !key || !value)
|
|
248
|
-
return { e: 'category, key, value required' };
|
|
249
|
-
const row = deps.truths.set(projectId, {
|
|
250
|
-
category, key, value,
|
|
251
|
-
rationale: typeof input.rationale === 'string' ? input.rationale : undefined,
|
|
252
|
-
source: typeof input.source === 'string' ? input.source : undefined,
|
|
253
|
-
confidence: typeof input.confidence === 'number' ? input.confidence : undefined,
|
|
254
|
-
ttl_days: typeof input.ttl_days === 'number' ? input.ttl_days : undefined,
|
|
255
|
-
});
|
|
256
|
-
return { ok: true, op, row };
|
|
257
|
-
}
|
|
258
|
-
case 'artifact_add': {
|
|
259
|
-
if (projectId === null)
|
|
260
|
-
return { e: 'project_id required' };
|
|
261
|
-
const kind = asString(input.kind);
|
|
262
|
-
const problem = asString(input.problem);
|
|
263
|
-
if (!kind || !problem)
|
|
264
|
-
return { e: 'kind, problem required' };
|
|
265
|
-
const row = deps.artifacts.add(projectId, {
|
|
266
|
-
kind, problem,
|
|
267
|
-
constraints: typeof input.constraints === 'string' ? input.constraints : undefined,
|
|
268
|
-
validatedFix: typeof input.validatedFix === 'string' ? input.validatedFix : undefined,
|
|
269
|
-
whyItWorked: typeof input.whyItWorked === 'string' ? input.whyItWorked : undefined,
|
|
270
|
-
outcome: typeof input.outcome === 'string' ? input.outcome : undefined,
|
|
271
|
-
sourceSessionId: typeof input.sourceSessionId === 'number' ? input.sourceSessionId : undefined,
|
|
272
|
-
tags: Array.isArray(input.tags) ? input.tags.filter((t) => typeof t === 'string') : undefined,
|
|
273
|
-
confidence: typeof input.confidence === 'number' ? input.confidence : undefined,
|
|
274
|
-
createdBy: typeof input.createdBy === 'string' ? input.createdBy : undefined,
|
|
275
|
-
needsReview: typeof input.needsReview === 'number' ? input.needsReview : undefined,
|
|
276
|
-
});
|
|
277
|
-
return { ok: true, op, row };
|
|
278
|
-
}
|
|
279
|
-
case 'quest_add': {
|
|
280
|
-
if (projectId === null)
|
|
281
|
-
return { e: 'project_id required' };
|
|
282
|
-
const title = asString(input.title);
|
|
283
|
-
if (!title)
|
|
284
|
-
return { e: 'title required' };
|
|
285
|
-
const row = deps.db.addQuest(projectId, title, typeof input.description === 'string' ? input.description : undefined, (typeof input.priority === 'string' ? input.priority : 'medium'), typeof input.tags === 'string' ? input.tags : undefined);
|
|
286
|
-
return { ok: true, op, row };
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
//# sourceMappingURL=daemon-write-endpoint.js.map
|
|
1
|
+
import{isSqliteConstraintError as _}from"./sqlite-busy.js";import{LEGACY_ENVELOPE as g,runWithActor as k,sanitizeActorId as y}from"./handlers/boundary.js";const w=["data_insert","failure_record","truth_set","artifact_add","quest_add"];function h(t){return typeof t=="string"&&w.includes(t)}function b(t){return typeof t=="number"&&Number.isInteger(t)&&t>0?t:null}function d(t){return typeof t=="string"&&t.length>0?t:null}const D=10*6e4,q=4096,f=new Map;function S(){f.clear()}function P(t){for(const i of f.values())i.committedAt-=t}function x(t,i){const s=Date.now();for(const[a,e]of f){if(s-e.committedAt<D)break;f.delete(a)}if(!f.has(t)&&f.size>=q){const a=f.keys().next().value;a!==void 0&&f.delete(a)}f.set(t,{result:i,committedAt:s})}function W(t){return typeof t=="string"&&t.length>0&&t.length<=64?t:null}function F(t,i){const s=i.op;if(!h(s))return{e:"unknown op"};const a=i.input??{},e=b(i.project_id),o=W(i.write_id);if(o!==null){const r=f.get(o);if(r!==void 0)return r.result}let n;try{const r=i.actor;if(r!=null&&typeof r=="object"){const c=r,u=y(c.agent_id),l=y(c.run_id);n=k(u===null&&l===null?g:{agent_id:u,run_id:l,source:"param"},()=>m(t,s,e,i.project_id,a))}else n=m(t,s,e,i.project_id,a)}catch(r){if(_(r))return{e:r instanceof Error?r.message:String(r)};throw r}return o!==null&&"ok"in n&&n.ok===!0&&x(o,n),n}function m(t,i,s,a,e){switch(i){case"data_insert":{if(s===null)return{e:"project_id required"};const o=d(e.category),n=d(e.key),r=d(e.value);if(!o||!n||!r)return{e:"category, key, value required"};const c=t.db.insertData(s,o,n,r,e.metadata);return{ok:!0,op:i,row:c}}case"failure_record":{if(a!=null&&s===null)return{e:"project_id must be an integer"};const o=d(e.target),n=d(e.description),r=d(e.scope);if(!r||!o||!n)return{e:"scope, target, description required"};const c=t.failures.record({project_id:s,scope:r,target:o,description:n,why_failed:typeof e.why_failed=="string"?e.why_failed:void 0,severity:typeof e.severity=="string"?e.severity:void 0});return{ok:!0,op:i,row:c}}case"truth_set":{if(s===null)return{e:"project_id required"};const o=d(e.category),n=d(e.key),r=d(e.value);if(!o||!n||!r)return{e:"category, key, value required"};const c=t.truths.set(s,{category:o,key:n,value:r,rationale:typeof e.rationale=="string"?e.rationale:void 0,source:typeof e.source=="string"?e.source:void 0,confidence:typeof e.confidence=="number"?e.confidence:void 0,ttl_days:typeof e.ttl_days=="number"?e.ttl_days:void 0});return{ok:!0,op:i,row:c}}case"artifact_add":{if(s===null)return{e:"project_id required"};const o=d(e.kind),n=d(e.problem);if(!o||!n)return{e:"kind, problem required"};const r=t.artifacts.add(s,{kind:o,problem:n,constraints:typeof e.constraints=="string"?e.constraints:void 0,validatedFix:typeof e.validatedFix=="string"?e.validatedFix:void 0,whyItWorked:typeof e.whyItWorked=="string"?e.whyItWorked:void 0,outcome:typeof e.outcome=="string"?e.outcome:void 0,sourceSessionId:typeof e.sourceSessionId=="number"?e.sourceSessionId:void 0,tags:Array.isArray(e.tags)?e.tags.filter(c=>typeof c=="string"):void 0,confidence:typeof e.confidence=="number"?e.confidence:void 0,createdBy:typeof e.createdBy=="string"?e.createdBy:void 0,needsReview:typeof e.needsReview=="number"?e.needsReview:void 0});return{ok:!0,op:i,row:r}}case"quest_add":{if(s===null)return{e:"project_id required"};const o=d(e.title);if(!o)return{e:"title required"};const n=t.db.addQuest(s,o,typeof e.description=="string"?e.description:void 0,typeof e.priority=="string"?e.priority:"medium",typeof e.tags=="string"?e.tags:void 0);return{ok:!0,op:i,row:n}}}}export{w as DAEMON_WRITE_OPS,D as DEDUP_TTL_MS,P as _ageDaemonWriteDedupForTests,S as _resetDaemonWriteDedupForTests,F as handleDaemonWrite,h as isDaemonWriteOp};
|