@norman-else/dsh-claude 0.1.52 → 0.1.54

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.
@@ -23,6 +23,7 @@ const CLAUDE_REPOSITORY_FILE_PATH = "/plugins/dsh-claude/repository/file";
23
23
  const CLAUDE_JIRA_PATH = "/plugins/dsh-claude/jira";
24
24
  const CLAUDE_ASK_PATH = "/plugins/dsh-claude/ask";
25
25
  const CLAUDE_REWIND_PATH = "/plugins/dsh-claude/rewind";
26
+ const CLAUDE_PERMISSION_MODE_PATH = "/plugins/dsh-claude/permission-mode";
26
27
  const CLAUDE_PLAN_FEEDBACK_PATH = "/plugins/dsh-claude/plan/feedback";
27
28
  const CLAUDE_PROMPTS_PATH = "/plugins/dsh-claude/prompts";
28
29
  const CLAUDE_PROMPT_NAME_PATH = "/plugins/dsh-claude/prompts/name";
@@ -211,6 +212,6 @@ function latestClaudeSessionBinding(events) {
211
212
  }
212
213
  }
213
214
  //#endregion
214
- export { CLAUDE_REPOSITORY_FILE_PATH as A, SDK_VERSION as B, CLAUDE_PROMPTS_PATH as C, CLAUDE_RENDER_MODES as D, CLAUDE_PROSE_MODES as E, CLAUDE_UPDATE_CHECK_PATH as F, isClaudeAlertMode as H, CLAUDE_UPDATE_PATH as I, CLAUDE_USAGE_PATH as L, CLAUDE_REPOSITORY_STATUS_PATH as M, CLAUDE_REVIEW_COMMENT_PATH as N, CLAUDE_REPOSITORY_ACTION_PATH as O, CLAUDE_REWIND_PATH as P, DEFAULT_CLAUDE_PROSE_MODE as R, CLAUDE_PROJECTION_PATH as S, CLAUDE_PROMPT_REFINE_PATH as T, isClaudeProseMode as U, TASK_TOOL_NAMES as V, isClaudeRenderMode as W, CLAUDE_CODE_PROVIDER_IDS as _, latestClaudeTasks as a, CLAUDE_JIRA_PATH as b, normalizeTasksEvent as c, CLAUDE_ACTIVITY_EVENT as d, CLAUDE_ALERT_MODES as f, CLAUDE_CODE_PROVIDER as g, CLAUDE_CODE_PRESET_ID as h, latestClaudeSessionBinding as i, CLAUDE_REPOSITORY_SETUP_PATH as j, CLAUDE_REPOSITORY_FEEDBACK_PATH as k, redactText as l, CLAUDE_CLIENT_DIAGNOSTICS_PATH as m, currentClaudeActivityCursor as n, normalizeActivity as o, CLAUDE_ASK_PATH as p, latestClaudeContextUsage as r, normalizeContextUsage as s, boundText as t, safeDetail as u, CLAUDE_DOCTOR_PATH as v, CLAUDE_PROMPT_NAME_PATH as w, CLAUDE_PLAN_FEEDBACK_PATH as x, CLAUDE_GLOBAL_SETTINGS_PATH as y, DEFAULT_CLAUDE_RENDER_MODE as z };
215
+ export { CLAUDE_REPOSITORY_FEEDBACK_PATH as A, DEFAULT_CLAUDE_RENDER_MODE as B, CLAUDE_PROJECTION_PATH as C, CLAUDE_PROSE_MODES as D, CLAUDE_PROMPT_REFINE_PATH as E, CLAUDE_REWIND_PATH as F, isClaudeRenderMode as G, TASK_TOOL_NAMES as H, CLAUDE_UPDATE_CHECK_PATH as I, CLAUDE_UPDATE_PATH as L, CLAUDE_REPOSITORY_SETUP_PATH as M, CLAUDE_REPOSITORY_STATUS_PATH as N, CLAUDE_RENDER_MODES as O, CLAUDE_REVIEW_COMMENT_PATH as P, CLAUDE_USAGE_PATH as R, CLAUDE_PLAN_FEEDBACK_PATH as S, CLAUDE_PROMPT_NAME_PATH as T, isClaudeAlertMode as U, SDK_VERSION as V, isClaudeProseMode as W, CLAUDE_CODE_PROVIDER_IDS as _, latestClaudeTasks as a, CLAUDE_JIRA_PATH as b, normalizeTasksEvent as c, CLAUDE_ACTIVITY_EVENT as d, CLAUDE_ALERT_MODES as f, CLAUDE_CODE_PROVIDER as g, CLAUDE_CODE_PRESET_ID as h, latestClaudeSessionBinding as i, CLAUDE_REPOSITORY_FILE_PATH as j, CLAUDE_REPOSITORY_ACTION_PATH as k, redactText as l, CLAUDE_CLIENT_DIAGNOSTICS_PATH as m, currentClaudeActivityCursor as n, normalizeActivity as o, CLAUDE_ASK_PATH as p, latestClaudeContextUsage as r, normalizeContextUsage as s, boundText as t, safeDetail as u, CLAUDE_DOCTOR_PATH as v, CLAUDE_PROMPTS_PATH as w, CLAUDE_PERMISSION_MODE_PATH as x, CLAUDE_GLOBAL_SETTINGS_PATH as y, DEFAULT_CLAUDE_PROSE_MODE as z };
215
216
 
