@bd7pil/ocrc 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +34 -0
- package/README.md +330 -0
- package/dist/cli/host-backends.js +216 -0
- package/dist/cli/host-backends.js.map +1 -0
- package/dist/cli/host.js +185 -0
- package/dist/cli/host.js.map +1 -0
- package/dist/cli/index.js +67 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.js +68 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/install.js +220 -0
- package/dist/cli/install.js.map +1 -0
- package/dist/cli/pair.js +11 -0
- package/dist/cli/pair.js.map +1 -0
- package/dist/cli/uninstall.js +75 -0
- package/dist/cli/uninstall.js.map +1 -0
- package/dist/connectivity/auth/cf-access.js +20 -0
- package/dist/connectivity/auth/cf-access.js.map +1 -0
- package/dist/connectivity/auth/index.js +2 -0
- package/dist/connectivity/auth/index.js.map +1 -0
- package/dist/connectivity/auth/select.js +19 -0
- package/dist/connectivity/auth/select.js.map +1 -0
- package/dist/connectivity/auth/token.js +157 -0
- package/dist/connectivity/auth/token.js.map +1 -0
- package/dist/connectivity/exposure/cloudflared.js +77 -0
- package/dist/connectivity/exposure/cloudflared.js.map +1 -0
- package/dist/connectivity/exposure/index.js +2 -0
- package/dist/connectivity/exposure/index.js.map +1 -0
- package/dist/connectivity/exposure/providers.js +49 -0
- package/dist/connectivity/exposure/providers.js.map +1 -0
- package/dist/connectivity/pairing.js +29 -0
- package/dist/connectivity/pairing.js.map +1 -0
- package/dist/core/agent/acp-backend.js +539 -0
- package/dist/core/agent/acp-backend.js.map +1 -0
- package/dist/core/agent/acp-connect.js +92 -0
- package/dist/core/agent/acp-connect.js.map +1 -0
- package/dist/core/agent/acp-normalizer.js +81 -0
- package/dist/core/agent/acp-normalizer.js.map +1 -0
- package/dist/core/agent/acp-replay.js +89 -0
- package/dist/core/agent/acp-replay.js.map +1 -0
- package/dist/core/agent/acp-store.js +129 -0
- package/dist/core/agent/acp-store.js.map +1 -0
- package/dist/core/agent/backend.js +2 -0
- package/dist/core/agent/backend.js.map +1 -0
- package/dist/core/agent/diff-util.js +70 -0
- package/dist/core/agent/diff-util.js.map +1 -0
- package/dist/core/agent/event.js +12 -0
- package/dist/core/agent/event.js.map +1 -0
- package/dist/core/agent/opencode-backend.js +598 -0
- package/dist/core/agent/opencode-backend.js.map +1 -0
- package/dist/core/agent/opencode-normalizer.js +69 -0
- package/dist/core/agent/opencode-normalizer.js.map +1 -0
- package/dist/core/agent/registry.js +55 -0
- package/dist/core/agent/registry.js.map +1 -0
- package/dist/core/agent/v2-backend.js +176 -0
- package/dist/core/agent/v2-backend.js.map +1 -0
- package/dist/core/card-bus.js +74 -0
- package/dist/core/card-bus.js.map +1 -0
- package/dist/core/channels.js +95 -0
- package/dist/core/channels.js.map +1 -0
- package/dist/core/history.js +91 -0
- package/dist/core/history.js.map +1 -0
- package/dist/core/list-files.js +50 -0
- package/dist/core/list-files.js.map +1 -0
- package/dist/core/opencode-events.js +29 -0
- package/dist/core/opencode-events.js.map +1 -0
- package/dist/core/primary-election.js +91 -0
- package/dist/core/primary-election.js.map +1 -0
- package/dist/core/push.js +152 -0
- package/dist/core/push.js.map +1 -0
- package/dist/core/relay.js +400 -0
- package/dist/core/relay.js.map +1 -0
- package/dist/core/scheduler.js +150 -0
- package/dist/core/scheduler.js.map +1 -0
- package/dist/core/state.js +222 -0
- package/dist/core/state.js.map +1 -0
- package/dist/core/stream-accumulator.js +76 -0
- package/dist/core/stream-accumulator.js.map +1 -0
- package/dist/core/structured-card.js +2 -0
- package/dist/core/structured-card.js.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/opencode/global-events.js +57 -0
- package/dist/opencode/global-events.js.map +1 -0
- package/dist/opencode/list-sessions.js +122 -0
- package/dist/opencode/list-sessions.js.map +1 -0
- package/dist/opencode/submit.js +39 -0
- package/dist/opencode/submit.js.map +1 -0
- package/dist/opencode/workspaces.js +51 -0
- package/dist/opencode/workspaces.js.map +1 -0
- package/dist/plugin/config.js +128 -0
- package/dist/plugin/config.js.map +1 -0
- package/dist/plugin/control-plane.js +133 -0
- package/dist/plugin/control-plane.js.map +1 -0
- package/dist/plugin/entry.js +409 -0
- package/dist/plugin/entry.js.map +1 -0
- package/dist/plugin/v2/event-map.js +193 -0
- package/dist/plugin/v2/event-map.js.map +1 -0
- package/dist/plugin/v2/types.js +15 -0
- package/dist/plugin/v2/types.js.map +1 -0
- package/dist/transport/interface.js +2 -0
- package/dist/transport/interface.js.map +1 -0
- package/dist/transport/telegram/esc.js +9 -0
- package/dist/transport/telegram/esc.js.map +1 -0
- package/dist/transport/telegram/handlers/info-commands.js +101 -0
- package/dist/transport/telegram/handlers/info-commands.js.map +1 -0
- package/dist/transport/telegram/handlers.js +1348 -0
- package/dist/transport/telegram/handlers.js.map +1 -0
- package/dist/transport/telegram/i18n/en.js +538 -0
- package/dist/transport/telegram/i18n/en.js.map +1 -0
- package/dist/transport/telegram/i18n/index.js +83 -0
- package/dist/transport/telegram/i18n/index.js.map +1 -0
- package/dist/transport/telegram/i18n/zh.js +538 -0
- package/dist/transport/telegram/i18n/zh.js.map +1 -0
- package/dist/transport/telegram/index.js +792 -0
- package/dist/transport/telegram/index.js.map +1 -0
- package/dist/transport/telegram/main-keyboard.js +36 -0
- package/dist/transport/telegram/main-keyboard.js.map +1 -0
- package/dist/transport/telegram/managers/abort-suppression-manager.js +33 -0
- package/dist/transport/telegram/managers/abort-suppression-manager.js.map +1 -0
- package/dist/transport/telegram/managers/external-input-suppression-manager.js +51 -0
- package/dist/transport/telegram/managers/external-input-suppression-manager.js.map +1 -0
- package/dist/transport/telegram/managers/interaction-manager.js +254 -0
- package/dist/transport/telegram/managers/interaction-manager.js.map +1 -0
- package/dist/transport/telegram/managers/permission-manager.js +242 -0
- package/dist/transport/telegram/managers/permission-manager.js.map +1 -0
- package/dist/transport/telegram/managers/question-manager.js +191 -0
- package/dist/transport/telegram/managers/question-manager.js.map +1 -0
- package/dist/transport/telegram/managers/rename-manager.js +56 -0
- package/dist/transport/telegram/managers/rename-manager.js.map +1 -0
- package/dist/transport/telegram/menus.js +77 -0
- package/dist/transport/telegram/menus.js.map +1 -0
- package/dist/transport/telegram/permission-flow.js +156 -0
- package/dist/transport/telegram/permission-flow.js.map +1 -0
- package/dist/transport/telegram/question-flow.js +224 -0
- package/dist/transport/telegram/question-flow.js.map +1 -0
- package/dist/transport/telegram/render/block-parser.js +365 -0
- package/dist/transport/telegram/render/block-parser.js.map +1 -0
- package/dist/transport/telegram/render/block-plain-text.js +87 -0
- package/dist/transport/telegram/render/block-plain-text.js.map +1 -0
- package/dist/transport/telegram/render/block-splitter.js +152 -0
- package/dist/transport/telegram/render/block-splitter.js.map +1 -0
- package/dist/transport/telegram/render/chunker.js +71 -0
- package/dist/transport/telegram/render/chunker.js.map +1 -0
- package/dist/transport/telegram/render/limits.js +13 -0
- package/dist/transport/telegram/render/limits.js.map +1 -0
- package/dist/transport/telegram/render/markdown-normalizer.js +102 -0
- package/dist/transport/telegram/render/markdown-normalizer.js.map +1 -0
- package/dist/transport/telegram/render/markdown-to-telegram-v2.js +116 -0
- package/dist/transport/telegram/render/markdown-to-telegram-v2.js.map +1 -0
- package/dist/transport/telegram/render/part-signature.js +14 -0
- package/dist/transport/telegram/render/part-signature.js.map +1 -0
- package/dist/transport/telegram/render/pipeline.js +23 -0
- package/dist/transport/telegram/render/pipeline.js.map +1 -0
- package/dist/transport/telegram/render/rich-blocks.js +311 -0
- package/dist/transport/telegram/render/rich-blocks.js.map +1 -0
- package/dist/transport/telegram/render/text-splitter.js +64 -0
- package/dist/transport/telegram/render/text-splitter.js.map +1 -0
- package/dist/transport/telegram/render/types.js +2 -0
- package/dist/transport/telegram/render/types.js.map +1 -0
- package/dist/transport/telegram/renderer.js +305 -0
- package/dist/transport/telegram/renderer.js.map +1 -0
- package/dist/transport/telegram/streaming/duration-formatter.js +68 -0
- package/dist/transport/telegram/streaming/duration-formatter.js.map +1 -0
- package/dist/transport/telegram/streaming/finalize-assistant-response.js +37 -0
- package/dist/transport/telegram/streaming/finalize-assistant-response.js.map +1 -0
- package/dist/transport/telegram/streaming/response-streamer.js +400 -0
- package/dist/transport/telegram/streaming/response-streamer.js.map +1 -0
- package/dist/transport/telegram/streaming/running-tool-tracker.js +150 -0
- package/dist/transport/telegram/streaming/running-tool-tracker.js.map +1 -0
- package/dist/transport/telegram/streaming/stream-throttle.js +57 -0
- package/dist/transport/telegram/streaming/stream-throttle.js.map +1 -0
- package/dist/transport/telegram/streaming/tool-call-streamer.js +390 -0
- package/dist/transport/telegram/streaming/tool-call-streamer.js.map +1 -0
- package/dist/transport/telegram/streaming-render.js +182 -0
- package/dist/transport/telegram/streaming-render.js.map +1 -0
- package/dist/transport/telegram/types/interaction.js +2 -0
- package/dist/transport/telegram/types/interaction.js.map +1 -0
- package/dist/transport/telegram/types/model.js +25 -0
- package/dist/transport/telegram/types/model.js.map +1 -0
- package/dist/transport/telegram/types/permission.js +2 -0
- package/dist/transport/telegram/types/permission.js.map +1 -0
- package/dist/transport/telegram/types/question.js +2 -0
- package/dist/transport/telegram/types/question.js.map +1 -0
- package/dist/transport/telegram/types/rename.js +2 -0
- package/dist/transport/telegram/types/rename.js.map +1 -0
- package/dist/transport/telegram/types/scheduled-task.js +23 -0
- package/dist/transport/telegram/types/scheduled-task.js.map +1 -0
- package/dist/transport/telegram/types/session.js +2 -0
- package/dist/transport/telegram/types/session.js.map +1 -0
- package/dist/transport/telegram/ui.js +28 -0
- package/dist/transport/telegram/ui.js.map +1 -0
- package/dist/transport/web/index.js +148 -0
- package/dist/transport/web/index.js.map +1 -0
- package/dist/transport/web/middleware/cf-access.js +104 -0
- package/dist/transport/web/middleware/cf-access.js.map +1 -0
- package/dist/transport/web/opencode-config.js +15 -0
- package/dist/transport/web/opencode-config.js.map +1 -0
- package/dist/transport/web/routes/abort.js +12 -0
- package/dist/transport/web/routes/abort.js.map +1 -0
- package/dist/transport/web/routes/approval.js +16 -0
- package/dist/transport/web/routes/approval.js.map +1 -0
- package/dist/transport/web/routes/catalog.js +11 -0
- package/dist/transport/web/routes/catalog.js.map +1 -0
- package/dist/transport/web/routes/channels.js +53 -0
- package/dist/transport/web/routes/channels.js.map +1 -0
- package/dist/transport/web/routes/commands.js +15 -0
- package/dist/transport/web/routes/commands.js.map +1 -0
- package/dist/transport/web/routes/context.js +17 -0
- package/dist/transport/web/routes/context.js.map +1 -0
- package/dist/transport/web/routes/controls.js +34 -0
- package/dist/transport/web/routes/controls.js.map +1 -0
- package/dist/transport/web/routes/create-session.js +21 -0
- package/dist/transport/web/routes/create-session.js.map +1 -0
- package/dist/transport/web/routes/diff.js +7 -0
- package/dist/transport/web/routes/diff.js.map +1 -0
- package/dist/transport/web/routes/files.js +22 -0
- package/dist/transport/web/routes/files.js.map +1 -0
- package/dist/transport/web/routes/logs.js +9 -0
- package/dist/transport/web/routes/logs.js.map +1 -0
- package/dist/transport/web/routes/m8.js +69 -0
- package/dist/transport/web/routes/m8.js.map +1 -0
- package/dist/transport/web/routes/mcp.js +7 -0
- package/dist/transport/web/routes/mcp.js.map +1 -0
- package/dist/transport/web/routes/message.js +32 -0
- package/dist/transport/web/routes/message.js.map +1 -0
- package/dist/transport/web/routes/overrides.js +20 -0
- package/dist/transport/web/routes/overrides.js.map +1 -0
- package/dist/transport/web/routes/question.js +32 -0
- package/dist/transport/web/routes/question.js.map +1 -0
- package/dist/transport/web/routes/rename.js +12 -0
- package/dist/transport/web/routes/rename.js.map +1 -0
- package/dist/transport/web/routes/schedules.js +28 -0
- package/dist/transport/web/routes/schedules.js.map +1 -0
- package/dist/transport/web/routes/session.js +20 -0
- package/dist/transport/web/routes/session.js.map +1 -0
- package/dist/transport/web/routes/sessions.js +25 -0
- package/dist/transport/web/routes/sessions.js.map +1 -0
- package/dist/transport/web/routes/subagents.js +11 -0
- package/dist/transport/web/routes/subagents.js.map +1 -0
- package/dist/transport/web/routes/suggestions.js +7 -0
- package/dist/transport/web/routes/suggestions.js.map +1 -0
- package/dist/transport/web/routes/todo.js +7 -0
- package/dist/transport/web/routes/todo.js.map +1 -0
- package/dist/transport/web/routes/version.js +5 -0
- package/dist/transport/web/routes/version.js.map +1 -0
- package/dist/transport/web/routes/workspaces.js +7 -0
- package/dist/transport/web/routes/workspaces.js.map +1 -0
- package/dist/transport/web/server.js +111 -0
- package/dist/transport/web/server.js.map +1 -0
- package/dist/transport/web/session-summary.js +46 -0
- package/dist/transport/web/session-summary.js.map +1 -0
- package/dist/transport/web/ws-hub.js +83 -0
- package/dist/transport/web/ws-hub.js.map +1 -0
- package/dist/utils/logger.js +105 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/markdown.js +129 -0
- package/dist/utils/markdown.js.map +1 -0
- package/dist/utils/paths.js +18 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/version.js +44 -0
- package/dist/utils/version.js.map +1 -0
- package/package.json +91 -0
- package/web/dist/_app/env.js +1 -0
- package/web/dist/_app/immutable/assets/0.DxN3RsuG.css +1 -0
- package/web/dist/_app/immutable/assets/2.BNuGfmZP.css +1 -0
- package/web/dist/_app/immutable/assets/3.CTDprntu.css +1 -0
- package/web/dist/_app/immutable/chunks/BUpwHpMJ.js +1 -0
- package/web/dist/_app/immutable/chunks/BjY4dxcB.js +2 -0
- package/web/dist/_app/immutable/chunks/C2FuqD3s.js +1 -0
- package/web/dist/_app/immutable/chunks/CUHGq08X.js +2 -0
- package/web/dist/_app/immutable/chunks/CWj6FrbW.js +1 -0
- package/web/dist/_app/immutable/chunks/ClvoqtGj.js +1 -0
- package/web/dist/_app/immutable/chunks/DIEDQ_hk.js +1 -0
- package/web/dist/_app/immutable/entry/app.BoRpcVMj.js +2 -0
- package/web/dist/_app/immutable/entry/start.Cj-PQNTq.js +1 -0
- package/web/dist/_app/immutable/nodes/0.y9YEms5p.js +3 -0
- package/web/dist/_app/immutable/nodes/1.CPhhiRM2.js +1 -0
- package/web/dist/_app/immutable/nodes/2.B_c84Mc9.js +1 -0
- package/web/dist/_app/immutable/nodes/3.ClTd0J3D.js +64 -0
- package/web/dist/_app/version.json +1 -0
- package/web/dist/apple-touch-icon.png +0 -0
- package/web/dist/favicon.png +0 -0
- package/web/dist/favicon.svg +17 -0
- package/web/dist/icon-192.png +0 -0
- package/web/dist/icon-512-maskable.png +0 -0
- package/web/dist/icon-512.png +0 -0
- package/web/dist/index.html +73 -0
- package/web/dist/manifest.webmanifest +28 -0
- package/web/dist/service-worker.js +1 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, renameSync, existsSync, mkdirSync } from 'node:fs';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
import { createLogger } from '../utils/logger.js';
|
|
4
|
+
const log = createLogger('state');
|
|
5
|
+
/** Minimum length for a short display suffix to be resolved via endsWith. */
|
|
6
|
+
const MIN_SUFFIX_LEN = 6;
|
|
7
|
+
export function createFileBackedState(path) {
|
|
8
|
+
let cache = load(path);
|
|
9
|
+
let writeQueued;
|
|
10
|
+
let pending;
|
|
11
|
+
let resolvePending;
|
|
12
|
+
const aborts = new Map();
|
|
13
|
+
// In-memory only — suggestions are ephemeral UI sugar, never state of record.
|
|
14
|
+
const sessionSuggestions = new Map();
|
|
15
|
+
const sessionCosts = new Map();
|
|
16
|
+
const assistantDeliveredAt = new Map();
|
|
17
|
+
const normalizeSessionId = (sessionId) => {
|
|
18
|
+
// Guard: undefined throws on startsWith, and '' matches EVERY key via
|
|
19
|
+
// endsWith('') — pass both through untouched.
|
|
20
|
+
if (!sessionId)
|
|
21
|
+
return sessionId;
|
|
22
|
+
// Full IDs (opencode ses_*, ACP session_*, raw UUIDs) pass through.
|
|
23
|
+
if (sessionId.startsWith('ses_') || sessionId.startsWith('session_') || /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(sessionId)) {
|
|
24
|
+
return sessionId;
|
|
25
|
+
}
|
|
26
|
+
// Short display suffix — too short to disambiguate reliably.
|
|
27
|
+
if (sessionId.length < MIN_SUFFIX_LEN)
|
|
28
|
+
return sessionId;
|
|
29
|
+
// Scan sessionBackends for full keys ending in the suffix.
|
|
30
|
+
const backs = cache.sessionBackends ?? {};
|
|
31
|
+
const matches = Object.keys(backs).filter((key) => key.endsWith(sessionId));
|
|
32
|
+
if (matches.length === 1)
|
|
33
|
+
return matches[0];
|
|
34
|
+
// Ambiguous — fail loud instead of silently picking an arbitrary session.
|
|
35
|
+
if (matches.length > 1) {
|
|
36
|
+
log.warn(`normalizeSessionId: suffix "${sessionId}" matches ${matches.length} sessions; leaving unresolved`);
|
|
37
|
+
}
|
|
38
|
+
// No match found; return input as-is (graceful fallback).
|
|
39
|
+
return sessionId;
|
|
40
|
+
};
|
|
41
|
+
// Debounced atomic write. All set() calls within the debounce window share a
|
|
42
|
+
// single pending promise that resolves once the write lands — earlier code
|
|
43
|
+
// created a fresh promise per call and cleared the prior timer, so every
|
|
44
|
+
// promise but the last never resolved (flush()'s await could hang).
|
|
45
|
+
function persist() {
|
|
46
|
+
if (!pending) {
|
|
47
|
+
pending = new Promise((res) => { resolvePending = res; });
|
|
48
|
+
}
|
|
49
|
+
if (writeQueued)
|
|
50
|
+
clearTimeout(writeQueued);
|
|
51
|
+
writeQueued = setTimeout(() => {
|
|
52
|
+
try {
|
|
53
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
54
|
+
const tmp = `${path}.tmp`;
|
|
55
|
+
writeFileSync(tmp, JSON.stringify(cache, null, 2));
|
|
56
|
+
renameSync(tmp, path);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
log.warn('failed to persist state', err.message);
|
|
60
|
+
}
|
|
61
|
+
writeQueued = undefined;
|
|
62
|
+
const res = resolvePending;
|
|
63
|
+
pending = undefined;
|
|
64
|
+
resolvePending = undefined;
|
|
65
|
+
res?.();
|
|
66
|
+
}, 100);
|
|
67
|
+
return pending;
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
getLastSessionId: () => cache.lastSessionId,
|
|
71
|
+
setLastSessionId: (id) => {
|
|
72
|
+
if (id === undefined)
|
|
73
|
+
delete cache.lastSessionId;
|
|
74
|
+
else
|
|
75
|
+
cache.lastSessionId = id;
|
|
76
|
+
void persist();
|
|
77
|
+
},
|
|
78
|
+
getPinnedSessionId: () => cache.pinnedSessionId,
|
|
79
|
+
setPinnedSessionId: (id) => {
|
|
80
|
+
if (id === undefined)
|
|
81
|
+
delete cache.pinnedSessionId;
|
|
82
|
+
else
|
|
83
|
+
cache.pinnedSessionId = id;
|
|
84
|
+
void persist();
|
|
85
|
+
},
|
|
86
|
+
getNextAgent: () => cache.nextAgent,
|
|
87
|
+
setNextAgent: (name) => {
|
|
88
|
+
if (name === undefined)
|
|
89
|
+
delete cache.nextAgent;
|
|
90
|
+
else
|
|
91
|
+
cache.nextAgent = name;
|
|
92
|
+
void persist();
|
|
93
|
+
},
|
|
94
|
+
getNextModel: () => cache.nextModel,
|
|
95
|
+
setNextModel: (m) => {
|
|
96
|
+
if (m === undefined)
|
|
97
|
+
delete cache.nextModel;
|
|
98
|
+
else
|
|
99
|
+
cache.nextModel = m;
|
|
100
|
+
void persist();
|
|
101
|
+
},
|
|
102
|
+
getTuiSelectedSession: () => cache.tuiSelectedSession,
|
|
103
|
+
setTuiSelectedSession: (id) => {
|
|
104
|
+
if (id === undefined)
|
|
105
|
+
delete cache.tuiSelectedSession;
|
|
106
|
+
else
|
|
107
|
+
cache.tuiSelectedSession = id;
|
|
108
|
+
void persist();
|
|
109
|
+
},
|
|
110
|
+
getCurrentAgent: () => cache.currentAgent,
|
|
111
|
+
setCurrentAgent: (name) => {
|
|
112
|
+
if (name === undefined)
|
|
113
|
+
delete cache.currentAgent;
|
|
114
|
+
else
|
|
115
|
+
cache.currentAgent = name;
|
|
116
|
+
void persist();
|
|
117
|
+
},
|
|
118
|
+
getActiveWorkspace: () => cache.activeWorkspace,
|
|
119
|
+
setActiveWorkspace: (dir) => {
|
|
120
|
+
if (dir === undefined)
|
|
121
|
+
delete cache.activeWorkspace;
|
|
122
|
+
else
|
|
123
|
+
cache.activeWorkspace = dir;
|
|
124
|
+
void persist();
|
|
125
|
+
},
|
|
126
|
+
getActiveAbort: (sid) => aborts.get(sid),
|
|
127
|
+
setActiveAbort: (sid, ac) => {
|
|
128
|
+
if (ac === undefined)
|
|
129
|
+
aborts.delete(sid);
|
|
130
|
+
else
|
|
131
|
+
aborts.set(sid, ac);
|
|
132
|
+
},
|
|
133
|
+
hasActiveGeneration: (sessionId) => {
|
|
134
|
+
if (sessionId === undefined)
|
|
135
|
+
return aborts.size > 0;
|
|
136
|
+
const normalized = normalizeSessionId(sessionId);
|
|
137
|
+
return aborts.has(normalized) || (normalized !== sessionId && aborts.has(sessionId));
|
|
138
|
+
},
|
|
139
|
+
markAssistantDelivered: (sid) => { assistantDeliveredAt.set(sid, Date.now()); },
|
|
140
|
+
getAssistantDeliveredAt: (sid) => assistantDeliveredAt.get(sid),
|
|
141
|
+
dropSession: (sid) => {
|
|
142
|
+
aborts.get(sid)?.abort();
|
|
143
|
+
aborts.delete(sid);
|
|
144
|
+
sessionCosts.delete(sid);
|
|
145
|
+
assistantDeliveredAt.delete(sid);
|
|
146
|
+
let dirty = false;
|
|
147
|
+
if (cache.lastSessionId === sid) {
|
|
148
|
+
delete cache.lastSessionId;
|
|
149
|
+
dirty = true;
|
|
150
|
+
}
|
|
151
|
+
if (cache.pinnedSessionId === sid) {
|
|
152
|
+
delete cache.pinnedSessionId;
|
|
153
|
+
dirty = true;
|
|
154
|
+
}
|
|
155
|
+
if (cache.tuiSelectedSession === sid) {
|
|
156
|
+
delete cache.tuiSelectedSession;
|
|
157
|
+
dirty = true;
|
|
158
|
+
}
|
|
159
|
+
if (cache.sessionBackends?.[sid]) {
|
|
160
|
+
delete cache.sessionBackends[sid];
|
|
161
|
+
dirty = true;
|
|
162
|
+
}
|
|
163
|
+
if (dirty)
|
|
164
|
+
void persist();
|
|
165
|
+
},
|
|
166
|
+
getSessionCost: (sid) => sessionCosts.get(sid),
|
|
167
|
+
setSessionCost: (sid, cost) => {
|
|
168
|
+
if (cost === undefined)
|
|
169
|
+
sessionCosts.delete(sid);
|
|
170
|
+
else
|
|
171
|
+
sessionCosts.set(sid, cost);
|
|
172
|
+
},
|
|
173
|
+
getSessionBackend: (sid) => cache.sessionBackends?.[sid],
|
|
174
|
+
setSessionBackend: (sid, backendId) => {
|
|
175
|
+
if (backendId === undefined) {
|
|
176
|
+
if (cache.sessionBackends)
|
|
177
|
+
delete cache.sessionBackends[sid];
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
;
|
|
181
|
+
(cache.sessionBackends ??= {})[sid] = backendId;
|
|
182
|
+
}
|
|
183
|
+
void persist();
|
|
184
|
+
},
|
|
185
|
+
getActiveBackend: () => cache.activeBackend,
|
|
186
|
+
setActiveBackend: (backendId) => {
|
|
187
|
+
if (backendId === undefined)
|
|
188
|
+
delete cache.activeBackend;
|
|
189
|
+
else
|
|
190
|
+
cache.activeBackend = backendId;
|
|
191
|
+
void persist();
|
|
192
|
+
},
|
|
193
|
+
normalizeSessionId,
|
|
194
|
+
getSessionSuggestions: (sid) => {
|
|
195
|
+
const e = sessionSuggestions.get(sid);
|
|
196
|
+
if (!e)
|
|
197
|
+
return undefined;
|
|
198
|
+
if (Date.now() - e.at > 10 * 60_000) {
|
|
199
|
+
sessionSuggestions.delete(sid);
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
return e.items;
|
|
203
|
+
},
|
|
204
|
+
setSessionSuggestions: (sid, items) => {
|
|
205
|
+
sessionSuggestions.set(sid, { items, at: Date.now() });
|
|
206
|
+
},
|
|
207
|
+
flush: async () => persist(),
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function load(path) {
|
|
211
|
+
if (!existsSync(path))
|
|
212
|
+
return {};
|
|
213
|
+
try {
|
|
214
|
+
const raw = readFileSync(path, 'utf-8');
|
|
215
|
+
return JSON.parse(raw);
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
log.warn(`state file malformed, treating as empty: ${err.message}`);
|
|
219
|
+
return {};
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/core/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export function createStreamAccumulator() {
|
|
2
|
+
const blocks = [];
|
|
3
|
+
const order = [];
|
|
4
|
+
const index = new Map();
|
|
5
|
+
function upsert(block, partId) {
|
|
6
|
+
const existing = index.get(partId);
|
|
7
|
+
if (existing !== undefined) {
|
|
8
|
+
blocks[existing] = block;
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
order.push(partId);
|
|
12
|
+
index.set(partId, blocks.length);
|
|
13
|
+
blocks.push(block);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function toContentBlocks() {
|
|
17
|
+
const result = [];
|
|
18
|
+
for (const b of blocks) {
|
|
19
|
+
if (b.type === 'text')
|
|
20
|
+
result.push({ type: 'text', text: b.text });
|
|
21
|
+
else if (b.type === 'tool')
|
|
22
|
+
result.push({ type: 'tool', tool: b.tool ?? 'unknown', args: b.args, status: b.status });
|
|
23
|
+
// reasoning is internal-only, excluded from public output
|
|
24
|
+
}
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
update(parts) {
|
|
29
|
+
for (const p of parts) {
|
|
30
|
+
const partId = p.id;
|
|
31
|
+
if (p.type === 'text' && typeof p.text === 'string') {
|
|
32
|
+
// Skip empty text overwrites — SDK sends text="" on some part.updated
|
|
33
|
+
// events, which would erase previously accumulated text for this partId.
|
|
34
|
+
if (p.text === '' && index.has(partId) && blocks[index.get(partId)].type === 'text' && blocks[index.get(partId)].text !== '') {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
upsert({ type: 'text', partId, text: p.text, args: '', status: 'done' }, partId);
|
|
38
|
+
}
|
|
39
|
+
if (p.type === 'tool' && typeof p.tool === 'string') {
|
|
40
|
+
upsert({
|
|
41
|
+
type: 'tool',
|
|
42
|
+
partId,
|
|
43
|
+
tool: p.tool,
|
|
44
|
+
text: '',
|
|
45
|
+
args: p.args ?? '',
|
|
46
|
+
status: p.status ?? 'running',
|
|
47
|
+
}, partId);
|
|
48
|
+
}
|
|
49
|
+
if (p.type === 'reasoning' && typeof p.text === 'string') {
|
|
50
|
+
upsert({ type: 'reasoning', partId, text: p.text, args: '', status: 'done' }, partId);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return toContentBlocks();
|
|
54
|
+
},
|
|
55
|
+
finalize() {
|
|
56
|
+
return toContentBlocks();
|
|
57
|
+
},
|
|
58
|
+
getText() {
|
|
59
|
+
let out = '';
|
|
60
|
+
for (const b of blocks) {
|
|
61
|
+
if (b.type === 'text')
|
|
62
|
+
out += b.text;
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
},
|
|
66
|
+
getTools() {
|
|
67
|
+
return blocks.filter(b => b.type === 'tool').map(b => ({ type: 'tool', tool: b.tool ?? 'unknown', args: b.args, status: b.status }));
|
|
68
|
+
},
|
|
69
|
+
reset() {
|
|
70
|
+
blocks.length = 0;
|
|
71
|
+
order.length = 0;
|
|
72
|
+
index.clear();
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=stream-accumulator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-accumulator.js","sourceRoot":"","sources":["../../src/core/stream-accumulator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structured-card.js","sourceRoot":"","sources":["../../src/core/structured-card.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { createLogger } from '../utils/logger.js';
|
|
2
|
+
const log = createLogger('global-events');
|
|
3
|
+
/**
|
|
4
|
+
* Subscribe to opencode's cross-workspace event stream (`GET /global/event`)
|
|
5
|
+
* and forward each event. opencode loads the plugin per-workspace, so a
|
|
6
|
+
* per-instance `event` hook only sees its own directory — the global stream is
|
|
7
|
+
* the only way for the PRIMARY instance to observe every workspace. Reconnects
|
|
8
|
+
* with exponential backoff (capped 30s) until stop() is called.
|
|
9
|
+
*/
|
|
10
|
+
export function startGlobalEvents(opts) {
|
|
11
|
+
let stopped = false;
|
|
12
|
+
const retryBase = opts.retryBaseMs ?? 1000;
|
|
13
|
+
async function run() {
|
|
14
|
+
let attempt = 0;
|
|
15
|
+
while (!stopped) {
|
|
16
|
+
try {
|
|
17
|
+
const res = await opts.client.global.event();
|
|
18
|
+
attempt = 0;
|
|
19
|
+
log.info('global event stream connected');
|
|
20
|
+
const stream = res.stream;
|
|
21
|
+
// Note: stop() sets `stopped` but cannot interrupt a for-await that is
|
|
22
|
+
// blocked awaiting the next item — the flag is only checked between
|
|
23
|
+
// items. We deliberately don't force-close the generator via
|
|
24
|
+
// stream.return?.() (would need manual iteration); the SSE connection is
|
|
25
|
+
// released when the server ends it or on the next reconnect. Acceptable
|
|
26
|
+
// for opencode's event stream, which delivers events steadily.
|
|
27
|
+
for await (const item of stream) {
|
|
28
|
+
if (stopped)
|
|
29
|
+
break;
|
|
30
|
+
if (item?.payload) {
|
|
31
|
+
try {
|
|
32
|
+
opts.onEvent(item.payload, item.directory);
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
log.warn(`onEvent threw (ignored): ${err.message}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (stopped)
|
|
40
|
+
break;
|
|
41
|
+
log.warn('global event stream ended, reconnecting');
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
if (stopped)
|
|
45
|
+
break;
|
|
46
|
+
log.warn(`global event stream error: ${err.message}`);
|
|
47
|
+
}
|
|
48
|
+
const delay = Math.min(retryBase * 2 ** attempt, 30000);
|
|
49
|
+
attempt++;
|
|
50
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
51
|
+
}
|
|
52
|
+
log.info('global event stream stopped');
|
|
53
|
+
}
|
|
54
|
+
void run();
|
|
55
|
+
return { stop() { stopped = true; } };
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=global-events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"global-events.js","sourceRoot":"","sources":["../../src/opencode/global-events.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,MAAM,GAAG,GAAG,YAAY,CAAC,eAAe,CAAC,CAAA;AAiBzC;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAyB;IACzD,IAAI,OAAO,GAAG,KAAK,CAAA;IACnB,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,IAAI,IAAI,CAAA;IAE1C,KAAK,UAAU,GAAG;QAChB,IAAI,OAAO,GAAG,CAAC,CAAA;QACf,OAAO,CAAC,OAAO,EAAE,CAAC;YAChB,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAA;gBAC5C,OAAO,GAAG,CAAC,CAAA;gBACX,GAAG,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAA;gBACzC,MAAM,MAAM,GAAG,GAAG,CAAC,MAAiE,CAAA;gBACpF,uEAAuE;gBACvE,oEAAoE;gBACpE,6DAA6D;gBAC7D,yEAAyE;gBACzE,wEAAwE;gBACxE,+DAA+D;gBAC/D,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;oBAChC,IAAI,OAAO;wBAAE,MAAK;oBAClB,IAAI,IAAI,EAAE,OAAO,EAAE,CAAC;wBAClB,IAAI,CAAC;4BACH,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;wBAC5C,CAAC;wBAAC,OAAO,GAAG,EAAE,CAAC;4BACb,GAAG,CAAC,IAAI,CAAC,4BAA6B,GAAa,CAAC,OAAO,EAAE,CAAC,CAAA;wBAChE,CAAC;oBACH,CAAC;gBACH,CAAC;gBACD,IAAI,OAAO;oBAAE,MAAK;gBAClB,GAAG,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAA;YACrD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,OAAO;oBAAE,MAAK;gBAClB,GAAG,CAAC,IAAI,CAAC,8BAA+B,GAAa,CAAC,OAAO,EAAE,CAAC,CAAA;YAClE,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,IAAI,OAAO,EAAE,KAAK,CAAC,CAAA;YACvD,OAAO,EAAE,CAAA;YACT,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAA;QAChD,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAA;IACzC,CAAC;IAED,KAAK,GAAG,EAAE,CAAA;IACV,OAAO,EAAE,IAAI,KAAK,OAAO,GAAG,IAAI,CAAA,CAAC,CAAC,EAAE,CAAA;AACtC,CAAC"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
/** Resolve opencode's global sqlite db path (XDG-aware). */
|
|
5
|
+
function opencodeDbPath() {
|
|
6
|
+
const dataHome = process.env.XDG_DATA_HOME || join(homedir(), '.local', 'share');
|
|
7
|
+
return join(dataHome, 'opencode', 'opencode.db');
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Read the distinct working directories opencode has stored sessions in,
|
|
11
|
+
* straight from its sqlite storage.
|
|
12
|
+
*
|
|
13
|
+
* Why we must: opencode's HTTP API only lists sessions by EXACT `directory`
|
|
14
|
+
* match (`GET /session?directory=…`) and exposes no "list all" route. Sessions
|
|
15
|
+
* started in ad-hoc folders (anything that isn't its own git project, e.g.
|
|
16
|
+
* `~/AgentWorks`) all live under the synthetic "global" project whose worktree
|
|
17
|
+
* is "/". Querying "/" matches zero sessions, so those directories are
|
|
18
|
+
* otherwise undiscoverable — the only place that knows them is the db itself.
|
|
19
|
+
*
|
|
20
|
+
* Best-effort and cross-runtime: prefers Bun's `bun:sqlite` (opencode's own
|
|
21
|
+
* runtime / the plugin hub) and falls back to Node's built-in `node:sqlite`
|
|
22
|
+
* (the standalone host runs under Node ≥22.5). Returns [] only if neither sqlite
|
|
23
|
+
* binding nor the db is available, so callers degrade to project-worktree listing.
|
|
24
|
+
*/
|
|
25
|
+
const DB_DIRS_SQL = 'SELECT DISTINCT directory FROM session WHERE directory IS NOT NULL';
|
|
26
|
+
export async function directoriesFromDb() {
|
|
27
|
+
const dbPath = opencodeDbPath();
|
|
28
|
+
if (!existsSync(dbPath))
|
|
29
|
+
return [];
|
|
30
|
+
// 1) Bun's sqlite (db.query(sql).all(); { readonly }).
|
|
31
|
+
try {
|
|
32
|
+
const specifier = 'bun:sqlite'; // variable specifier hides this Bun builtin from tsc/node
|
|
33
|
+
const { Database } = (await import(specifier));
|
|
34
|
+
const db = new Database(dbPath, { readonly: true });
|
|
35
|
+
try {
|
|
36
|
+
const rows = db.query(DB_DIRS_SQL).all();
|
|
37
|
+
return rows.map((r) => r.directory).filter(Boolean);
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
db.close();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
/* not running under Bun — fall through to node:sqlite */
|
|
45
|
+
}
|
|
46
|
+
// 2) Node's built-in sqlite (db.prepare(sql).all(); { readOnly }).
|
|
47
|
+
try {
|
|
48
|
+
const specifier = 'node:sqlite';
|
|
49
|
+
const { DatabaseSync } = (await import(specifier));
|
|
50
|
+
const db = new DatabaseSync(dbPath, { readOnly: true });
|
|
51
|
+
try {
|
|
52
|
+
const rows = db.prepare(DB_DIRS_SQL).all();
|
|
53
|
+
return rows.map((r) => r.directory).filter(Boolean);
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
db.close();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* List sessions across ALL opencode projects/directories.
|
|
65
|
+
*
|
|
66
|
+
* opencode scopes sessions per directory: `client.session.list()` returns only
|
|
67
|
+
* the sessions for the server's current directory, and `session.list({
|
|
68
|
+
* directory })` matches that directory EXACTLY. A session started in another
|
|
69
|
+
* folder's TUI is therefore invisible unless we query its exact directory. We
|
|
70
|
+
* collect directories from two sources and aggregate:
|
|
71
|
+
* 1. project worktrees (covers real git projects)
|
|
72
|
+
* 2. the db's distinct session directories (covers the "global" project's
|
|
73
|
+
* ad-hoc dirs, which the API can't enumerate)
|
|
74
|
+
* The global project's worktree "/" is skipped — it matches nothing.
|
|
75
|
+
*
|
|
76
|
+
* Best-effort: if project enumeration fails we still return the default listing.
|
|
77
|
+
*/
|
|
78
|
+
export async function listAllSessions(client, opts = {}) {
|
|
79
|
+
const extraDirectories = opts.extraDirectories ?? directoriesFromDb;
|
|
80
|
+
const byId = new Map();
|
|
81
|
+
const add = (arr) => {
|
|
82
|
+
for (const s of arr ?? [])
|
|
83
|
+
if (s?.id)
|
|
84
|
+
byId.set(s.id, s);
|
|
85
|
+
};
|
|
86
|
+
// Always include the default (current-directory) listing.
|
|
87
|
+
try {
|
|
88
|
+
add((await client.session.list()).data);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
/* ignore */
|
|
92
|
+
}
|
|
93
|
+
// Build the set of directories to query.
|
|
94
|
+
const dirs = new Set();
|
|
95
|
+
try {
|
|
96
|
+
const projects = ((await client.project.list()).data ?? []);
|
|
97
|
+
for (const p of projects)
|
|
98
|
+
if (p.worktree && p.worktree !== '/')
|
|
99
|
+
dirs.add(p.worktree);
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
/* ignore — fall back to whatever the default listing returned */
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
for (const d of await extraDirectories())
|
|
106
|
+
if (d && d !== '/')
|
|
107
|
+
dirs.add(d);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
/* ignore — db discovery is best-effort */
|
|
111
|
+
}
|
|
112
|
+
if (dirs.size > 0) {
|
|
113
|
+
const lists = await Promise.all([...dirs].map((directory) => client.session
|
|
114
|
+
.list({ query: { directory } })
|
|
115
|
+
.then((r) => r.data)
|
|
116
|
+
.catch(() => [])));
|
|
117
|
+
for (const l of lists)
|
|
118
|
+
add(l);
|
|
119
|
+
}
|
|
120
|
+
return [...byId.values()];
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=list-sessions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-sessions.js","sourceRoot":"","sources":["../../src/opencode/list-sessions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Sessions created for internal side calls (e.g. Tier2 suggestion generation).
|
|
2
|
+
// Their turns stream through the same event hook as real sessions; transports
|
|
3
|
+
// and the relay check isEphemeralSession() so the mirrored output never leaks
|
|
4
|
+
// into user-facing feeds.
|
|
5
|
+
const ephemeralSessions = new Set();
|
|
6
|
+
export function markEphemeralSession(id) {
|
|
7
|
+
ephemeralSessions.add(id);
|
|
8
|
+
}
|
|
9
|
+
export function isEphemeralSession(id) {
|
|
10
|
+
return ephemeralSessions.has(id);
|
|
11
|
+
}
|
|
12
|
+
/** Build one prompt body from text + optional image attachments (pure; unit-tested). */
|
|
13
|
+
export function buildPromptBody(opts) {
|
|
14
|
+
const parts = [{ type: 'text', text: opts.text }];
|
|
15
|
+
for (const img of opts.images ?? []) {
|
|
16
|
+
// opencode FilePartInput: {type:'file', mime, filename?, url} — a data URL
|
|
17
|
+
// carries the base64 payload inline (the plugin has no public file host).
|
|
18
|
+
const ext = img.mimeType.split('/')[1] ?? 'bin';
|
|
19
|
+
parts.push({
|
|
20
|
+
type: 'file',
|
|
21
|
+
mime: img.mimeType,
|
|
22
|
+
filename: img.filename ?? `image.${ext}`,
|
|
23
|
+
url: `data:${img.mimeType};base64,${img.data}`,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
parts,
|
|
28
|
+
...(opts.agent ? { agent: opts.agent } : {}),
|
|
29
|
+
...(opts.model ? { model: opts.model } : {}),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export async function submitPrompt(client, opts) {
|
|
33
|
+
await client.session.promptAsync({
|
|
34
|
+
path: { id: opts.sessionId },
|
|
35
|
+
body: buildPromptBody(opts),
|
|
36
|
+
signal: opts.signal,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=submit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submit.js","sourceRoot":"","sources":["../../src/opencode/submit.ts"],"names":[],"mappings":"AAeA,+EAA+E;AAC/E,8EAA8E;AAC9E,8EAA8E;AAC9E,0BAA0B;AAC1B,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAU,CAAA;AAE3C,MAAM,UAAU,oBAAoB,CAAC,EAAU;IAC7C,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;AAC3B,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,EAAU;IAC3C,OAAO,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;AAClC,CAAC;AAWD,wFAAwF;AACxF,MAAM,UAAU,eAAe,CAAC,IAK/B;IACC,MAAM,KAAK,GAAmC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;IACjF,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;QACpC,2EAA2E;QAC3E,0EAA0E;QAC1E,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAA;QAC/C,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,GAAG,CAAC,QAAQ;YAClB,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,SAAS,GAAG,EAAE;YACxC,GAAG,EAAE,QAAQ,GAAG,CAAC,QAAQ,WAAW,GAAG,CAAC,IAAI,EAAE;SAC/C,CAAC,CAAA;IACJ,CAAC;IACD,OAAO;QACL,KAAK;QACL,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5C,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/B,CAAA;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAsB,EACtB,IAAmB;IAEnB,MAAM,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC;QAC/B,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE;QAC5B,IAAI,EAAE,eAAe,CAAC,IAAI,CAAC;QAC3B,MAAM,EAAE,IAAI,CAAC,MAAM;KACpB,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { basename } from 'node:path';
|
|
2
|
+
import { directoriesFromDb, listAllSessions } from './list-sessions.js';
|
|
3
|
+
/** Normalize a directory path by stripping a single trailing slash (except for root). */
|
|
4
|
+
function normalizeDir(d) {
|
|
5
|
+
return d.endsWith('/') && d !== '/' ? d.replace(/\/+$/, '') : d;
|
|
6
|
+
}
|
|
7
|
+
/** Pure: merge directories (project worktrees + db + sessions), attach per-dir
|
|
8
|
+
* session stats, name by basename, drop the synthetic "/" worktree, sort by
|
|
9
|
+
* most recent activity (desc). */
|
|
10
|
+
export function buildWorkspaces(input) {
|
|
11
|
+
const dirs = new Set();
|
|
12
|
+
for (const d of input.worktrees) {
|
|
13
|
+
const n = normalizeDir(d);
|
|
14
|
+
if (n && n !== '/')
|
|
15
|
+
dirs.add(n);
|
|
16
|
+
}
|
|
17
|
+
for (const d of input.dbDirs) {
|
|
18
|
+
const n = normalizeDir(d);
|
|
19
|
+
if (n && n !== '/')
|
|
20
|
+
dirs.add(n);
|
|
21
|
+
}
|
|
22
|
+
for (const s of input.sessions) {
|
|
23
|
+
const n = s.directory ? normalizeDir(s.directory) : '';
|
|
24
|
+
if (n && n !== '/')
|
|
25
|
+
dirs.add(n);
|
|
26
|
+
}
|
|
27
|
+
const out = [];
|
|
28
|
+
for (const dir of dirs) {
|
|
29
|
+
const sessions = input.sessions.filter((s) => s.directory && normalizeDir(s.directory) === dir);
|
|
30
|
+
const lastActiveAt = sessions.reduce((max, s) => Math.max(max, s.time?.updated ?? s.time?.created ?? 0), 0);
|
|
31
|
+
out.push({ directory: dir, name: basename(dir) || dir, sessionCount: sessions.length, lastActiveAt });
|
|
32
|
+
}
|
|
33
|
+
out.sort((a, b) => b.lastActiveAt - a.lastActiveAt);
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
/** Enumerate workspaces from the live opencode client. */
|
|
37
|
+
export async function listWorkspaces(client) {
|
|
38
|
+
// project worktrees are fetched explicitly so workspaces with zero sessions still appear.
|
|
39
|
+
let worktrees = [];
|
|
40
|
+
try {
|
|
41
|
+
const projects = ((await client.project.list()).data ?? []);
|
|
42
|
+
worktrees = projects.map((p) => p.worktree).filter((w) => !!w);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
/* ignore */
|
|
46
|
+
}
|
|
47
|
+
const dbDirs = await directoriesFromDb().catch(() => []);
|
|
48
|
+
const sessions = (await listAllSessions(client, { extraDirectories: async () => dbDirs }).catch(() => []));
|
|
49
|
+
return buildWorkspaces({ worktrees, dbDirs, sessions });
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=workspaces.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspaces.js","sourceRoot":"","sources":["../../src/opencode/workspaces.ts"],"names":[],"mappings":"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"}
|