@norman-else/dsh-claude 0.1.35 → 0.1.36

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.
@@ -29,6 +29,11 @@ const DEFAULT_CLAUDE_RENDER_MODE = "plugin";
29
29
  function isClaudeRenderMode(value) {
30
30
  return value === "plugin" || value === "native";
31
31
  }
32
+ const CLAUDE_PROSE_MODES = ["plain", "enhanced"];
33
+ const DEFAULT_CLAUDE_PROSE_MODE = "plain";
34
+ function isClaudeProseMode(value) {
35
+ return value === "plain" || value === "enhanced";
36
+ }
32
37
  //#endregion
33
38
  //#region src/events.ts
34
39
  const SECRET_KEY = /(?:^|[_-])(password|passwd|secret|token|api[_-]?key|authorization|credential|private[_-]?key|session[_-]?key|env|environ|environment)(?:$|[_-])/i;
@@ -199,6 +204,6 @@ function latestClaudeSessionBinding(events) {
199
204
  }
200
205
  }
201
206
  //#endregion
202
- export { CLAUDE_UPDATE_CHECK_PATH as A, CLAUDE_REPOSITORY_ACTION_PATH as C, CLAUDE_REPOSITORY_STATUS_PATH as D, CLAUDE_REPOSITORY_SETUP_PATH as E, TASK_TOOL_NAMES as F, isClaudeRenderMode as I, CLAUDE_USAGE_PATH as M, DEFAULT_CLAUDE_RENDER_MODE as N, CLAUDE_REVIEW_COMMENT_PATH as O, SDK_VERSION as P, CLAUDE_RENDER_MODES as S, CLAUDE_REPOSITORY_FILE_PATH as T, CLAUDE_DOCTOR_PATH as _, latestClaudeTasks as a, CLAUDE_JIRA_PATH as b, normalizeTasksEvent as c, CLAUDE_ACTIVITY_EVENT as d, CLAUDE_ASK_PATH as f, CLAUDE_CODE_PROVIDER_IDS as g, CLAUDE_CODE_PROVIDER as h, latestClaudeSessionBinding as i, CLAUDE_UPDATE_PATH as j, CLAUDE_REWIND_PATH as k, redactText as l, CLAUDE_CODE_PRESET_ID as m, currentClaudeActivityCursor as n, normalizeActivity as o, CLAUDE_CLIENT_DIAGNOSTICS_PATH as p, latestClaudeContextUsage as r, normalizeContextUsage as s, boundText as t, safeDetail as u, CLAUDE_EDITOR_OPEN_PATH as v, CLAUDE_REPOSITORY_FEEDBACK_PATH as w, CLAUDE_PROJECTION_PATH as x, CLAUDE_GLOBAL_SETTINGS_PATH as y };
207
+ export { CLAUDE_REWIND_PATH as A, CLAUDE_RENDER_MODES as C, CLAUDE_REPOSITORY_SETUP_PATH as D, CLAUDE_REPOSITORY_FILE_PATH as E, DEFAULT_CLAUDE_RENDER_MODE as F, SDK_VERSION as I, TASK_TOOL_NAMES as L, CLAUDE_UPDATE_PATH as M, CLAUDE_USAGE_PATH as N, CLAUDE_REPOSITORY_STATUS_PATH as O, DEFAULT_CLAUDE_PROSE_MODE as P, isClaudeProseMode as R, CLAUDE_PROSE_MODES as S, CLAUDE_REPOSITORY_FEEDBACK_PATH as T, CLAUDE_DOCTOR_PATH as _, latestClaudeTasks as a, CLAUDE_JIRA_PATH as b, normalizeTasksEvent as c, CLAUDE_ACTIVITY_EVENT as d, CLAUDE_ASK_PATH as f, CLAUDE_CODE_PROVIDER_IDS as g, CLAUDE_CODE_PROVIDER as h, latestClaudeSessionBinding as i, CLAUDE_UPDATE_CHECK_PATH as j, CLAUDE_REVIEW_COMMENT_PATH as k, redactText as l, CLAUDE_CODE_PRESET_ID as m, currentClaudeActivityCursor as n, normalizeActivity as o, CLAUDE_CLIENT_DIAGNOSTICS_PATH as p, latestClaudeContextUsage as r, normalizeContextUsage as s, boundText as t, safeDetail as u, CLAUDE_EDITOR_OPEN_PATH as v, CLAUDE_REPOSITORY_ACTION_PATH as w, CLAUDE_PROJECTION_PATH as x, CLAUDE_GLOBAL_SETTINGS_PATH as y, isClaudeRenderMode as z };
203
208
 
