negotium 0.1.6 → 0.1.8
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/README.md +2 -2
- package/dist/chunk-0ay6cjdy.js +1331 -0
- package/dist/chunk-0ay6cjdy.js.map +16 -0
- package/dist/chunk-1k7t7bnx.js +97 -0
- package/dist/chunk-1k7t7bnx.js.map +10 -0
- package/dist/chunk-5ahkew9c.js +806 -0
- package/dist/chunk-5ahkew9c.js.map +17 -0
- package/dist/chunk-6cpn7ht2.js +287 -0
- package/dist/chunk-6cpn7ht2.js.map +13 -0
- package/dist/chunk-6kctn20e.js +3529 -0
- package/dist/chunk-6kctn20e.js.map +20 -0
- package/dist/chunk-7xqj7aex.js +77 -0
- package/dist/chunk-7xqj7aex.js.map +11 -0
- package/dist/chunk-9p0ww3tk.js +41 -0
- package/dist/chunk-9p0ww3tk.js.map +10 -0
- package/dist/chunk-a92a7nrk.js +252 -0
- package/dist/chunk-a92a7nrk.js.map +10 -0
- package/dist/chunk-c500xe9z.js +33 -0
- package/dist/chunk-c500xe9z.js.map +10 -0
- package/dist/chunk-cds1qxsf.js +1644 -0
- package/dist/chunk-cds1qxsf.js.map +17 -0
- package/dist/chunk-e4407g8x.js +274 -0
- package/dist/chunk-e4407g8x.js.map +10 -0
- package/dist/chunk-e5pbggsh.js +363 -0
- package/dist/chunk-e5pbggsh.js.map +11 -0
- package/dist/chunk-edb07sjp.js +567 -0
- package/dist/chunk-edb07sjp.js.map +14 -0
- package/dist/chunk-exd0v74a.js +3012 -0
- package/dist/chunk-exd0v74a.js.map +32 -0
- package/dist/chunk-fgrme9tr.js +4398 -0
- package/dist/chunk-fgrme9tr.js.map +47 -0
- package/dist/chunk-fka9eqe1.js +581 -0
- package/dist/chunk-fka9eqe1.js.map +11 -0
- package/dist/chunk-g82jygez.js +108 -0
- package/dist/chunk-g82jygez.js.map +10 -0
- package/dist/chunk-ghs2j1fr.js +312 -0
- package/dist/chunk-ghs2j1fr.js.map +10 -0
- package/dist/chunk-gmy11efb.js +125 -0
- package/dist/chunk-gmy11efb.js.map +10 -0
- package/dist/chunk-gxma4c70.js +110 -0
- package/dist/chunk-gxma4c70.js.map +10 -0
- package/dist/chunk-hkdqhm34.js +61 -0
- package/dist/chunk-hkdqhm34.js.map +10 -0
- package/dist/chunk-hpa0cpzh.js +134 -0
- package/dist/chunk-hpa0cpzh.js.map +10 -0
- package/dist/chunk-hwy3n31w.js +21 -0
- package/dist/chunk-hwy3n31w.js.map +9 -0
- package/dist/chunk-j2behpy7.js +214 -0
- package/dist/chunk-j2behpy7.js.map +10 -0
- package/dist/chunk-jc0at0tc.js +102 -0
- package/dist/chunk-jc0at0tc.js.map +10 -0
- package/dist/chunk-jkqq5ef6.js +243 -0
- package/dist/chunk-jkqq5ef6.js.map +11 -0
- package/dist/chunk-jzkw2f01.js +51 -0
- package/dist/chunk-jzkw2f01.js.map +10 -0
- package/dist/chunk-jzz91jwh.js +70 -0
- package/dist/chunk-jzz91jwh.js.map +10 -0
- package/dist/chunk-k9z47mab.js +247 -0
- package/dist/chunk-k9z47mab.js.map +12 -0
- package/dist/chunk-n17yxpa8.js +23 -0
- package/dist/chunk-n17yxpa8.js.map +10 -0
- package/dist/chunk-naa09ags.js +2143 -0
- package/dist/chunk-naa09ags.js.map +15 -0
- package/dist/chunk-ns3ke88n.js +142 -0
- package/dist/chunk-ns3ke88n.js.map +10 -0
- package/dist/chunk-p3cr2ejg.js +1626 -0
- package/dist/chunk-p3cr2ejg.js.map +15 -0
- package/dist/chunk-q5bcpf23.js +2925 -0
- package/dist/chunk-q5bcpf23.js.map +20 -0
- package/dist/chunk-rafc55bs.js +424 -0
- package/dist/chunk-rafc55bs.js.map +11 -0
- package/dist/chunk-rbrxjvbj.js +2830 -0
- package/dist/chunk-rbrxjvbj.js.map +23 -0
- package/dist/chunk-sa874j5c.js +9 -0
- package/dist/chunk-sa874j5c.js.map +10 -0
- package/dist/chunk-sgsz2fpq.js +289 -0
- package/dist/chunk-sgsz2fpq.js.map +10 -0
- package/dist/chunk-sm6fh5c5.js +569 -0
- package/dist/chunk-sm6fh5c5.js.map +14 -0
- package/dist/chunk-t9zcg8f1.js +499 -0
- package/dist/chunk-t9zcg8f1.js.map +13 -0
- package/dist/chunk-vp2db42d.js +121 -0
- package/dist/chunk-vp2db42d.js.map +10 -0
- package/dist/chunk-w13jjf4a.js +46 -0
- package/dist/chunk-w13jjf4a.js.map +10 -0
- package/dist/chunk-x1arr7ze.js +63 -0
- package/dist/chunk-x1arr7ze.js.map +10 -0
- package/dist/chunk-xfq68rch.js +583 -0
- package/dist/chunk-xfq68rch.js.map +11 -0
- package/dist/main.js +132 -20
- package/dist/main.js.map +4 -4
- package/dist/runtime/scripts/faster-whisper-wrapper.py +87 -0
- package/dist/runtime/scripts/mcp-patchright-http.mjs +349 -0
- package/dist/runtime/src/agents/api-topic-agent-switch.ts +178 -0
- package/dist/runtime/src/agents/archiver.ts +396 -0
- package/dist/runtime/src/agents/auth-check.ts +64 -0
- package/dist/runtime/src/agents/claude-provider.ts +737 -0
- package/dist/runtime/src/agents/claude-registry.ts +115 -0
- package/dist/runtime/src/agents/codex-native-multi-agent.ts +177 -0
- package/dist/runtime/src/agents/codex-provider.ts +785 -0
- package/dist/runtime/src/agents/codex-registry.ts +115 -0
- package/dist/runtime/src/agents/codex-tree-kill.ts +365 -0
- package/dist/runtime/src/agents/contracts.ts +69 -0
- package/dist/runtime/src/agents/deep-map.ts +13 -0
- package/dist/runtime/src/agents/execution-host.ts +91 -0
- package/dist/runtime/src/agents/fixtures/claude-attachments.jsonl +2 -0
- package/dist/runtime/src/agents/fixtures/codex-shell.jsonl +5 -0
- package/dist/runtime/src/agents/fork.ts +65 -0
- package/dist/runtime/src/agents/hosted-agent.ts +48 -0
- package/dist/runtime/src/agents/idle-archiver.ts +128 -0
- package/dist/runtime/src/agents/index.ts +205 -0
- package/dist/runtime/src/agents/maestro-provider.ts +206 -0
- package/dist/runtime/src/agents/maestro-registry.ts +31 -0
- package/dist/runtime/src/agents/mcp-tools/ask-user.ts +280 -0
- package/dist/runtime/src/agents/mcp-tools/common.ts +21 -0
- package/dist/runtime/src/agents/mcp-tools/self-config.ts +220 -0
- package/dist/runtime/src/agents/mcp-tools/spawn-subagent.ts +525 -0
- package/dist/runtime/src/agents/mcp-tools/visuals.ts +88 -0
- package/dist/runtime/src/agents/model-catalog.ts +151 -0
- package/dist/runtime/src/agents/registry.ts +24 -0
- package/dist/runtime/src/agents/rollout/claude.ts +331 -0
- package/dist/runtime/src/agents/rollout/codex.ts +569 -0
- package/dist/runtime/src/agents/rollout/shared.ts +205 -0
- package/dist/runtime/src/agents/self-config-core.ts +415 -0
- package/dist/runtime/src/agents/task-events.ts +44 -0
- package/dist/runtime/src/agents/tool-format.ts +352 -0
- package/dist/runtime/src/agents/topic-agent-switch.ts +193 -0
- package/dist/runtime/src/agents/topic-cleanup.ts +231 -0
- package/dist/runtime/src/agents/vault-tool-policy.ts +33 -0
- package/dist/runtime/src/application/execute-external-user-turn.ts +23 -0
- package/dist/runtime/src/application/submit-user-message.ts +47 -0
- package/dist/runtime/src/application/switch-topic-effort.ts +48 -0
- package/dist/runtime/src/application/switch-topic-model.ts +79 -0
- package/dist/runtime/src/application/topic-service.ts +139 -0
- package/dist/runtime/src/application/vault-command.ts +170 -0
- package/dist/runtime/src/bus.ts +319 -0
- package/dist/runtime/src/index.ts +333 -0
- package/dist/runtime/src/mcp/agent-health-server.ts +309 -0
- package/dist/runtime/src/mcp/background-bash-server.ts +346 -0
- package/dist/runtime/src/mcp/canonical-bridge-config.ts +84 -0
- package/dist/runtime/src/mcp/canonical-proxy-server.ts +171 -0
- package/dist/runtime/src/mcp/dm-ipc.ts +60 -0
- package/dist/runtime/src/mcp/mcp-helpers.ts +40 -0
- package/dist/runtime/src/mcp/paddleocr-server.ts +105 -0
- package/dist/runtime/src/mcp/peer-bridge.ts +114 -0
- package/dist/runtime/src/mcp/runtime-spec.ts +134 -0
- package/dist/runtime/src/mcp/session-comm/bridge-ipc-config.ts +27 -0
- package/dist/runtime/src/mcp/session-comm/peer-forward.ts +165 -0
- package/dist/runtime/src/mcp/session-comm/runtime.ts +115 -0
- package/dist/runtime/src/mcp/session-comm/server.ts +649 -0
- package/dist/runtime/src/mcp/session-comm/topic-config.ts +131 -0
- package/dist/runtime/src/mcp/session-comm/topics.ts +229 -0
- package/dist/runtime/src/mcp/stdio-protect.ts +84 -0
- package/dist/runtime/src/mcp/system-health-server.ts +130 -0
- package/dist/runtime/src/mcp/task-server.ts +173 -0
- package/dist/runtime/src/mcp/token-stats-server.ts +98 -0
- package/dist/runtime/src/mcp/vault-http.ts +219 -0
- package/dist/runtime/src/mcp/vault-run.ts +153 -0
- package/dist/runtime/src/mcp/vault-server.ts +104 -0
- package/dist/runtime/src/mcp/wiki-server.ts +755 -0
- package/dist/runtime/src/media/file-events.ts +33 -0
- package/dist/runtime/src/media/text-extractor.ts +312 -0
- package/dist/runtime/src/media/video.ts +92 -0
- package/dist/runtime/src/outbox/file-ops.ts +210 -0
- package/dist/runtime/src/outbox/index.ts +8 -0
- package/dist/runtime/src/outbox/utils.ts +51 -0
- package/dist/runtime/src/platform/background-bash/manager.ts +279 -0
- package/dist/runtime/src/platform/config.ts +371 -0
- package/dist/runtime/src/platform/constants.ts +18 -0
- package/dist/runtime/src/platform/debug-users.ts +14 -0
- package/dist/runtime/src/platform/delay.ts +1 -0
- package/dist/runtime/src/platform/error.ts +9 -0
- package/dist/runtime/src/platform/file-utils.ts +16 -0
- package/dist/runtime/src/platform/jsonl.ts +202 -0
- package/dist/runtime/src/platform/lifecycle.ts +174 -0
- package/dist/runtime/src/platform/logger.ts +31 -0
- package/dist/runtime/src/platform/maestro-bootstrap-env.ts +3 -0
- package/dist/runtime/src/platform/mcp-config.ts +865 -0
- package/dist/runtime/src/platform/modules.ts +145 -0
- package/dist/runtime/src/platform/node-plugins.ts +46 -0
- package/dist/runtime/src/platform/playwright/manager.ts +1233 -0
- package/dist/runtime/src/prompts/agents/wiki-archiver.md +261 -0
- package/dist/runtime/src/prompts/builders.ts +357 -0
- package/dist/runtime/src/prompts/sessions/channel-system.md +48 -0
- package/dist/runtime/src/prompts/sessions/manager-system.md +37 -0
- package/dist/runtime/src/prompts/sessions/topic-system.md +47 -0
- package/dist/runtime/src/prompts/sessions/visual-design.md +86 -0
- package/dist/runtime/src/query/active-rooms.ts +532 -0
- package/dist/runtime/src/query/control.ts +313 -0
- package/dist/runtime/src/query/index.ts +24 -0
- package/dist/runtime/src/query/session-inbox-cleanup.ts +44 -0
- package/dist/runtime/src/query/session-inbox-path.ts +42 -0
- package/dist/runtime/src/query/state.ts +94 -0
- package/dist/runtime/src/query/types.ts +83 -0
- package/dist/runtime/src/runtime/ask-callbacks.ts +153 -0
- package/dist/runtime/src/runtime/attachments.ts +151 -0
- package/dist/runtime/src/runtime/background-sessions.ts +83 -0
- package/dist/runtime/src/runtime/channel-context.ts +107 -0
- package/dist/runtime/src/runtime/errors.ts +69 -0
- package/dist/runtime/src/runtime/event-heartbeat.ts +77 -0
- package/dist/runtime/src/runtime/file-hooks.ts +81 -0
- package/dist/runtime/src/runtime/footer.ts +23 -0
- package/dist/runtime/src/runtime/inbox.ts +946 -0
- package/dist/runtime/src/runtime/tasks.ts +56 -0
- package/dist/runtime/src/runtime/topic-config.ts +29 -0
- package/dist/runtime/src/runtime/turn-runner.ts +2286 -0
- package/dist/runtime/src/runtime/usage-alert.ts +84 -0
- package/dist/runtime/src/runtime/visual-html.ts +109 -0
- package/dist/runtime/src/runtime/visual-store.ts +430 -0
- package/dist/runtime/src/runtime/visuals.ts +171 -0
- package/dist/runtime/src/security/sanitize.ts +27 -0
- package/dist/runtime/src/security/sensitive-path.ts +34 -0
- package/dist/runtime/src/storage/activity-log.ts +152 -0
- package/dist/runtime/src/storage/api-messages.ts +617 -0
- package/dist/runtime/src/storage/api-topic-brief.ts +127 -0
- package/dist/runtime/src/storage/api-topic-config.ts +192 -0
- package/dist/runtime/src/storage/api-topics.ts +844 -0
- package/dist/runtime/src/storage/app-settings.ts +44 -0
- package/dist/runtime/src/storage/browser-profiles.ts +133 -0
- package/dist/runtime/src/storage/conversations.ts +268 -0
- package/dist/runtime/src/storage/forum/agent-settings.ts +20 -0
- package/dist/runtime/src/storage/forum/index.ts +4 -0
- package/dist/runtime/src/storage/forum/repository.ts +283 -0
- package/dist/runtime/src/storage/forum/schema.ts +300 -0
- package/dist/runtime/src/storage/forum-db.ts +23 -0
- package/dist/runtime/src/storage/runtime-events.ts +130 -0
- package/dist/runtime/src/storage/runtime-leases.ts +189 -0
- package/dist/runtime/src/storage/runtime-process-leases.ts +216 -0
- package/dist/runtime/src/storage/runtime-topic-state.ts +148 -0
- package/dist/runtime/src/storage/runtime-turn-requests.ts +300 -0
- package/dist/runtime/src/storage/self-schedules.ts +298 -0
- package/dist/runtime/src/storage/session-asks.ts +347 -0
- package/dist/runtime/src/storage/sqlite.ts +129 -0
- package/dist/runtime/src/storage/tasks.ts +179 -0
- package/dist/runtime/src/storage/token-stats.ts +144 -0
- package/dist/runtime/src/storage/topic-archive-state.ts +59 -0
- package/dist/runtime/src/storage/topic-archive.ts +74 -0
- package/dist/runtime/src/storage/topic-settings.ts +67 -0
- package/dist/runtime/src/storage/topic-transcript.ts +98 -0
- package/dist/runtime/src/storage/vault-crypto.ts +65 -0
- package/dist/runtime/src/storage/vault.ts +225 -0
- package/dist/runtime/src/storage/wiki-summary-names.ts +33 -0
- package/dist/runtime/src/storage/wiki.ts +85 -0
- package/dist/runtime/src/topics/create.ts +123 -0
- package/dist/runtime/src/topics/derive.ts +398 -0
- package/dist/runtime/src/topics/lifecycle.ts +311 -0
- package/dist/runtime/src/topics/links.ts +7 -0
- package/dist/runtime/src/topics/personal-general.ts +65 -0
- package/dist/runtime/src/topics/session.ts +381 -0
- package/dist/runtime/src/types/api.ts +497 -0
- package/dist/runtime/src/types.ts +255 -0
- package/dist/runtime/src/version.ts +1 -0
- package/dist/runtime/tsconfig.json +13 -0
- package/package.json +16 -3
- package/dist/main.d.ts +0 -3
- package/dist/main.d.ts.map +0 -1
|
@@ -0,0 +1,569 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
cancelAskCallbacksForTopic
|
|
4
|
+
} from "./chunk-jc0at0tc.js";
|
|
5
|
+
import {
|
|
6
|
+
deletePendingAsksForTopic
|
|
7
|
+
} from "./chunk-sgsz2fpq.js";
|
|
8
|
+
import"./chunk-1k7t7bnx.js";
|
|
9
|
+
import {
|
|
10
|
+
archiveTopicMessages,
|
|
11
|
+
cancelIdleArchiveForTopic,
|
|
12
|
+
cancelRuntimeUserTurnRequests,
|
|
13
|
+
cancelRuntimeUserTurnRequestsBeforeEpoch,
|
|
14
|
+
cancelSubagentWatchForDeletedTopic,
|
|
15
|
+
clearQueryState,
|
|
16
|
+
clearQueryUsageAlert,
|
|
17
|
+
deleteFilesForTopic,
|
|
18
|
+
deleteTopicArchiveState,
|
|
19
|
+
deleteTopicBrief,
|
|
20
|
+
deleteTopicVisuals,
|
|
21
|
+
killBgBash,
|
|
22
|
+
runArchiverTurn
|
|
23
|
+
} from "./chunk-fgrme9tr.js";
|
|
24
|
+
import {
|
|
25
|
+
WsHub,
|
|
26
|
+
closeBrowserOwnerTabs,
|
|
27
|
+
delay,
|
|
28
|
+
deleteMessagesForTopic,
|
|
29
|
+
deleteTopicProfileDir,
|
|
30
|
+
getBrowserProfileOwner,
|
|
31
|
+
getTopicBrowserProfile
|
|
32
|
+
} from "./chunk-0ay6cjdy.js";
|
|
33
|
+
import {
|
|
34
|
+
GENERAL_TOPIC_ID,
|
|
35
|
+
deleteTopic,
|
|
36
|
+
getTopicMemoryOrigin,
|
|
37
|
+
getTopicSessionId,
|
|
38
|
+
listTopics,
|
|
39
|
+
reparentTopicChildren
|
|
40
|
+
} from "./chunk-xfq68rch.js";
|
|
41
|
+
import {
|
|
42
|
+
deleteApiTopicConfig
|
|
43
|
+
} from "./chunk-gmy11efb.js";
|
|
44
|
+
import {
|
|
45
|
+
TOPIC_MAINTENANCE_STALE_MS,
|
|
46
|
+
TURN_LEASE_STALE_MS,
|
|
47
|
+
abortRoom,
|
|
48
|
+
beginRuntimeTopicMaintenance,
|
|
49
|
+
getRoomQuery,
|
|
50
|
+
getRuntimeTurnLease,
|
|
51
|
+
interSessionQueue
|
|
52
|
+
} from "./chunk-t9zcg8f1.js";
|
|
53
|
+
import {
|
|
54
|
+
db
|
|
55
|
+
} from "./chunk-7xqj7aex.js";
|
|
56
|
+
import {
|
|
57
|
+
getRegistry
|
|
58
|
+
} from "./chunk-5ahkew9c.js";
|
|
59
|
+
import {
|
|
60
|
+
getConversationPath,
|
|
61
|
+
readConversation
|
|
62
|
+
} from "./chunk-6cpn7ht2.js";
|
|
63
|
+
import {
|
|
64
|
+
SESSION_INBOX_DIR,
|
|
65
|
+
SUPPORTED_AGENTS,
|
|
66
|
+
logger,
|
|
67
|
+
resolveTopicWorkspaceDir
|
|
68
|
+
} from "./chunk-k9z47mab.js";
|
|
69
|
+
import"./chunk-hwy3n31w.js";
|
|
70
|
+
|
|
71
|
+
// ../../packages/core/src/topics/lifecycle.ts
|
|
72
|
+
import { rmSync } from "fs";
|
|
73
|
+
|
|
74
|
+
// ../../packages/core/src/agents/topic-cleanup.ts
|
|
75
|
+
import { mkdirSync, renameSync, unlinkSync, writeFileSync } from "fs";
|
|
76
|
+
import { dirname } from "path";
|
|
77
|
+
function collectSessionIdsByAgent(entries, extraSessions = []) {
|
|
78
|
+
const out = new Map;
|
|
79
|
+
for (const e of entries) {
|
|
80
|
+
if (e.event.type !== "session")
|
|
81
|
+
continue;
|
|
82
|
+
const set = out.get(e.agent) ?? new Set;
|
|
83
|
+
set.add(e.event.sessionId);
|
|
84
|
+
out.set(e.agent, set);
|
|
85
|
+
}
|
|
86
|
+
for (const { agent, sessionId } of extraSessions) {
|
|
87
|
+
if (!sessionId)
|
|
88
|
+
continue;
|
|
89
|
+
const set = out.get(agent) ?? new Set;
|
|
90
|
+
set.add(sessionId);
|
|
91
|
+
out.set(agent, set);
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
async function cleanupSessionRollouts(opts, entries) {
|
|
96
|
+
const { userId, topicName, cwd, extraSessions = [] } = opts;
|
|
97
|
+
const idsByAgent = collectSessionIdsByAgent(entries, extraSessions);
|
|
98
|
+
let cleanupFailed = false;
|
|
99
|
+
await Promise.all(SUPPORTED_AGENTS.map(async (agent) => {
|
|
100
|
+
const ids = idsByAgent.get(agent);
|
|
101
|
+
if (!ids || ids.size === 0)
|
|
102
|
+
return;
|
|
103
|
+
try {
|
|
104
|
+
await getRegistry(agent).cleanupRollouts({
|
|
105
|
+
cwd,
|
|
106
|
+
sessionIds: Array.from(ids)
|
|
107
|
+
});
|
|
108
|
+
} catch (e) {
|
|
109
|
+
logger.warn({ err: e, userId, topicName, agent, count: ids.size }, "topic logs: agent cleanup failed");
|
|
110
|
+
cleanupFailed = true;
|
|
111
|
+
}
|
|
112
|
+
}));
|
|
113
|
+
return !cleanupFailed;
|
|
114
|
+
}
|
|
115
|
+
async function cleanupTopicRollouts(opts) {
|
|
116
|
+
return cleanupSessionRollouts(opts, readConversation(opts.userId, opts.topicName));
|
|
117
|
+
}
|
|
118
|
+
async function rotateTopicLogs(opts) {
|
|
119
|
+
const retainTurns = Math.max(0, Math.floor(opts.retainTurns));
|
|
120
|
+
const entries = readConversation(opts.userId, opts.topicName);
|
|
121
|
+
const userEntryIndexes = entries.flatMap((entry, index) => entry.event.type === "user_message" ? [index] : []);
|
|
122
|
+
const totalTurns = userEntryIndexes.length;
|
|
123
|
+
const firstRetainedIndex = retainTurns === 0 ? entries.length : userEntryIndexes[Math.max(0, totalTurns - retainTurns)] ?? 0;
|
|
124
|
+
const retained = entries.slice(firstRetainedIndex).filter((entry) => entry.event.type !== "session");
|
|
125
|
+
if (!await cleanupSessionRollouts(opts, entries)) {
|
|
126
|
+
logger.warn({ userId: opts.userId, topicName: opts.topicName }, "rotateTopicLogs: keeping current context because rollout cleanup failed");
|
|
127
|
+
return {
|
|
128
|
+
rotated: false,
|
|
129
|
+
totalTurns,
|
|
130
|
+
retainedTurns: Math.min(totalTurns, retainTurns),
|
|
131
|
+
retainedEntries: retained.length
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
const path = getConversationPath(opts.userId, opts.topicName);
|
|
135
|
+
const tempPath = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
136
|
+
try {
|
|
137
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
138
|
+
writeFileSync(tempPath, retained.length > 0 ? `${retained.map((entry) => JSON.stringify(entry)).join(`
|
|
139
|
+
`)}
|
|
140
|
+
` : "", { flag: "wx" });
|
|
141
|
+
renameSync(tempPath, path);
|
|
142
|
+
} catch (e) {
|
|
143
|
+
try {
|
|
144
|
+
unlinkSync(tempPath);
|
|
145
|
+
} catch {}
|
|
146
|
+
logger.warn({ err: e, path }, "rotateTopicLogs: conversation replacement failed");
|
|
147
|
+
return {
|
|
148
|
+
rotated: false,
|
|
149
|
+
totalTurns,
|
|
150
|
+
retainedTurns: Math.min(totalTurns, retainTurns),
|
|
151
|
+
retainedEntries: retained.length
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
rotated: true,
|
|
156
|
+
totalTurns,
|
|
157
|
+
retainedTurns: Math.min(totalTurns, retainTurns),
|
|
158
|
+
retainedEntries: retained.length
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
async function purgeTopicLogs(opts) {
|
|
162
|
+
const { userId, topicName } = opts;
|
|
163
|
+
const entries = readConversation(userId, topicName);
|
|
164
|
+
if (!await cleanupSessionRollouts(opts, entries)) {
|
|
165
|
+
logger.warn({ userId, topicName }, "purgeTopicLogs: keeping unified log because one or more rollout cleanups failed");
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const path = getConversationPath(userId, topicName);
|
|
169
|
+
try {
|
|
170
|
+
unlinkSync(path);
|
|
171
|
+
} catch (e) {
|
|
172
|
+
if (e?.code !== "ENOENT") {
|
|
173
|
+
logger.warn({ err: e, path }, "purgeTopicLogs: unified log unlink failed");
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ../../packages/core/src/query/session-inbox-cleanup.ts
|
|
179
|
+
import { unlinkSync as unlinkSync2 } from "fs";
|
|
180
|
+
import { basename, join as join2 } from "path";
|
|
181
|
+
|
|
182
|
+
// ../../packages/core/src/query/session-inbox-path.ts
|
|
183
|
+
import { join } from "path";
|
|
184
|
+
var TOPIC_ID_FILE_PREFIX = "topic-id-";
|
|
185
|
+
var JSONL_SUFFIX = ".jsonl";
|
|
186
|
+
var SCHEDULE_SUFFIX = ".schedule";
|
|
187
|
+
function sessionInboxPath(userId, topicId) {
|
|
188
|
+
const key = Buffer.from(topicId, "utf8").toString("base64url");
|
|
189
|
+
return join(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${JSONL_SUFFIX}`);
|
|
190
|
+
}
|
|
191
|
+
function scheduledSessionInboxPath(userId, topicId) {
|
|
192
|
+
const key = Buffer.from(topicId, "utf8").toString("base64url");
|
|
193
|
+
return join(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${SCHEDULE_SUFFIX}`);
|
|
194
|
+
}
|
|
195
|
+
function decodeTopicIdFileName(fileName, suffix) {
|
|
196
|
+
if (!fileName.startsWith(TOPIC_ID_FILE_PREFIX) || !fileName.endsWith(suffix))
|
|
197
|
+
return null;
|
|
198
|
+
const encoded = fileName.slice(TOPIC_ID_FILE_PREFIX.length, -suffix.length);
|
|
199
|
+
if (!encoded || !/^[A-Za-z0-9_-]+$/.test(encoded))
|
|
200
|
+
return null;
|
|
201
|
+
try {
|
|
202
|
+
return Buffer.from(encoded, "base64url").toString("utf8") || null;
|
|
203
|
+
} catch {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function topicIdFromSessionInboxFileName(fileName) {
|
|
208
|
+
return decodeTopicIdFileName(fileName, JSONL_SUFFIX);
|
|
209
|
+
}
|
|
210
|
+
function topicIdFromScheduledSessionInboxFileName(fileName) {
|
|
211
|
+
const base = fileName.endsWith(".processing") ? fileName.slice(0, -".processing".length) : fileName;
|
|
212
|
+
return decodeTopicIdFileName(base, SCHEDULE_SUFFIX);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ../../packages/core/src/query/session-inbox-cleanup.ts
|
|
216
|
+
function cleanupSessionInboxFiles(userId, topicId, legacyTopicTitle) {
|
|
217
|
+
const live = sessionInboxPath(userId, topicId);
|
|
218
|
+
const scheduled = scheduledSessionInboxPath(userId, topicId);
|
|
219
|
+
const candidates = new Set([live, `${live}.processing`, scheduled, `${scheduled}.processing`]);
|
|
220
|
+
if (legacyTopicTitle && legacyTopicTitle !== "." && legacyTopicTitle !== ".." && basename(legacyTopicTitle) === legacyTopicTitle) {
|
|
221
|
+
const legacyBase = join2(SESSION_INBOX_DIR, userId, legacyTopicTitle);
|
|
222
|
+
for (const suffix of [".jsonl", ".jsonl.processing", ".schedule", ".schedule.processing"]) {
|
|
223
|
+
candidates.add(`${legacyBase}${suffix}`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
let deleted = 0;
|
|
227
|
+
for (const path of candidates) {
|
|
228
|
+
try {
|
|
229
|
+
unlinkSync2(path);
|
|
230
|
+
deleted++;
|
|
231
|
+
} catch (err) {
|
|
232
|
+
if (err?.code !== "ENOENT") {
|
|
233
|
+
logger.warn({ err, path, topicId, userId }, "topic cleanup: inbox unlink failed");
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return deleted;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ../../packages/core/src/storage/self-schedules.ts
|
|
241
|
+
import { randomUUID } from "crypto";
|
|
242
|
+
db.exec(`
|
|
243
|
+
CREATE TABLE IF NOT EXISTS runtime_self_schedules (
|
|
244
|
+
id TEXT PRIMARY KEY,
|
|
245
|
+
topic_id TEXT NOT NULL,
|
|
246
|
+
user_id TEXT NOT NULL,
|
|
247
|
+
message TEXT NOT NULL,
|
|
248
|
+
deliver_at INTEGER NOT NULL,
|
|
249
|
+
created_at INTEGER NOT NULL,
|
|
250
|
+
updated_at INTEGER NOT NULL,
|
|
251
|
+
status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'running')),
|
|
252
|
+
claimed_by TEXT,
|
|
253
|
+
claimed_at INTEGER,
|
|
254
|
+
running_query_id TEXT
|
|
255
|
+
)
|
|
256
|
+
`);
|
|
257
|
+
db.exec(`
|
|
258
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_runtime_self_schedules_one_pending
|
|
259
|
+
ON runtime_self_schedules(topic_id)
|
|
260
|
+
WHERE status = 'pending'
|
|
261
|
+
`);
|
|
262
|
+
db.exec(`
|
|
263
|
+
CREATE INDEX IF NOT EXISTS idx_runtime_self_schedules_due
|
|
264
|
+
ON runtime_self_schedules(status, deliver_at)
|
|
265
|
+
`);
|
|
266
|
+
function rowToSchedule(row) {
|
|
267
|
+
return {
|
|
268
|
+
id: row.id,
|
|
269
|
+
topicId: row.topic_id,
|
|
270
|
+
userId: row.user_id,
|
|
271
|
+
message: row.message,
|
|
272
|
+
deliverAt: Number(row.deliver_at),
|
|
273
|
+
createdAt: Number(row.created_at),
|
|
274
|
+
updatedAt: Number(row.updated_at),
|
|
275
|
+
status: row.status === "running" ? "running" : "pending",
|
|
276
|
+
claimedBy: row.claimed_by ?? undefined,
|
|
277
|
+
claimedAt: row.claimed_at === null ? undefined : Number(row.claimed_at),
|
|
278
|
+
runningQueryId: row.running_query_id ?? undefined
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
function createPendingSelfSchedule(input) {
|
|
282
|
+
return db.transaction(() => {
|
|
283
|
+
const existing = getPendingSelfSchedule(input.topicId);
|
|
284
|
+
if (existing)
|
|
285
|
+
return { ok: false, existing };
|
|
286
|
+
const now = input.now ?? Date.now();
|
|
287
|
+
const schedule = {
|
|
288
|
+
id: `scheduled-${randomUUID()}`,
|
|
289
|
+
topicId: input.topicId,
|
|
290
|
+
userId: input.userId,
|
|
291
|
+
message: input.message,
|
|
292
|
+
deliverAt: input.deliverAt,
|
|
293
|
+
createdAt: now,
|
|
294
|
+
updatedAt: now,
|
|
295
|
+
status: "pending"
|
|
296
|
+
};
|
|
297
|
+
db.query(`INSERT INTO runtime_self_schedules
|
|
298
|
+
(id, topic_id, user_id, message, deliver_at, created_at, updated_at, status)
|
|
299
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, 'pending')`).run(schedule.id, schedule.topicId, schedule.userId, schedule.message, schedule.deliverAt, schedule.createdAt, schedule.updatedAt);
|
|
300
|
+
return { ok: true, schedule };
|
|
301
|
+
}).immediate();
|
|
302
|
+
}
|
|
303
|
+
function getPendingSelfSchedule(topicId) {
|
|
304
|
+
const row = db.query("SELECT * FROM runtime_self_schedules WHERE topic_id = ? AND status = 'pending'").get(topicId);
|
|
305
|
+
return row ? rowToSchedule(row) : null;
|
|
306
|
+
}
|
|
307
|
+
function updatePendingSelfSchedule(input) {
|
|
308
|
+
const existing = getPendingSelfSchedule(input.topicId);
|
|
309
|
+
if (!existing || existing.id !== input.scheduleId)
|
|
310
|
+
return null;
|
|
311
|
+
const result = db.query(`UPDATE runtime_self_schedules
|
|
312
|
+
SET message = ?, deliver_at = ?, updated_at = ?
|
|
313
|
+
WHERE id = ? AND topic_id = ? AND status = 'pending'`).run(input.message ?? existing.message, input.deliverAt ?? existing.deliverAt, input.now ?? Date.now(), input.scheduleId, input.topicId);
|
|
314
|
+
return Number(result.changes ?? 0) > 0 ? getPendingSelfSchedule(input.topicId) : null;
|
|
315
|
+
}
|
|
316
|
+
function cancelPendingSelfSchedule(topicId, scheduleId) {
|
|
317
|
+
const result = db.query("DELETE FROM runtime_self_schedules WHERE id = ? AND topic_id = ? AND status = 'pending'").run(scheduleId, topicId);
|
|
318
|
+
return Number(result.changes ?? 0) > 0;
|
|
319
|
+
}
|
|
320
|
+
function claimNextDueSelfSchedule(ownerId, now = Date.now()) {
|
|
321
|
+
const staleBefore = now - TURN_LEASE_STALE_MS;
|
|
322
|
+
return db.transaction(() => {
|
|
323
|
+
const row = db.query(`SELECT s.*
|
|
324
|
+
FROM runtime_self_schedules s
|
|
325
|
+
LEFT JOIN runtime_turn_leases l ON l.topic_id = s.topic_id
|
|
326
|
+
LEFT JOIN runtime_topic_state t ON t.topic_id = s.topic_id
|
|
327
|
+
WHERE (l.topic_id IS NULL OR l.heartbeat_at < ?)
|
|
328
|
+
AND (t.topic_id IS NULL OR t.maintenance = 0 OR t.heartbeat_at < ?)
|
|
329
|
+
AND (
|
|
330
|
+
(s.status = 'pending' AND s.deliver_at <= ?)
|
|
331
|
+
OR (s.status = 'running' AND (s.claimed_at IS NULL OR s.claimed_at < ?))
|
|
332
|
+
)
|
|
333
|
+
ORDER BY CASE s.status WHEN 'running' THEN 0 ELSE 1 END, s.deliver_at ASC
|
|
334
|
+
LIMIT 1`).get(staleBefore, now - TOPIC_MAINTENANCE_STALE_MS, now, staleBefore);
|
|
335
|
+
if (!row)
|
|
336
|
+
return null;
|
|
337
|
+
const result = db.query(`UPDATE runtime_self_schedules
|
|
338
|
+
SET status = 'running', claimed_by = ?, claimed_at = ?, running_query_id = NULL
|
|
339
|
+
WHERE id = ? AND (
|
|
340
|
+
(status = 'pending' AND deliver_at <= ?)
|
|
341
|
+
OR (status = 'running' AND (claimed_at IS NULL OR claimed_at < ?))
|
|
342
|
+
)`).run(ownerId, now, row.id, now, staleBefore);
|
|
343
|
+
if (Number(result.changes ?? 0) === 0)
|
|
344
|
+
return null;
|
|
345
|
+
return rowToSchedule({
|
|
346
|
+
...row,
|
|
347
|
+
status: "running",
|
|
348
|
+
claimed_by: ownerId,
|
|
349
|
+
claimed_at: now,
|
|
350
|
+
running_query_id: null
|
|
351
|
+
});
|
|
352
|
+
}).immediate();
|
|
353
|
+
}
|
|
354
|
+
function markSelfScheduleRunning(scheduleId, ownerId, queryId) {
|
|
355
|
+
const result = db.query(`UPDATE runtime_self_schedules
|
|
356
|
+
SET running_query_id = ?, claimed_at = ?
|
|
357
|
+
WHERE id = ? AND status = 'running' AND claimed_by = ?`).run(queryId, Date.now(), scheduleId, ownerId);
|
|
358
|
+
return Number(result.changes ?? 0) > 0;
|
|
359
|
+
}
|
|
360
|
+
function heartbeatSelfScheduleClaim(scheduleId, ownerId, now = Date.now()) {
|
|
361
|
+
const result = db.query(`UPDATE runtime_self_schedules
|
|
362
|
+
SET claimed_at = ?
|
|
363
|
+
WHERE id = ? AND status = 'running' AND claimed_by = ?`).run(now, scheduleId, ownerId);
|
|
364
|
+
return Number(result.changes ?? 0) > 0;
|
|
365
|
+
}
|
|
366
|
+
function releaseSelfScheduleClaim(scheduleId, ownerId) {
|
|
367
|
+
return db.transaction(() => {
|
|
368
|
+
const row = db.query("SELECT * FROM runtime_self_schedules WHERE id = ? AND status = 'running' AND claimed_by = ?").get(scheduleId, ownerId);
|
|
369
|
+
if (!row)
|
|
370
|
+
return "dropped";
|
|
371
|
+
const newer = getPendingSelfSchedule(row.topic_id);
|
|
372
|
+
if (newer) {
|
|
373
|
+
db.query("DELETE FROM runtime_self_schedules WHERE id = ?").run(scheduleId);
|
|
374
|
+
return "dropped";
|
|
375
|
+
}
|
|
376
|
+
db.query(`UPDATE runtime_self_schedules
|
|
377
|
+
SET status = 'pending', claimed_by = NULL, claimed_at = NULL,
|
|
378
|
+
running_query_id = NULL, updated_at = ?
|
|
379
|
+
WHERE id = ? AND claimed_by = ?`).run(Date.now(), scheduleId, ownerId);
|
|
380
|
+
return "released";
|
|
381
|
+
}).immediate();
|
|
382
|
+
}
|
|
383
|
+
function completeSelfSchedule(scheduleId, ownerId) {
|
|
384
|
+
const result = ownerId ? db.query("DELETE FROM runtime_self_schedules WHERE id = ? AND claimed_by = ?").run(scheduleId, ownerId) : db.query("DELETE FROM runtime_self_schedules WHERE id = ?").run(scheduleId);
|
|
385
|
+
return Number(result.changes ?? 0) > 0;
|
|
386
|
+
}
|
|
387
|
+
function deleteSelfSchedulesForTopic(topicId) {
|
|
388
|
+
const result = db.query("DELETE FROM runtime_self_schedules WHERE topic_id = ?").run(topicId);
|
|
389
|
+
return Number(result.changes ?? 0);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// ../../packages/core/src/topics/lifecycle.ts
|
|
393
|
+
var DELETE_TURN_WAIT_MS = 5000;
|
|
394
|
+
async function abortAndWaitForTopic(topicId) {
|
|
395
|
+
interSessionQueue.drop(topicId);
|
|
396
|
+
cancelIdleArchiveForTopic(topicId);
|
|
397
|
+
const aborted = abortRoom(topicId);
|
|
398
|
+
if (!aborted)
|
|
399
|
+
return true;
|
|
400
|
+
logger.info({ topicId }, "deleteTopicCascade: aborted in-flight turn");
|
|
401
|
+
const deadline = Date.now() + DELETE_TURN_WAIT_MS;
|
|
402
|
+
while ((getRoomQuery(topicId) || getRuntimeTurnLease(topicId)) && Date.now() < deadline) {
|
|
403
|
+
await delay(50);
|
|
404
|
+
}
|
|
405
|
+
if (getRoomQuery(topicId) || getRuntimeTurnLease(topicId)) {
|
|
406
|
+
logger.warn({ topicId, timeoutMs: DELETE_TURN_WAIT_MS }, "deleteTopicCascade: timed out waiting for in-flight turn cleanup");
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
return true;
|
|
410
|
+
}
|
|
411
|
+
function currentSessionRef(topic, sessionId) {
|
|
412
|
+
return topic.agent && sessionId ? [{ agent: topic.agent, sessionId }] : [];
|
|
413
|
+
}
|
|
414
|
+
async function cleanupParticipantResources(topic, userIds, sessionId, cwd) {
|
|
415
|
+
for (const [index, participantUserId] of userIds.entries()) {
|
|
416
|
+
try {
|
|
417
|
+
await purgeTopicLogs({
|
|
418
|
+
userId: participantUserId,
|
|
419
|
+
topicName: topic.title,
|
|
420
|
+
cwd,
|
|
421
|
+
extraSessions: index === 0 ? currentSessionRef(topic, sessionId) : []
|
|
422
|
+
});
|
|
423
|
+
} catch (err) {
|
|
424
|
+
logger.warn({ err, topicId: topic.id, userId: participantUserId }, "deleteTopicCascade: participant rollout cleanup failed");
|
|
425
|
+
}
|
|
426
|
+
cleanupSessionInboxFiles(participantUserId, topic.id, topic.title);
|
|
427
|
+
clearQueryState(participantUserId, topic.title);
|
|
428
|
+
clearQueryUsageAlert(participantUserId, topic.id);
|
|
429
|
+
deletePendingAsksForTopic({ userId: participantUserId, topicName: topic.title });
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
class TopicArchiveRequiredError extends Error {
|
|
434
|
+
code = "TOPIC_ARCHIVE_FAILED";
|
|
435
|
+
topicId;
|
|
436
|
+
constructor(topicId, cause) {
|
|
437
|
+
super("Topic archive failed; deletion was blocked to avoid losing conversation history.");
|
|
438
|
+
this.name = "TopicArchiveRequiredError";
|
|
439
|
+
this.topicId = topicId;
|
|
440
|
+
this.cause = cause;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
class TopicTurnStillActiveError extends Error {
|
|
445
|
+
code = "TOPIC_TURN_STILL_ACTIVE";
|
|
446
|
+
topicId;
|
|
447
|
+
constructor(topicId) {
|
|
448
|
+
super("The active turn did not stop in time; deletion was blocked. Use force-delete explicitly.");
|
|
449
|
+
this.name = "TopicTurnStillActiveError";
|
|
450
|
+
this.topicId = topicId;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
async function deleteTopicCascade(topic, userId, options = {}) {
|
|
454
|
+
await deleteTopicCascadeImpl(topic, userId, options, new Set);
|
|
455
|
+
}
|
|
456
|
+
async function deleteTopicCascadeImpl(topic, userId, options, deletingAncestorIds) {
|
|
457
|
+
const topicId = topic.id;
|
|
458
|
+
if (topicId === GENERAL_TOPIC_ID || topic.kind === "manager" && !options.allowManager) {
|
|
459
|
+
logger.warn({ topicId }, "deleteTopicCascade: refused to delete essential topic");
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
const deletingTopicIds = new Set(deletingAncestorIds);
|
|
463
|
+
deletingTopicIds.add(topicId);
|
|
464
|
+
const force = options.force === true;
|
|
465
|
+
const maintenance = beginRuntimeTopicMaintenance(topicId);
|
|
466
|
+
if (!maintenance)
|
|
467
|
+
throw new Error("Topic maintenance is already in progress.");
|
|
468
|
+
let deleted = false;
|
|
469
|
+
const cancelledQueryIds = cancelRuntimeUserTurnRequestsBeforeEpoch(topicId, maintenance.epoch);
|
|
470
|
+
for (const queryId of cancelledQueryIds) {
|
|
471
|
+
WsHub.get().broadcastAborted(topicId, queryId, "stopped");
|
|
472
|
+
}
|
|
473
|
+
try {
|
|
474
|
+
const turnStopped = await abortAndWaitForTopic(topicId);
|
|
475
|
+
if (!turnStopped && !force)
|
|
476
|
+
throw new TopicTurnStillActiveError(topicId);
|
|
477
|
+
if (!maintenance.isOwned())
|
|
478
|
+
throw new Error("Topic maintenance ownership was lost.");
|
|
479
|
+
let archived = null;
|
|
480
|
+
if (!options.skipArchive) {
|
|
481
|
+
try {
|
|
482
|
+
archived = archiveTopicMessages(topicId, topic.title);
|
|
483
|
+
} catch (err) {
|
|
484
|
+
if (!force) {
|
|
485
|
+
logger.warn({ err, topicId }, "deleteTopicCascade: archive failed - blocking delete unless force=true");
|
|
486
|
+
throw new TopicArchiveRequiredError(topicId, err);
|
|
487
|
+
}
|
|
488
|
+
logger.warn({ err, topicId }, "deleteTopicCascade: archive failed but force=true - continuing with hard delete");
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
if (archived) {
|
|
492
|
+
try {
|
|
493
|
+
const memoryTopic = getTopicMemoryOrigin(topicId) ?? topic;
|
|
494
|
+
runArchiverTurn({
|
|
495
|
+
userId,
|
|
496
|
+
...memoryTopic.id !== topicId && !deletingTopicIds.has(memoryTopic.id) ? { topicId: memoryTopic.id } : {},
|
|
497
|
+
topicTitle: memoryTopic.title,
|
|
498
|
+
archivePath: archived.path,
|
|
499
|
+
messageCount: archived.messageCount
|
|
500
|
+
});
|
|
501
|
+
} catch (err) {
|
|
502
|
+
logger.warn({ err, topicId, archive: archived.path }, "deleteTopicCascade: background archiver launch failed - raw archive preserved");
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
cancelSubagentWatchForDeletedTopic(topicId);
|
|
506
|
+
const spawnedChildren = listTopics().filter((candidate) => candidate.parentTopicId === topicId && candidate.isSubagent && !deletingTopicIds.has(candidate.id));
|
|
507
|
+
for (const child of spawnedChildren) {
|
|
508
|
+
await deleteTopicCascadeImpl(child, userId, options, deletingTopicIds);
|
|
509
|
+
}
|
|
510
|
+
const sessionId = getTopicSessionId(topicId);
|
|
511
|
+
const cwd = resolveTopicWorkspaceDir(topicId);
|
|
512
|
+
const participantUserIds = Array.from(new Set([userId, ...topic.participants.map((participant) => participant.userId)]));
|
|
513
|
+
killBgBash(userId, topicId);
|
|
514
|
+
const browserProfileOwner = getBrowserProfileOwner(topicId, userId);
|
|
515
|
+
const browserProfile = getTopicBrowserProfile(topicId);
|
|
516
|
+
try {
|
|
517
|
+
await closeBrowserOwnerTabs(browserProfileOwner, browserProfile, `topic:${topicId}`);
|
|
518
|
+
} catch (err) {
|
|
519
|
+
logger.warn({ err, topicId }, "deleteTopicCascade: browser owner cleanup failed");
|
|
520
|
+
}
|
|
521
|
+
deleteTopicProfileDir(userId, topicId);
|
|
522
|
+
cancelAskCallbacksForTopic(topicId);
|
|
523
|
+
deleteSelfSchedulesForTopic(topicId);
|
|
524
|
+
await cleanupParticipantResources(topic, participantUserIds, sessionId, cwd);
|
|
525
|
+
try {
|
|
526
|
+
await deleteFilesForTopic(topicId);
|
|
527
|
+
} catch (err) {
|
|
528
|
+
logger.warn({ err, topicId }, "deleteTopicCascade: host file cleanup failed");
|
|
529
|
+
}
|
|
530
|
+
try {
|
|
531
|
+
rmSync(cwd, { recursive: true, force: true });
|
|
532
|
+
} catch (err) {
|
|
533
|
+
logger.warn({ err, topicId, cwd }, "deleteTopicCascade: workspace cleanup failed");
|
|
534
|
+
}
|
|
535
|
+
deleteTopicVisuals(topicId);
|
|
536
|
+
deleteTopicArchiveState(topicId);
|
|
537
|
+
deleteMessagesForTopic(topicId);
|
|
538
|
+
deleteApiTopicConfig(topicId);
|
|
539
|
+
deleteTopicBrief(topicId);
|
|
540
|
+
const reparentedChildIds = reparentTopicChildren(topicId, topic.parentTopicId ?? null);
|
|
541
|
+
const rowDeleted = deleteTopic(topicId, { allowManager: options.allowManager });
|
|
542
|
+
if (!rowDeleted) {
|
|
543
|
+
logger.warn({ topicId }, "deleteTopicCascade: topic row was not deleted");
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
deleted = true;
|
|
547
|
+
WsHub.get().broadcastTopicDeleted(topicId);
|
|
548
|
+
for (const childId of reparentedChildIds)
|
|
549
|
+
WsHub.get().broadcastTopicUpdated(childId);
|
|
550
|
+
} finally {
|
|
551
|
+
if (deleted) {
|
|
552
|
+
for (const queryId of cancelRuntimeUserTurnRequests(topicId)) {
|
|
553
|
+
WsHub.get().broadcastAborted(topicId, queryId, "stopped");
|
|
554
|
+
}
|
|
555
|
+
maintenance.finish({ deleteState: true });
|
|
556
|
+
} else {
|
|
557
|
+
maintenance.finish();
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
export {
|
|
562
|
+
deleteTopicCascade,
|
|
563
|
+
TopicTurnStillActiveError,
|
|
564
|
+
TopicArchiveRequiredError
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
export { createPendingSelfSchedule, getPendingSelfSchedule, updatePendingSelfSchedule, cancelPendingSelfSchedule, claimNextDueSelfSchedule, markSelfScheduleRunning, heartbeatSelfScheduleClaim, releaseSelfScheduleClaim, completeSelfSchedule, cleanupTopicRollouts, rotateTopicLogs, purgeTopicLogs, sessionInboxPath, topicIdFromSessionInboxFileName, topicIdFromScheduledSessionInboxFileName, TopicArchiveRequiredError, TopicTurnStillActiveError, deleteTopicCascade };
|
|
568
|
+
|
|
569
|
+
//# debugId=CD7A49E8BD3277ED64756E2164756E21
|