wicked-crew 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/audit.d.ts +70 -0
- package/dist/api/audit.d.ts.map +1 -0
- package/dist/api/audit.js +131 -0
- package/dist/api/audit.js.map +1 -0
- package/dist/api/auth.d.ts +192 -0
- package/dist/api/auth.d.ts.map +1 -0
- package/dist/api/auth.js +515 -0
- package/dist/api/auth.js.map +1 -0
- package/dist/api/gate-cache.d.ts +8 -0
- package/dist/api/gate-cache.d.ts.map +1 -1
- package/dist/api/gate-cache.js +10 -0
- package/dist/api/gate-cache.js.map +1 -1
- package/dist/api/guidance-index.d.ts +39 -0
- package/dist/api/guidance-index.d.ts.map +1 -0
- package/dist/api/guidance-index.js +67 -0
- package/dist/api/guidance-index.js.map +1 -0
- package/dist/api/open-path.d.ts +34 -0
- package/dist/api/open-path.d.ts.map +1 -0
- package/dist/api/open-path.js +101 -0
- package/dist/api/open-path.js.map +1 -0
- package/dist/api/retry-index.d.ts +30 -0
- package/dist/api/retry-index.d.ts.map +1 -0
- package/dist/api/retry-index.js +45 -0
- package/dist/api/retry-index.js.map +1 -0
- package/dist/api/routes.d.ts +164 -1
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +769 -21
- package/dist/api/routes.js.map +1 -1
- package/dist/api/run-files.d.ts +63 -0
- package/dist/api/run-files.d.ts.map +1 -0
- package/dist/api/run-files.js +271 -0
- package/dist/api/run-files.js.map +1 -0
- package/dist/api/seat-health.d.ts +55 -0
- package/dist/api/seat-health.d.ts.map +1 -0
- package/dist/api/seat-health.js +273 -0
- package/dist/api/seat-health.js.map +1 -0
- package/dist/api/seat-signin.d.ts +27 -0
- package/dist/api/seat-signin.d.ts.map +1 -0
- package/dist/api/seat-signin.js +143 -0
- package/dist/api/seat-signin.js.map +1 -0
- package/dist/api/server.d.ts +190 -3
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +365 -11
- package/dist/api/server.js.map +1 -1
- package/dist/api/stall-watchdog.d.ts +62 -0
- package/dist/api/stall-watchdog.d.ts.map +1 -0
- package/dist/api/stall-watchdog.js +138 -0
- package/dist/api/stall-watchdog.js.map +1 -0
- package/dist/cli/index.js +171 -12
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp.d.ts +14 -0
- package/dist/cli/mcp.d.ts.map +1 -0
- package/dist/cli/mcp.js +119 -0
- package/dist/cli/mcp.js.map +1 -0
- package/dist/core/adapter.d.ts +87 -10
- package/dist/core/adapter.d.ts.map +1 -1
- package/dist/core/adapter.js +347 -28
- package/dist/core/adapter.js.map +1 -1
- package/dist/core/bridge-reaper.d.ts +134 -0
- package/dist/core/bridge-reaper.d.ts.map +1 -0
- package/dist/core/bridge-reaper.js +286 -0
- package/dist/core/bridge-reaper.js.map +1 -0
- package/dist/core/deliver.d.ts +118 -0
- package/dist/core/deliver.d.ts.map +1 -0
- package/dist/core/deliver.js +241 -0
- package/dist/core/deliver.js.map +1 -0
- package/dist/core/deliverable-floor.d.ts +103 -0
- package/dist/core/deliverable-floor.d.ts.map +1 -0
- package/dist/core/deliverable-floor.js +173 -0
- package/dist/core/deliverable-floor.js.map +1 -0
- package/dist/core/exec.d.ts +2 -0
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js.map +1 -1
- package/dist/core/types.d.ts +92 -352
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +14 -4
- package/dist/core/types.js.map +1 -1
- package/dist/interactive/bridge-pool.d.ts +99 -0
- package/dist/interactive/bridge-pool.d.ts.map +1 -0
- package/dist/interactive/bridge-pool.js +244 -0
- package/dist/interactive/bridge-pool.js.map +1 -0
- package/dist/interactive/bridge-root.d.ts +36 -0
- package/dist/interactive/bridge-root.d.ts.map +1 -0
- package/dist/interactive/bridge-root.js +48 -0
- package/dist/interactive/bridge-root.js.map +1 -0
- package/dist/interactive/chat-events.d.ts +207 -0
- package/dist/interactive/chat-events.d.ts.map +1 -0
- package/dist/interactive/chat-events.js +769 -0
- package/dist/interactive/chat-events.js.map +1 -0
- package/dist/interactive/demo-events.d.ts +283 -0
- package/dist/interactive/demo-events.d.ts.map +1 -0
- package/dist/interactive/demo-events.js +889 -0
- package/dist/interactive/demo-events.js.map +1 -0
- package/dist/interactive/draft-events.d.ts +224 -0
- package/dist/interactive/draft-events.d.ts.map +1 -0
- package/dist/interactive/draft-events.js +793 -0
- package/dist/interactive/draft-events.js.map +1 -0
- package/dist/interactive/edit-events.d.ts +194 -0
- package/dist/interactive/edit-events.d.ts.map +1 -0
- package/dist/interactive/edit-events.js +601 -0
- package/dist/interactive/edit-events.js.map +1 -0
- package/dist/interactive/ledger.d.ts +39 -0
- package/dist/interactive/ledger.d.ts.map +1 -0
- package/dist/interactive/ledger.js +93 -0
- package/dist/interactive/ledger.js.map +1 -0
- package/dist/interactive/proxy-routes.d.ts +39 -0
- package/dist/interactive/proxy-routes.d.ts.map +1 -0
- package/dist/interactive/proxy-routes.js +189 -0
- package/dist/interactive/proxy-routes.js.map +1 -0
- package/dist/interactive/repo-snapshot.d.ts +100 -0
- package/dist/interactive/repo-snapshot.d.ts.map +1 -0
- package/dist/interactive/repo-snapshot.js +289 -0
- package/dist/interactive/repo-snapshot.js.map +1 -0
- package/dist/interactive/ws-relay.d.ts +85 -0
- package/dist/interactive/ws-relay.d.ts.map +1 -0
- package/dist/interactive/ws-relay.js +191 -0
- package/dist/interactive/ws-relay.js.map +1 -0
- package/dist/projects/activity.d.ts +29 -0
- package/dist/projects/activity.d.ts.map +1 -0
- package/dist/projects/activity.js +172 -0
- package/dist/projects/activity.js.map +1 -0
- package/dist/projects/charter.d.ts +28 -0
- package/dist/projects/charter.d.ts.map +1 -0
- package/dist/projects/charter.js +53 -0
- package/dist/projects/charter.js.map +1 -0
- package/dist/projects/events.d.ts +55 -0
- package/dist/projects/events.d.ts.map +1 -0
- package/dist/projects/events.js +141 -0
- package/dist/projects/events.js.map +1 -0
- package/dist/projects/graph-paths.d.ts +92 -0
- package/dist/projects/graph-paths.d.ts.map +1 -0
- package/dist/projects/graph-paths.js +130 -0
- package/dist/projects/graph-paths.js.map +1 -0
- package/dist/projects/graph.d.ts +179 -0
- package/dist/projects/graph.d.ts.map +1 -0
- package/dist/projects/graph.js +775 -0
- package/dist/projects/graph.js.map +1 -0
- package/dist/projects/membership-index.d.ts +25 -0
- package/dist/projects/membership-index.d.ts.map +1 -0
- package/dist/projects/membership-index.js +46 -0
- package/dist/projects/membership-index.js.map +1 -0
- package/dist/projects/routes.d.ts +97 -0
- package/dist/projects/routes.d.ts.map +1 -0
- package/dist/projects/routes.js +510 -0
- package/dist/projects/routes.js.map +1 -0
- package/dist/projects/settings.d.ts +32 -0
- package/dist/projects/settings.d.ts.map +1 -0
- package/dist/projects/settings.js +64 -0
- package/dist/projects/settings.js.map +1 -0
- package/dist/qe/acceptance.d.ts +137 -0
- package/dist/qe/acceptance.d.ts.map +1 -0
- package/dist/qe/acceptance.js +249 -0
- package/dist/qe/acceptance.js.map +1 -0
- package/dist/qe/gate-events.d.ts +111 -0
- package/dist/qe/gate-events.d.ts.map +1 -0
- package/dist/qe/gate-events.js +168 -0
- package/dist/qe/gate-events.js.map +1 -0
- package/dist/qe/ledger.d.ts +100 -0
- package/dist/qe/ledger.d.ts.map +1 -0
- package/dist/qe/ledger.js +154 -0
- package/dist/qe/ledger.js.map +1 -0
- package/dist/studio/assets/index-8p8uwCxG.js +530 -0
- package/dist/studio/assets/index-D6S9zUtO.css +32 -0
- package/dist/studio/index.html +5 -3
- package/package.json +10 -4
- package/dist/studio/assets/index-DaaUU8Ep.css +0 -32
- package/dist/studio/assets/index-Fu5DRC00.js +0 -423
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The project activity feed (DES-PROJECT-001 §5.2) — a READ-SIDE MERGE, not a new store.
|
|
3
|
+
*
|
|
4
|
+
* Two sources, one normalized shape:
|
|
5
|
+
* - CREW: the durable core-event log of the project's `crew.run`/`crew.chat` members
|
|
6
|
+
* (`adapter.runEvents` — the same log `/runs/:id/events` serves), entry id `crew:<run>:<seq>`.
|
|
7
|
+
* - INTERACTIVE: `wicked.interactive.*` bus events carrying this `project_id`, read directly
|
|
8
|
+
* from the bus SQLite READ-ONLY (`node:sqlite`, the `requirements.ts` precedent — wicked-bus
|
|
9
|
+
* exposes subscribe-cursors, not ad-hoc history queries, and a durable cursor per feed-read
|
|
10
|
+
* would turn a GET into a write), entry id `bus:<event_id>`.
|
|
11
|
+
*
|
|
12
|
+
* Newest-first, cursor on `(ts, id)` — an opaque `<ts>:<id>` token, base64url. The merge is
|
|
13
|
+
* recomputed per read; members are few and the log excludes high-volume frames, so the simple
|
|
14
|
+
* full-merge is the honest v1 (the ADR explicitly rejects a new store here).
|
|
15
|
+
*/
|
|
16
|
+
let sqliteMod;
|
|
17
|
+
async function sqlite() {
|
|
18
|
+
if (sqliteMod === undefined) {
|
|
19
|
+
try {
|
|
20
|
+
const name = 'node:sqlite';
|
|
21
|
+
sqliteMod = (await import(name));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
sqliteMod = null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return sqliteMod;
|
|
28
|
+
}
|
|
29
|
+
/** One-line human summary of a core frame (best-effort; `raw` carries the whole frame). */
|
|
30
|
+
function summarizeCoreEvent(frame, runId) {
|
|
31
|
+
const type = typeof frame['type'] === 'string' ? frame['type'] : 'event';
|
|
32
|
+
switch (type) {
|
|
33
|
+
case 'sessionStarted':
|
|
34
|
+
return `run ${runId} started`;
|
|
35
|
+
case 'awaitingHuman':
|
|
36
|
+
return `run ${runId} paused at a human gate${typeof frame['prompt'] === 'string' ? `: ${frame['prompt'].slice(0, 120)}` : ''}`;
|
|
37
|
+
case 'resumed':
|
|
38
|
+
return `run ${runId} resumed`;
|
|
39
|
+
case 'sessionCompleted':
|
|
40
|
+
return `run ${runId} completed`;
|
|
41
|
+
case 'sessionFailed':
|
|
42
|
+
return `run ${runId} failed`;
|
|
43
|
+
case 'runCancelled':
|
|
44
|
+
return `run ${runId} cancelled`;
|
|
45
|
+
case 'gateDecided':
|
|
46
|
+
return `run ${runId}: gate decided (${String(frame['allow'] ?? '?')})`;
|
|
47
|
+
default:
|
|
48
|
+
return `run ${runId}: ${type}`;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function summarizeInteractive(eventType, payload) {
|
|
52
|
+
const doc = payload !== null && typeof payload['document_id'] === 'string' ? payload['document_id'] : '?';
|
|
53
|
+
const short = eventType.replace(/^wicked\.interactive\./, '');
|
|
54
|
+
return `doc ${doc}: ${short}`;
|
|
55
|
+
}
|
|
56
|
+
/** Opaque cursor: base64url of `<ts>:<id>`. */
|
|
57
|
+
export function encodeCursor(ts, id) {
|
|
58
|
+
return Buffer.from(`${ts}:${id}`, 'utf8').toString('base64url');
|
|
59
|
+
}
|
|
60
|
+
export function decodeCursor(cursor) {
|
|
61
|
+
try {
|
|
62
|
+
const raw = Buffer.from(cursor, 'base64url').toString('utf8');
|
|
63
|
+
const sep = raw.indexOf(':');
|
|
64
|
+
if (sep < 1)
|
|
65
|
+
return null;
|
|
66
|
+
const ts = Number(raw.slice(0, sep));
|
|
67
|
+
if (!Number.isFinite(ts))
|
|
68
|
+
return null;
|
|
69
|
+
return { ts, id: raw.slice(sep + 1) };
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/** Newest-first ordering on `(ts, id)` — the cursor's total order. */
|
|
76
|
+
function newerFirst(a, b) {
|
|
77
|
+
return b.ts - a.ts || (a.id < b.id ? 1 : a.id > b.id ? -1 : 0);
|
|
78
|
+
}
|
|
79
|
+
/** Strictly older than the cursor position (the page the caller has not seen). */
|
|
80
|
+
function olderThan(entry, cur) {
|
|
81
|
+
return entry.ts < cur.ts || (entry.ts === cur.ts && entry.id < cur.id);
|
|
82
|
+
}
|
|
83
|
+
/** The crew half: fold each member run/chat's durable log into entries. */
|
|
84
|
+
async function crewEntries(adapter, refs) {
|
|
85
|
+
const entries = [];
|
|
86
|
+
for (const ref of refs) {
|
|
87
|
+
const events = await adapter.runEvents(ref);
|
|
88
|
+
if (events === null)
|
|
89
|
+
break; // no event-log binding on this addon — the crew half is empty
|
|
90
|
+
for (const event of events) {
|
|
91
|
+
const frame = event;
|
|
92
|
+
const ts = typeof frame['ts'] === 'number' ? frame['ts'] : 0;
|
|
93
|
+
const seq = typeof frame['seq'] === 'number' ? frame['seq'] : 0;
|
|
94
|
+
entries.push({
|
|
95
|
+
id: `crew:${ref}:${seq}`,
|
|
96
|
+
ts,
|
|
97
|
+
source: 'crew',
|
|
98
|
+
kind: typeof frame['type'] === 'string' ? frame['type'] : 'event',
|
|
99
|
+
ref,
|
|
100
|
+
summary: summarizeCoreEvent(frame, ref),
|
|
101
|
+
raw: event,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return entries;
|
|
106
|
+
}
|
|
107
|
+
/** The interactive half: bus events carrying this `project_id`, read-only. */
|
|
108
|
+
async function interactiveEntries(busDbPath, projectId) {
|
|
109
|
+
if (busDbPath === null)
|
|
110
|
+
return [];
|
|
111
|
+
const mod = await sqlite();
|
|
112
|
+
if (mod === null)
|
|
113
|
+
return [];
|
|
114
|
+
let db = null;
|
|
115
|
+
const entries = [];
|
|
116
|
+
try {
|
|
117
|
+
db = new mod.DatabaseSync(busDbPath, { readOnly: true });
|
|
118
|
+
const rows = db
|
|
119
|
+
.prepare(`SELECT event_id, event_type, payload, emitted_at FROM events
|
|
120
|
+
WHERE event_type LIKE 'wicked.interactive.%'
|
|
121
|
+
AND json_extract(payload, '$.project_id') = ?
|
|
122
|
+
ORDER BY emitted_at DESC LIMIT 1000`)
|
|
123
|
+
.all(projectId);
|
|
124
|
+
for (const row of rows) {
|
|
125
|
+
let payload = null;
|
|
126
|
+
try {
|
|
127
|
+
payload = JSON.parse(row.payload);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
/* raw stays the string */
|
|
131
|
+
}
|
|
132
|
+
entries.push({
|
|
133
|
+
id: `bus:${row.event_id}`,
|
|
134
|
+
ts: row.emitted_at,
|
|
135
|
+
source: 'interactive',
|
|
136
|
+
kind: row.event_type,
|
|
137
|
+
ref: payload !== null && typeof payload['document_id'] === 'string'
|
|
138
|
+
? payload['document_id']
|
|
139
|
+
: '',
|
|
140
|
+
summary: summarizeInteractive(row.event_type, payload),
|
|
141
|
+
raw: { event_type: row.event_type, payload: payload ?? row.payload, emitted_at: row.emitted_at },
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
// No bus db / schema mismatch — the interactive half is empty, never an error:
|
|
147
|
+
// a project with no bound docs must not 500 its activity feed.
|
|
148
|
+
return entries;
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
db?.close();
|
|
152
|
+
}
|
|
153
|
+
return entries;
|
|
154
|
+
}
|
|
155
|
+
/** Build one page of the merged feed. `refs` = the project's run/chat member refs. */
|
|
156
|
+
export async function buildActivityPage(adapter, projectId, refs, busDbPath, cursor, limit) {
|
|
157
|
+
const merged = [...(await crewEntries(adapter, refs)), ...(await interactiveEntries(busDbPath, projectId))];
|
|
158
|
+
merged.sort(newerFirst);
|
|
159
|
+
let page = merged;
|
|
160
|
+
if (cursor !== undefined) {
|
|
161
|
+
const decoded = decodeCursor(cursor);
|
|
162
|
+
if (decoded !== null)
|
|
163
|
+
page = merged.filter((e) => olderThan(e, decoded));
|
|
164
|
+
}
|
|
165
|
+
const entries = page.slice(0, limit);
|
|
166
|
+
const last = entries[entries.length - 1];
|
|
167
|
+
const nextCursor = entries.length === limit && page.length > limit && last !== undefined
|
|
168
|
+
? encodeCursor(last.ts, last.id)
|
|
169
|
+
: null;
|
|
170
|
+
return { entries, nextCursor };
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=activity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity.js","sourceRoot":"","sources":["../../src/projects/activity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAcH,IAAI,SAA0C,CAAC;AAC/C,KAAK,UAAU,MAAM;IACnB,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,aAAa,CAAC;YAC3B,SAAS,GAAG,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,CAAiB,CAAC;QACnD,CAAC;QAAC,MAAM,CAAC;YACP,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,2FAA2F;AAC3F,SAAS,kBAAkB,CAAC,KAA8B,EAAE,KAAa;IACvE,MAAM,IAAI,GAAG,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,KAAK,CAAC,MAAM,CAAY,CAAC,CAAC,CAAC,OAAO,CAAC;IACrF,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,gBAAgB;YACnB,OAAO,OAAO,KAAK,UAAU,CAAC;QAChC,KAAK,eAAe;YAClB,OAAO,OAAO,KAAK,0BACjB,OAAO,KAAK,CAAC,QAAQ,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAM,KAAK,CAAC,QAAQ,CAAY,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAC3F,EAAE,CAAC;QACL,KAAK,SAAS;YACZ,OAAO,OAAO,KAAK,UAAU,CAAC;QAChC,KAAK,kBAAkB;YACrB,OAAO,OAAO,KAAK,YAAY,CAAC;QAClC,KAAK,eAAe;YAClB,OAAO,OAAO,KAAK,SAAS,CAAC;QAC/B,KAAK,cAAc;YACjB,OAAO,OAAO,KAAK,YAAY,CAAC;QAClC,KAAK,aAAa;YAChB,OAAO,OAAO,KAAK,mBAAmB,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC;QACzE;YACE,OAAO,OAAO,KAAK,KAAK,IAAI,EAAE,CAAC;IACnC,CAAC;AACH,CAAC;AAED,SAAS,oBAAoB,CAAC,SAAiB,EAAE,OAAuC;IACtF,MAAM,GAAG,GAAG,OAAO,KAAK,IAAI,IAAI,OAAO,OAAO,CAAC,aAAa,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,OAAO,CAAC,aAAa,CAAY,CAAC,CAAC,CAAC,GAAG,CAAC;IACtH,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,wBAAwB,EAAE,EAAE,CAAC,CAAC;IAC9D,OAAO,OAAO,GAAG,KAAK,KAAK,EAAE,CAAC;AAChC,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,YAAY,CAAC,EAAU,EAAE,EAAU;IACjD,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC9D,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,GAAG,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACzB,MAAM,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QACrC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YAAE,OAAO,IAAI,CAAC;QACtC,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,sEAAsE;AACtE,SAAS,UAAU,CAAC,CAAgB,EAAE,CAAgB;IACpD,OAAO,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,kFAAkF;AAClF,SAAS,SAAS,CAAC,KAAoB,EAAE,GAA+B;IACtE,OAAO,KAAK,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,IAAI,KAAK,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC;AACzE,CAAC;AAED,2EAA2E;AAC3E,KAAK,UAAU,WAAW,CAAC,OAAoB,EAAE,IAAc;IAC7D,MAAM,OAAO,GAAoB,EAAE,CAAC;IACpC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAC5C,IAAI,MAAM,KAAK,IAAI;YAAE,MAAM,CAAC,8DAA8D;QAC1F,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,KAA2C,CAAC;YAC1D,MAAM,EAAE,GAAG,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,KAAK,CAAC,IAAI,CAAY,CAAC,CAAC,CAAC,CAAC,CAAC;YACzE,MAAM,GAAG,GAAG,OAAO,KAAK,CAAC,KAAK,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,KAAK,CAAC,KAAK,CAAY,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5E,OAAO,CAAC,IAAI,CAAC;gBACX,EAAE,EAAE,QAAQ,GAAG,IAAI,GAAG,EAAE;gBACxB,EAAE;gBACF,MAAM,EAAE,MAAM;gBACd,IAAI,EAAE,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,KAAK,CAAC,MAAM,CAAY,CAAC,CAAC,CAAC,OAAO;gBAC7E,GAAG;gBACH,OAAO,EAAE,kBAAkB,CAAC,KAAK,EAAE,GAAG,CAAC;gBACvC,GAAG,EAAE,KAAK;aACX,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,8EAA8E;AAC9E,KAAK,UAAU,kBAAkB,CAC/B,SAAwB,EACxB,SAAiB;IAEjB,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,GAAG,GAAG,MAAM,MAAM,EAAE,CAAC;IAC3B,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IAC5B,IAAI,EAAE,GAA0B,IAAI,CAAC;IACrC,MAAM,OAAO,GAAoB,EAAE,CAAC;IACpC,IAAI,CAAC;QACH,EAAE,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,EAAE;aACZ,OAAO,CACN;;;6CAGqC,CACtC;aACA,GAAG,CAAC,SAAS,CAAoF,CAAC;QACrG,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,OAAO,GAAmC,IAAI,CAAC;YACnD,IAAI,CAAC;gBACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAA4B,CAAC;YAC/D,CAAC;YAAC,MAAM,CAAC;gBACP,0BAA0B;YAC5B,CAAC;YACD,OAAO,CAAC,IAAI,CAAC;gBACX,EAAE,EAAE,OAAO,GAAG,CAAC,QAAQ,EAAE;gBACzB,EAAE,EAAE,GAAG,CAAC,UAAU;gBAClB,MAAM,EAAE,aAAa;gBACrB,IAAI,EAAE,GAAG,CAAC,UAAU;gBACpB,GAAG,EACD,OAAO,KAAK,IAAI,IAAI,OAAO,OAAO,CAAC,aAAa,CAAC,KAAK,QAAQ;oBAC5D,CAAC,CAAE,OAAO,CAAC,aAAa,CAAY;oBACpC,CAAC,CAAC,EAAE;gBACR,OAAO,EAAE,oBAAoB,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC;gBACtD,GAAG,EAAE,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,IAAI,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE;aACjG,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,+EAA+E;QAC/E,+DAA+D;QAC/D,OAAO,OAAO,CAAC;IACjB,CAAC;YAAS,CAAC;QACT,EAAE,EAAE,KAAK,EAAE,CAAC;IACd,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,sFAAsF;AACtF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,OAAoB,EACpB,SAAiB,EACjB,IAAc,EACd,SAAwB,EACxB,MAA0B,EAC1B,KAAa;IAEb,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,kBAAkB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IAC5G,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAExB,IAAI,IAAI,GAAG,MAAM,CAAC;IAClB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACrC,IAAI,OAAO,KAAK,IAAI;YAAE,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IAC3E,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzC,MAAM,UAAU,GACd,OAAO,CAAC,MAAM,KAAK,KAAK,IAAI,IAAI,CAAC,MAAM,GAAG,KAAK,IAAI,IAAI,KAAK,SAAS;QACnE,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC;QAChC,CAAC,CAAC,IAAI,CAAC;IACX,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The foundation record of a project (DES-PROJECT-001 §3.2) — thin crew glue, deliberately.
|
|
3
|
+
*
|
|
4
|
+
* On create/update/archive the daemon writes the PROJECT CHARTER (name, description, lifecycle
|
|
5
|
+
* note) into the engine's knowledge store under the project's stored scope, and a memory at that
|
|
6
|
+
* scope. On a project-bound run's completion it writes the EVIDENCE POINTER (run id → the
|
|
7
|
+
* conventional in-repo verdict path). Estate needs no schema change: `project:` is pure
|
|
8
|
+
* convention over the kind:id scope grammar.
|
|
9
|
+
*
|
|
10
|
+
* Everything here is BEST-EFFORT with retry-free logging: the record is eventually consistent
|
|
11
|
+
* with the state by design ("no cross-plane transactionality", ADR §10) — a knowledge-store
|
|
12
|
+
* hiccup must never fail the API call that already committed control state. And the plane rule
|
|
13
|
+
* holds in both directions: delete core.db and the charter + memories still say what this
|
|
14
|
+
* project was; delete the record and the project still operates, with amnesia.
|
|
15
|
+
*/
|
|
16
|
+
import type { CoreAdapter } from '../core/adapter.js';
|
|
17
|
+
import type { Project } from '../core/types.js';
|
|
18
|
+
type Log = (msg: string) => void;
|
|
19
|
+
/** Write/refresh the charter after a committed create/update/archive. Fire-and-forget. */
|
|
20
|
+
export declare function writeCharter(adapter: CoreAdapter, project: Project, action: 'created' | 'updated' | 'archived' | 'restored', log: Log): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Write the evidence pointer for a completed project-bound run (§3.2 row 3): the run id plus the
|
|
23
|
+
* conventional in-repo verdict path. The evidence FILES stay in-repo (QE convention) — the
|
|
24
|
+
* foundation holds pointers, never copies.
|
|
25
|
+
*/
|
|
26
|
+
export declare function writeRunEvidencePointer(adapter: CoreAdapter, projectScope: string, runId: string, repoRoot: string | null, log: Log): Promise<void>;
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=charter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"charter.d.ts","sourceRoot":"","sources":["../../src/projects/charter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAEhD,KAAK,GAAG,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;AAEjC,0FAA0F;AAC1F,wBAAsB,YAAY,CAChC,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,EACvD,GAAG,EAAE,GAAG,GACP,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,WAAW,EACpB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,GAAG,EAAE,GAAG,GACP,OAAO,CAAC,IAAI,CAAC,CAiBf"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The foundation record of a project (DES-PROJECT-001 §3.2) — thin crew glue, deliberately.
|
|
3
|
+
*
|
|
4
|
+
* On create/update/archive the daemon writes the PROJECT CHARTER (name, description, lifecycle
|
|
5
|
+
* note) into the engine's knowledge store under the project's stored scope, and a memory at that
|
|
6
|
+
* scope. On a project-bound run's completion it writes the EVIDENCE POINTER (run id → the
|
|
7
|
+
* conventional in-repo verdict path). Estate needs no schema change: `project:` is pure
|
|
8
|
+
* convention over the kind:id scope grammar.
|
|
9
|
+
*
|
|
10
|
+
* Everything here is BEST-EFFORT with retry-free logging: the record is eventually consistent
|
|
11
|
+
* with the state by design ("no cross-plane transactionality", ADR §10) — a knowledge-store
|
|
12
|
+
* hiccup must never fail the API call that already committed control state. And the plane rule
|
|
13
|
+
* holds in both directions: delete core.db and the charter + memories still say what this
|
|
14
|
+
* project was; delete the record and the project still operates, with amnesia.
|
|
15
|
+
*/
|
|
16
|
+
/** Write/refresh the charter after a committed create/update/archive. Fire-and-forget. */
|
|
17
|
+
export async function writeCharter(adapter, project, action, log) {
|
|
18
|
+
try {
|
|
19
|
+
const when = new Date(project.updated_at).toISOString();
|
|
20
|
+
const chunks = [
|
|
21
|
+
`Project charter — ${project.name} (${project.id}). Status: ${project.status}. ` +
|
|
22
|
+
`Scope: ${project.scope}. ${action} at ${when} via crew.`,
|
|
23
|
+
...(project.description !== null && project.description !== undefined
|
|
24
|
+
? [project.description]
|
|
25
|
+
: []),
|
|
26
|
+
];
|
|
27
|
+
await adapter.ingestKnowledge(project.scope, chunks);
|
|
28
|
+
await adapter.captureMemory(`Project '${project.name}' (${project.id}) ${action}. Charter recorded in the knowledge store under ${project.scope}.`, project.scope);
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
log(`[projects] charter write for ${project.id} failed (state committed; record lags): ${err instanceof Error ? err.message : String(err)}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Write the evidence pointer for a completed project-bound run (§3.2 row 3): the run id plus the
|
|
36
|
+
* conventional in-repo verdict path. The evidence FILES stay in-repo (QE convention) — the
|
|
37
|
+
* foundation holds pointers, never copies.
|
|
38
|
+
*/
|
|
39
|
+
export async function writeRunEvidencePointer(adapter, projectScope, runId, repoRoot, log) {
|
|
40
|
+
try {
|
|
41
|
+
const scope = `${projectScope}/run:${runId}`;
|
|
42
|
+
const pointer = repoRoot !== null
|
|
43
|
+
? `${repoRoot}/.wicked-testing/evidence/${runId}/verdict.json`
|
|
44
|
+
: `(repo-less run — no evidence tree)`;
|
|
45
|
+
await adapter.ingestKnowledge(scope, [
|
|
46
|
+
`Run ${runId} completed under ${projectScope}. Evidence pointer: ${pointer}`,
|
|
47
|
+
]);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
log(`[projects] evidence-pointer write for ${runId} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=charter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"charter.js","sourceRoot":"","sources":["../../src/projects/charter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAOH,0FAA0F;AAC1F,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAoB,EACpB,OAAgB,EAChB,MAAuD,EACvD,GAAQ;IAER,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,CAAC;QACxD,MAAM,MAAM,GAAG;YACb,qBAAqB,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,EAAE,cAAc,OAAO,CAAC,MAAM,IAAI;gBAC9E,UAAU,OAAO,CAAC,KAAK,KAAK,MAAM,OAAO,IAAI,YAAY;YAC3D,GAAG,CAAC,OAAO,CAAC,WAAW,KAAK,IAAI,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS;gBACnE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;gBACvB,CAAC,CAAC,EAAE,CAAC;SACR,CAAC;QACF,MAAM,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACrD,MAAM,OAAO,CAAC,aAAa,CACzB,YAAY,OAAO,CAAC,IAAI,MAAM,OAAO,CAAC,EAAE,KAAK,MAAM,mDAAmD,OAAO,CAAC,KAAK,GAAG,EACtH,OAAO,CAAC,KAAK,CACd,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CACD,gCAAgC,OAAO,CAAC,EAAE,2CACxC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CACjD,EAAE,CACH,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,OAAoB,EACpB,YAAoB,EACpB,KAAa,EACb,QAAuB,EACvB,GAAQ;IAER,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,GAAG,YAAY,QAAQ,KAAK,EAAE,CAAC;QAC7C,MAAM,OAAO,GACX,QAAQ,KAAK,IAAI;YACf,CAAC,CAAC,GAAG,QAAQ,6BAA6B,KAAK,eAAe;YAC9D,CAAC,CAAC,oCAAoC,CAAC;QAC3C,MAAM,OAAO,CAAC,eAAe,CAAC,KAAK,EAAE;YACnC,OAAO,KAAK,oBAAoB,YAAY,uBAAuB,OAAO,EAAE;SAC7E,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CACD,yCAAyC,KAAK,YAC5C,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CACjD,EAAE,CACH,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The project bus seam (DES-PROJECT-001 §4) — crew's side of the conversation.
|
|
3
|
+
*
|
|
4
|
+
* Two halves, one bus handle:
|
|
5
|
+
*
|
|
6
|
+
* 1. EMIT `wicked.crew.project.{created,updated,archived}` and
|
|
7
|
+
* `wicked.crew.membership.{attached,detached}` — always POST-COMMIT (the route handlers call
|
|
8
|
+
* these only after the engine's reply, so a phantom event for a write that never landed cannot
|
|
9
|
+
* exist). Idempotency keys are TYPE-INCLUSIVE (DES-EXEC-001 rev0.2 correction #4a — two event
|
|
10
|
+
* types sharing a key silently drop one on the bus's UNIQUE constraint) and occurrence-unique
|
|
11
|
+
* (an attach after a detach is a new fact, so the key carries the attach timestamp).
|
|
12
|
+
*
|
|
13
|
+
* 2. BRIDGE `wicked.interactive.*` events that carry a `project_id` onto the daemon's `/ws`
|
|
14
|
+
* stream as `projectActivity` frames, so an open project view sees creator-skin progress live
|
|
15
|
+
* without a reload (ADR §5.2 / §8 step 7). The durable feed read is `activity.ts`; this is
|
|
16
|
+
* only the liveness tap.
|
|
17
|
+
*
|
|
18
|
+
* Posture mirrors the QE/interactive-draft seams: the bus is OPTIONAL. A machine without
|
|
19
|
+
* wicked-bus (or with a broken db) gets a loudly-logged null — project CRUD keeps working, the
|
|
20
|
+
* events simply don't ride, and the daemon boots regardless.
|
|
21
|
+
*/
|
|
22
|
+
/** Crew's bus DOMAIN COLUMN value — the product-scoped plugin name, matching the repo precedent
|
|
23
|
+
* (`INTERACTIVE_DOMAIN = 'wicked-interactive'`). The EVENT TYPES carry the §4 grammar's bare
|
|
24
|
+
* `crew` segment (`wicked.crew.project.created`); the two spellings are different fields. */
|
|
25
|
+
export declare const CREW_BUS_DOMAIN = "wicked-crew";
|
|
26
|
+
export declare const PROJECT_CREATED = "wicked.crew.project.created";
|
|
27
|
+
export declare const PROJECT_UPDATED = "wicked.crew.project.updated";
|
|
28
|
+
export declare const PROJECT_ARCHIVED = "wicked.crew.project.archived";
|
|
29
|
+
export declare const MEMBERSHIP_ATTACHED = "wicked.crew.membership.attached";
|
|
30
|
+
export declare const MEMBERSHIP_DETACHED = "wicked.crew.membership.detached";
|
|
31
|
+
export interface ProjectBus {
|
|
32
|
+
/** Emit one post-commit project event. Never throws; WB-002 (duplicate key) is success. */
|
|
33
|
+
emit(type: string, payload: Record<string, unknown>, idempotencyKey: string): boolean;
|
|
34
|
+
/** The resolved bus db path (the activity feed's read side opens the same file). */
|
|
35
|
+
dbPath: string | null;
|
|
36
|
+
stop(): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
export interface ProjectBusOptions {
|
|
39
|
+
/** Bus db path; omit for wicked-bus's own resolution (honors WICKED_BUS_DATA_DIR). */
|
|
40
|
+
dbPath?: string;
|
|
41
|
+
/** Poll cadence for the /ws bridge subscriber, ms (tests shorten it). */
|
|
42
|
+
pollIntervalMs?: number;
|
|
43
|
+
log?: (msg: string) => void;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Open the bus and arm both halves. Returns `null` (logged) when wicked-bus is not importable
|
|
47
|
+
* or the db cannot open — the caller degrades to CRUD-without-events.
|
|
48
|
+
*/
|
|
49
|
+
export declare function startProjectBus(opts?: ProjectBusOptions): Promise<ProjectBus | null>;
|
|
50
|
+
export declare function projectCreatedKey(projectId: string): string;
|
|
51
|
+
export declare function projectUpdatedKey(projectId: string, updatedAt: number): string;
|
|
52
|
+
export declare function projectArchivedKey(projectId: string, updatedAt: number): string;
|
|
53
|
+
export declare function membershipAttachedKey(projectId: string, kind: string, ref: string, attachedAt: number): string;
|
|
54
|
+
export declare function membershipDetachedKey(projectId: string, memberId: string, at: number): string;
|
|
55
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/projects/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAKH;;8FAE8F;AAC9F,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAM7C,eAAO,MAAM,eAAe,gCAAgC,CAAC;AAC7D,eAAO,MAAM,eAAe,gCAAgC,CAAC;AAC7D,eAAO,MAAM,gBAAgB,iCAAiC,CAAC;AAC/D,eAAO,MAAM,mBAAmB,oCAAoC,CAAC;AACrE,eAAO,MAAM,mBAAmB,oCAAoC,CAAC;AAErE,MAAM,WAAW,UAAU;IACzB,2FAA2F;IAC3F,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC;IACtF,oFAAoF;IACpF,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,IAAI,GAAE,iBAAsB,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAgG9F;AAID,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3D;AACD,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE9E;AACD,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE/E;AACD,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GACjB,MAAM,CAER;AACD,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAE7F"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The project bus seam (DES-PROJECT-001 §4) — crew's side of the conversation.
|
|
3
|
+
*
|
|
4
|
+
* Two halves, one bus handle:
|
|
5
|
+
*
|
|
6
|
+
* 1. EMIT `wicked.crew.project.{created,updated,archived}` and
|
|
7
|
+
* `wicked.crew.membership.{attached,detached}` — always POST-COMMIT (the route handlers call
|
|
8
|
+
* these only after the engine's reply, so a phantom event for a write that never landed cannot
|
|
9
|
+
* exist). Idempotency keys are TYPE-INCLUSIVE (DES-EXEC-001 rev0.2 correction #4a — two event
|
|
10
|
+
* types sharing a key silently drop one on the bus's UNIQUE constraint) and occurrence-unique
|
|
11
|
+
* (an attach after a detach is a new fact, so the key carries the attach timestamp).
|
|
12
|
+
*
|
|
13
|
+
* 2. BRIDGE `wicked.interactive.*` events that carry a `project_id` onto the daemon's `/ws`
|
|
14
|
+
* stream as `projectActivity` frames, so an open project view sees creator-skin progress live
|
|
15
|
+
* without a reload (ADR §5.2 / §8 step 7). The durable feed read is `activity.ts`; this is
|
|
16
|
+
* only the liveness tap.
|
|
17
|
+
*
|
|
18
|
+
* Posture mirrors the QE/interactive-draft seams: the bus is OPTIONAL. A machine without
|
|
19
|
+
* wicked-bus (or with a broken db) gets a loudly-logged null — project CRUD keeps working, the
|
|
20
|
+
* events simply don't ride, and the daemon boots regardless.
|
|
21
|
+
*/
|
|
22
|
+
import { broadcast } from '../events/bus.js';
|
|
23
|
+
/** Crew's bus DOMAIN COLUMN value — the product-scoped plugin name, matching the repo precedent
|
|
24
|
+
* (`INTERACTIVE_DOMAIN = 'wicked-interactive'`). The EVENT TYPES carry the §4 grammar's bare
|
|
25
|
+
* `crew` segment (`wicked.crew.project.created`); the two spellings are different fields. */
|
|
26
|
+
export const CREW_BUS_DOMAIN = 'wicked-crew';
|
|
27
|
+
const CREW_PRODUCER = 'wicked-crew';
|
|
28
|
+
/** The subscriber identity of the /ws liveness bridge. */
|
|
29
|
+
const BRIDGE_PLUGIN = 'wicked-crew-projects';
|
|
30
|
+
const INTERACTIVE_FILTER = 'wicked.interactive.**';
|
|
31
|
+
export const PROJECT_CREATED = 'wicked.crew.project.created';
|
|
32
|
+
export const PROJECT_UPDATED = 'wicked.crew.project.updated';
|
|
33
|
+
export const PROJECT_ARCHIVED = 'wicked.crew.project.archived';
|
|
34
|
+
export const MEMBERSHIP_ATTACHED = 'wicked.crew.membership.attached';
|
|
35
|
+
export const MEMBERSHIP_DETACHED = 'wicked.crew.membership.detached';
|
|
36
|
+
/**
|
|
37
|
+
* Open the bus and arm both halves. Returns `null` (logged) when wicked-bus is not importable
|
|
38
|
+
* or the db cannot open — the caller degrades to CRUD-without-events.
|
|
39
|
+
*/
|
|
40
|
+
export async function startProjectBus(opts = {}) {
|
|
41
|
+
const log = opts.log ?? (() => undefined);
|
|
42
|
+
let bus;
|
|
43
|
+
try {
|
|
44
|
+
bus = await import('wicked-bus');
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
log(`[projects] wicked-bus is not importable — project events disabled: ${err instanceof Error ? err.message : String(err)}`);
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
let db;
|
|
51
|
+
let config;
|
|
52
|
+
try {
|
|
53
|
+
config = bus.loadConfig(opts.dbPath !== undefined ? { db_path: opts.dbPath } : {});
|
|
54
|
+
db = bus.openDb(opts.dbPath !== undefined ? { db_path: opts.dbPath } : {});
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
log(`[projects] could not open the bus db${opts.dbPath !== undefined ? ` at ${opts.dbPath}` : ''} — project events disabled: ${err instanceof Error ? err.message : String(err)}`);
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
function emit(type, payload, idempotencyKey) {
|
|
61
|
+
try {
|
|
62
|
+
bus.emit(db, config, {
|
|
63
|
+
event_type: type,
|
|
64
|
+
domain: CREW_BUS_DOMAIN,
|
|
65
|
+
subdomain: type.startsWith('wicked.crew.membership.') ? 'membership' : 'project',
|
|
66
|
+
payload: { ts: new Date().toISOString(), ...payload },
|
|
67
|
+
producer_id: CREW_PRODUCER,
|
|
68
|
+
idempotency_key: idempotencyKey,
|
|
69
|
+
});
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
const code = err.error;
|
|
74
|
+
if (code === 'WB-002')
|
|
75
|
+
return true; // duplicate key — the emit already happened
|
|
76
|
+
log(`[projects] emit ${type} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// The /ws liveness bridge: interactive events that name a project become `projectActivity`
|
|
81
|
+
// frames. Consumers that don't know the frame ignore it (additive CoreEvent contract).
|
|
82
|
+
let bridge = null;
|
|
83
|
+
try {
|
|
84
|
+
bridge = bus.subscribe({
|
|
85
|
+
db,
|
|
86
|
+
plugin: BRIDGE_PLUGIN,
|
|
87
|
+
filter: INTERACTIVE_FILTER,
|
|
88
|
+
cursor_init: 'latest',
|
|
89
|
+
pollIntervalMs: opts.pollIntervalMs ?? 2000,
|
|
90
|
+
// Fold-into-a-socket only; a retry loop / DLQ entry for a lost liveness frame is noise —
|
|
91
|
+
// the durable read (`/projects/:id/activity`) is the record, this is the tap.
|
|
92
|
+
maxRetries: 0,
|
|
93
|
+
handler: (event) => {
|
|
94
|
+
const payload = event.payload;
|
|
95
|
+
const projectId = payload !== null && typeof payload === 'object' ? payload['project_id'] : undefined;
|
|
96
|
+
if (typeof projectId !== 'string' || projectId === '')
|
|
97
|
+
return;
|
|
98
|
+
broadcast({
|
|
99
|
+
type: 'projectActivity',
|
|
100
|
+
project_id: projectId,
|
|
101
|
+
source: 'interactive',
|
|
102
|
+
event_type: event.event_type,
|
|
103
|
+
payload,
|
|
104
|
+
ts: event.emitted_at,
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
onError: (err, event) => {
|
|
108
|
+
log(`[projects] /ws bridge error on event ${String(event?.event_id ?? '?')}: ${err.message}`);
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
log(`[projects] could not arm the /ws activity bridge (events still emit): ${err instanceof Error ? err.message : String(err)}`);
|
|
114
|
+
}
|
|
115
|
+
const dbPath = typeof config['db_path'] === 'string' ? config['db_path'] : null;
|
|
116
|
+
return {
|
|
117
|
+
emit,
|
|
118
|
+
dbPath,
|
|
119
|
+
stop: async () => {
|
|
120
|
+
if (bridge !== null)
|
|
121
|
+
await bridge.stop();
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
// ── Idempotency keys (type-inclusive + occurrence-unique) ───────────────────────
|
|
126
|
+
export function projectCreatedKey(projectId) {
|
|
127
|
+
return `crew:project.created:${projectId}:v1`;
|
|
128
|
+
}
|
|
129
|
+
export function projectUpdatedKey(projectId, updatedAt) {
|
|
130
|
+
return `crew:project.updated:${projectId}:${updatedAt}`;
|
|
131
|
+
}
|
|
132
|
+
export function projectArchivedKey(projectId, updatedAt) {
|
|
133
|
+
return `crew:project.archived:${projectId}:${updatedAt}`;
|
|
134
|
+
}
|
|
135
|
+
export function membershipAttachedKey(projectId, kind, ref, attachedAt) {
|
|
136
|
+
return `crew:membership.attached:${projectId}:${kind}:${ref}:${attachedAt}`;
|
|
137
|
+
}
|
|
138
|
+
export function membershipDetachedKey(projectId, memberId, at) {
|
|
139
|
+
return `crew:membership.detached:${projectId}:${memberId}:${at}`;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/projects/events.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a PROJECT's co-located code graph lives, and what each member repo is called inside it.
|
|
3
|
+
*
|
|
4
|
+
* # Why a module instead of a `join()` at each call site
|
|
5
|
+
*
|
|
6
|
+
* This is `repoPaths.ts`'s posture applied one level up (see that module's header for the bill:
|
|
7
|
+
* five spellings of the per-repo graph path against a sixth inside wicked-core, and every graph
|
|
8
|
+
* query answering "nothing found" about a repo full of code). One producer, one consumer. Nothing
|
|
9
|
+
* outside this module spells a project-graph path or mints a repo label.
|
|
10
|
+
*
|
|
11
|
+
* # Why NOT inside a repo checkout
|
|
12
|
+
*
|
|
13
|
+
* The per-repo graph lives at `<repo>/.codegraph/estate.db` — inside the working tree — and we have
|
|
14
|
+
* just spent the effort removing that directory from six checkouts it had polluted. A PROJECT graph
|
|
15
|
+
* is worse on that axis, not better: it holds N repos, so there is no one checkout it belongs to,
|
|
16
|
+
* and writing it into the first member's tree would make repo A's working directory grow with repo
|
|
17
|
+
* B's symbols. It goes in the daemon's own state directory.
|
|
18
|
+
*
|
|
19
|
+
* # Why `~/.wicked-crew/project-graphs/<projectId>/`
|
|
20
|
+
*
|
|
21
|
+
* `~/.wicked-crew/` is already where this package keeps crew-side per-project state that the engine
|
|
22
|
+
* does not own — `project-settings.json` (DES-MERGE-001 §7.1) sits there today. The project graph is
|
|
23
|
+
* exactly that kind of thing: crew-owned, per-project, derived, and rebuildable. A directory per
|
|
24
|
+
* project (rather than `<projectId>.db` files in one flat folder) keeps the db and the refresh
|
|
25
|
+
* manifest that describes it together, so removing a project's graph is one `rm -rf` that cannot
|
|
26
|
+
* leave a manifest describing a database that is gone.
|
|
27
|
+
*
|
|
28
|
+
* Overridable with `WICKED_CREW_PROJECT_GRAPH_ROOT` — the same escape hatch
|
|
29
|
+
* `WICKED_CREW_PROJECT_SETTINGS` gives the settings store, and what lets the tests and the proof
|
|
30
|
+
* scripts run without touching a developer's real home.
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* The estate label charset, copied from the rule that enforces it
|
|
34
|
+
* (`wicked-estate/src/repo_scope.rs::validate_label`): 1–64 chars of `[A-Za-z0-9._-]`, and never
|
|
35
|
+
* `.` or `..`.
|
|
36
|
+
*
|
|
37
|
+
* The constraint is not cosmetic and not ours to relax. estate splices the label into `files.path`
|
|
38
|
+
* AND into every SymbolId derived from it, so a `/` or a `..` in a label would forge paths inside
|
|
39
|
+
* another repo's namespace — the exact collision the whole labelling mechanism exists to prevent.
|
|
40
|
+
* A label that fails this test is refused by estate before a single row is written; we mint labels
|
|
41
|
+
* that pass it instead of discovering that at index time.
|
|
42
|
+
*/
|
|
43
|
+
export declare function isValidRepoLabel(label: string): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* The label one registered repo carries inside a project graph — its REGISTRY ID when that id is
|
|
46
|
+
* already a legal estate label, and a deterministic sanitized form when it is not.
|
|
47
|
+
*
|
|
48
|
+
* WHY the registry id. The label becomes a path prefix on every row the repo writes and shows up in
|
|
49
|
+
* every result this surface returns, so it has to be a name an operator can map back to a repo
|
|
50
|
+
* without a lookup table. It also has to be STABLE: estate binds a label to a repo permanently
|
|
51
|
+
* (re-indexing under a second label is refused as a duplicate; re-using a label for a different repo
|
|
52
|
+
* is refused as a collision), so a label derived from anything mutable — the repo's display name,
|
|
53
|
+
* its root path, its position in the member list — would break the next refresh after a rename or a
|
|
54
|
+
* move. The registry id is the one identifier that is both stable and already unique per repo.
|
|
55
|
+
*
|
|
56
|
+
* Every repo id in the live registry today (`wicked-ledger`, `wicked-vault`, `pageindex-proof`, …)
|
|
57
|
+
* satisfies estate's rule as-is, so the common path is the identity function and the label IS the
|
|
58
|
+
* id. That is not guaranteed for ids minted later, so the fallback is real rather than theoretical:
|
|
59
|
+
* illegal characters collapse to `-`, the stem is capped, and a 12-hex digest of the FULL id is
|
|
60
|
+
* appended — the digest is what keeps `a/b` and `a:b` (which sanitize identically) apart, and what
|
|
61
|
+
* keeps a truncated 200-character id distinct from another that shares its first 51 characters.
|
|
62
|
+
*
|
|
63
|
+
* The mapping is a pure function of the id, which is what makes it safe against estate's permanent
|
|
64
|
+
* binding: the same repo resolves to the same label on every refresh, for the life of the graph.
|
|
65
|
+
*/
|
|
66
|
+
export declare function repoLabel(repoId: string): string;
|
|
67
|
+
/**
|
|
68
|
+
* Project ids are REJECTED, never sanitized.
|
|
69
|
+
*
|
|
70
|
+
* A sanitizing map is what would let two distinct project ids land in one directory and share one
|
|
71
|
+
* database — the same class of silent collision that made a multi-repo graph impossible in the first
|
|
72
|
+
* place, reintroduced at the project level. It is also the traversal guard: the id is a path
|
|
73
|
+
* segment, so `../../x` must never be spelled into a path. Engine-minted ids (`proj_1787…`) and the
|
|
74
|
+
* synthesized `default` both pass; anything that does not is a bug worth hearing about.
|
|
75
|
+
*/
|
|
76
|
+
export declare function assertProjectIdIsPathSafe(projectId: string): void;
|
|
77
|
+
/** The root every project graph directory hangs off. */
|
|
78
|
+
export declare function projectGraphRoot(env?: NodeJS.ProcessEnv): string;
|
|
79
|
+
/** One project's graph directory — holds the database and the manifest that describes it. */
|
|
80
|
+
export declare function projectGraphDir(projectId: string, env?: NodeJS.ProcessEnv): string;
|
|
81
|
+
/** The ONE database holding every member repo of this project, co-located under their labels. */
|
|
82
|
+
export declare function projectGraphDb(projectId: string, env?: NodeJS.ProcessEnv): string;
|
|
83
|
+
/**
|
|
84
|
+
* What the last refresh put in that database, per repo — the record incremental refresh reads.
|
|
85
|
+
*
|
|
86
|
+
* Deliberately a SIDECAR rather than a read of estate's own `repo:<label>:commit` meta: estate
|
|
87
|
+
* exposes that only through `stats`, whose output is human text with no `--json`, and deciding
|
|
88
|
+
* whether to re-index a repo by regex-matching a report is the kind of coupling that breaks on a
|
|
89
|
+
* formatting change with no test to catch it.
|
|
90
|
+
*/
|
|
91
|
+
export declare function projectGraphManifest(projectId: string, env?: NodeJS.ProcessEnv): string;
|
|
92
|
+
//# sourceMappingURL=graph-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-paths.d.ts","sourceRoot":"","sources":["../../src/projects/graph-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAMH;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAQvD;AAMD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKhD;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAcjE;AAED,wDAAwD;AACxD,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAE7E;AAED,6FAA6F;AAC7F,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAG/F;AAED,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAE9F;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAEpG"}
|