204
- //# sourceMappingURL=events-Doid-tq7.mjs.map
209
+ //# sourceMappingURL=events-OhBoFNKO.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events-OhBoFNKO.mjs","names":[],"sources":["../src/constants.ts","../src/events.ts"],"sourcesContent":["export const CLAUDE_CODE_PROVIDER = 'claude'\nexport const CLAUDE_CODE_PRESET_ID = 'claude'\nexport const CLAUDE_CODE_PROVIDER_IDS = [CLAUDE_CODE_PROVIDER] as const\nexport const CLAUDE_SESSION_BOUND_EVENT = 'claude-code/session-bound'\nexport const CLAUDE_ACTIVITY_EVENT = 'claude-code/activity'\nexport const CLAUDE_CONTEXT_USAGE_EVENT = 'claude-code/context-usage'\nexport const CLAUDE_TASKS_EVENT = 'claude-code/tasks'\n/** Claude's subagent dispatch tools; rendered as plugin-owned group cards\n * gathering subagent activity instead of native tool cards. */\nexport const TASK_TOOL_NAMES: ReadonlySet<string> = new Set(['Task', 'Agent'])\nexport const SDK_VERSION = '0.3.247'\nexport const CLAUDE_DOCTOR_PATH = '/plugins/dsh-claude/doctor'\nexport const CLAUDE_CLIENT_DIAGNOSTICS_PATH = '/plugins/dsh-claude/client-diagnostics'\nexport const CLAUDE_UPDATE_CHECK_PATH = '/plugins/dsh-claude/update/check'\nexport const CLAUDE_USAGE_PATH = '/plugins/dsh-claude/usage'\nexport const CLAUDE_UPDATE_PATH = '/plugins/dsh-claude/update'\nexport const CLAUDE_PROJECTION_PATH = '/plugins/dsh-claude/projection'\nexport const CLAUDE_GLOBAL_SETTINGS_PATH = '/plugins/dsh-claude/settings/global'\nexport const CLAUDE_REPOSITORY_SETUP_PATH = '/plugins/dsh-claude/repository/setup'\nexport const CLAUDE_REPOSITORY_ACTION_PATH = '/plugins/dsh-claude/repository/action'\nexport const CLAUDE_REVIEW_COMMENT_PATH = '/plugins/dsh-claude/review-comments'\nexport const CLAUDE_REPOSITORY_FEEDBACK_PATH = '/plugins/dsh-claude/repository/feedback'\nexport const CLAUDE_REPOSITORY_STATUS_PATH = '/plugins/dsh-claude/repository/status'\nexport const CLAUDE_REPOSITORY_FILE_PATH = '/plugins/dsh-claude/repository/file'\nexport const CLAUDE_JIRA_PATH = '/plugins/dsh-claude/jira'\nexport const CLAUDE_ASK_PATH = '/plugins/dsh-claude/ask'\nexport const CLAUDE_EDITOR_OPEN_PATH = '/plugins/dsh-claude/editor/open'\nexport const CLAUDE_REWIND_PATH = '/plugins/dsh-claude/rewind'\n\n/** Which renderer draws Claude's visible output.\n *\n * 'plugin' keeps the sidecar-backed transcript this package owns (interleaved\n * prose, grouped tool cards, activity rows). 'native' hands the same turn to\n * DSH's own conversation renderer: prose streams as ordinary assistant text\n * blocks, thinking as reasoning blocks, and root Claude tools are mirrored\n * into the durable `tool/call`/`tool/result` channel so the Host's tool\n * presentation pipeline draws them exactly like DSH-executed calls. */\nexport type ClaudeRenderMode = 'plugin' | 'native'\nexport const CLAUDE_RENDER_MODES = ['plugin', 'native'] as const\nexport const DEFAULT_CLAUDE_RENDER_MODE: ClaudeRenderMode = 'plugin'\n\nexport function isClaudeRenderMode(value: unknown): value is ClaudeRenderMode {\n return value === 'plugin' || value === 'native'\n}\n\n/** How this package paints the PROSE of a Claude answer.\n *\n * 'plain' is Claude's own presentation: body text in the Host's text colour,\n * colour reserved for code. 'enhanced' gives headings, emphasis, list markers,\n * quotes and links their own hues and darkens the code surface — the way a\n * Markdown-highlighting editor shows a document rather than the way Claude\n * desktop shows an answer. It is opt-in because it deliberately breaks the\n * parity the rest of `markdown-theme.ts` exists to hold.\n *\n * Only meaningful under {@link ClaudeRenderMode} 'plugin': the stylesheet is\n * scoped to markup this package renders, and 'native' turns are drawn by the\n * Host, where it has no reach. */\nexport type ClaudeProseMode = 'plain' | 'enhanced'\nexport const CLAUDE_PROSE_MODES = ['plain', 'enhanced'] as const\nexport const DEFAULT_CLAUDE_PROSE_MODE: ClaudeProseMode = 'plain'\n\nexport function isClaudeProseMode(value: unknown): value is ClaudeProseMode {\n return value === 'plain' || value === 'enhanced'\n}\n","import type { SessionEvent } from '@deepseek-ai/dsh-session'\nimport {\n CLAUDE_ACTIVITY_EVENT,\n CLAUDE_CONTEXT_USAGE_EVENT,\n CLAUDE_SESSION_BOUND_EVENT,\n CLAUDE_TASKS_EVENT,\n isClaudeRenderMode,\n type ClaudeRenderMode,\n} from './constants.ts'\n\nexport type ClaudeActivityKind =\n | 'text'\n | 'status'\n /** Context compaction boundary; the transcript draws it as a divider. */\n | 'compaction'\n | 'thinking'\n | 'tool-call'\n | 'tool-result'\n | 'permission'\n | 'question'\n | 'subagent'\n | 'usage'\n | 'warning'\n | 'error'\n\nexport type ClaudeActivityPhase =\n | 'started'\n | 'updated'\n | 'completed'\n | 'denied'\n | 'failed'\n\nexport interface ClaudeUsage {\n inputTokens?: number\n outputTokens?: number\n cacheReadTokens?: number\n cacheCreationTokens?: number\n cumulativeCostUsd?: number\n /** Wall time from the turn being admitted to it settling. Measured here\n * rather than derived on the client: activities carry no timestamps. */\n durationMs?: number\n /** Wall time to the first visible token of the turn. */\n ttftMs?: number\n}\n\nexport interface ClaudeSessionBoundEvent {\n claudeSessionId: string\n cliVersion?: string\n sdkVersion: string\n cwd: string\n}\n\nexport interface ClaudeActivityEvent {\n turn: number\n step: number\n ordinal: number\n kind: ClaudeActivityKind\n phase?: ClaudeActivityPhase\n /** Claude task-board identity for lifecycle activity; never a transcript path. */\n taskId?: string\n toolUseId?: string\n /** Enclosing Claude tool call for subagent-nested activity. */\n parentToolUseId?: string\n toolName?: string\n title?: string\n summary?: string\n detail?: string\n /** Redacted visible Claude prose used by the plugin-owned interleaved transcript. */\n text?: string\n isError?: boolean\n usage?: ClaudeUsage\n /** Which renderer this record was produced for. Stamped only when the Host\n * drew the step natively, so a record written before the setting existed —\n * and every record written under the plugin renderer — reads as 'plugin'.\n * It travels with the data so a step always renders the way it was\n * recorded, whatever the setting says now. */\n renderer?: ClaudeRenderMode\n}\n\nexport interface ClaudeContextUsageCategory {\n name: string\n tokens: number\n color: string\n isDeferred?: boolean\n}\n\nexport interface ClaudeContextUsageEvent {\n model: string\n totalTokens: number\n maxTokens: number\n percentage: number\n categories: readonly ClaudeContextUsageCategory[]\n}\n\nexport interface ClaudeContextUsageInput {\n model: unknown\n totalTokens: unknown\n maxTokens: unknown\n percentage: unknown\n categories: readonly {\n name?: unknown\n tokens?: unknown\n color?: unknown\n isDeferred?: unknown\n }[]\n}\n\ndeclare module '@deepseek-ai/dsh-session/types' {\n interface SessionEventMap {\n 'claude-code/session-bound': ClaudeSessionBoundEvent\n 'claude-code/activity': ClaudeActivityEvent\n 'claude-code/context-usage': ClaudeContextUsageEvent\n 'claude-code/tasks': ClaudeTasksEvent\n }\n}\n\nconst SECRET_KEY = /(?:^|[_-])(password|passwd|secret|token|api[_-]?key|authorization|credential|private[_-]?key|session[_-]?key|env|environ|environment)(?:$|[_-])/i\nconst MAX_SUMMARY_CHARS = 1_000\nconst MAX_DETAIL_CHARS = 4_000\nconst MAX_TRANSCRIPT_TEXT_CHARS = 64_000\nconst MAX_DEPTH = 6\nconst MAX_ARRAY_ITEMS = 40\nconst MAX_OBJECT_KEYS = 60\nconst REDACTED = '[REDACTED]'\nconst TRUNCATED = '…[truncated]'\nconst SECRET_ASSIGNMENT = /((?:password|passwd|secret|token|api[_-]?key|authorization|credential|private[_-]?key|session[_-]?key)\\s*(?:=|:)\\s*)(?:\"[^\"]*\"|'[^']*'|[^\\s,;&]+)/giu\nconst BEARER_TOKEN = /(\\bbearer\\s+)[A-Za-z0-9._~+/=-]+/giu\nconst PREFIXED_TOKEN = /\\b(?:sk-(?:ant-|proj-)?|xox[baprs]-|ghp_|github_pat_)[A-Za-z0-9_-]{8,}/giu\nconst JWT_TOKEN = /\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\b/gu\nconst URL_USERINFO = /([a-z][a-z0-9+.-]*:\\/\\/[^:\\s/@]+:)[^@\\s/]+@/giu\nconst URL_SECRET_PARAM = /([?&](?:password|secret|token|api[_-]?key|access[_-]?token|refresh[_-]?token)=)[^&#\\s]+/giu\n\nexport function boundText(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value\n return `${value.slice(0, Math.max(0, maxChars - TRUNCATED.length))}${TRUNCATED}`\n}\n\nexport function redactText(value: string, maxChars = MAX_DETAIL_CHARS): string {\n return boundText(\n value\n .replace(JWT_TOKEN, REDACTED)\n .replace(PREFIXED_TOKEN, REDACTED)\n .replace(BEARER_TOKEN, `$1${REDACTED}`)\n .replace(URL_USERINFO, `$1${REDACTED}@`)\n .replace(URL_SECRET_PARAM, `$1${REDACTED}`)\n .replace(SECRET_ASSIGNMENT, `$1${REDACTED}`),\n maxChars,\n )\n}\n\nexport function redactValue(value: unknown, depth = 0, seen = new WeakSet<object>()): unknown {\n if (depth > MAX_DEPTH) return '[max-depth]'\n if (value === null || typeof value === 'boolean' || typeof value === 'number') return value\n if (typeof value === 'string') return redactText(value)\n if (typeof value === 'bigint') return value.toString()\n if (typeof value === 'undefined') return null\n if (typeof value === 'function' || typeof value === 'symbol') return `[${typeof value}]`\n if (value instanceof Error) {\n return { name: value.name, message: redactText(value.message, MAX_SUMMARY_CHARS) }\n }\n if (typeof value !== 'object') return String(value)\n if (seen.has(value)) return '[circular]'\n seen.add(value)\n try {\n if (Array.isArray(value)) {\n const items = value.slice(0, MAX_ARRAY_ITEMS).map(item => redactValue(item, depth + 1, seen))\n if (value.length > MAX_ARRAY_ITEMS) items.push(`[${value.length - MAX_ARRAY_ITEMS} more items]`)\n return items\n }\n const result: Record<string, unknown> = {}\n const entries = Object.entries(value as Record<string, unknown>)\n for (const [key, item] of entries.slice(0, MAX_OBJECT_KEYS)) {\n result[key] = SECRET_KEY.test(key) ? REDACTED : redactValue(item, depth + 1, seen)\n }\n if (entries.length > MAX_OBJECT_KEYS) result.__truncatedKeys = entries.length - MAX_OBJECT_KEYS\n return result\n } finally {\n seen.delete(value)\n }\n}\n\nexport function safeDetail(value: unknown): string | undefined {\n if (value === undefined) return undefined\n const redacted = redactValue(value)\n const text = typeof redacted === 'string' ? redacted : JSON.stringify(redacted)\n return boundText(text, MAX_DETAIL_CHARS)\n}\n\nexport function normalizeActivity(\n activity: Omit<ClaudeActivityEvent, 'summary' | 'detail'> & {\n summary?: unknown\n detail?: unknown\n },\n): ClaudeActivityEvent {\n const normalized: ClaudeActivityEvent = {\n turn: activity.turn,\n step: activity.step,\n ordinal: activity.ordinal,\n kind: activity.kind,\n }\n if (activity.phase !== undefined) normalized.phase = activity.phase\n if (activity.taskId !== undefined) normalized.taskId = redactText(activity.taskId, 128)\n if (activity.toolUseId !== undefined) normalized.toolUseId = redactText(activity.toolUseId, 256)\n if (activity.parentToolUseId !== undefined) normalized.parentToolUseId = redactText(activity.parentToolUseId, 256)\n if (activity.toolName !== undefined) normalized.toolName = redactText(activity.toolName, 256)\n if (activity.title !== undefined) normalized.title = redactText(activity.title, MAX_SUMMARY_CHARS)\n if (activity.summary !== undefined) {\n normalized.summary = redactText(\n typeof activity.summary === 'string' ? activity.summary : safeDetail(activity.summary) ?? '',\n MAX_SUMMARY_CHARS,\n )\n }\n const detail = safeDetail(activity.detail)\n if (detail !== undefined) normalized.detail = detail\n if (activity.text !== undefined) normalized.text = redactText(activity.text, MAX_TRANSCRIPT_TEXT_CHARS)\n if (activity.isError !== undefined) normalized.isError = activity.isError\n if (activity.usage !== undefined) normalized.usage = { ...activity.usage }\n if (isClaudeRenderMode(activity.renderer)) normalized.renderer = activity.renderer\n return normalized\n}\n\nconst MAX_CONTEXT_CATEGORIES = 24\nconst FALLBACK_CONTEXT_COLOR = '#8b95a5'\nconst SAFE_CONTEXT_COLOR = /^#[0-9a-f]{3,8}$/iu\n\nfunction nonNegativeInteger(value: unknown): number {\n return typeof value === 'number' && Number.isFinite(value)\n ? Math.max(0, Math.floor(value))\n : 0\n}\n\nexport function normalizeContextUsage(input: ClaudeContextUsageInput): ClaudeContextUsageEvent {\n return {\n model: redactText(typeof input.model === 'string' ? input.model : 'unknown', 128),\n totalTokens: nonNegativeInteger(input.totalTokens),\n maxTokens: nonNegativeInteger(input.maxTokens),\n percentage: Math.min(100, nonNegativeInteger(input.percentage)),\n categories: input.categories.slice(0, MAX_CONTEXT_CATEGORIES).map(category => ({\n name: redactText(typeof category.name === 'string' ? category.name : 'Unknown', 128),\n tokens: nonNegativeInteger(category.tokens),\n color: typeof category.color === 'string' && SAFE_CONTEXT_COLOR.test(category.color)\n ? category.color\n : FALLBACK_CONTEXT_COLOR,\n ...(category.isDeferred === true ? { isDeferred: true } : {}),\n })),\n }\n}\n\nexport function latestClaudeContextUsage(\n events: readonly SessionEvent[],\n): ClaudeContextUsageEvent | undefined {\n for (let index = events.length - 1; index >= 0; index -= 1) {\n const event = events[index]\n if (event?.type === CLAUDE_CONTEXT_USAGE_EVENT) return event.data as ClaudeContextUsageEvent\n }\n return undefined\n}\n\nexport type ClaudeTaskStatus = 'running' | 'completed' | 'failed' | 'stopped' | 'killed'\n\nexport interface ClaudeTaskUsage {\n totalTokens?: number\n toolUses?: number\n durationMs?: number\n}\n\nexport interface ClaudeTaskInfo {\n taskId: string\n description: string\n status: ClaudeTaskStatus\n /** DSH turn during which this task was first observed, when known. */\n originTurn?: number\n subagentType?: string\n taskType?: string\n lastToolName?: string\n summary?: string\n usage?: ClaudeTaskUsage\n /** True while the task runs detached (background command/subagent). */\n backgrounded?: boolean\n}\n\n/** Level snapshot of one session's Claude task board, REPLACE semantics. */\nexport interface ClaudeTasksEvent {\n tasks: readonly ClaudeTaskInfo[]\n}\n\nconst MAX_TASKS_PER_SNAPSHOT = 50\nconst MAX_TASK_TEXT_CHARS = 300\n\nconst TASK_STATUSES: ReadonlySet<string> = new Set(['running', 'completed', 'failed', 'stopped', 'killed'])\n\nfunction normalizeTaskUsage(input: ClaudeTaskUsage | undefined): ClaudeTaskUsage | undefined {\n if (input === undefined) return undefined\n const usage: ClaudeTaskUsage = {}\n if (input.totalTokens !== undefined) usage.totalTokens = nonNegativeInteger(input.totalTokens)\n if (input.toolUses !== undefined) usage.toolUses = nonNegativeInteger(input.toolUses)\n if (input.durationMs !== undefined) usage.durationMs = nonNegativeInteger(input.durationMs)\n return Object.keys(usage).length === 0 ? undefined : usage\n}\n\nexport function normalizeTasksEvent(tasks: readonly ClaudeTaskInfo[]): ClaudeTasksEvent {\n return {\n tasks: tasks.slice(0, MAX_TASKS_PER_SNAPSHOT).map(task => {\n const usage = normalizeTaskUsage(task.usage)\n return {\n taskId: redactText(String(task.taskId), 128),\n description: redactText(String(task.description), MAX_TASK_TEXT_CHARS),\n status: TASK_STATUSES.has(task.status) ? task.status : 'running',\n ...(task.originTurn === undefined ? {} : { originTurn: nonNegativeInteger(task.originTurn) }),\n ...(task.subagentType === undefined ? {} : { subagentType: redactText(task.subagentType, 64) }),\n ...(task.taskType === undefined ? {} : { taskType: redactText(task.taskType, 64) }),\n ...(task.lastToolName === undefined ? {} : { lastToolName: redactText(task.lastToolName, 64) }),\n ...(task.summary === undefined ? {} : { summary: redactText(task.summary, MAX_TASK_TEXT_CHARS) }),\n ...(usage === undefined ? {} : { usage }),\n ...(task.backgrounded === true ? { backgrounded: true } : {}),\n }\n }),\n }\n}\n\nexport function latestClaudeTasks(\n events: readonly SessionEvent[],\n): ClaudeTasksEvent | undefined {\n for (let index = events.length - 1; index >= 0; index -= 1) {\n const event = events[index]\n if (event?.type === CLAUDE_TASKS_EVENT) return event.data as ClaudeTasksEvent\n }\n return undefined\n}\n\nexport type ClaudeActivityInput = Omit<\n ClaudeActivityEvent,\n 'turn' | 'step' | 'ordinal' | 'summary' | 'detail'\n> & {\n summary?: unknown\n detail?: unknown\n}\n\nexport interface ClaudeActivityCursor {\n turn: number\n step: number\n nextOrdinal: number\n}\n\n/** Derive the current DSH turn/step; activity ordinals are completed from the sidecar. */\nexport function currentClaudeActivityCursor(events: readonly SessionEvent[]): ClaudeActivityCursor {\n let turn = 0\n let step = 0\n for (const event of events) {\n if (event.type !== 'step/start') continue\n const data = event.data as { turn: number; step: number }\n turn = data.turn\n step = data.step\n }\n if (turn < 1 || step < 1) {\n throw new Error('dsh-claude: Claude activity requires an open DSH step')\n }\n return { turn, step, nextOrdinal: 0 }\n}\n\nexport function latestClaudeSessionBinding(\n events: readonly SessionEvent[],\n): ClaudeSessionBoundEvent | undefined {\n for (let index = events.length - 1; index >= 0; index -= 1) {\n const event = events[index]\n if (event?.type === CLAUDE_SESSION_BOUND_EVENT) {\n return event.data as ClaudeSessionBoundEvent\n }\n }\n return undefined\n}\n"],"mappings":"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"}
package/lib/index.d.mts CHANGED
@@ -53,6 +53,11 @@ interface ClaudeUsage {
53
53
  cacheReadTokens?: number;
54
54
  cacheCreationTokens?: number;
55
55
  cumulativeCostUsd?: number;
56
+ /** Wall time from the turn being admitted to it settling. Measured here
57
+ * rather than derived on the client: activities carry no timestamps. */
58
+ durationMs?: number;
59
+ /** Wall time to the first visible token of the turn. */
60
+ ttftMs?: number;
56
61
  }
