kimaki 0.26.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-model.e2e.test.js +250 -164
- package/dist/anthropic-account-identity.js +9 -1
- package/dist/anthropic-auth-plugin.js +10 -13
- package/dist/anthropic-auth-plugin.test.js +17 -0
- package/dist/anthropic-auth-state.js +1 -0
- package/dist/bash-tool-schema-plugin.js +32 -0
- package/dist/bash-tool-schema-plugin.test.js +49 -0
- package/dist/bin.js +73 -19
- package/dist/cli-commands/maintenance.js +46 -7
- package/dist/cli-commands/project.js +11 -27
- package/dist/cli-commands/send.js +30 -1
- package/dist/cli-commands/session.js +322 -90
- package/dist/cli-commands/task.js +34 -15
- package/dist/cli-parsing.test.js +83 -4
- package/dist/cli-runner.js +44 -8
- package/dist/cli-runner.test.js +27 -0
- package/dist/cli-send-thread.e2e.test.js +9 -9
- package/dist/cli.js +32 -0
- package/dist/commands/abort.js +5 -1
- package/dist/commands/action-buttons.js +2 -1
- package/dist/commands/add-project.js +4 -7
- package/dist/commands/agent.js +164 -32
- package/dist/commands/ask-question.js +23 -33
- package/dist/commands/ask-question.test.js +43 -1
- package/dist/commands/btw.js +28 -6
- package/dist/commands/file-upload.js +2 -1
- package/dist/commands/fork-subagent.js +2 -4
- package/dist/commands/fork.js +4 -4
- package/dist/commands/last-sessions.js +17 -10
- package/dist/commands/login.js +6 -0
- package/dist/commands/merge-worktree.js +47 -14
- package/dist/commands/model-variant.js +8 -1
- package/dist/commands/model.js +16 -9
- package/dist/commands/multioauth.js +1 -0
- package/dist/commands/new-worktree.js +170 -102
- package/dist/commands/queue.js +3 -2
- package/dist/commands/resume.js +4 -4
- package/dist/commands/session.js +78 -63
- package/dist/commands/user-command.js +6 -8
- package/dist/commands/worktrees.js +5 -13
- package/dist/config.js +16 -1
- package/dist/cpu-profiler.js +211 -0
- package/dist/cpu-profiler.test.js +160 -0
- package/dist/database.js +152 -3
- package/dist/db.js +33 -0
- package/dist/db.test.js +267 -1
- package/dist/default-channel-provisioning.test.js +148 -0
- package/dist/discord-bot.js +517 -488
- package/dist/discord-command-registration.js +25 -10
- package/dist/discord-command-registration.test.js +17 -0
- package/dist/discord-utils.js +97 -5
- package/dist/discord-utils.test.js +151 -1
- package/dist/errors.js +10 -0
- package/dist/exec-async.js +17 -5
- package/dist/external-directory-permissions.e2e.test.js +11 -7
- package/dist/external-directory-project-deny.e2e.test.js +5 -3
- package/dist/external-opencode-sync.js +94 -17
- package/dist/external-opencode-sync.test.js +206 -0
- package/dist/extract-sdk-error-message.test.js +13 -0
- package/dist/file-edit-log.js +197 -0
- package/dist/file-edit-log.test.js +258 -0
- package/dist/format-tables.js +52 -0
- package/dist/format-tables.test.js +93 -0
- package/dist/gateway-proxy-reconnect.e2e.test.js +28 -8
- package/dist/gateway-proxy.e2e.test.js +18 -18
- package/dist/git-worktree-core.js +182 -17
- package/dist/interaction-handler.js +416 -398
- package/dist/ipc-tools-plugin.js +68 -3
- package/dist/kimaki-opencode-plugin-loading.e2e.test.js +122 -58
- package/dist/kimaki-opencode-plugin.js +9 -3
- package/dist/kimaki-workspace-adaptor.js +33 -10
- package/dist/logger.js +11 -1
- package/dist/markdown.js +3 -1
- package/dist/markdown.test.js +11 -3
- package/dist/message-formatting.js +181 -51
- package/dist/message-formatting.test.js +529 -22
- package/dist/message-preprocessing.js +105 -1
- package/dist/oauth-rotation-shared.js +10 -0
- package/dist/openai-auth-plugin.js +1 -0
- package/dist/openai-auth-state.js +1 -0
- package/dist/opencode-command.js +28 -0
- package/dist/opencode-command.test.js +109 -1
- package/dist/opencode-interrupt-plugin.js +4 -0
- package/dist/opencode-interrupt-plugin.test.js +24 -0
- package/dist/opencode.js +82 -15
- package/dist/project-add.test.js +62 -0
- package/dist/question-abort-clears-dropdown.e2e.test.js +89 -0
- package/dist/question-abort-retry-text-before-dropdown.e2e.test.js +150 -0
- package/dist/question-text-before-dropdown.e2e.test.js +52 -0
- package/dist/queue-advanced-abort.e2e.test.js +8 -10
- package/dist/queue-advanced-action-buttons.e2e.test.js +8 -8
- package/dist/queue-advanced-e2e-setup.js +78 -5
- package/dist/queue-advanced-footer.e2e.test.js +60 -269
- package/dist/queue-advanced-model-switch.e2e.test.js +9 -11
- package/dist/queue-advanced-permissions-typing.e2e.test.js +15 -15
- package/dist/queue-advanced-question.e2e.test.js +32 -27
- package/dist/queue-advanced-typing-interrupt.e2e.test.js +10 -12
- package/dist/queue-advanced-typing.e2e.test.js +7 -9
- package/dist/queue-delete-message.e2e.test.js +3 -3
- package/dist/queue-drain-after-interactive-ui.e2e.test.js +5 -5
- package/dist/queue-interrupt-drain.e2e.test.js +122 -12
- package/dist/queue-question-select-drain.e2e.test.js +34 -132
- package/dist/runtime-lifecycle.e2e.test.js +21 -51
- package/dist/schema.js +35 -1
- package/dist/session-handler/event-stream-state.js +391 -50
- package/dist/session-handler/event-stream-state.test.js +736 -8
- package/dist/session-handler/model-utils.js +172 -5
- package/dist/session-handler/model-utils.test.js +445 -0
- package/dist/session-handler/opencode-session-event-log.js +30 -1
- package/dist/session-handler/thread-ingress.test.js +41 -0
- package/dist/session-handler/thread-runtime-state.js +2 -0
- package/dist/session-handler/thread-session-runtime-summary.test.js +121 -0
- package/dist/session-handler/thread-session-runtime.js +574 -299
- package/dist/session-search.js +123 -4
- package/dist/session-search.test.js +248 -1
- package/dist/session-sleep.test.js +224 -0
- package/dist/session-title-rename.test.js +37 -39
- package/dist/sleep.e2e.test.js +494 -0
- package/dist/startup-time.e2e.test.js +2 -1
- package/dist/store.js +3 -0
- package/dist/system-message.js +102 -16
- package/dist/system-message.test.js +192 -15
- package/dist/task-runner.js +96 -5
- package/dist/task-schedule.js +87 -1
- package/dist/task-schedule.test.js +149 -1
- package/dist/test-utils.js +17 -9
- package/dist/thinking-utils.js +10 -0
- package/dist/thinking-utils.test.js +35 -0
- package/dist/thread-message-queue.e2e.test.js +65 -213
- package/dist/undo-redo.e2e.test.js +17 -9
- package/dist/voice-attachment.js +23 -1
- package/dist/voice-handler.js +21 -4
- package/dist/voice-message.e2e.test.js +144 -30
- package/dist/voice-routing-input.e2e.test.js +195 -0
- package/dist/voice-routing-question.e2e.test.js +125 -0
- package/dist/voice.js +28 -8
- package/dist/voice.test.js +96 -30
- package/dist/worktree-clone-isolation.e2e.test.js +188 -0
- package/dist/worktree-lifecycle.e2e.test.js +55 -36
- package/dist/worktrees.js +226 -443
- package/dist/worktrees.test.js +435 -58
- package/dist/xai-auth-plugin.js +1 -0
- package/dist/xai-auth-state.js +1 -0
- package/package.json +8 -6
- package/skills/bump-holocron-consumers/SKILL.md +137 -0
- package/skills/critique/SKILL.md +4 -4
- package/skills/errore/SKILL.md +60 -218
- package/skills/goke/SKILL.md +150 -10
- package/skills/holocron/SKILL.md +154 -17
- package/skills/npm-package/SKILL.md +55 -35
- package/skills/profano/SKILL.md +17 -2
- package/skills/spiceflow/SKILL.md +39 -3
- package/skills/strada/SKILL.md +39 -0
- package/skills/zele/SKILL.md +19 -0
- package/src/agent-model.e2e.test.ts +287 -186
- package/src/anthropic-account-identity.ts +20 -1
- package/src/anthropic-auth-plugin.test.ts +19 -0
- package/src/anthropic-auth-plugin.ts +12 -16
- package/src/anthropic-auth-state.ts +1 -0
- package/src/bash-tool-schema-plugin.test.ts +55 -0
- package/src/bash-tool-schema-plugin.ts +46 -0
- package/src/bin.ts +78 -26
- package/src/cli-commands/maintenance.ts +59 -13
- package/src/cli-commands/project.ts +14 -35
- package/src/cli-commands/send.ts +31 -1
- package/src/cli-commands/session.ts +374 -114
- package/src/cli-commands/task.ts +34 -15
- package/src/cli-parsing.test.ts +103 -4
- package/src/cli-runner.test.ts +49 -0
- package/src/cli-runner.ts +44 -7
- package/src/cli-send-thread.e2e.test.ts +9 -11
- package/src/cli.ts +53 -0
- package/src/commands/abort.ts +6 -1
- package/src/commands/action-buttons.ts +2 -1
- package/src/commands/add-project.ts +4 -8
- package/src/commands/agent.ts +205 -29
- package/src/commands/ask-question.test.ts +48 -1
- package/src/commands/ask-question.ts +23 -33
- package/src/commands/btw.ts +40 -5
- package/src/commands/file-upload.ts +2 -1
- package/src/commands/fork-subagent.ts +2 -3
- package/src/commands/fork.ts +4 -3
- package/src/commands/last-sessions.ts +10 -4
- package/src/commands/login.ts +6 -0
- package/src/commands/merge-worktree.ts +54 -16
- package/src/commands/model-variant.ts +9 -1
- package/src/commands/model.ts +20 -9
- package/src/commands/multioauth.ts +1 -0
- package/src/commands/new-worktree.ts +138 -55
- package/src/commands/queue.ts +3 -2
- package/src/commands/resume.ts +4 -3
- package/src/commands/session.ts +94 -70
- package/src/commands/user-command.ts +6 -6
- package/src/commands/worktrees.ts +5 -12
- package/src/config.ts +18 -1
- package/src/cpu-profiler.test.ts +183 -0
- package/src/cpu-profiler.ts +293 -0
- package/src/database.ts +235 -3
- package/src/db.test.ts +293 -0
- package/src/db.ts +38 -0
- package/src/default-channel-provisioning.test.ts +155 -0
- package/src/discord-bot.ts +78 -36
- package/src/discord-command-registration.test.ts +20 -0
- package/src/discord-command-registration.ts +42 -12
- package/src/discord-utils.test.ts +176 -0
- package/src/discord-utils.ts +152 -7
- package/src/errors.ts +12 -0
- package/src/exec-async.ts +20 -11
- package/src/external-directory-permissions.e2e.test.ts +11 -7
- package/src/external-directory-project-deny.e2e.test.ts +5 -3
- package/src/external-opencode-sync.test.ts +248 -0
- package/src/external-opencode-sync.ts +122 -19
- package/src/extract-sdk-error-message.test.ts +18 -0
- package/src/file-edit-log.test.ts +287 -0
- package/src/file-edit-log.ts +283 -0
- package/src/format-tables.test.ts +101 -0
- package/src/format-tables.ts +75 -0
- package/src/gateway-proxy-reconnect.e2e.test.ts +38 -8
- package/src/gateway-proxy.e2e.test.ts +18 -17
- package/src/git-worktree-core.ts +247 -20
- package/src/interaction-handler.ts +36 -13
- package/src/ipc-tools-plugin.ts +82 -5
- package/src/kimaki-opencode-plugin-loading.e2e.test.ts +188 -97
- package/src/kimaki-opencode-plugin.ts +9 -3
- package/src/kimaki-workspace-adaptor.ts +40 -11
- package/src/logger.ts +14 -4
- package/src/markdown.test.ts +13 -3
- package/src/markdown.ts +4 -1
- package/src/message-formatting.test.ts +672 -25
- package/src/message-formatting.ts +242 -53
- package/src/message-preprocessing.ts +116 -1
- package/src/oauth-rotation-shared.ts +10 -0
- package/src/openai-auth-plugin.ts +1 -0
- package/src/openai-auth-state.ts +1 -0
- package/src/opencode-command.test.ts +140 -0
- package/src/opencode-command.ts +38 -0
- package/src/opencode-interrupt-plugin.test.ts +32 -0
- package/src/opencode-interrupt-plugin.ts +3 -0
- package/src/opencode.ts +115 -15
- package/src/project-add.test.ts +80 -0
- package/src/question-abort-clears-dropdown.e2e.test.ts +109 -0
- package/src/question-abort-retry-text-before-dropdown.e2e.test.ts +172 -0
- package/src/question-text-before-dropdown.e2e.test.ts +67 -0
- package/src/queue-advanced-abort.e2e.test.ts +8 -9
- package/src/queue-advanced-action-buttons.e2e.test.ts +8 -8
- package/src/queue-advanced-e2e-setup.ts +83 -4
- package/src/queue-advanced-footer.e2e.test.ts +67 -315
- package/src/queue-advanced-model-switch.e2e.test.ts +9 -10
- package/src/queue-advanced-permissions-typing.e2e.test.ts +15 -15
- package/src/queue-advanced-question.e2e.test.ts +36 -30
- package/src/queue-advanced-typing-interrupt.e2e.test.ts +11 -11
- package/src/queue-advanced-typing.e2e.test.ts +8 -8
- package/src/queue-delete-message.e2e.test.ts +3 -3
- package/src/queue-drain-after-interactive-ui.e2e.test.ts +5 -5
- package/src/queue-interrupt-drain.e2e.test.ts +133 -12
- package/src/queue-question-select-drain.e2e.test.ts +36 -161
- package/src/runtime-lifecycle.e2e.test.ts +21 -54
- package/src/schema.sql +15 -2
- package/src/schema.ts +37 -1
- package/src/session-handler/event-stream-state.test.ts +790 -7
- package/src/session-handler/event-stream-state.ts +568 -53
- package/src/session-handler/model-utils.test.ts +537 -0
- package/src/session-handler/model-utils.ts +281 -5
- package/src/session-handler/opencode-session-event-log.ts +31 -1
- package/src/session-handler/thread-ingress.test.ts +54 -0
- package/src/session-handler/thread-runtime-state.ts +3 -0
- package/src/session-handler/thread-session-runtime-summary.test.ts +169 -0
- package/src/session-handler/thread-session-runtime.ts +712 -358
- package/src/session-search.test.ts +281 -0
- package/src/session-search.ts +241 -7
- package/src/session-sleep.test.ts +294 -0
- package/src/session-title-rename.test.ts +54 -48
- package/src/sleep.e2e.test.ts +565 -0
- package/src/startup-time.e2e.test.ts +5 -1
- package/src/store.ts +22 -0
- package/src/system-message.test.ts +226 -15
- package/src/system-message.ts +130 -16
- package/src/task-runner.ts +138 -3
- package/src/task-schedule.test.ts +170 -0
- package/src/task-schedule.ts +141 -1
- package/src/test-utils.ts +21 -10
- package/src/thinking-utils.test.ts +46 -0
- package/src/thinking-utils.ts +21 -0
- package/src/thread-message-queue.e2e.test.ts +65 -245
- package/src/undo-redo.e2e.test.ts +17 -9
- package/src/voice-attachment.ts +29 -1
- package/src/voice-handler.ts +23 -4
- package/src/voice-message.e2e.test.ts +149 -29
- package/src/voice-routing-input.e2e.test.ts +203 -0
- package/src/voice-routing-question.e2e.test.ts +131 -0
- package/src/voice.test.ts +107 -29
- package/src/voice.ts +34 -6
- package/src/worktree-clone-isolation.e2e.test.ts +213 -0
- package/src/worktree-lifecycle.e2e.test.ts +55 -35
- package/src/worktrees.test.ts +505 -64
- package/src/worktrees.ts +257 -603
- package/src/xai-auth-plugin.ts +1 -0
- package/src/xai-auth-state.ts +1 -0
- package/dist/message-finish-field.e2e.test.js +0 -169
- package/dist/subagent-rate-limit-plugin.js +0 -184
- package/src/message-finish-field.e2e.test.ts +0 -196
- package/src/subagent-rate-limit-plugin.ts +0 -228
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Session inspection and archival terminal commands.
|
|
2
2
|
import { goke } from 'goke'
|
|
3
3
|
import { z } from 'zod'
|
|
4
|
+
import dedent from 'string-dedent'
|
|
4
5
|
import { note } from '@clack/prompts'
|
|
5
6
|
import YAML from 'yaml'
|
|
6
7
|
import * as errore from 'errore'
|
|
@@ -12,15 +13,18 @@ import { fileURLToPath } from 'node:url'
|
|
|
12
13
|
import { spawn, execSync } from 'node:child_process'
|
|
13
14
|
import { createLogger, LogPrefix, initLogFile } from '../logger.js'
|
|
14
15
|
import { createDiscordClient, initDatabase, getChannelDirectory, initializeOpencodeForDirectory, createProjectChannels } from '../discord-bot.js'
|
|
15
|
-
import { getBotTokenWithMode, getThreadSession, getThreadIdBySessionId, getSessionEventSnapshot, getDb, createScheduledTask, listScheduledTasks, cancelScheduledTask, getScheduledTask, updateScheduledTask, getSessionStartSourcesBySessionIds, deleteChannelDirectoryById, findChannelsByDirectory, getThreadWorktreeOrWorkspace } from '../database.js'
|
|
16
|
+
import { getBotTokenWithMode, getThreadSession, getThreadIdBySessionId, getSessionEventSnapshot, getDb, createScheduledTask, listScheduledTasks, cancelScheduledTask, getScheduledTask, updateScheduledTask, getSessionStartSourcesBySessionIds, deleteChannelDirectoryById, findChannelsByDirectory, getThreadWorktreeOrWorkspace, getAllTextChannelDirectories } from '../database.js'
|
|
16
17
|
import { ShareMarkdown } from '../markdown.js'
|
|
17
|
-
import { parseSessionSearchPattern,
|
|
18
|
+
import { parseSessionSearchPattern, collectSessionSearchMatches, validateSessionSearchScope, resolveSessionSearchDirectories, parseSessionSearchDays, sessionSearchMinUpdated, SESSION_SEARCH_DEFAULT_DAYS, type SessionSearchMatch } from '../session-search.js'
|
|
18
19
|
import { formatWorktreeName, formatAutoWorktreeName } from '../commands/new-worktree.js'
|
|
20
|
+
import { formatTimeAgo } from '../commands/worktrees.js'
|
|
21
|
+
import { editorsForFile, loadFileEditEvents } from '../file-edit-log.js'
|
|
19
22
|
import { WORKTREE_PREFIX } from '../commands/merge-worktree.js'
|
|
20
23
|
import type { ThreadStartMarker } from '../system-message.js'
|
|
21
24
|
import { buildOpencodeEventLogLine } from '../session-handler/opencode-session-event-log.js'
|
|
22
25
|
import { createDiscordRest } from '../discord-urls.js'
|
|
23
26
|
import { archiveThread, uploadFilesToDiscord, stripMentions } from '../discord-utils.js'
|
|
27
|
+
import { OpenCodeSdkError } from '../errors.js'
|
|
24
28
|
import { setDataDir, setProjectsDir, getDataDir, getProjectsDir } from '../config.js'
|
|
25
29
|
import { execAsync, validateWorktreeDirectory } from '../worktrees.js'
|
|
26
30
|
import { upgrade, getCurrentVersion } from '../upgrade.js'
|
|
@@ -90,8 +94,10 @@ cli
|
|
|
90
94
|
'--project <path>',
|
|
91
95
|
'Project directory to list sessions for (defaults to cwd)',
|
|
92
96
|
)
|
|
97
|
+
.option('--active', 'Only list active sessions; exits 1 when none remain')
|
|
98
|
+
.option('--exclude <sessionId>', 'Exclude one session ID from the results')
|
|
93
99
|
.option('--json', 'Output as JSON')
|
|
94
|
-
.action(async (options
|
|
100
|
+
.action(async (options) => {
|
|
95
101
|
try {
|
|
96
102
|
const projectDirectory = path.resolve(options.project || '.')
|
|
97
103
|
|
|
@@ -106,10 +112,28 @@ cli
|
|
|
106
112
|
|
|
107
113
|
const sessionsResponse = await getClient().session.list()
|
|
108
114
|
const sessions = sessionsResponse.data || []
|
|
115
|
+
const statuses = await (async () => {
|
|
116
|
+
if (!options.active) return null
|
|
117
|
+
const response = await getClient().session.status({
|
|
118
|
+
directory: projectDirectory,
|
|
119
|
+
})
|
|
120
|
+
if (response.error) {
|
|
121
|
+
cliLogger.error('Failed to list active sessions')
|
|
122
|
+
process.exit(EXIT_NO_RESTART)
|
|
123
|
+
}
|
|
124
|
+
return response.data || {}
|
|
125
|
+
})()
|
|
126
|
+
const selectedSessions = sessions.filter((session) => {
|
|
127
|
+
if (session.id === options.exclude) return false
|
|
128
|
+
if (!options.active) return true
|
|
129
|
+
const status = statuses?.[session.id]
|
|
130
|
+
return Boolean(status && status.type !== 'idle')
|
|
131
|
+
})
|
|
109
132
|
|
|
110
|
-
if (
|
|
111
|
-
|
|
112
|
-
|
|
133
|
+
if (selectedSessions.length === 0) {
|
|
134
|
+
if (options.json) console.log('[]')
|
|
135
|
+
else cliLogger.log(options.active ? 'No active sessions found' : 'No sessions found')
|
|
136
|
+
process.exit(options.active ? 1 : 0)
|
|
113
137
|
}
|
|
114
138
|
|
|
115
139
|
// Look up which sessions were started via kimaki (have a thread mapping)
|
|
@@ -123,7 +147,7 @@ cli
|
|
|
123
147
|
.map((row) => [row.session_id, row.thread_id]),
|
|
124
148
|
)
|
|
125
149
|
const sessionStartSources = await getSessionStartSourcesBySessionIds(
|
|
126
|
-
|
|
150
|
+
selectedSessions.map((session) => session.id),
|
|
127
151
|
)
|
|
128
152
|
|
|
129
153
|
const scheduleModeLabel = ({
|
|
@@ -138,7 +162,7 @@ cli
|
|
|
138
162
|
}
|
|
139
163
|
|
|
140
164
|
if (options.json) {
|
|
141
|
-
const output =
|
|
165
|
+
const output = selectedSessions.map((session) => {
|
|
142
166
|
const startSource = sessionStartSources.get(session.id)
|
|
143
167
|
const startedBy = startSource
|
|
144
168
|
? `scheduled-${scheduleModeLabel({ scheduleKind: startSource.schedule_kind })}`
|
|
@@ -152,13 +176,14 @@ cli
|
|
|
152
176
|
threadId: sessionToThread.get(session.id) || null,
|
|
153
177
|
startedBy,
|
|
154
178
|
scheduledTaskId: startSource?.scheduled_task_id || null,
|
|
179
|
+
status: options.active ? statuses?.[session.id]?.type || 'busy' : undefined,
|
|
155
180
|
}
|
|
156
181
|
})
|
|
157
182
|
console.log(JSON.stringify(output, null, 2))
|
|
158
183
|
process.exit(0)
|
|
159
184
|
}
|
|
160
185
|
|
|
161
|
-
for (const session of
|
|
186
|
+
for (const session of selectedSessions) {
|
|
162
187
|
const threadId = sessionToThread.get(session.id)
|
|
163
188
|
const startSource = sessionStartSources.get(session.id)
|
|
164
189
|
const source = threadId ? '(kimaki)' : '(opencode)'
|
|
@@ -167,8 +192,11 @@ cli
|
|
|
167
192
|
: ''
|
|
168
193
|
const updatedAt = new Date(session.time.updated).toISOString()
|
|
169
194
|
const threadInfo = threadId ? ` | thread: ${threadId}` : ''
|
|
195
|
+
const statusInfo = options.active
|
|
196
|
+
? ` | status: ${statuses?.[session.id]?.type || 'busy'}`
|
|
197
|
+
: ''
|
|
170
198
|
console.log(
|
|
171
|
-
`${session.id} | ${session.title || 'Untitled Session'} | ${session.directory} | ${updatedAt} | ${source}${threadInfo}${startedBy}`,
|
|
199
|
+
`${session.id} | ${session.title || 'Untitled Session'} | ${session.directory} | ${updatedAt} | ${source}${threadInfo}${startedBy}${statusInfo}`,
|
|
172
200
|
)
|
|
173
201
|
}
|
|
174
202
|
|
|
@@ -182,6 +210,89 @@ cli
|
|
|
182
210
|
}
|
|
183
211
|
})
|
|
184
212
|
|
|
213
|
+
cli
|
|
214
|
+
.command(
|
|
215
|
+
'session editors <file>',
|
|
216
|
+
dedent`
|
|
217
|
+
List sessions that last edited a file, newest first.
|
|
218
|
+
|
|
219
|
+
Use this before a commit in another session so the \`Session:\` line
|
|
220
|
+
uses the session that actually edited the file.
|
|
221
|
+
`,
|
|
222
|
+
)
|
|
223
|
+
.option('--json', 'Output as JSON')
|
|
224
|
+
.option(
|
|
225
|
+
'--limit <n>',
|
|
226
|
+
z.number().default(20).describe('Max sessions to show'),
|
|
227
|
+
)
|
|
228
|
+
.example('kimaki session editors src/cli.ts')
|
|
229
|
+
.example('kimaki session editors src/cli.ts --json')
|
|
230
|
+
.action(async (file, options, { console, process }) => {
|
|
231
|
+
try {
|
|
232
|
+
const cwd = process.cwd
|
|
233
|
+
const loaded = loadFileEditEvents({ dataDir: getDataDir() })
|
|
234
|
+
if (loaded instanceof Error) {
|
|
235
|
+
console.error(loaded.message)
|
|
236
|
+
process.exit(EXIT_NO_RESTART)
|
|
237
|
+
return
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const editors = editorsForFile({
|
|
241
|
+
events: loaded,
|
|
242
|
+
filePath: file,
|
|
243
|
+
cwd,
|
|
244
|
+
}).slice(0, options.limit)
|
|
245
|
+
if (editors.length === 0) {
|
|
246
|
+
console.error(`No recorded editors for ${path.resolve(cwd, file)}`)
|
|
247
|
+
process.exit(1)
|
|
248
|
+
return
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const titles = new Map<string, string>()
|
|
252
|
+
try {
|
|
253
|
+
await initDatabase()
|
|
254
|
+
const db = await getDb()
|
|
255
|
+
const sessionRows = await db.query.thread_sessions.findMany({
|
|
256
|
+
columns: { session_id: true, last_synced_name: true },
|
|
257
|
+
where: { session_id: { in: editors.map((editor) => editor.sessionId) } },
|
|
258
|
+
orderBy: { updated_at: 'desc' },
|
|
259
|
+
})
|
|
260
|
+
for (const row of sessionRows) {
|
|
261
|
+
if (!titles.has(row.session_id) && row.last_synced_name) {
|
|
262
|
+
titles.set(row.session_id, row.last_synced_name)
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
} catch (error) {
|
|
266
|
+
console.error(error instanceof Error ? error.message : String(error))
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const rows = editors.map((editor) => {
|
|
270
|
+
const title = titles.get(editor.sessionId) || '-'
|
|
271
|
+
const editedAt = new Date(editor.at)
|
|
272
|
+
return {
|
|
273
|
+
sessionId: editor.sessionId,
|
|
274
|
+
title,
|
|
275
|
+
editedAt: editedAt.toISOString(),
|
|
276
|
+
ago: formatTimeAgo(editedAt),
|
|
277
|
+
}
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
if (options.json) {
|
|
281
|
+
console.log(JSON.stringify(rows, null, 2))
|
|
282
|
+
process.exit(0)
|
|
283
|
+
return
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
for (const row of rows) {
|
|
287
|
+
console.log(`${row.sessionId} | ${row.title} | ${row.ago}`)
|
|
288
|
+
}
|
|
289
|
+
process.exit(0)
|
|
290
|
+
} catch (error) {
|
|
291
|
+
console.error(error instanceof Error ? error.stack : String(error))
|
|
292
|
+
process.exit(EXIT_NO_RESTART)
|
|
293
|
+
}
|
|
294
|
+
})
|
|
295
|
+
|
|
185
296
|
cli
|
|
186
297
|
.command(
|
|
187
298
|
'session read <sessionId>',
|
|
@@ -293,18 +404,31 @@ cli
|
|
|
293
404
|
cli
|
|
294
405
|
.command(
|
|
295
406
|
'session search <query>',
|
|
296
|
-
|
|
407
|
+
`Search past sessions for text or /regex/flags. Defaults to the last ${SESSION_SEARCH_DEFAULT_DAYS} days; use --days 0 for all time. Add --all for every locally registered project.`,
|
|
297
408
|
)
|
|
298
409
|
.option('--project <path>', 'Project directory (defaults to cwd)')
|
|
299
410
|
.option('--channel <channelId>', 'Resolve project from a Discord channel ID')
|
|
411
|
+
.option('--all', 'Search every locally registered project')
|
|
412
|
+
.option(
|
|
413
|
+
'--days <n>',
|
|
414
|
+
`Only search sessions updated in the last n days (default: ${SESSION_SEARCH_DEFAULT_DAYS}; 0 = all time)`,
|
|
415
|
+
)
|
|
300
416
|
.option('--limit <n>', 'Maximum matched sessions to return (default: 20)')
|
|
301
417
|
.option('--json', 'Output as JSON')
|
|
418
|
+
.example('kimaki session search "auth timeout"')
|
|
419
|
+
.example('kimaki session search "auth timeout" --days 0')
|
|
420
|
+
.example('kimaki session search "auth timeout" --all')
|
|
302
421
|
.action(async (query, options) => {
|
|
303
422
|
try {
|
|
304
423
|
await initDatabase()
|
|
305
424
|
|
|
306
|
-
|
|
307
|
-
|
|
425
|
+
const scopeError = validateSessionSearchScope({
|
|
426
|
+
all: options.all,
|
|
427
|
+
project: options.project,
|
|
428
|
+
channel: options.channel,
|
|
429
|
+
})
|
|
430
|
+
if (scopeError) {
|
|
431
|
+
cliLogger.error(scopeError.message)
|
|
308
432
|
process.exit(EXIT_NO_RESTART)
|
|
309
433
|
}
|
|
310
434
|
|
|
@@ -323,9 +447,19 @@ cli
|
|
|
323
447
|
process.exit(EXIT_NO_RESTART)
|
|
324
448
|
}
|
|
325
449
|
|
|
326
|
-
const
|
|
327
|
-
string
|
|
328
|
-
|
|
450
|
+
const days = parseSessionSearchDays(
|
|
451
|
+
typeof options.days === 'string' ? options.days : undefined,
|
|
452
|
+
)
|
|
453
|
+
if (days instanceof Error) {
|
|
454
|
+
cliLogger.error(days.message)
|
|
455
|
+
process.exit(EXIT_NO_RESTART)
|
|
456
|
+
}
|
|
457
|
+
const minUpdated = sessionSearchMinUpdated({ days })
|
|
458
|
+
|
|
459
|
+
const explicitDirectory = await (async (): Promise<string | Error | undefined> => {
|
|
460
|
+
if (options.all) {
|
|
461
|
+
return undefined
|
|
462
|
+
}
|
|
329
463
|
if (options.channel) {
|
|
330
464
|
const channelConfig = await getChannelDirectory(options.channel)
|
|
331
465
|
if (!channelConfig) {
|
|
@@ -335,17 +469,50 @@ cli
|
|
|
335
469
|
}
|
|
336
470
|
return path.resolve(channelConfig.directory)
|
|
337
471
|
}
|
|
338
|
-
|
|
472
|
+
if (options.project) {
|
|
473
|
+
return path.resolve(options.project)
|
|
474
|
+
}
|
|
475
|
+
return undefined
|
|
339
476
|
})()
|
|
340
477
|
|
|
341
|
-
if (
|
|
342
|
-
cliLogger.error(
|
|
478
|
+
if (explicitDirectory instanceof Error) {
|
|
479
|
+
cliLogger.error(explicitDirectory.message)
|
|
343
480
|
process.exit(EXIT_NO_RESTART)
|
|
344
481
|
}
|
|
345
482
|
|
|
346
|
-
const
|
|
347
|
-
|
|
348
|
-
|
|
483
|
+
const registeredDirectories = options.all
|
|
484
|
+
? (await getAllTextChannelDirectories()).map((directory) => {
|
|
485
|
+
return path.resolve(directory)
|
|
486
|
+
})
|
|
487
|
+
: []
|
|
488
|
+
const projectDirectories = resolveSessionSearchDirectories({
|
|
489
|
+
all: Boolean(options.all),
|
|
490
|
+
registeredDirectories,
|
|
491
|
+
cwd: path.resolve('.'),
|
|
492
|
+
explicitDirectory,
|
|
493
|
+
})
|
|
494
|
+
if (projectDirectories instanceof Error) {
|
|
495
|
+
cliLogger.error(projectDirectories.message)
|
|
496
|
+
process.exit(EXIT_NO_RESTART)
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const existingDirectories: string[] = []
|
|
500
|
+
for (const directory of projectDirectories) {
|
|
501
|
+
if (fs.existsSync(directory)) {
|
|
502
|
+
existingDirectories.push(directory)
|
|
503
|
+
continue
|
|
504
|
+
}
|
|
505
|
+
if (options.all) {
|
|
506
|
+
cliLogger.warn(`Skipping missing directory: ${directory}`)
|
|
507
|
+
continue
|
|
508
|
+
}
|
|
509
|
+
cliLogger.error(`Directory does not exist: ${directory}`)
|
|
510
|
+
process.exit(EXIT_NO_RESTART)
|
|
511
|
+
}
|
|
512
|
+
if (existingDirectories.length === 0) {
|
|
513
|
+
cliLogger.error(
|
|
514
|
+
'No searchable project directories found. Add a project with `kimaki project add`, or pass --project.',
|
|
515
|
+
)
|
|
349
516
|
process.exit(EXIT_NO_RESTART)
|
|
350
517
|
}
|
|
351
518
|
|
|
@@ -355,16 +522,61 @@ cli
|
|
|
355
522
|
process.exit(EXIT_NO_RESTART)
|
|
356
523
|
}
|
|
357
524
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
525
|
+
type OpencodeGetClient = Exclude<
|
|
526
|
+
Awaited<ReturnType<typeof initializeOpencodeForDirectory>>,
|
|
527
|
+
Error
|
|
528
|
+
>
|
|
529
|
+
const clientsBySessionId = new Map<string, OpencodeGetClient>()
|
|
530
|
+
const searchedDirectories: string[] = []
|
|
531
|
+
const searchableSessions: Array<{
|
|
532
|
+
id: string
|
|
533
|
+
title: string
|
|
534
|
+
directory: string
|
|
535
|
+
updated: number
|
|
536
|
+
}> = []
|
|
537
|
+
|
|
538
|
+
const listedDirectories = await Promise.all(
|
|
539
|
+
existingDirectories.map(async (projectDirectory) => {
|
|
540
|
+
cliLogger.log(`Connecting to OpenCode server for ${projectDirectory}...`)
|
|
541
|
+
const getClient = await initializeOpencodeForDirectory(projectDirectory)
|
|
542
|
+
if (getClient instanceof Error) {
|
|
543
|
+
return { projectDirectory, getClient, sessions: [] }
|
|
544
|
+
}
|
|
545
|
+
const sessionsResponse = await getClient().session.list()
|
|
546
|
+
return {
|
|
547
|
+
projectDirectory,
|
|
548
|
+
getClient,
|
|
549
|
+
sessions: sessionsResponse.data || [],
|
|
550
|
+
}
|
|
551
|
+
}),
|
|
552
|
+
)
|
|
553
|
+
for (const listed of listedDirectories) {
|
|
554
|
+
if (listed.getClient instanceof Error) {
|
|
555
|
+
if (options.all) {
|
|
556
|
+
cliLogger.warn(
|
|
557
|
+
`Skipping ${listed.projectDirectory}: failed to connect to OpenCode: ${listed.getClient.message}`,
|
|
558
|
+
)
|
|
559
|
+
continue
|
|
560
|
+
}
|
|
561
|
+
cliLogger.error(
|
|
562
|
+
'Failed to connect to OpenCode:',
|
|
563
|
+
listed.getClient.message,
|
|
564
|
+
)
|
|
565
|
+
process.exit(EXIT_NO_RESTART)
|
|
566
|
+
}
|
|
567
|
+
searchedDirectories.push(listed.projectDirectory)
|
|
568
|
+
for (const session of listed.sessions) {
|
|
569
|
+
clientsBySessionId.set(session.id, listed.getClient)
|
|
570
|
+
searchableSessions.push({
|
|
571
|
+
id: session.id,
|
|
572
|
+
title: session.title || 'Untitled Session',
|
|
573
|
+
directory: session.directory || listed.projectDirectory,
|
|
574
|
+
updated: session.time.updated,
|
|
575
|
+
})
|
|
576
|
+
}
|
|
363
577
|
}
|
|
364
578
|
|
|
365
|
-
|
|
366
|
-
const sessions = sessionsResponse.data || []
|
|
367
|
-
if (sessions.length === 0) {
|
|
579
|
+
if (searchableSessions.length === 0) {
|
|
368
580
|
cliLogger.log('No sessions found')
|
|
369
581
|
process.exit(0)
|
|
370
582
|
}
|
|
@@ -379,84 +591,62 @@ cli
|
|
|
379
591
|
.map((row) => [row.session_id, row.thread_id]),
|
|
380
592
|
)
|
|
381
593
|
|
|
382
|
-
const
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
snippets
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
let scannedSessions = 0
|
|
397
|
-
|
|
398
|
-
for (const session of sortedSessions) {
|
|
399
|
-
scannedSessions++
|
|
400
|
-
const messagesResponse = await getClient().session.messages({
|
|
401
|
-
sessionID: session.id,
|
|
594
|
+
const scopeLabel = options.all
|
|
595
|
+
? `${searchedDirectories.length} project(s)`
|
|
596
|
+
: searchedDirectories[0] || path.resolve('.')
|
|
597
|
+
const daysLabel =
|
|
598
|
+
days === 0 ? 'all time' : `the last ${days} day${days === 1 ? '' : 's'}`
|
|
599
|
+
const printMatch = (match: SessionSearchMatch) => {
|
|
600
|
+
const threadInfo = match.threadId ? ` | thread: ${match.threadId}` : ''
|
|
601
|
+
console.log(
|
|
602
|
+
`${match.id} | ${match.title} | ${match.updated} | ${match.source}${threadInfo}`,
|
|
603
|
+
)
|
|
604
|
+
console.log(` Directory: ${match.directory}`)
|
|
605
|
+
match.snippets.forEach((snippet) => {
|
|
606
|
+
console.log(` - ${snippet}`)
|
|
402
607
|
})
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
return []
|
|
422
|
-
}
|
|
423
|
-
const snippet = buildSessionSearchSnippet({ text, hit })
|
|
424
|
-
if (!snippet) {
|
|
425
|
-
return []
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
let printedHeader = false
|
|
611
|
+
const { matches: matchedSessions, scannedSessions } =
|
|
612
|
+
await collectSessionSearchMatches({
|
|
613
|
+
sessions: searchableSessions,
|
|
614
|
+
searchPattern,
|
|
615
|
+
sessionToThread,
|
|
616
|
+
limit,
|
|
617
|
+
minUpdated,
|
|
618
|
+
onMatch: options.json
|
|
619
|
+
? undefined
|
|
620
|
+
: (match) => {
|
|
621
|
+
if (!printedHeader) {
|
|
622
|
+
printedHeader = true
|
|
623
|
+
cliLogger.log(
|
|
624
|
+
`Found matching session(s) for ${searchPattern.raw} in ${scopeLabel} (${daysLabel})`,
|
|
625
|
+
)
|
|
426
626
|
}
|
|
427
|
-
|
|
428
|
-
}
|
|
627
|
+
printMatch(match)
|
|
628
|
+
},
|
|
629
|
+
loadMessages: async (session) => {
|
|
630
|
+
const getClient = clientsBySessionId.get(session.id)
|
|
631
|
+
if (!getClient) {
|
|
632
|
+
return []
|
|
633
|
+
}
|
|
634
|
+
const messagesResponse = await getClient().session.messages({
|
|
635
|
+
sessionID: session.id,
|
|
429
636
|
})
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
if (snippets.length === 0) {
|
|
434
|
-
continue
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
const threadId = sessionToThread.get(session.id)
|
|
438
|
-
matchedSessions.push({
|
|
439
|
-
id: session.id,
|
|
440
|
-
title: session.title || 'Untitled Session',
|
|
441
|
-
directory: session.directory,
|
|
442
|
-
updated: new Date(session.time.updated).toISOString(),
|
|
443
|
-
source: threadId ? 'kimaki' : 'opencode',
|
|
444
|
-
threadId: threadId || null,
|
|
445
|
-
snippets,
|
|
637
|
+
return messagesResponse.data || []
|
|
638
|
+
},
|
|
446
639
|
})
|
|
447
640
|
|
|
448
|
-
if (matchedSessions.length >= limit) {
|
|
449
|
-
break
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
|
|
453
641
|
if (options.json) {
|
|
454
642
|
console.log(
|
|
455
643
|
JSON.stringify(
|
|
456
644
|
{
|
|
457
645
|
query: searchPattern.raw,
|
|
458
646
|
mode: searchPattern.mode,
|
|
459
|
-
|
|
647
|
+
all: Boolean(options.all),
|
|
648
|
+
days,
|
|
649
|
+
projectDirectories: searchedDirectories,
|
|
460
650
|
scannedSessions,
|
|
461
651
|
matches: matchedSessions,
|
|
462
652
|
},
|
|
@@ -468,27 +658,14 @@ cli
|
|
|
468
658
|
}
|
|
469
659
|
|
|
470
660
|
if (matchedSessions.length === 0) {
|
|
661
|
+
const cutoffHint =
|
|
662
|
+
days === 0 ? '' : '. Use --days 0 to search all time'
|
|
471
663
|
cliLogger.log(
|
|
472
|
-
`No matches found for ${searchPattern.raw} in ${
|
|
664
|
+
`No matches found for ${searchPattern.raw} in ${scopeLabel} (${scannedSessions} sessions scanned, ${daysLabel})${cutoffHint}`,
|
|
473
665
|
)
|
|
474
666
|
process.exit(0)
|
|
475
667
|
}
|
|
476
668
|
|
|
477
|
-
cliLogger.log(
|
|
478
|
-
`Found ${matchedSessions.length} matching session(s) for ${searchPattern.raw} in ${projectDirectory}`,
|
|
479
|
-
)
|
|
480
|
-
|
|
481
|
-
for (const match of matchedSessions) {
|
|
482
|
-
const threadInfo = match.threadId ? ` | thread: ${match.threadId}` : ''
|
|
483
|
-
console.log(
|
|
484
|
-
`${match.id} | ${match.title} | ${match.updated} | ${match.source}${threadInfo}`,
|
|
485
|
-
)
|
|
486
|
-
console.log(` Directory: ${match.directory}`)
|
|
487
|
-
match.snippets.forEach((snippet) => {
|
|
488
|
-
console.log(` - ${snippet}`)
|
|
489
|
-
})
|
|
490
|
-
}
|
|
491
|
-
|
|
492
669
|
process.exit(0)
|
|
493
670
|
} catch (error) {
|
|
494
671
|
cliLogger.error(
|
|
@@ -600,7 +777,7 @@ cli
|
|
|
600
777
|
cli
|
|
601
778
|
.command(
|
|
602
779
|
'session archive [threadId]',
|
|
603
|
-
'Archive a Discord thread
|
|
780
|
+
'Archive a Discord thread without stopping its mapped OpenCode session',
|
|
604
781
|
)
|
|
605
782
|
.option('--session <sessionId>', 'Resolve thread from an OpenCode session ID')
|
|
606
783
|
.action(async (threadIdArg: string | undefined, options: { session?: string }) => {
|
|
@@ -753,6 +930,89 @@ cli
|
|
|
753
930
|
}
|
|
754
931
|
})
|
|
755
932
|
|
|
933
|
+
cli
|
|
934
|
+
.command(
|
|
935
|
+
'session title <title>',
|
|
936
|
+
'Update the OpenCode session title. Discord thread name follows automatically.',
|
|
937
|
+
)
|
|
938
|
+
.option('--session <sessionId>', 'OpenCode session ID')
|
|
939
|
+
.option('--thread <threadId>', 'Discord thread ID')
|
|
940
|
+
.example("kimaki session title 'Fix queue draining' --session ses_xxx")
|
|
941
|
+
.action(async (title, options) => {
|
|
942
|
+
try {
|
|
943
|
+
await initDatabase()
|
|
944
|
+
|
|
945
|
+
const trimmedTitle = title.trim()
|
|
946
|
+
if (!trimmedTitle) {
|
|
947
|
+
cliLogger.error('Title must not be empty')
|
|
948
|
+
process.exit(EXIT_NO_RESTART)
|
|
949
|
+
}
|
|
950
|
+
if (options.session && options.thread) {
|
|
951
|
+
cliLogger.error('Use either --session or --thread, not both')
|
|
952
|
+
process.exit(EXIT_NO_RESTART)
|
|
953
|
+
}
|
|
954
|
+
if (!options.session && !options.thread) {
|
|
955
|
+
cliLogger.error('Provide --session <sessionId> or --thread <threadId>')
|
|
956
|
+
process.exit(EXIT_NO_RESTART)
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
const sessionId = await (async () => {
|
|
960
|
+
if (options.session) return options.session
|
|
961
|
+
const threadId = options.thread
|
|
962
|
+
if (!threadId) return null
|
|
963
|
+
return getThreadSession(threadId)
|
|
964
|
+
})()
|
|
965
|
+
if (!sessionId) {
|
|
966
|
+
cliLogger.error(
|
|
967
|
+
options.thread
|
|
968
|
+
? `No OpenCode session found for thread: ${options.thread}`
|
|
969
|
+
: 'Provide --session <sessionId> or --thread <threadId>',
|
|
970
|
+
)
|
|
971
|
+
process.exit(EXIT_NO_RESTART)
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
const directory = await resolveSessionDirectoryFromDatabase({
|
|
975
|
+
sessionId,
|
|
976
|
+
})
|
|
977
|
+
if (directory instanceof Error) {
|
|
978
|
+
cliLogger.error(directory.message)
|
|
979
|
+
process.exit(EXIT_NO_RESTART)
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
const serverResult = await initializeOpencodeForDirectory(directory)
|
|
983
|
+
if (serverResult instanceof Error) {
|
|
984
|
+
cliLogger.error(`Failed to initialize OpenCode: ${serverResult.message}`)
|
|
985
|
+
process.exit(EXIT_NO_RESTART)
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
const updateResult = await serverResult()
|
|
989
|
+
.session.update({
|
|
990
|
+
sessionID: sessionId,
|
|
991
|
+
title: trimmedTitle,
|
|
992
|
+
})
|
|
993
|
+
.catch((e) =>
|
|
994
|
+
new OpenCodeSdkError({ operation: 'session.update', cause: e }),
|
|
995
|
+
)
|
|
996
|
+
if (updateResult instanceof Error) {
|
|
997
|
+
cliLogger.error(updateResult.message)
|
|
998
|
+
process.exit(EXIT_NO_RESTART)
|
|
999
|
+
}
|
|
1000
|
+
if (updateResult.error) {
|
|
1001
|
+
cliLogger.error('OpenCode rejected the session title update')
|
|
1002
|
+
process.exit(EXIT_NO_RESTART)
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
note(`Updated OpenCode title: ${trimmedTitle}`, 'Title updated')
|
|
1006
|
+
process.exit(0)
|
|
1007
|
+
} catch (error) {
|
|
1008
|
+
cliLogger.error(
|
|
1009
|
+
'Error:',
|
|
1010
|
+
error instanceof Error ? error.stack : String(error),
|
|
1011
|
+
)
|
|
1012
|
+
process.exit(EXIT_NO_RESTART)
|
|
1013
|
+
}
|
|
1014
|
+
})
|
|
1015
|
+
|
|
756
1016
|
cli
|
|
757
1017
|
.command(
|
|
758
1018
|
'session discord-url <sessionId>',
|