216
- //# sourceMappingURL=events-B498uofA.mjs.map
217
+ //# sourceMappingURL=events-QGz0a_LH.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events-QGz0a_LH.mjs","names":[],"sources":["../src/constants.ts","../src/events.ts"],"sourcesContent":["export const CLAUDE_CODE_PROVIDER = 'claude'\r\nexport const CLAUDE_CODE_PRESET_ID = 'claude'\r\nexport const CLAUDE_CODE_PROVIDER_IDS = [CLAUDE_CODE_PROVIDER] as const\r\nexport const CLAUDE_SESSION_BOUND_EVENT = 'claude-code/session-bound'\r\nexport const CLAUDE_ACTIVITY_EVENT = 'claude-code/activity'\r\nexport const CLAUDE_CONTEXT_USAGE_EVENT = 'claude-code/context-usage'\r\nexport const CLAUDE_TASKS_EVENT = 'claude-code/tasks'\r\n/** Claude's subagent dispatch tools; rendered as plugin-owned group cards\r\n * gathering subagent activity instead of native tool cards. */\r\nexport const TASK_TOOL_NAMES: ReadonlySet<string> = new Set(['Task', 'Agent'])\r\nexport const SDK_VERSION = '0.3.247'\r\nexport const CLAUDE_DOCTOR_PATH = '/plugins/dsh-claude/doctor'\r\nexport const CLAUDE_CLIENT_DIAGNOSTICS_PATH = '/plugins/dsh-claude/client-diagnostics'\r\nexport const CLAUDE_UPDATE_CHECK_PATH = '/plugins/dsh-claude/update/check'\r\nexport const CLAUDE_USAGE_PATH = '/plugins/dsh-claude/usage'\r\nexport const CLAUDE_UPDATE_PATH = '/plugins/dsh-claude/update'\r\nexport const CLAUDE_PROJECTION_PATH = '/plugins/dsh-claude/projection'\r\nexport const CLAUDE_GLOBAL_SETTINGS_PATH = '/plugins/dsh-claude/settings/global'\r\nexport const CLAUDE_REPOSITORY_SETUP_PATH = '/plugins/dsh-claude/repository/setup'\r\nexport const CLAUDE_REPOSITORY_ACTION_PATH = '/plugins/dsh-claude/repository/action'\r\nexport const CLAUDE_REVIEW_COMMENT_PATH = '/plugins/dsh-claude/review-comments'\r\nexport const CLAUDE_REPOSITORY_FEEDBACK_PATH = '/plugins/dsh-claude/repository/feedback'\r\nexport const CLAUDE_REPOSITORY_STATUS_PATH = '/plugins/dsh-claude/repository/status'\r\nexport const CLAUDE_REPOSITORY_FILE_PATH = '/plugins/dsh-claude/repository/file'\r\nexport const CLAUDE_JIRA_PATH = '/plugins/dsh-claude/jira'\r\nexport const CLAUDE_ASK_PATH = '/plugins/dsh-claude/ask'\r\nexport const CLAUDE_REWIND_PATH = '/plugins/dsh-claude/rewind'\r\nexport const CLAUDE_PERMISSION_MODE_PATH = '/plugins/dsh-claude/permission-mode'\r\nexport const CLAUDE_PLAN_FEEDBACK_PATH = '/plugins/dsh-claude/plan/feedback'\r\nexport const CLAUDE_PROMPTS_PATH = '/plugins/dsh-claude/prompts'\r\nexport const CLAUDE_PROMPT_NAME_PATH = '/plugins/dsh-claude/prompts/name'\r\nexport const CLAUDE_PROMPT_REFINE_PATH = '/plugins/dsh-claude/prompts/refine'\r\n\r\n/** Which renderer draws Claude's visible output.\r\n *\r\n * 'plugin' keeps the sidecar-backed transcript this package owns (interleaved\r\n * prose, grouped tool cards, activity rows). 'native' hands the same turn to\r\n * DSH's own conversation renderer: prose streams as ordinary assistant text\r\n * blocks, thinking as reasoning blocks, and root Claude tools are mirrored\r\n * into the durable `tool/call`/`tool/result` channel so the Host's tool\r\n * presentation pipeline draws them exactly like DSH-executed calls. */\r\nexport type ClaudeRenderMode = 'plugin' | 'native'\r\nexport const CLAUDE_RENDER_MODES = ['plugin', 'native'] as const\r\nexport const DEFAULT_CLAUDE_RENDER_MODE: ClaudeRenderMode = 'plugin'\r\n\r\nexport function isClaudeRenderMode(value: unknown): value is ClaudeRenderMode {\r\n return value === 'plugin' || value === 'native'\r\n}\r\n\r\n/** How this package paints the PROSE of a Claude answer.\r\n *\r\n * 'plain' is Claude's own presentation: body text in the Host's text colour,\r\n * colour reserved for code. 'enhanced' gives headings, emphasis, list markers,\r\n * quotes and links their own hues and darkens the code surface — the way a\r\n * Markdown-highlighting editor shows a document rather than the way Claude\r\n * desktop shows an answer. It is opt-in because it deliberately breaks the\r\n * parity the rest of `markdown-theme.ts` exists to hold.\r\n *\r\n * Only meaningful under {@link ClaudeRenderMode} 'plugin': the stylesheet is\r\n * scoped to markup this package renders, and 'native' turns are drawn by the\r\n * Host, where it has no reach. */\r\nexport type ClaudeProseMode = 'plain' | 'enhanced'\r\nexport const CLAUDE_PROSE_MODES = ['plain', 'enhanced'] as const\r\nexport const DEFAULT_CLAUDE_PROSE_MODE: ClaudeProseMode = 'plain'\r\n\r\nexport function isClaudeProseMode(value: unknown): value is ClaudeProseMode {\r\n return value === 'plain' || value === 'enhanced'\r\n}\r\n\r\n/** Whether a session that needs the user raises a desktop notification while\r\n * the user is looking at another session. Client-side presentation, like\r\n * {@link ClaudeProseMode}: nothing on the server reads it back. */\r\nexport type ClaudeAlertMode = 'off' | 'on'\r\nexport const CLAUDE_ALERT_MODES = ['off', 'on'] as const\r\nexport const DEFAULT_CLAUDE_ALERT_MODE: ClaudeAlertMode = 'on'\r\n\r\nexport function isClaudeAlertMode(value: unknown): value is ClaudeAlertMode {\r\n return value === 'off' || value === 'on'\r\n}\r\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
@@ -31,6 +31,20 @@ interface ClaudeCommandView {
31
31
  prefixed: boolean;
32
32
  }
