@jonit-dev/night-watch-cli 1.7.10 → 1.7.13
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 +1 -1
- package/dist/commands/dashboard/tab-config.d.ts.map +1 -1
- package/dist/commands/dashboard/tab-config.js +8 -1
- package/dist/commands/dashboard/tab-config.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +3 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/review.d.ts +4 -0
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +30 -0
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/run.d.ts +11 -0
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +47 -7
- package/dist/commands/run.js.map +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +43 -3
- package/dist/server/index.js.map +1 -1
- package/dist/shared/types.d.ts +223 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +7 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/src/agents/soul-compiler.d.ts +11 -0
- package/dist/src/agents/soul-compiler.d.ts.map +1 -0
- package/dist/src/agents/soul-compiler.js +103 -0
- package/dist/src/agents/soul-compiler.js.map +1 -0
- package/dist/src/board/factory.d.ts +3 -0
- package/dist/src/board/factory.d.ts.map +1 -0
- package/dist/src/board/factory.js +10 -0
- package/dist/src/board/factory.js.map +1 -0
- package/dist/src/board/providers/github-graphql.d.ts +16 -0
- package/dist/src/board/providers/github-graphql.d.ts.map +1 -0
- package/dist/src/board/providers/github-graphql.js +43 -0
- package/dist/src/board/providers/github-graphql.js.map +1 -0
- package/dist/src/board/providers/github-projects.d.ts +51 -0
- package/dist/src/board/providers/github-projects.d.ts.map +1 -0
- package/dist/src/board/providers/github-projects.js +672 -0
- package/dist/src/board/providers/github-projects.js.map +1 -0
- package/dist/src/board/types.d.ts +60 -0
- package/dist/src/board/types.d.ts.map +1 -0
- package/dist/src/board/types.js +4 -0
- package/dist/src/board/types.js.map +1 -0
- package/dist/src/cli.d.ts +3 -0
- package/dist/src/cli.d.ts.map +1 -0
- package/dist/src/cli.js +80 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/commands/board.d.ts +9 -0
- package/dist/src/commands/board.d.ts.map +1 -0
- package/dist/src/commands/board.js +294 -0
- package/dist/src/commands/board.js.map +1 -0
- package/dist/src/commands/cancel.d.ts +46 -0
- package/dist/src/commands/cancel.d.ts.map +1 -0
- package/dist/src/commands/cancel.js +241 -0
- package/dist/src/commands/cancel.js.map +1 -0
- package/dist/src/commands/dashboard/tab-actions.d.ts +10 -0
- package/dist/src/commands/dashboard/tab-actions.d.ts.map +1 -0
- package/dist/src/commands/dashboard/tab-actions.js +245 -0
- package/dist/src/commands/dashboard/tab-actions.js.map +1 -0
- package/dist/src/commands/dashboard/tab-config.d.ts +21 -0
- package/dist/src/commands/dashboard/tab-config.d.ts.map +1 -0
- package/dist/src/commands/dashboard/tab-config.js +829 -0
- package/dist/src/commands/dashboard/tab-config.js.map +1 -0
- package/dist/src/commands/dashboard/tab-logs.d.ts +10 -0
- package/dist/src/commands/dashboard/tab-logs.d.ts.map +1 -0
- package/dist/src/commands/dashboard/tab-logs.js +178 -0
- package/dist/src/commands/dashboard/tab-logs.js.map +1 -0
- package/dist/src/commands/dashboard/tab-schedules.d.ts +21 -0
- package/dist/src/commands/dashboard/tab-schedules.d.ts.map +1 -0
- package/dist/src/commands/dashboard/tab-schedules.js +304 -0
- package/dist/src/commands/dashboard/tab-schedules.js.map +1 -0
- package/dist/src/commands/dashboard/tab-status.d.ts +32 -0
- package/dist/src/commands/dashboard/tab-status.d.ts.map +1 -0
- package/dist/src/commands/dashboard/tab-status.js +421 -0
- package/dist/src/commands/dashboard/tab-status.js.map +1 -0
- package/dist/src/commands/dashboard/types.d.ts +43 -0
- package/dist/src/commands/dashboard/types.d.ts.map +1 -0
- package/dist/src/commands/dashboard/types.js +5 -0
- package/dist/src/commands/dashboard/types.js.map +1 -0
- package/dist/src/commands/dashboard.d.ts +11 -0
- package/dist/src/commands/dashboard.d.ts.map +1 -0
- package/dist/src/commands/dashboard.js +239 -0
- package/dist/src/commands/dashboard.js.map +1 -0
- package/dist/src/commands/doctor.d.ts +16 -0
- package/dist/src/commands/doctor.d.ts.map +1 -0
- package/dist/src/commands/doctor.js +202 -0
- package/dist/src/commands/doctor.js.map +1 -0
- package/dist/src/commands/history.d.ts +7 -0
- package/dist/src/commands/history.d.ts.map +1 -0
- package/dist/src/commands/history.js +56 -0
- package/dist/src/commands/history.js.map +1 -0
- package/dist/src/commands/init.d.ts +25 -0
- package/dist/src/commands/init.d.ts.map +1 -0
- package/dist/src/commands/init.js +543 -0
- package/dist/src/commands/init.js.map +1 -0
- package/dist/src/commands/install.d.ts +48 -0
- package/dist/src/commands/install.d.ts.map +1 -0
- package/dist/src/commands/install.js +303 -0
- package/dist/src/commands/install.js.map +1 -0
- package/dist/src/commands/logs.d.ts +15 -0
- package/dist/src/commands/logs.d.ts.map +1 -0
- package/dist/src/commands/logs.js +104 -0
- package/dist/src/commands/logs.js.map +1 -0
- package/dist/src/commands/prd-state.d.ts +12 -0
- package/dist/src/commands/prd-state.d.ts.map +1 -0
- package/dist/src/commands/prd-state.js +47 -0
- package/dist/src/commands/prd-state.js.map +1 -0
- package/dist/src/commands/prd.d.ts +24 -0
- package/dist/src/commands/prd.d.ts.map +1 -0
- package/dist/src/commands/prd.js +283 -0
- package/dist/src/commands/prd.js.map +1 -0
- package/dist/src/commands/prds.d.ts +13 -0
- package/dist/src/commands/prds.d.ts.map +1 -0
- package/dist/src/commands/prds.js +196 -0
- package/dist/src/commands/prds.js.map +1 -0
- package/dist/src/commands/prs.d.ts +14 -0
- package/dist/src/commands/prs.d.ts.map +1 -0
- package/dist/src/commands/prs.js +106 -0
- package/dist/src/commands/prs.js.map +1 -0
- package/dist/src/commands/qa.d.ts +30 -0
- package/dist/src/commands/qa.d.ts.map +1 -0
- package/dist/src/commands/qa.js +159 -0
- package/dist/src/commands/qa.js.map +1 -0
- package/dist/src/commands/retry.d.ts +9 -0
- package/dist/src/commands/retry.d.ts.map +1 -0
- package/dist/src/commands/retry.js +72 -0
- package/dist/src/commands/retry.js.map +1 -0
- package/dist/src/commands/review.d.ts +35 -0
- package/dist/src/commands/review.d.ts.map +1 -0
- package/dist/src/commands/review.js +252 -0
- package/dist/src/commands/review.js.map +1 -0
- package/dist/src/commands/run.d.ts +61 -0
- package/dist/src/commands/run.d.ts.map +1 -0
- package/dist/src/commands/run.js +364 -0
- package/dist/src/commands/run.js.map +1 -0
- package/dist/src/commands/serve.d.ts +7 -0
- package/dist/src/commands/serve.d.ts.map +1 -0
- package/dist/src/commands/serve.js +27 -0
- package/dist/src/commands/serve.js.map +1 -0
- package/dist/src/commands/slice.d.ts +26 -0
- package/dist/src/commands/slice.d.ts.map +1 -0
- package/dist/src/commands/slice.js +175 -0
- package/dist/src/commands/slice.js.map +1 -0
- package/dist/src/commands/state.d.ts +8 -0
- package/dist/src/commands/state.d.ts.map +1 -0
- package/dist/src/commands/state.js +56 -0
- package/dist/src/commands/state.js.map +1 -0
- package/dist/src/commands/status.d.ts +14 -0
- package/dist/src/commands/status.d.ts.map +1 -0
- package/dist/src/commands/status.js +147 -0
- package/dist/src/commands/status.js.map +1 -0
- package/dist/src/commands/uninstall.d.ts +25 -0
- package/dist/src/commands/uninstall.d.ts.map +1 -0
- package/dist/src/commands/uninstall.js +141 -0
- package/dist/src/commands/uninstall.js.map +1 -0
- package/dist/src/commands/update.d.ts +21 -0
- package/dist/src/commands/update.d.ts.map +1 -0
- package/dist/src/commands/update.js +87 -0
- package/dist/src/commands/update.js.map +1 -0
- package/dist/src/config.d.ts +23 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +629 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/constants.d.ts +60 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +118 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/server/index.d.ts +23 -0
- package/dist/src/server/index.d.ts.map +1 -0
- package/dist/src/server/index.js +1645 -0
- package/dist/src/server/index.js.map +1 -0
- package/dist/src/slack/channel-manager.d.ts +32 -0
- package/dist/src/slack/channel-manager.d.ts.map +1 -0
- package/dist/src/slack/channel-manager.js +128 -0
- package/dist/src/slack/channel-manager.js.map +1 -0
- package/dist/src/slack/client.d.ts +63 -0
- package/dist/src/slack/client.d.ts.map +1 -0
- package/dist/src/slack/client.js +151 -0
- package/dist/src/slack/client.js.map +1 -0
- package/dist/src/slack/deliberation.d.ts +45 -0
- package/dist/src/slack/deliberation.d.ts.map +1 -0
- package/dist/src/slack/deliberation.js +539 -0
- package/dist/src/slack/deliberation.js.map +1 -0
- package/dist/src/slack/index.d.ts +6 -0
- package/dist/src/slack/index.d.ts.map +1 -0
- package/dist/src/slack/index.js +5 -0
- package/dist/src/slack/index.js.map +1 -0
- package/dist/src/slack/interaction-listener.d.ts +53 -0
- package/dist/src/slack/interaction-listener.d.ts.map +1 -0
- package/dist/src/slack/interaction-listener.js +253 -0
- package/dist/src/slack/interaction-listener.js.map +1 -0
- package/dist/src/storage/json-state-migrator.d.ts +24 -0
- package/dist/src/storage/json-state-migrator.d.ts.map +1 -0
- package/dist/src/storage/json-state-migrator.js +197 -0
- package/dist/src/storage/json-state-migrator.js.map +1 -0
- package/dist/src/storage/repositories/index.d.ts +25 -0
- package/dist/src/storage/repositories/index.d.ts.map +1 -0
- package/dist/src/storage/repositories/index.js +43 -0
- package/dist/src/storage/repositories/index.js.map +1 -0
- package/dist/src/storage/repositories/interfaces.d.ts +59 -0
- package/dist/src/storage/repositories/interfaces.d.ts.map +1 -0
- package/dist/src/storage/repositories/interfaces.js +6 -0
- package/dist/src/storage/repositories/interfaces.js.map +1 -0
- package/dist/src/storage/repositories/sqlite/agent-persona-repository.d.ts +27 -0
- package/dist/src/storage/repositories/sqlite/agent-persona-repository.d.ts.map +1 -0
- package/dist/src/storage/repositories/sqlite/agent-persona-repository.js +569 -0
- package/dist/src/storage/repositories/sqlite/agent-persona-repository.js.map +1 -0
- package/dist/src/storage/repositories/sqlite/execution-history-repository.d.ts +21 -0
- package/dist/src/storage/repositories/sqlite/execution-history-repository.d.ts.map +1 -0
- package/dist/src/storage/repositories/sqlite/execution-history-repository.js +94 -0
- package/dist/src/storage/repositories/sqlite/execution-history-repository.js.map +1 -0
- package/dist/src/storage/repositories/sqlite/prd-state-repository.d.ts +17 -0
- package/dist/src/storage/repositories/sqlite/prd-state-repository.d.ts.map +1 -0
- package/dist/src/storage/repositories/sqlite/prd-state-repository.js +74 -0
- package/dist/src/storage/repositories/sqlite/prd-state-repository.js.map +1 -0
- package/dist/src/storage/repositories/sqlite/project-registry-repository.d.ts +17 -0
- package/dist/src/storage/repositories/sqlite/project-registry-repository.d.ts.map +1 -0
- package/dist/src/storage/repositories/sqlite/project-registry-repository.js +43 -0
- package/dist/src/storage/repositories/sqlite/project-registry-repository.js.map +1 -0
- package/dist/src/storage/repositories/sqlite/roadmap-state-repository.d.ts +14 -0
- package/dist/src/storage/repositories/sqlite/roadmap-state-repository.d.ts.map +1 -0
- package/dist/src/storage/repositories/sqlite/roadmap-state-repository.js +47 -0
- package/dist/src/storage/repositories/sqlite/roadmap-state-repository.js.map +1 -0
- package/dist/src/storage/repositories/sqlite/slack-discussion-repository.d.ts +20 -0
- package/dist/src/storage/repositories/sqlite/slack-discussion-repository.d.ts.map +1 -0
- package/dist/src/storage/repositories/sqlite/slack-discussion-repository.js +88 -0
- package/dist/src/storage/repositories/sqlite/slack-discussion-repository.js.map +1 -0
- package/dist/src/storage/sqlite/client.d.ts +23 -0
- package/dist/src/storage/sqlite/client.d.ts.map +1 -0
- package/dist/src/storage/sqlite/client.js +47 -0
- package/dist/src/storage/sqlite/client.js.map +1 -0
- package/dist/src/storage/sqlite/migrations.d.ts +11 -0
- package/dist/src/storage/sqlite/migrations.d.ts.map +1 -0
- package/dist/src/storage/sqlite/migrations.js +94 -0
- package/dist/src/storage/sqlite/migrations.js.map +1 -0
- package/dist/src/templates/prd-template.d.ts +11 -0
- package/dist/src/templates/prd-template.d.ts.map +1 -0
- package/dist/src/templates/prd-template.js +166 -0
- package/dist/src/templates/prd-template.js.map +1 -0
- package/dist/src/templates/slicer-prompt.d.ts +54 -0
- package/dist/src/templates/slicer-prompt.d.ts.map +1 -0
- package/dist/src/templates/slicer-prompt.js +163 -0
- package/dist/src/templates/slicer-prompt.js.map +1 -0
- package/dist/src/types.d.ts +127 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +5 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils/checks.d.ts +55 -0
- package/dist/src/utils/checks.d.ts.map +1 -0
- package/dist/src/utils/checks.js +246 -0
- package/dist/src/utils/checks.js.map +1 -0
- package/dist/src/utils/config-writer.d.ts +16 -0
- package/dist/src/utils/config-writer.d.ts.map +1 -0
- package/dist/src/utils/config-writer.js +45 -0
- package/dist/src/utils/config-writer.js.map +1 -0
- package/dist/src/utils/crontab.d.ts +62 -0
- package/dist/src/utils/crontab.d.ts.map +1 -0
- package/dist/src/utils/crontab.js +168 -0
- package/dist/src/utils/crontab.js.map +1 -0
- package/dist/src/utils/execution-history.d.ts +54 -0
- package/dist/src/utils/execution-history.d.ts.map +1 -0
- package/dist/src/utils/execution-history.js +80 -0
- package/dist/src/utils/execution-history.js.map +1 -0
- package/dist/src/utils/github.d.ts +40 -0
- package/dist/src/utils/github.d.ts.map +1 -0
- package/dist/src/utils/github.js +126 -0
- package/dist/src/utils/github.js.map +1 -0
- package/dist/src/utils/notify.d.ts +63 -0
- package/dist/src/utils/notify.d.ts.map +1 -0
- package/dist/src/utils/notify.js +389 -0
- package/dist/src/utils/notify.js.map +1 -0
- package/dist/src/utils/prd-states.d.ts +16 -0
- package/dist/src/utils/prd-states.d.ts.map +1 -0
- package/dist/src/utils/prd-states.js +28 -0
- package/dist/src/utils/prd-states.js.map +1 -0
- package/dist/src/utils/registry.d.ts +45 -0
- package/dist/src/utils/registry.d.ts.map +1 -0
- package/dist/src/utils/registry.js +86 -0
- package/dist/src/utils/registry.js.map +1 -0
- package/dist/src/utils/roadmap-parser.d.ts +45 -0
- package/dist/src/utils/roadmap-parser.d.ts.map +1 -0
- package/dist/src/utils/roadmap-parser.js +136 -0
- package/dist/src/utils/roadmap-parser.js.map +1 -0
- package/dist/src/utils/roadmap-scanner.d.ts +92 -0
- package/dist/src/utils/roadmap-scanner.d.ts.map +1 -0
- package/dist/src/utils/roadmap-scanner.js +349 -0
- package/dist/src/utils/roadmap-scanner.js.map +1 -0
- package/dist/src/utils/roadmap-state.d.ts +90 -0
- package/dist/src/utils/roadmap-state.d.ts.map +1 -0
- package/dist/src/utils/roadmap-state.js +154 -0
- package/dist/src/utils/roadmap-state.js.map +1 -0
- package/dist/src/utils/script-result.d.ts +12 -0
- package/dist/src/utils/script-result.d.ts.map +1 -0
- package/dist/src/utils/script-result.js +46 -0
- package/dist/src/utils/script-result.js.map +1 -0
- package/dist/src/utils/shell.d.ts +27 -0
- package/dist/src/utils/shell.d.ts.map +1 -0
- package/dist/src/utils/shell.js +64 -0
- package/dist/src/utils/shell.js.map +1 -0
- package/dist/src/utils/status-data.d.ts +148 -0
- package/dist/src/utils/status-data.d.ts.map +1 -0
- package/dist/src/utils/status-data.js +593 -0
- package/dist/src/utils/status-data.js.map +1 -0
- package/dist/src/utils/ui.d.ts +55 -0
- package/dist/src/utils/ui.d.ts.map +1 -0
- package/dist/src/utils/ui.js +121 -0
- package/dist/src/utils/ui.js.map +1 -0
- package/package.json +3 -1
- package/scripts/night-watch-cron.sh +7 -0
- package/scripts/night-watch-helpers.sh +33 -4
- package/scripts/night-watch-pr-reviewer-cron.sh +11 -3
- package/web/dist/assets/index-BtxQU4oX.css +1 -0
- package/web/dist/assets/index-CzAWcldp.js +473 -0
- package/web/dist/index.html +2 -2
- package/web/dist/assets/index-BPW-7_1C.js +0 -380
- package/web/dist/assets/index-DVqjjJEO.css +0 -1
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack interaction listener.
|
|
3
|
+
* Listens to human messages (Socket Mode), routes @persona mentions,
|
|
4
|
+
* and applies loop-protection safeguards.
|
|
5
|
+
*/
|
|
6
|
+
import { SocketModeClient } from '@slack/socket-mode';
|
|
7
|
+
import { getDb } from '../storage/sqlite/client.js';
|
|
8
|
+
import { getRepositories } from '../storage/repositories/index.js';
|
|
9
|
+
import { DeliberationEngine } from './deliberation.js';
|
|
10
|
+
import { SlackClient } from './client.js';
|
|
11
|
+
const MAX_PROCESSED_MESSAGE_KEYS = 2000;
|
|
12
|
+
const PERSONA_REPLY_COOLDOWN_MS = 45_000;
|
|
13
|
+
function normalizeHandle(value) {
|
|
14
|
+
return value.toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Extract @handle mentions from raw Slack text.
|
|
18
|
+
* Example: "@maya please check this" -> ["maya"]
|
|
19
|
+
*/
|
|
20
|
+
export function extractMentionHandles(text) {
|
|
21
|
+
const matches = text.match(/@([a-z0-9._-]{2,32})/gi) ?? [];
|
|
22
|
+
const seen = new Set();
|
|
23
|
+
const handles = [];
|
|
24
|
+
for (const match of matches) {
|
|
25
|
+
const normalized = normalizeHandle(match.slice(1));
|
|
26
|
+
if (!normalized || seen.has(normalized)) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
seen.add(normalized);
|
|
30
|
+
handles.push(normalized);
|
|
31
|
+
}
|
|
32
|
+
return handles;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Resolve mention handles to active personas by display name.
|
|
36
|
+
*/
|
|
37
|
+
export function resolveMentionedPersonas(text, personas) {
|
|
38
|
+
const handles = extractMentionHandles(text);
|
|
39
|
+
if (handles.length === 0)
|
|
40
|
+
return [];
|
|
41
|
+
const byHandle = new Map();
|
|
42
|
+
for (const persona of personas) {
|
|
43
|
+
byHandle.set(normalizeHandle(persona.name), persona);
|
|
44
|
+
}
|
|
45
|
+
const resolved = [];
|
|
46
|
+
const seenPersonaIds = new Set();
|
|
47
|
+
for (const handle of handles) {
|
|
48
|
+
const persona = byHandle.get(handle);
|
|
49
|
+
if (!persona || seenPersonaIds.has(persona.id)) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
seenPersonaIds.add(persona.id);
|
|
53
|
+
resolved.push(persona);
|
|
54
|
+
}
|
|
55
|
+
return resolved;
|
|
56
|
+
}
|
|
57
|
+
export function shouldIgnoreInboundSlackEvent(event, botUserId) {
|
|
58
|
+
if (!event.channel || !event.ts)
|
|
59
|
+
return true;
|
|
60
|
+
if (!event.user)
|
|
61
|
+
return true;
|
|
62
|
+
if (event.subtype)
|
|
63
|
+
return true;
|
|
64
|
+
if (event.bot_id)
|
|
65
|
+
return true;
|
|
66
|
+
if (botUserId && event.user === botUserId)
|
|
67
|
+
return true;
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
export class SlackInteractionListener {
|
|
71
|
+
_config;
|
|
72
|
+
_slackClient;
|
|
73
|
+
_engine;
|
|
74
|
+
_socketClient = null;
|
|
75
|
+
_botUserId = null;
|
|
76
|
+
_processedMessageKeys = new Set();
|
|
77
|
+
_processedMessageOrder = [];
|
|
78
|
+
_lastPersonaReplyAt = new Map();
|
|
79
|
+
constructor(config) {
|
|
80
|
+
this._config = config;
|
|
81
|
+
const token = config.slack?.botToken ?? '';
|
|
82
|
+
this._slackClient = new SlackClient(token);
|
|
83
|
+
this._engine = new DeliberationEngine(this._slackClient, config);
|
|
84
|
+
}
|
|
85
|
+
async start() {
|
|
86
|
+
const slack = this._config.slack;
|
|
87
|
+
if (!slack?.enabled ||
|
|
88
|
+
!slack.discussionEnabled ||
|
|
89
|
+
!slack.botToken ||
|
|
90
|
+
!slack.appToken) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (this._socketClient) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
this._botUserId = await this._slackClient.getBotUserId();
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
101
|
+
console.warn(`Slack interaction listener: failed to resolve bot user id (${msg})`);
|
|
102
|
+
this._botUserId = null;
|
|
103
|
+
}
|
|
104
|
+
const socket = new SocketModeClient({
|
|
105
|
+
appToken: slack.appToken,
|
|
106
|
+
});
|
|
107
|
+
socket.on('events_api', (payload) => {
|
|
108
|
+
void this._handleEventsApi(payload);
|
|
109
|
+
});
|
|
110
|
+
socket.on('error', (err) => {
|
|
111
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
112
|
+
console.warn(`Slack interaction listener error: ${msg}`);
|
|
113
|
+
});
|
|
114
|
+
await socket.start();
|
|
115
|
+
this._socketClient = socket;
|
|
116
|
+
console.log('Slack interaction listener started (Socket Mode)');
|
|
117
|
+
void this._postPersonaIntros();
|
|
118
|
+
}
|
|
119
|
+
async stop() {
|
|
120
|
+
if (!this._socketClient) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const socket = this._socketClient;
|
|
124
|
+
this._socketClient = null;
|
|
125
|
+
try {
|
|
126
|
+
socket.removeAllListeners();
|
|
127
|
+
await socket.disconnect();
|
|
128
|
+
console.log('Slack interaction listener stopped');
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
132
|
+
console.warn(`Slack interaction listener shutdown failed: ${msg}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Post a self-introduction message for each active persona that hasn't
|
|
137
|
+
* introduced themselves to the eng channel yet. Tracked persistently in
|
|
138
|
+
* schema_meta so it only fires once per persona across restarts.
|
|
139
|
+
*/
|
|
140
|
+
async _postPersonaIntros() {
|
|
141
|
+
const channelId = this._config.slack?.channels?.eng;
|
|
142
|
+
if (!channelId)
|
|
143
|
+
return;
|
|
144
|
+
const db = getDb();
|
|
145
|
+
const metaRow = db
|
|
146
|
+
.prepare(`SELECT value FROM schema_meta WHERE key = 'slack_persona_intros'`)
|
|
147
|
+
.get();
|
|
148
|
+
const introduced = new Set(metaRow ? JSON.parse(metaRow.value) : []);
|
|
149
|
+
const repos = getRepositories();
|
|
150
|
+
const personas = repos.agentPersona.getActive();
|
|
151
|
+
for (const persona of personas) {
|
|
152
|
+
if (introduced.has(persona.id))
|
|
153
|
+
continue;
|
|
154
|
+
const whoIAm = persona.soul?.whoIAm?.trim() ?? '';
|
|
155
|
+
const intro = whoIAm
|
|
156
|
+
? `👋 Hey! I'm *${persona.name}*, ${persona.role}. ${whoIAm}`
|
|
157
|
+
: `👋 Hey! I'm *${persona.name}*, ${persona.role}. Ready to collaborate!`;
|
|
158
|
+
try {
|
|
159
|
+
await this._slackClient.postAsAgent(channelId, intro, persona);
|
|
160
|
+
introduced.add(persona.id);
|
|
161
|
+
db.prepare(`INSERT INTO schema_meta (key, value) VALUES ('slack_persona_intros', ?)
|
|
162
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(JSON.stringify(Array.from(introduced)));
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
166
|
+
console.warn(`Slack persona intro failed for ${persona.name}: ${msg}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
async _handleEventsApi(payload) {
|
|
171
|
+
try {
|
|
172
|
+
await payload.ack();
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
// Ignore ack races/timeouts; processing can continue.
|
|
176
|
+
}
|
|
177
|
+
const event = payload.event;
|
|
178
|
+
if (!event)
|
|
179
|
+
return;
|
|
180
|
+
if (event.type !== 'message' && event.type !== 'app_mention')
|
|
181
|
+
return;
|
|
182
|
+
try {
|
|
183
|
+
await this._handleInboundMessage(event);
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
187
|
+
console.warn(`Slack interaction message handling failed: ${msg}`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
_rememberMessageKey(key) {
|
|
191
|
+
if (this._processedMessageKeys.has(key)) {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
this._processedMessageKeys.add(key);
|
|
195
|
+
this._processedMessageOrder.push(key);
|
|
196
|
+
while (this._processedMessageOrder.length > MAX_PROCESSED_MESSAGE_KEYS) {
|
|
197
|
+
const oldest = this._processedMessageOrder.shift();
|
|
198
|
+
if (oldest) {
|
|
199
|
+
this._processedMessageKeys.delete(oldest);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
_isPersonaOnCooldown(channel, threadTs, personaId) {
|
|
205
|
+
const key = `${channel}:${threadTs}:${personaId}`;
|
|
206
|
+
const last = this._lastPersonaReplyAt.get(key);
|
|
207
|
+
if (!last)
|
|
208
|
+
return false;
|
|
209
|
+
return Date.now() - last < PERSONA_REPLY_COOLDOWN_MS;
|
|
210
|
+
}
|
|
211
|
+
_markPersonaReply(channel, threadTs, personaId) {
|
|
212
|
+
const key = `${channel}:${threadTs}:${personaId}`;
|
|
213
|
+
this._lastPersonaReplyAt.set(key, Date.now());
|
|
214
|
+
}
|
|
215
|
+
async _handleInboundMessage(event) {
|
|
216
|
+
if (shouldIgnoreInboundSlackEvent(event, this._botUserId)) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const channel = event.channel;
|
|
220
|
+
const ts = event.ts;
|
|
221
|
+
const threadTs = event.thread_ts ?? ts;
|
|
222
|
+
const text = event.text ?? '';
|
|
223
|
+
const messageKey = `${channel}:${ts}`;
|
|
224
|
+
// Deduplicate retried/replayed events to prevent response loops.
|
|
225
|
+
if (!this._rememberMessageKey(messageKey)) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
const repos = getRepositories();
|
|
229
|
+
const discussion = repos
|
|
230
|
+
.slackDiscussion
|
|
231
|
+
.getActive('')
|
|
232
|
+
.find((d) => d.channelId === channel && d.threadTs === threadTs);
|
|
233
|
+
if (!discussion) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const personas = repos.agentPersona.getActive();
|
|
237
|
+
const mentionedPersonas = resolveMentionedPersonas(text, personas);
|
|
238
|
+
// Explicit @persona mention -> only those persona(s) respond.
|
|
239
|
+
if (mentionedPersonas.length > 0) {
|
|
240
|
+
for (const persona of mentionedPersonas) {
|
|
241
|
+
if (this._isPersonaOnCooldown(channel, threadTs, persona.id)) {
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
await this._engine.contributeAsAgent(discussion.id, persona);
|
|
245
|
+
this._markPersonaReply(channel, threadTs, persona.id);
|
|
246
|
+
}
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
// No explicit persona mention -> treat as generic human input for the discussion.
|
|
250
|
+
await this._engine.handleHumanMessage(channel, threadTs, text, event.user);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=interaction-listener.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interaction-listener.js","sourceRoot":"","sources":["../../../src/slack/interaction-listener.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON → SQLite migration logic for Night Watch CLI.
|
|
3
|
+
* Reads legacy JSON state files and inserts their contents into SQLite
|
|
4
|
+
* via the repository layer. Safe to run multiple times (idempotent).
|
|
5
|
+
*/
|
|
6
|
+
export interface IMigrationResult {
|
|
7
|
+
projectsMigrated: number;
|
|
8
|
+
historyRecordsMigrated: number;
|
|
9
|
+
prdStatesMigrated: number;
|
|
10
|
+
roadmapStatesMigrated: number;
|
|
11
|
+
backupDir: string;
|
|
12
|
+
alreadyMigrated: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Migrate legacy JSON state files into SQLite.
|
|
16
|
+
*
|
|
17
|
+
* The migration is idempotent: if the key "json_migration_completed" already
|
|
18
|
+
* exists in schema_meta the function returns early without touching the DB.
|
|
19
|
+
*
|
|
20
|
+
* @param nightWatchHome - Path to the Night Watch home directory
|
|
21
|
+
* (e.g. ~/.night-watch or the value of NIGHT_WATCH_HOME).
|
|
22
|
+
*/
|
|
23
|
+
export declare function migrateJsonToSqlite(nightWatchHome: string): IMigrationResult;
|
|
24
|
+
//# sourceMappingURL=json-state-migrator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-state-migrator.d.ts","sourceRoot":"","sources":["../../../src/storage/json-state-migrator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAaH,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,EAAE,MAAM,CAAC;IACzB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAyED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,cAAc,EAAE,MAAM,GAAG,gBAAgB,CAsK5E"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON → SQLite migration logic for Night Watch CLI.
|
|
3
|
+
* Reads legacy JSON state files and inserts their contents into SQLite
|
|
4
|
+
* via the repository layer. Safe to run multiple times (idempotent).
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from "fs";
|
|
7
|
+
import * as path from "path";
|
|
8
|
+
import { CONFIG_FILE_NAME } from "../constants.js";
|
|
9
|
+
import { getDb } from "./sqlite/client.js";
|
|
10
|
+
import { getRepositories } from "./repositories/index.js";
|
|
11
|
+
/**
|
|
12
|
+
* Attempt to parse a JSON file, returning null if the file does not exist
|
|
13
|
+
* or its content cannot be parsed.
|
|
14
|
+
*/
|
|
15
|
+
function tryReadJson(filePath) {
|
|
16
|
+
if (!fs.existsSync(filePath)) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
21
|
+
return JSON.parse(content);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Copy a file to the backup directory if it exists.
|
|
29
|
+
*/
|
|
30
|
+
function backupFile(src, backupDir) {
|
|
31
|
+
if (fs.existsSync(src)) {
|
|
32
|
+
fs.copyFileSync(src, path.join(backupDir, path.basename(src)));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Collect all PRD directories from the registered projects by reading each
|
|
37
|
+
* project's night-watch.config.json. Falls back to the default "docs/PRDs/night-watch"
|
|
38
|
+
* directory when the config cannot be read.
|
|
39
|
+
*/
|
|
40
|
+
function collectPrdDirs(projectPaths) {
|
|
41
|
+
const prdDirs = [];
|
|
42
|
+
for (const projectPath of projectPaths) {
|
|
43
|
+
const configPath = path.join(projectPath, CONFIG_FILE_NAME);
|
|
44
|
+
let prdDir = "docs/PRDs/night-watch";
|
|
45
|
+
if (fs.existsSync(configPath)) {
|
|
46
|
+
try {
|
|
47
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
48
|
+
if (typeof config.prdDir === "string" && config.prdDir.length > 0) {
|
|
49
|
+
prdDir = config.prdDir;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// use default
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const fullPrdDir = path.join(projectPath, prdDir);
|
|
57
|
+
if (fs.existsSync(fullPrdDir)) {
|
|
58
|
+
prdDirs.push(fullPrdDir);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return prdDirs;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Migrate legacy JSON state files into SQLite.
|
|
65
|
+
*
|
|
66
|
+
* The migration is idempotent: if the key "json_migration_completed" already
|
|
67
|
+
* exists in schema_meta the function returns early without touching the DB.
|
|
68
|
+
*
|
|
69
|
+
* @param nightWatchHome - Path to the Night Watch home directory
|
|
70
|
+
* (e.g. ~/.night-watch or the value of NIGHT_WATCH_HOME).
|
|
71
|
+
*/
|
|
72
|
+
export function migrateJsonToSqlite(nightWatchHome) {
|
|
73
|
+
const db = getDb();
|
|
74
|
+
const { projectRegistry, executionHistory, prdState, roadmapState } = getRepositories();
|
|
75
|
+
// --- Idempotency check ---
|
|
76
|
+
const alreadyDone = db
|
|
77
|
+
.prepare("SELECT key FROM schema_meta WHERE key = 'json_migration_completed'")
|
|
78
|
+
.get();
|
|
79
|
+
if (alreadyDone) {
|
|
80
|
+
return {
|
|
81
|
+
projectsMigrated: 0,
|
|
82
|
+
historyRecordsMigrated: 0,
|
|
83
|
+
prdStatesMigrated: 0,
|
|
84
|
+
roadmapStatesMigrated: 0,
|
|
85
|
+
backupDir: "",
|
|
86
|
+
alreadyMigrated: true,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
// --- Backup directory ---
|
|
90
|
+
const backupDir = path.join(nightWatchHome, "backups", `json-migration-${Date.now()}`);
|
|
91
|
+
fs.mkdirSync(backupDir, { recursive: true });
|
|
92
|
+
const projectsJsonPath = path.join(nightWatchHome, "projects.json");
|
|
93
|
+
const historyJsonPath = path.join(nightWatchHome, "history.json");
|
|
94
|
+
const prdStatesJsonPath = path.join(nightWatchHome, "prd-states.json");
|
|
95
|
+
backupFile(projectsJsonPath, backupDir);
|
|
96
|
+
backupFile(historyJsonPath, backupDir);
|
|
97
|
+
backupFile(prdStatesJsonPath, backupDir);
|
|
98
|
+
// --- Migrate projects.json ---
|
|
99
|
+
let projectsMigrated = 0;
|
|
100
|
+
const legacyProjects = tryReadJson(projectsJsonPath) ?? [];
|
|
101
|
+
const migrateProjects = db.transaction(() => {
|
|
102
|
+
for (const entry of legacyProjects) {
|
|
103
|
+
if (typeof entry.name === "string" &&
|
|
104
|
+
typeof entry.path === "string" &&
|
|
105
|
+
entry.name.length > 0 &&
|
|
106
|
+
entry.path.length > 0) {
|
|
107
|
+
projectRegistry.upsert(entry);
|
|
108
|
+
projectsMigrated++;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
migrateProjects();
|
|
113
|
+
// --- Migrate history.json ---
|
|
114
|
+
let historyRecordsMigrated = 0;
|
|
115
|
+
const legacyHistory = tryReadJson(historyJsonPath) ?? {};
|
|
116
|
+
const migrateHistory = db.transaction(() => {
|
|
117
|
+
for (const [projectPath, prdMap] of Object.entries(legacyHistory)) {
|
|
118
|
+
for (const [prdFile, prdHistory] of Object.entries(prdMap)) {
|
|
119
|
+
if (!Array.isArray(prdHistory.records)) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
for (const record of prdHistory.records) {
|
|
123
|
+
if (typeof record.timestamp !== "number" ||
|
|
124
|
+
typeof record.outcome !== "string" ||
|
|
125
|
+
typeof record.exitCode !== "number" ||
|
|
126
|
+
typeof record.attempt !== "number") {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
executionHistory.addRecord(projectPath, prdFile, record);
|
|
130
|
+
historyRecordsMigrated++;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
migrateHistory();
|
|
136
|
+
// --- Migrate prd-states.json ---
|
|
137
|
+
let prdStatesMigrated = 0;
|
|
138
|
+
const legacyPrdStates = tryReadJson(prdStatesJsonPath) ?? {};
|
|
139
|
+
const migratePrdStates = db.transaction(() => {
|
|
140
|
+
for (const [projectDir, prdMap] of Object.entries(legacyPrdStates)) {
|
|
141
|
+
for (const [prdName, entry] of Object.entries(prdMap)) {
|
|
142
|
+
if (typeof entry.status === "string" &&
|
|
143
|
+
typeof entry.branch === "string" &&
|
|
144
|
+
typeof entry.timestamp === "number") {
|
|
145
|
+
prdState.set(projectDir, prdName, entry);
|
|
146
|
+
prdStatesMigrated++;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
migratePrdStates();
|
|
152
|
+
// --- Migrate .roadmap-state.json files ---
|
|
153
|
+
let roadmapStatesMigrated = 0;
|
|
154
|
+
const projectPaths = legacyProjects.map((e) => e.path);
|
|
155
|
+
const prdDirs = collectPrdDirs(projectPaths);
|
|
156
|
+
const migrateRoadmapStates = db.transaction(() => {
|
|
157
|
+
for (const prdDir of prdDirs) {
|
|
158
|
+
const stateFilePath = path.join(prdDir, ".roadmap-state.json");
|
|
159
|
+
const state = tryReadJson(stateFilePath);
|
|
160
|
+
if (state === null) {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (typeof state.version !== "number" ||
|
|
164
|
+
typeof state.items !== "object" ||
|
|
165
|
+
state.items === null) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
// Back up the .roadmap-state.json alongside the other backup files
|
|
169
|
+
const backupName = `roadmap-state-${Buffer.from(prdDir).toString("base64url").slice(0, 32)}.json`;
|
|
170
|
+
try {
|
|
171
|
+
fs.copyFileSync(stateFilePath, path.join(backupDir, backupName));
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
// non-fatal — backup is best-effort
|
|
175
|
+
}
|
|
176
|
+
roadmapState.save(prdDir, {
|
|
177
|
+
version: state.version,
|
|
178
|
+
lastScan: typeof state.lastScan === "string" ? state.lastScan : "",
|
|
179
|
+
items: state.items,
|
|
180
|
+
});
|
|
181
|
+
roadmapStatesMigrated++;
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
migrateRoadmapStates();
|
|
185
|
+
// --- Record completion ---
|
|
186
|
+
db.prepare(`INSERT OR REPLACE INTO schema_meta (key, value)
|
|
187
|
+
VALUES ('json_migration_completed', ?)`).run(new Date().toISOString());
|
|
188
|
+
return {
|
|
189
|
+
projectsMigrated,
|
|
190
|
+
historyRecordsMigrated,
|
|
191
|
+
prdStatesMigrated,
|
|
192
|
+
roadmapStatesMigrated,
|
|
193
|
+
backupDir,
|
|
194
|
+
alreadyMigrated: false,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=json-state-migrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-state-migrator.js","sourceRoot":"","sources":["../../../src/storage/json-state-migrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repository factory for Night Watch CLI.
|
|
3
|
+
* Returns singleton repository instances backed by the SQLite database.
|
|
4
|
+
* Migrations are applied lazily on first access.
|
|
5
|
+
*/
|
|
6
|
+
import { IAgentPersonaRepository, IExecutionHistoryRepository, IPrdStateRepository, IProjectRegistryRepository, IRoadmapStateRepository, ISlackDiscussionRepository } from "./interfaces.js";
|
|
7
|
+
export interface IRepositories {
|
|
8
|
+
projectRegistry: IProjectRegistryRepository;
|
|
9
|
+
executionHistory: IExecutionHistoryRepository;
|
|
10
|
+
prdState: IPrdStateRepository;
|
|
11
|
+
roadmapState: IRoadmapStateRepository;
|
|
12
|
+
agentPersona: IAgentPersonaRepository;
|
|
13
|
+
slackDiscussion: ISlackDiscussionRepository;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Return the set of available repositories, initialising the database and
|
|
17
|
+
* running schema migrations on first call.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getRepositories(): IRepositories;
|
|
20
|
+
/**
|
|
21
|
+
* Reset the initialization flag.
|
|
22
|
+
* Primarily useful in tests when the database connection is recycled.
|
|
23
|
+
*/
|
|
24
|
+
export declare function resetRepositories(): void;
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/storage/repositories/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAC3B,mBAAmB,EACnB,0BAA0B,EAC1B,uBAAuB,EACvB,0BAA0B,EAC3B,MAAM,iBAAiB,CAAC;AAQzB,MAAM,WAAW,aAAa;IAC5B,eAAe,EAAE,0BAA0B,CAAC;IAC5C,gBAAgB,EAAE,2BAA2B,CAAC;IAC9C,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,YAAY,EAAE,uBAAuB,CAAC;IACtC,YAAY,EAAE,uBAAuB,CAAC;IACtC,eAAe,EAAE,0BAA0B,CAAC;CAC7C;AAID;;;GAGG;AACH,wBAAgB,eAAe,IAAI,aAAa,CAkB/C;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repository factory for Night Watch CLI.
|
|
3
|
+
* Returns singleton repository instances backed by the SQLite database.
|
|
4
|
+
* Migrations are applied lazily on first access.
|
|
5
|
+
*/
|
|
6
|
+
import { getDb } from "../sqlite/client.js";
|
|
7
|
+
import { runMigrations } from "../sqlite/migrations.js";
|
|
8
|
+
import { SqliteProjectRegistryRepository } from "./sqlite/project-registry-repository.js";
|
|
9
|
+
import { SqliteExecutionHistoryRepository } from "./sqlite/execution-history-repository.js";
|
|
10
|
+
import { SqlitePrdStateRepository } from "./sqlite/prd-state-repository.js";
|
|
11
|
+
import { SqliteRoadmapStateRepository } from "./sqlite/roadmap-state-repository.js";
|
|
12
|
+
import { SqliteAgentPersonaRepository } from "./sqlite/agent-persona-repository.js";
|
|
13
|
+
import { SqliteSlackDiscussionRepository } from "./sqlite/slack-discussion-repository.js";
|
|
14
|
+
let _initialized = false;
|
|
15
|
+
/**
|
|
16
|
+
* Return the set of available repositories, initialising the database and
|
|
17
|
+
* running schema migrations on first call.
|
|
18
|
+
*/
|
|
19
|
+
export function getRepositories() {
|
|
20
|
+
const db = getDb();
|
|
21
|
+
if (!_initialized) {
|
|
22
|
+
runMigrations(db);
|
|
23
|
+
const agentPersonaRepo = new SqliteAgentPersonaRepository(db);
|
|
24
|
+
agentPersonaRepo.seedDefaultsOnFirstRun();
|
|
25
|
+
_initialized = true;
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
projectRegistry: new SqliteProjectRegistryRepository(db),
|
|
29
|
+
executionHistory: new SqliteExecutionHistoryRepository(db),
|
|
30
|
+
prdState: new SqlitePrdStateRepository(db),
|
|
31
|
+
roadmapState: new SqliteRoadmapStateRepository(db),
|
|
32
|
+
agentPersona: new SqliteAgentPersonaRepository(db),
|
|
33
|
+
slackDiscussion: new SqliteSlackDiscussionRepository(db),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Reset the initialization flag.
|
|
38
|
+
* Primarily useful in tests when the database connection is recycled.
|
|
39
|
+
*/
|
|
40
|
+
export function resetRepositories() {
|
|
41
|
+
_initialized = false;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/storage/repositories/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AASxD,OAAO,EAAE,+BAA+B,EAAE,MAAM,yCAAyC,CAAC;AAC1F,OAAO,EAAE,gCAAgC,EAAE,MAAM,0CAA0C,CAAC;AAC5F,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AACpF,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AACpF,OAAO,EAAE,+BAA+B,EAAE,MAAM,yCAAyC,CAAC;AAW1F,IAAI,YAAY,GAAG,KAAK,CAAC;AAEzB;;;GAGG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IAEnB,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,aAAa,CAAC,EAAE,CAAC,CAAC;QAClB,MAAM,gBAAgB,GAAG,IAAI,4BAA4B,CAAC,EAAE,CAAC,CAAC;QAC9D,gBAAgB,CAAC,sBAAsB,EAAE,CAAC;QAC1C,YAAY,GAAG,IAAI,CAAC;IACtB,CAAC;IAED,OAAO;QACL,eAAe,EAAE,IAAI,+BAA+B,CAAC,EAAE,CAAC;QACxD,gBAAgB,EAAE,IAAI,gCAAgC,CAAC,EAAE,CAAC;QAC1D,QAAQ,EAAE,IAAI,wBAAwB,CAAC,EAAE,CAAC;QAC1C,YAAY,EAAE,IAAI,4BAA4B,CAAC,EAAE,CAAC;QAClD,YAAY,EAAE,IAAI,4BAA4B,CAAC,EAAE,CAAC;QAClD,eAAe,EAAE,IAAI,+BAA+B,CAAC,EAAE,CAAC;KACzD,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,YAAY,GAAG,KAAK,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repository interface contracts for Night Watch CLI storage layer.
|
|
3
|
+
* These interfaces define the API that concrete SQLite implementations must satisfy.
|
|
4
|
+
*/
|
|
5
|
+
import { IRegistryEntry } from "../../utils/registry.js";
|
|
6
|
+
import { IExecutionRecord } from "../../utils/execution-history.js";
|
|
7
|
+
import { IPrdStateEntry } from "../../utils/prd-states.js";
|
|
8
|
+
import { IRoadmapState } from "../../utils/roadmap-state.js";
|
|
9
|
+
import { ConsensusResult, CreateAgentPersonaInput, DiscussionStatus, IAgentPersona, ISlackDiscussion, TriggerType, UpdateAgentPersonaInput } from "../../../shared/types.js";
|
|
10
|
+
export interface IProjectRegistryRepository {
|
|
11
|
+
getAll(): IRegistryEntry[];
|
|
12
|
+
upsert(entry: IRegistryEntry): void;
|
|
13
|
+
remove(path: string): boolean;
|
|
14
|
+
clear(): void;
|
|
15
|
+
updateSlackChannel(path: string, channelId: string): void;
|
|
16
|
+
}
|
|
17
|
+
export interface IExecutionHistoryRepository {
|
|
18
|
+
getRecords(projectPath: string, prdFile: string): IExecutionRecord[];
|
|
19
|
+
addRecord(projectPath: string, prdFile: string, record: IExecutionRecord): void;
|
|
20
|
+
trimRecords(projectPath: string, prdFile: string, maxCount: number): void;
|
|
21
|
+
getAllHistory(): Record<string, Record<string, {
|
|
22
|
+
records: IExecutionRecord[];
|
|
23
|
+
}>>;
|
|
24
|
+
replaceAll(history: Record<string, Record<string, {
|
|
25
|
+
records: IExecutionRecord[];
|
|
26
|
+
}>>): void;
|
|
27
|
+
}
|
|
28
|
+
export interface IPrdStateRepository {
|
|
29
|
+
get(projectPath: string, prdName: string): IPrdStateEntry | null;
|
|
30
|
+
getAll(projectPath: string): Record<string, IPrdStateEntry>;
|
|
31
|
+
readAll(): Record<string, Record<string, IPrdStateEntry>>;
|
|
32
|
+
set(projectPath: string, prdName: string, entry: IPrdStateEntry): void;
|
|
33
|
+
delete(projectPath: string, prdName: string): void;
|
|
34
|
+
}
|
|
35
|
+
export interface IRoadmapStateRepository {
|
|
36
|
+
load(prdDir: string): IRoadmapState | null;
|
|
37
|
+
save(prdDir: string, state: IRoadmapState): void;
|
|
38
|
+
}
|
|
39
|
+
export interface IAgentPersonaRepository {
|
|
40
|
+
getAll(): IAgentPersona[];
|
|
41
|
+
getById(id: string): IAgentPersona | null;
|
|
42
|
+
getActive(): IAgentPersona[];
|
|
43
|
+
create(input: CreateAgentPersonaInput): IAgentPersona;
|
|
44
|
+
update(id: string, input: UpdateAgentPersonaInput): IAgentPersona;
|
|
45
|
+
delete(id: string): void;
|
|
46
|
+
seedDefaultsOnFirstRun(): void;
|
|
47
|
+
seedDefaults(): void;
|
|
48
|
+
}
|
|
49
|
+
export interface ISlackDiscussionRepository {
|
|
50
|
+
getById(id: string): ISlackDiscussion | null;
|
|
51
|
+
getActive(projectPath: string): ISlackDiscussion[];
|
|
52
|
+
getLatestByTrigger(projectPath: string, triggerType: TriggerType, triggerRef: string): ISlackDiscussion | null;
|
|
53
|
+
create(discussion: Omit<ISlackDiscussion, 'id' | 'createdAt' | 'updatedAt'>): ISlackDiscussion;
|
|
54
|
+
updateStatus(id: string, status: DiscussionStatus, consensusResult?: ConsensusResult): void;
|
|
55
|
+
updateRound(id: string, round: number): void;
|
|
56
|
+
addParticipant(id: string, agentId: string): void;
|
|
57
|
+
close(id: string): void;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=interfaces.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../../../../src/storage/repositories/interfaces.ts"],"names":[],"mappings":"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"}
|