57
62
  interface ClaudeSessionBoundEvent {
58
63
  claudeSessionId: string;
package/lib/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { A as CLAUDE_UPDATE_CHECK_PATH, C as CLAUDE_REPOSITORY_ACTION_PATH, D as CLAUDE_REPOSITORY_STATUS_PATH, E as CLAUDE_REPOSITORY_SETUP_PATH, F as TASK_TOOL_NAMES, I as isClaudeRenderMode, M as CLAUDE_USAGE_PATH, N as DEFAULT_CLAUDE_RENDER_MODE, O as CLAUDE_REVIEW_COMMENT_PATH, S as CLAUDE_RENDER_MODES, T as CLAUDE_REPOSITORY_FILE_PATH, _ as CLAUDE_DOCTOR_PATH, a as latestClaudeTasks, b as CLAUDE_JIRA_PATH, c as normalizeTasksEvent, d as CLAUDE_ACTIVITY_EVENT, f as CLAUDE_ASK_PATH, g as CLAUDE_CODE_PROVIDER_IDS, h as CLAUDE_CODE_PROVIDER, i as latestClaudeSessionBinding, j as CLAUDE_UPDATE_PATH, k as CLAUDE_REWIND_PATH, l as redactText, m as CLAUDE_CODE_PRESET_ID, n as currentClaudeActivityCursor, o as normalizeActivity, p as CLAUDE_CLIENT_DIAGNOSTICS_PATH, r as latestClaudeContextUsage, s as normalizeContextUsage, t as boundText, u as safeDetail, v as CLAUDE_EDITOR_OPEN_PATH, w as CLAUDE_REPOSITORY_FEEDBACK_PATH, x as CLAUDE_PROJECTION_PATH, y as CLAUDE_GLOBAL_SETTINGS_PATH } from "./events-Doid-tq7.mjs";
2
- import { a as projectClaudeCommands, i as CLAUDE_COMMANDS_SERVICE, r as dynamicPresenterDefinition, t as CLAUDE_PRESENTER_NAMES } from "./presenters-CXtE8qve.mjs";
3
- import { a as resolveClaudeExecutable, n as ensureManagedPreset, o as runClaudeDoctor, t as ManagedPresetConflictError } from "./preset-installer-BMyKr5eQ.mjs";
1
+ import { A as CLAUDE_REWIND_PATH, C as CLAUDE_RENDER_MODES, D as CLAUDE_REPOSITORY_SETUP_PATH, E as CLAUDE_REPOSITORY_FILE_PATH, F as DEFAULT_CLAUDE_RENDER_MODE, L as TASK_TOOL_NAMES, M as CLAUDE_UPDATE_PATH, N as CLAUDE_USAGE_PATH, O as CLAUDE_REPOSITORY_STATUS_PATH, P as DEFAULT_CLAUDE_PROSE_MODE, R as isClaudeProseMode, S as CLAUDE_PROSE_MODES, T as CLAUDE_REPOSITORY_FEEDBACK_PATH, _ as CLAUDE_DOCTOR_PATH, a as latestClaudeTasks, b as CLAUDE_JIRA_PATH, c as normalizeTasksEvent, d as CLAUDE_ACTIVITY_EVENT, f as CLAUDE_ASK_PATH, g as CLAUDE_CODE_PROVIDER_IDS, h as CLAUDE_CODE_PROVIDER, i as latestClaudeSessionBinding, j as CLAUDE_UPDATE_CHECK_PATH, k as CLAUDE_REVIEW_COMMENT_PATH, l as redactText, m as CLAUDE_CODE_PRESET_ID, n as currentClaudeActivityCursor, o as normalizeActivity, p as CLAUDE_CLIENT_DIAGNOSTICS_PATH, r as latestClaudeContextUsage, s as normalizeContextUsage, t as boundText, u as safeDetail, v as CLAUDE_EDITOR_OPEN_PATH, w as CLAUDE_REPOSITORY_ACTION_PATH, x as CLAUDE_PROJECTION_PATH, y as CLAUDE_GLOBAL_SETTINGS_PATH, z as isClaudeRenderMode } from "./events-OhBoFNKO.mjs";
2
+ import { a as projectClaudeCommands, i as CLAUDE_COMMANDS_SERVICE, r as dynamicPresenterDefinition, t as CLAUDE_PRESENTER_NAMES } from "./presenters-BBoM1Ju1.mjs";
3
+ import { a as resolveClaudeExecutable, n as ensureManagedPreset, o as runClaudeDoctor, t as ManagedPresetConflictError } from "./preset-installer-loenwnLS.mjs";
4
4
  import z from "@deepseek-ai/schemastery";
5
5
  import { createHash, randomUUID } from "node:crypto";
6
6
  import { chmod, mkdir, opendir, readFile, realpath, rename, rm, stat, writeFile } from "node:fs/promises";
@@ -1610,9 +1610,11 @@ var ClaudeSupervisor = class {
1610
1610
  transcriptTextOrdinal: void 0,
1611
1611
  thinking: "",
1612
1612
  requestUsage: void 0,
1613
+ startedAt: Date.now(),
1614
+ firstOutputAt: void 0,
1613
1615
  aborted: false,
1614
1616
  deniedToolUseIds: /* @__PURE__ */ new Set(),
1615
- callNames: /* @__PURE__ */ new Map(),
1617
+ openCalls: /* @__PURE__ */ new Map(),
1616
1618
  ...request.signal === void 0 ? {} : { signal: request.signal }
1617
1619
  };
1618
1620
  entry.active = active;
@@ -1898,6 +1900,7 @@ var ClaudeSupervisor = class {
1898
1900
  active.text += message.text;
1899
1901
  active.transcriptText += message.text;
1900
1902
  await this.#upsertTranscriptText(active);
1903
+ active.firstOutputAt ??= Date.now();
1901
1904
  active.output.push({
1902
1905
  type: "text-delta",
1903
1906
  text: message.text
@@ -1910,6 +1913,7 @@ var ClaudeSupervisor = class {
1910
1913
  active.text += message.text;
1911
1914
  active.transcriptText += message.text;
1912
1915
  await this.#upsertTranscriptText(active);
1916
+ active.firstOutputAt ??= Date.now();
1913
1917
  active.output.push({
1914
1918
  type: "text-delta",
1915
1919
  text: message.text
@@ -1947,7 +1951,7 @@ var ClaudeSupervisor = class {
1947
1951
  detail: message.input
1948
1952
  });
1949
1953
  if (message.parentToolUseId === void 0) {
1950
- active.callNames.set(message.toolUseId, message.toolName);
1954
+ active.openCalls.set(message.toolUseId, message.toolName);
1951
1955
  if (this.#nativeRendering()) {
1952
1956
  this.#ensureDynamicPresenter(active.agent, message.toolName);
1953
1957
  await this.#appendNativeToolCall(active, message);
@@ -1955,6 +1959,7 @@ var ClaudeSupervisor = class {
1955
1959
  }
1956
1960
  return;
1957
1961
  case "tool-result":
1962
+ active.openCalls.delete(message.toolUseId);
1958
1963
  await this.#appendActivity(active, {
1959
1964
  kind: message.parentToolUseId === void 0 ? "tool-result" : "subagent",
1960
1965
  phase: message.isError ? "failed" : "completed",
@@ -2023,6 +2028,17 @@ var ClaudeSupervisor = class {
2023
2028
  return;
2024
2029
  }
2025
2030
  }
2031
+ /** The turn's accounting with its wall clock attached. The transcript draws
2032
+ * this line itself under the plugin renderer: activities carry no
2033
+ * timestamps, so a duration it did not measure is a duration nobody has. */
2034
+ #timedUsage(active, usage) {
2035
+ const now = Date.now();
2036
+ return {
2037
+ ...usage,
2038
+ durationMs: Math.max(0, now - active.startedAt),
2039
+ ...active.firstOutputAt === void 0 ? {} : { ttftMs: Math.max(0, active.firstOutputAt - active.startedAt) }
2040
+ };
2041
+ }
2026
2042
  #nativeRendering() {
2027
2043
  return (this.#config.renderMode ?? "plugin") === "native";
2028
2044
  }
@@ -2214,7 +2230,7 @@ var ClaudeSupervisor = class {
2214
2230
  phase: "completed",
2215
2231
  title: "Claude usage",
2216
2232
  summary: usageSummary(result.usage),
2217
- usage: result.usage
2233
+ usage: this.#timedUsage(active, result.usage)
2218
2234
  });
2219
2235
  active.output.push({
2220
2236
  type: "usage",
@@ -2245,6 +2261,7 @@ var ClaudeSupervisor = class {
2245
2261
  if (active.aborted) {
2246
2262
  await this.#upsertTranscriptText(active);
2247
2263
  await this.#flushTranscript(active);
2264
+ await this.#settleOpenCalls(active, "Cancelled with the turn");
2248
2265
  await this.#appendSafely(active, {
2249
2266
  kind: "status",
2250
2267
  phase: "failed",
@@ -2264,7 +2281,7 @@ var ClaudeSupervisor = class {
2264
2281
  phase: "completed",
2265
2282
  title: "Claude usage",
2266
2283
  summary: usageSummary(result.usage),
2267
- usage: result.usage
2284
+ usage: this.#timedUsage(active, result.usage)
2268
2285
  });
2269
2286
  active.output.push({
2270
2287
  type: "usage",
@@ -2408,6 +2425,33 @@ var ClaudeSupervisor = class {
2408
2425
  this.#interruptions.set(entry.sessionId, interruption);
2409
2426
  return interruption;
2410
2427
  }
2428
+ /** Close out the root tool calls a turn is ending without answers for.
2429
+ *
2430
+ * A tool result is the only thing that ever settles a call, and a turn that
2431
+ * is cancelled or disconnected produces none: the transcript would keep
2432
+ * drawing those calls as running for as long as the session lives, and no
2433
+ * later event would ever correct it. Written as the failures they are. */
2434
+ async #settleOpenCalls(active, summary) {
2435
+ const open = [...active.openCalls];
2436
+ active.openCalls.clear();
2437
+ for (const [toolUseId, toolName] of open) {
2438
+ await this.#appendSafely(active, {
2439
+ kind: "tool-result",
2440
+ phase: "failed",
2441
+ toolUseId,
2442
+ toolName,
2443
+ title: "Tool cancelled",
2444
+ summary,
2445
+ isError: true
2446
+ });
2447
+ if (this.#nativeRendering()) await this.#appendNativeToolResult(active, {
2448
+ kind: "tool-result",
2449
+ toolUseId,
2450
+ output: summary,
2451
+ isError: true
2452
+ });
2453
+ }
2454
+ }
2411
2455
  async #interrupt(entry) {
2412
2456
  const active = entry.active;
2413
2457
  if (active === void 0 || entry.state === "interrupting") return;
@@ -2421,6 +2465,7 @@ var ClaudeSupervisor = class {
2421
2465
  } catch (error) {
2422
2466
  interruptError = error;
2423
2467
  }
2468
+ await this.#settleOpenCalls(active, "Cancelled with the turn").catch(() => void 0);
2424
2469
  try {
2425
2470
  await this.#appendActivity(active, {
2426
2471
  kind: "status",
@@ -2442,6 +2487,7 @@ var ClaudeSupervisor = class {
2442
2487
  const unknown = active.sawActivity;
2443
2488
  entry.state = unknown ? "outcome-unknown" : "disconnected";
2444
2489
  const failure = unknown ? new ClaudeOutcomeUnknownError(stderr === void 0 || stderr.length === 0 ? void 0 : `Claude Code exited after activity; outcome unknown. ${stderr}`) : new Error(stderr === void 0 || stderr.length === 0 ? errorSummary(error) : stderr);
2490
+ await this.#settleOpenCalls(active, "Claude Code stopped before the tool answered").catch(() => void 0);
2445
2491
  await this.#appendSafely(active, {
2446
2492
  kind: "error",
2447
2493
  phase: "failed",
@@ -7258,6 +7304,32 @@ const RENDERER = {
7258
7304
  else document.renderer = value;
7259
7305
  }
7260
7306
  };
7307
+ /** Whether Claude's prose gets the highlight palette. Presentation only: no
7308
+ * record carries it and nothing on the server reads it back, so unlike
7309
+ * {@link RENDERER} the switch lands the moment the Client rewrites its own
7310
+ * stylesheet — hence 'immediate' rather than 'next-turn'. */
7311
+ const PROSE = {
7312
+ key: "prose",
7313
+ kind: "select",
7314
+ document: "plugin",
7315
+ effect: "immediate",
7316
+ async options() {
7317
+ return CLAUDE_PROSE_MODES.map((value) => ({
7318
+ value,
7319
+ label: value,
7320
+ source: "built-in"
7321
+ }));
7322
+ },
7323
+ read(document) {
7324
+ const value = document.prose;
7325
+ return isClaudeProseMode(value) ? value : DEFAULT_CLAUDE_PROSE_MODE;
7326
+ },
7327
+ apply(document, value) {
7328
+ if (!isClaudeProseMode(value)) throw new Error("Invalid value for global setting prose");
7329
+ if (value === "plain") delete document.prose;
7330
+ else document.prose = value;
7331
+ }
7332
+ };
7261
7333
  function isBoundedInteger(value, min, max) {
7262
7334
  return typeof value === "number" && Number.isInteger(value) && value >= min && value <= max;
7263
7335
  }
@@ -7282,6 +7354,7 @@ function integerSetting(key, min, max, defaultFor) {
7282
7354
  const DESCRIPTORS = [
7283
7355
  OUTPUT_STYLE,
7284
7356
  RENDERER,
7357
+ PROSE,
7285
7358
  WORKTREE_BRANCH_PREFIX,
7286
7359
  integerSetting("maxProcesses", 1, MAX_PROCESSES_LIMIT, (limits) => limits.maxProcesses),
7287
7360
  integerSetting("idleTimeoutMinutes", 1, MAX_IDLE_TIMEOUT_MINUTES, (limits) => Math.max(1, Math.round(limits.idleTimeoutMs / 6e4)))