33
33
  //#endregion
34
+ //#region src/permission-mode.d.ts
35
+ /** Every mode the selector offers, in the order it lists them: tightest
36
+ * first. `auto` hands each ask to Claude Code's own classifier and is a
37
+ * per-model capability, so the selector greys it out where the catalog says
38
+ * the session's model lacks it. */
39
+ declare const CLAUDE_PERMISSION_MODES: readonly ["plan", "default", "acceptEdits", "dontAsk", "auto", "bypassPermissions"];
40
+ type ClaudePermissionMode = typeof CLAUDE_PERMISSION_MODES[number];
41
+ /** Which access control a Claude session shows and obeys: the Host's own
42
+ * three-preset selector with the sandbox mapping alone (`native`), or this
43
+ * plugin's selector over Claude Code's modes with the default mode and the
44
+ * creation-time alignment (`plugin`). */
45
+ declare const CLAUDE_PERMISSION_SELECTORS: readonly ["plugin", "native"];
46
+ type ClaudePermissionSelector = typeof CLAUDE_PERMISSION_SELECTORS[number];
47
+ //#endregion
34
48
  //#region src/constants.d.ts
35
49
  /** Which renderer draws Claude's visible output.
36
50
  *
@@ -196,6 +210,9 @@ interface ClaudeSidecarProjection {
196
210
  readonly contextUsage?: ClaudeContextUsageEvent;
197
211
  readonly tasks?: ClaudeTasksEvent;
198
212
  readonly rewind?: ClaudeRewindState;
213
+ /** The Claude permission mode the user picked in this plugin's selector;
214
+ * see permission-mode.ts for how it folds with the Host's sandbox mode. */
215
+ readonly permissionMode?: ClaudePermissionMode;
199
216
  }
200
217
  /** Change notification published to live subscribers after each accepted write.
201
218
  *
@@ -275,6 +292,9 @@ declare class ClaudeSidecarRepository {
275
292
  ordinal: number;
276
293
  }): Promise<ClaudeSidecarProjection>;
277
294
  writeContextUsage(sessionId: string, value: ClaudeContextUsageInput): Promise<ClaudeSidecarProjection>;
295
+ /** Record the mode the selector picked. No delta: the projection carries
296
+ * it as metadata, which the carrier refreshes on its own cadence. */
297
+ writePermissionMode(sessionId: string, mode: ClaudePermissionMode): Promise<ClaudeSidecarProjection>;
278
298
  writeTasks(sessionId: string, value: readonly ClaudeTaskInfo[]): Promise<ClaudeSidecarProjection>;
279
299
  /** Land one planned rewind: hidden ranges, surviving anchors, and the fork
280
300
  * target the next Claude spawn consumes.
@@ -393,6 +413,12 @@ declare class ClaudeSupervisor {
393
413
  queryFactory?: ClaudeQueryFactory;
394
414
  runDetached?: <T>(operation: () => T) => T;
395
415
  sidecar?: ClaudeSidecarRepository;
416
+ /** The mode a session runs under until it chooses one; absent, the DSH
417
+ * sandbox alone decides (see permission-mode.ts). */
418
+ defaultPermissionMode?: () => Promise<ClaudePermissionMode | undefined>;
419
+ /** Which access control the session obeys; `native` ignores both the
420
+ * session's recorded choice and the default and reads the sandbox alone. */
421
+ permissionSelector?: () => Promise<ClaudePermissionSelector>;
396
422
  });
397
423
  snapshots(): ClaudeSupervisorSnapshot[];
398
424
  supportedCommands(agent: Agent, model?: string): Promise<readonly SlashCommand[]>;