@allternit/gizzi-code 1.0.0 → 1.0.1

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.
Files changed (158) hide show
  1. package/bin/gizzi +4 -0
  2. package/bin/gizzi-ink +5 -0
  3. package/package.json +137 -31
  4. package/src/Tool.ts +26 -0
  5. package/src/bootstrap/state.ts +165 -322
  6. package/src/commands.ts +209 -0
  7. package/src/context/QueuedMessageContext.tsx +63 -0
  8. package/src/context/fpsMetrics.tsx +30 -0
  9. package/src/context/mailbox.tsx +38 -0
  10. package/src/context/modalContext.tsx +58 -0
  11. package/src/context/notifications.tsx +240 -0
  12. package/src/context/overlayContext.tsx +151 -0
  13. package/src/context/promptOverlayContext.tsx +125 -0
  14. package/src/context/stats.tsx +220 -0
  15. package/src/context/voice.tsx +88 -0
  16. package/src/hooks/useCanUseTool.ts +11 -0
  17. package/src/hooks/useExitOnCtrlCD.ts +40 -187
  18. package/src/hooks/useExitOnCtrlCDWithKeybindings.ts +68 -0
  19. package/src/hooks/useKeybinding.ts +68 -209
  20. package/src/hooks/useTerminalSize.ts +31 -99
  21. package/src/hooks.ts +37 -0
  22. package/src/ink.ts +204 -0
  23. package/src/main.ts +7 -0
  24. package/src/types/command.ts +216 -0
  25. package/src/types/connectorText.ts +39 -0
  26. package/src/types/fileSuggestion.ts +15 -0
  27. package/src/types/generated/events_mono/claude_code/v1/claude_code_internal_event.ts +865 -0
  28. package/src/types/generated/events_mono/common/v1/auth.ts +100 -0
  29. package/src/types/generated/events_mono/growthbook/v1/growthbook_experiment_event.ts +223 -0
  30. package/src/types/generated/google/protobuf/timestamp.ts +187 -0
  31. package/src/types/hooks.ts +319 -0
  32. package/src/types/ids.ts +44 -0
  33. package/src/types/logs.ts +331 -0
  34. package/src/types/merged/index.ts +5 -0
  35. package/src/types/merged/message.ts +552 -0
  36. package/src/types/message.ts +927 -186
  37. package/src/types/messageQueueTypes.ts +21 -0
  38. package/src/types/notebook.ts +72 -0
  39. package/src/types/permissions.ts +447 -0
  40. package/src/types/plugin.ts +363 -0
  41. package/src/types/statusLine.ts +15 -0
  42. package/src/types/textInputTypes.ts +387 -0
  43. package/src/types/tools.ts +149 -0
  44. package/src/types/utils.ts +20 -0
  45. package/src/utils/advisor.ts +12 -0
  46. package/src/utils/api.ts +29 -0
  47. package/src/utils/array.ts +7 -0
  48. package/src/utils/attachments.ts +60 -0
  49. package/src/utils/auth.ts +3 -0
  50. package/src/utils/claudeInChrome/chromeNativeHost.ts +15 -0
  51. package/src/utils/claudeInChrome/common.ts +12 -0
  52. package/src/utils/claudeInChrome/mcpServer.ts +15 -0
  53. package/src/utils/computerUse/common.ts +19 -0
  54. package/src/utils/computerUse/mcpServer.ts +15 -0
  55. package/src/utils/config.ts +35 -0
  56. package/src/utils/context.ts +19 -0
  57. package/src/utils/cwd.ts +3 -0
  58. package/src/utils/debug.ts +3 -0
  59. package/src/utils/earlyInput.ts +7 -0
  60. package/src/utils/effort.ts +13 -0
  61. package/src/utils/embeddedTools.ts +12 -0
  62. package/src/utils/envUtils.ts +3 -0
  63. package/src/utils/errors.ts +3 -0
  64. package/src/utils/execFileNoThrow.ts +24 -0
  65. package/src/utils/feature-flags.ts +112 -0
  66. package/src/utils/file.ts +3 -0
  67. package/src/utils/fileHistory.ts +17 -0
  68. package/src/utils/fingerprint.ts +7 -0
  69. package/src/utils/format.ts +75 -305
  70. package/src/utils/frontmatterParser.ts +33 -0
  71. package/src/utils/fsOperations.ts +31 -0
  72. package/src/utils/fullscreen.ts +40 -350
  73. package/src/utils/git.ts +15 -0
  74. package/src/utils/imageResizer.ts +30 -0
  75. package/src/utils/lazySchema.ts +9 -0
  76. package/src/utils/log.ts +3 -0
  77. package/src/utils/markdownConfigLoader.ts +12 -0
  78. package/src/utils/messages.ts +13 -0
  79. package/src/utils/migration.ts +137 -0
  80. package/src/utils/model/providers.ts +15 -0
  81. package/src/utils/path.ts +3 -0
  82. package/src/utils/permissions/PermissionResult.ts +14 -0
  83. package/src/utils/permissions/autoModeState.ts +12 -0
  84. package/src/utils/permissions/filesystem.ts +12 -0
  85. package/src/utils/plugins/loadPluginOutputStyles.ts +12 -0
  86. package/src/utils/plugins/schemas.ts +25 -0
  87. package/src/utils/process.ts +16 -0
  88. package/src/utils/sandbox/sandbox-adapter.ts +19 -0
  89. package/src/utils/sessionStorage.ts +238 -472
  90. package/src/utils/settings/constants.ts +10 -0
  91. package/src/utils/settings/settings.ts +19 -0
  92. package/src/utils/settings/types.ts +18 -0
  93. package/src/utils/shell/shellToolUtils.ts +9 -0
  94. package/src/utils/sinks.ts +11 -0
  95. package/src/utils/sleep.ts +7 -0
  96. package/src/utils/sliceAnsi.ts +7 -0
  97. package/src/utils/slowOperations.ts +3 -0
  98. package/src/utils/startupProfiler.ts +11 -0
  99. package/src/utils/stringUtils.ts +106 -0
  100. package/src/utils/systemPromptType.ts +9 -0
  101. package/src/utils/teleport/api.ts +15 -0
  102. package/src/utils/textHighlighting.ts +16 -0
  103. package/src/utils/theme.ts +17 -0
  104. package/src/utils/thinking.ts +58 -0
  105. package/src/utils/tokens.ts +11 -0
  106. package/src/utils/toolResultStorage.ts +17 -0
  107. package/src/utils/worktreeModeEnabled.ts +7 -0
  108. package/WORKSPACE_INTEGRATION.md +0 -290
  109. package/chat-sessions/sessions-index.json +0 -98
  110. package/package.json.original +0 -31
  111. package/package.json.publish +0 -47
  112. package/src/bootstrap/state.d.ts +0 -169
  113. package/src/bootstrap/state.js +0 -261
  114. package/src/context/pack-builder.d.ts +0 -24
  115. package/src/context/pack-builder.js +0 -281
  116. package/src/hooks/useExitOnCtrlCD.d.ts +0 -86
  117. package/src/hooks/useExitOnCtrlCD.js +0 -130
  118. package/src/hooks/useKeybinding.d.ts +0 -89
  119. package/src/hooks/useKeybinding.js +0 -163
  120. package/src/hooks/useTerminalSize.d.ts +0 -41
  121. package/src/hooks/useTerminalSize.js +0 -90
  122. package/src/index.d.ts +0 -23
  123. package/src/index.js +0 -24
  124. package/src/runtime/brand/brand.d.ts +0 -488
  125. package/src/runtime/brand/brand.js +0 -464
  126. package/src/runtime/brand/brand.ts +0 -667
  127. package/src/runtime/services/tokenEstimation.d.ts +0 -187
  128. package/src/runtime/services/tokenEstimation.js +0 -423
  129. package/src/runtime/services/tokenEstimation.ts +0 -547
  130. package/src/runtime/tools/Tool.d.ts +0 -239
  131. package/src/runtime/tools/Tool.js +0 -285
  132. package/src/runtime/tools/Tool.ts +0 -524
  133. package/src/scheduler/TaskScheduler.d.ts +0 -98
  134. package/src/scheduler/TaskScheduler.js +0 -201
  135. package/src/scheduler/TaskScheduler.ts +0 -259
  136. package/src/state/AppStateStore.d.ts +0 -347
  137. package/src/state/AppStateStore.js +0 -439
  138. package/src/state/AppStateStore.ts +0 -658
  139. package/src/state/WorkspaceStateStore.d.ts +0 -43
  140. package/src/state/WorkspaceStateStore.js +0 -224
  141. package/src/state/WorkspaceStateStore.ts +0 -297
  142. package/src/types/message.d.ts +0 -190
  143. package/src/types/message.js +0 -77
  144. package/src/utils/format.d.ts +0 -126
  145. package/src/utils/format.js +0 -230
  146. package/src/utils/fullscreen.d.ts +0 -161
  147. package/src/utils/fullscreen.js +0 -277
  148. package/src/utils/sessionStorage.d.ts +0 -210
  149. package/src/utils/sessionStorage.js +0 -435
  150. package/src/watcher/WorkspaceWatcher.d.ts +0 -70
  151. package/src/watcher/WorkspaceWatcher.js +0 -191
  152. package/src/watcher/WorkspaceWatcher.ts +0 -251
  153. package/src/workspace/loader.d.ts +0 -30
  154. package/src/workspace/loader.js +0 -117
  155. package/src/workspace/types.d.ts +0 -91
  156. package/src/workspace/types.js +0 -7
  157. package/threads/thread_1775361175022.json +0 -9
  158. package/tsconfig.json +0 -14
@@ -0,0 +1,319 @@
1
+ // @ts-nocheck
2
+ // biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
3
+ import { z } from 'zod/v4'
4
+ import { lazySchema } from '../utils/lazySchema.js'
5
+ import {
6
+ type HookEvent,
7
+ HOOK_EVENTS,
8
+ type HookInput,
9
+ type PermissionUpdate,
10
+ } from '../../entrypoints/agentSdkTypes.js'
11
+ import type {
12
+ HookJSONOutput,
13
+ AsyncHookJSONOutput,
14
+ SyncHookJSONOutput,
15
+ } from '../../entrypoints/agentSdkTypes.js'
16
+ import type { Message } from '@/types/message.js'
17
+ import type { PermissionResult } from '../../utils/permissions/PermissionResult.js'
18
+ import { permissionBehaviorSchema } from '../../utils/permissions/PermissionRule.js'
19
+ import { permissionUpdateSchema } from '../../utils/permissions/PermissionUpdateSchema.js'
20
+ import type { AppState } from '@/state/AppState.js'
21
+ import type { AttributionState } from '../utils/commitAttribution.js'
22
+
23
+ export function isHookEvent(value: string): value is HookEvent {
24
+ return HOOK_EVENTS.includes(value as HookEvent)
25
+ }
26
+
27
+ // Prompt elicitation protocol types. The `prompt` key acts as discriminator
28
+ // (mirroring the {async:true} pattern), with the id as its value.
29
+ export const promptRequestSchema = lazySchema(() =>
30
+ z.object({
31
+ prompt: z.string(), // request id
32
+ message: z.string(),
33
+ options: z.array(
34
+ z.object({
35
+ key: z.string(),
36
+ label: z.string(),
37
+ description: z.string().optional(),
38
+ }),
39
+ ),
40
+ }),
41
+ )
42
+
43
+ export type PromptRequest = z.infer<ReturnType<typeof promptRequestSchema>>
44
+
45
+ export type PromptResponse = {
46
+ prompt_response: string // request id
47
+ selected: string
48
+ }
49
+
50
+ // Sync hook response schema
51
+ export const syncHookResponseSchema = lazySchema(() =>
52
+ z.object({
53
+ continue: z
54
+ .boolean()
55
+ .describe('Whether Claude should continue after hook (default: true)')
56
+ .optional(),
57
+ suppressOutput: z
58
+ .boolean()
59
+ .describe('Hide stdout from transcript (default: false)')
60
+ .optional(),
61
+ stopReason: z
62
+ .string()
63
+ .describe('Message shown when continue is false')
64
+ .optional(),
65
+ decision: z.enum(['approve', 'block']).optional(),
66
+ reason: z.string().describe('Explanation for the decision').optional(),
67
+ systemMessage: z
68
+ .string()
69
+ .describe('Warning message shown to the user')
70
+ .optional(),
71
+ hookSpecificOutput: z
72
+ .union([
73
+ z.object({
74
+ hookEventName: z.literal('PreToolUse'),
75
+ permissionDecision: permissionBehaviorSchema().optional(),
76
+ permissionDecisionReason: z.string().optional(),
77
+ updatedInput: z.record(z.string(), z.unknown()).optional(),
78
+ additionalContext: z.string().optional(),
79
+ }),
80
+ z.object({
81
+ hookEventName: z.literal('UserPromptSubmit'),
82
+ additionalContext: z.string().optional(),
83
+ }),
84
+ z.object({
85
+ hookEventName: z.literal('SessionStart'),
86
+ additionalContext: z.string().optional(),
87
+ initialUserMessage: z.string().optional(),
88
+ watchPaths: z
89
+ .array(z.string())
90
+ .describe('Absolute paths to watch for FileChanged hooks')
91
+ .optional(),
92
+ }),
93
+ z.object({
94
+ hookEventName: z.literal('Setup'),
95
+ additionalContext: z.string().optional(),
96
+ }),
97
+ z.object({
98
+ hookEventName: z.literal('SubagentStart'),
99
+ additionalContext: z.string().optional(),
100
+ }),
101
+ z.object({
102
+ hookEventName: z.literal('PostToolUse'),
103
+ additionalContext: z.string().optional(),
104
+ updatedMCPToolOutput: z
105
+ .unknown()
106
+ .describe('Updates the output for MCP tools')
107
+ .optional(),
108
+ }),
109
+ z.object({
110
+ hookEventName: z.literal('PostToolUseFailure'),
111
+ additionalContext: z.string().optional(),
112
+ }),
113
+ z.object({
114
+ hookEventName: z.literal('PermissionDenied'),
115
+ retry: z.boolean().optional(),
116
+ }),
117
+ z.object({
118
+ hookEventName: z.literal('Notification'),
119
+ additionalContext: z.string().optional(),
120
+ }),
121
+ z.object({
122
+ hookEventName: z.literal('PermissionRequest'),
123
+ decision: z.union([
124
+ z.object({
125
+ behavior: z.literal('allow'),
126
+ updatedInput: z.record(z.string(), z.unknown()).optional(),
127
+ updatedPermissions: z.array(permissionUpdateSchema()).optional(),
128
+ }),
129
+ z.object({
130
+ behavior: z.literal('deny'),
131
+ message: z.string().optional(),
132
+ interrupt: z.boolean().optional(),
133
+ }),
134
+ ]),
135
+ }),
136
+ z.object({
137
+ hookEventName: z.literal('Elicitation'),
138
+ action: z.enum(['accept', 'decline', 'cancel']).optional(),
139
+ content: z.record(z.string(), z.unknown()).optional(),
140
+ }),
141
+ z.object({
142
+ hookEventName: z.literal('ElicitationResult'),
143
+ action: z.enum(['accept', 'decline', 'cancel']).optional(),
144
+ content: z.record(z.string(), z.unknown()).optional(),
145
+ }),
146
+ z.object({
147
+ hookEventName: z.literal('CwdChanged'),
148
+ watchPaths: z
149
+ .array(z.string())
150
+ .describe('Absolute paths to watch for FileChanged hooks')
151
+ .optional(),
152
+ }),
153
+ z.object({
154
+ hookEventName: z.literal('FileChanged'),
155
+ watchPaths: z
156
+ .array(z.string())
157
+ .describe('Absolute paths to watch for FileChanged hooks')
158
+ .optional(),
159
+ }),
160
+ z.object({
161
+ hookEventName: z.literal('WorktreeCreate'),
162
+ worktreePath: z.string(),
163
+ }),
164
+ ])
165
+ .optional(),
166
+ }),
167
+ )
168
+
169
+ // Zod schema for hook JSON output validation
170
+ export const hookJSONOutputSchema = lazySchema(() => {
171
+ // Async hook response schema
172
+ const asyncHookResponseSchema = z.object({
173
+ async: z.literal(true),
174
+ asyncTimeout: z.number().optional(),
175
+ })
176
+ return z.union([asyncHookResponseSchema, syncHookResponseSchema()])
177
+ })
178
+
179
+ // Infer the TypeScript type from the schema
180
+ type SchemaHookJSONOutput = z.infer<ReturnType<typeof hookJSONOutputSchema>>
181
+
182
+ // Type guard function to check if response is sync
183
+ export function isSyncHookJSONOutput(
184
+ json: HookJSONOutput,
185
+ ): json is SyncHookJSONOutput {
186
+ return !('async' in json && json.async === true)
187
+ }
188
+
189
+ // Type guard function to check if response is async
190
+ export function isAsyncHookJSONOutput(
191
+ json: HookJSONOutput,
192
+ ): json is AsyncHookJSONOutput {
193
+ return 'async' in json && json.async === true
194
+ }
195
+
196
+ // Compile-time assertion that SDK and Zod types match
197
+ import type { IsEqual } from 'type-fest'
198
+ type Assert<T extends true> = T
199
+ type _assertSDKTypesMatch = Assert<
200
+ IsEqual<SchemaHookJSONOutput, HookJSONOutput>
201
+ >
202
+
203
+ /** Context passed to callback hooks for state access */
204
+ export type HookCallbackContext = {
205
+ getAppState: () => AppState
206
+ updateAttributionState: (
207
+ updater: (prev: AttributionState) => AttributionState,
208
+ ) => void
209
+ }
210
+
211
+ /** Hook that is a callback. */
212
+ export type HookCallback = {
213
+ type: 'callback'
214
+ callback: (
215
+ input: HookInput,
216
+ toolUseID: string | null,
217
+ abort: AbortSignal | undefined,
218
+ /** Hook index for SessionStart hooks to compute CLAUDE_ENV_FILE path */
219
+ hookIndex?: number,
220
+ /** Optional context for accessing app state */
221
+ context?: HookCallbackContext,
222
+ ) => Promise<HookJSONOutput>
223
+ /** Timeout in seconds for this hook */
224
+ timeout?: number
225
+ /** Internal hooks (e.g. session file access analytics) are excluded from tengu_run_hook metrics */
226
+ internal?: boolean
227
+ }
228
+
229
+ export type HookCallbackMatcher = {
230
+ matcher?: string
231
+ hooks: HookCallback[]
232
+ pluginName?: string
233
+ hookCallbackIds?: string[]
234
+ timeout?: number
235
+ }
236
+
237
+ export type HookProgress = {
238
+ type: 'hook_progress'
239
+ hookEvent: HookEvent
240
+ hookName: string
241
+ command: string
242
+ promptText?: string
243
+ statusMessage?: string
244
+ }
245
+
246
+ export type HookBlockingError = {
247
+ blockingError: string
248
+ command: string
249
+ }
250
+
251
+ export type PermissionRequestResult =
252
+ | {
253
+ behavior: 'allow'
254
+ updatedInput?: Record<string, unknown>
255
+ updatedPermissions?: PermissionUpdate[]
256
+ }
257
+ | {
258
+ behavior: 'deny'
259
+ message?: string
260
+ interrupt?: boolean
261
+ }
262
+
263
+ export type HookResult = {
264
+ message?: Message
265
+ systemMessage?: Message
266
+ blockingError?: HookBlockingError
267
+ outcome: 'success' | 'blocking' | 'non_blocking_error' | 'cancelled'
268
+ preventContinuation?: boolean
269
+ stopReason?: string
270
+ permissionBehavior?: 'ask' | 'deny' | 'allow' | 'passthrough'
271
+ hookPermissionDecisionReason?: string
272
+ additionalContext?: string
273
+ initialUserMessage?: string
274
+ updatedInput?: Record<string, unknown>
275
+ updatedMCPToolOutput?: unknown
276
+ permissionRequestResult?: PermissionRequestResult
277
+ retry?: boolean
278
+ }
279
+
280
+ export type AggregatedHookResult = {
281
+ message?: Message
282
+ blockingErrors?: HookBlockingError[]
283
+ preventContinuation?: boolean
284
+ stopReason?: string
285
+ hookPermissionDecisionReason?: string
286
+ permissionBehavior?: PermissionResult['behavior']
287
+ additionalContexts?: string[]
288
+ initialUserMessage?: string
289
+ updatedInput?: Record<string, unknown>
290
+ updatedMCPToolOutput?: unknown
291
+ permissionRequestResult?: PermissionRequestResult
292
+ retry?: boolean
293
+ }
294
+
295
+ // Re-export from entrypoints
296
+ export type HookEvent =
297
+ | 'beforeSampling'
298
+ | 'afterSampling'
299
+ | 'beforeToolExecution'
300
+ | 'afterToolExecution'
301
+ | 'onStop'
302
+ | 'onError'
303
+ | 'loaded'
304
+
305
+ export const HOOK_EVENTS: HookEvent[] = [
306
+ 'beforeSampling',
307
+ 'afterSampling',
308
+ 'beforeToolExecution',
309
+ 'afterToolExecution',
310
+ 'onStop',
311
+ 'onError',
312
+ 'loaded',
313
+ ]
314
+
315
+ export interface ModelUsage {
316
+ inputTokens: number
317
+ outputTokens: number
318
+ totalTokens: number
319
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Branded types for session and agent IDs.
3
+ * These prevent accidentally mixing up session IDs and agent IDs at compile time.
4
+ */
5
+
6
+ /**
7
+ * A session ID uniquely identifies a Gizzi session.
8
+ * Returned by getSessionId().
9
+ */
10
+ export type SessionId = string & { readonly __brand: 'SessionId' }
11
+
12
+ /**
13
+ * An agent ID uniquely identifies a subagent within a session.
14
+ * Returned by createAgentId().
15
+ * When present, indicates the context is a subagent (not the main session).
16
+ */
17
+ export type AgentId = string & { readonly __brand: 'AgentId' }
18
+
19
+ /**
20
+ * Cast a raw string to SessionId.
21
+ * Use sparingly - prefer getSessionId() when possible.
22
+ */
23
+ export function asSessionId(id: string): SessionId {
24
+ return id as SessionId
25
+ }
26
+
27
+ /**
28
+ * Cast a raw string to AgentId.
29
+ * Use sparingly - prefer createAgentId() when possible.
30
+ */
31
+ export function asAgentId(id: string): AgentId {
32
+ return id as AgentId
33
+ }
34
+
35
+ const AGENT_ID_PATTERN = /^a(?:.+-)?[0-9a-f]{16}$/
36
+
37
+ /**
38
+ * Validate and brand a string as AgentId.
39
+ * Matches the format produced by createAgentId(): `a` + optional `<label>-` + 16 hex chars.
40
+ * Returns null if the string doesn't match (e.g. teammate names, team-addressing).
41
+ */
42
+ export function toAgentId(s: string): AgentId | null {
43
+ return AGENT_ID_PATTERN.test(s) ? (s as AgentId) : null
44
+ }
@@ -0,0 +1,331 @@
1
+ // UUID type alias for compatibility
2
+ type UUID = string
3
+ import type { FileHistorySnapshot } from '../../utils/fileHistory.js'
4
+ import type { ContentReplacementRecord } from '../../utils/toolResultStorage.js'
5
+ import type { AgentId } from './ids.js'
6
+ import type { Message } from './message.js'
7
+ import type { QueueOperationMessage } from './messageQueueTypes.js'
8
+
9
+ export type SerializedMessage = Message & {
10
+ cwd: string
11
+ userType: string
12
+ entrypoint?: string // GIZZI_ENTRYPOINT — distinguishes cli/sdk-ts/sdk-py/etc.
13
+ sessionId: string
14
+ timestamp: string
15
+ version: string
16
+ gitBranch?: string
17
+ slug?: string // Session slug for files like plans (used for resume)
18
+ }
19
+
20
+ export type LogOption = {
21
+ date: string
22
+ messages: SerializedMessage[]
23
+ fullPath?: string
24
+ value: number
25
+ created: Date
26
+ modified: Date
27
+ firstPrompt: string
28
+ messageCount: number
29
+ fileSize?: number // File size in bytes (for display)
30
+ isSidechain: boolean
31
+ isLite?: boolean // True for lite logs (messages not loaded)
32
+ sessionId?: string // Session ID for lite logs
33
+ teamName?: string // Team name if this is a spawned agent session
34
+ agentName?: string // Agent's custom name (from /rename or swarm)
35
+ agentColor?: string // Agent's color (from /rename or swarm)
36
+ agentSetting?: string // Agent definition used (from --agent flag or settings.agent)
37
+ isTeammate?: boolean // Whether this session was created by a swarm teammate
38
+ leafUuid?: UUID // If given, this uuid must appear in the DB
39
+ summary?: string // Optional conversation summary
40
+ customTitle?: string // Optional user-set custom title
41
+ tag?: string // Optional tag for the session (searchable in /resume)
42
+ fileHistorySnapshots?: FileHistorySnapshot[] // Optional file history snapshots
43
+ attributionSnapshots?: AttributionSnapshotMessage[] // Optional attribution snapshots
44
+ contextCollapseCommits?: ContextCollapseCommitEntry[] // Ordered — commit B may reference commit A's summary
45
+ contextCollapseSnapshot?: ContextCollapseSnapshotEntry // Last-wins — staged queue + spawn state
46
+ gitBranch?: string // Git branch at the end of the session
47
+ projectPath?: string // Original project directory path
48
+ prNumber?: number // GitHub PR number linked to this session
49
+ prUrl?: string // Full URL to the linked PR
50
+ prRepository?: string // Repository in "owner/repo" format
51
+ mode?: 'coordinator' | 'normal' // Session mode for coordinator/normal detection
52
+ worktreeSession?: PersistedWorktreeSession | null // Worktree state at session end (null = exited, undefined = never entered)
53
+ contentReplacements?: ContentReplacementRecord[] // Replacement decisions for resume reconstruction
54
+ }
55
+
56
+ export type SummaryMessage = {
57
+ type: 'summary'
58
+ leafUuid: UUID
59
+ summary: string
60
+ }
61
+
62
+ export type CustomTitleMessage = {
63
+ type: 'custom-title'
64
+ sessionId: UUID
65
+ customTitle: string
66
+ }
67
+
68
+ /**
69
+ * AI-generated session title. Distinct from CustomTitleMessage so that:
70
+ * - User renames (custom-title) always win over AI titles in read preference
71
+ * - reAppendSessionMetadata never re-appends AI titles (they're ephemeral/
72
+ * regeneratable; re-appending would clobber user renames on resume)
73
+ * - VS Code's onlyIfNoCustomTitle CAS check only matches user titles,
74
+ * allowing AI to overwrite its own previous AI title but not user titles
75
+ */
76
+ export type AiTitleMessage = {
77
+ type: 'ai-title'
78
+ sessionId: UUID
79
+ aiTitle: string
80
+ }
81
+
82
+ export type LastPromptMessage = {
83
+ type: 'last-prompt'
84
+ sessionId: UUID
85
+ lastPrompt: string
86
+ }
87
+
88
+ /**
89
+ * Periodic fork-generated summary of what the agent is currently doing.
90
+ * Written every min(5 steps, 2min) by forking the main thread mid-turn so
91
+ * `claude ps` can show something more useful than the last user prompt
92
+ * (which is often "ok go" or "fix it").
93
+ */
94
+ export type TaskSummaryMessage = {
95
+ type: 'task-summary'
96
+ sessionId: UUID
97
+ summary: string
98
+ timestamp: string
99
+ }
100
+
101
+ export type TagMessage = {
102
+ type: 'tag'
103
+ sessionId: UUID
104
+ tag: string
105
+ }
106
+
107
+ export type AgentNameMessage = {
108
+ type: 'agent-name'
109
+ sessionId: UUID
110
+ agentName: string
111
+ }
112
+
113
+ export type AgentColorMessage = {
114
+ type: 'agent-color'
115
+ sessionId: UUID
116
+ agentColor: string
117
+ }
118
+
119
+ export type AgentSettingMessage = {
120
+ type: 'agent-setting'
121
+ sessionId: UUID
122
+ agentSetting: string
123
+ }
124
+
125
+ /**
126
+ * PR link message stored in session transcript.
127
+ * Links a session to a GitHub pull request for tracking and navigation.
128
+ */
129
+ export type PRLinkMessage = {
130
+ type: 'pr-link'
131
+ sessionId: UUID
132
+ prNumber: number
133
+ prUrl: string
134
+ prRepository: string // e.g., "owner/repo"
135
+ timestamp: string // ISO timestamp when linked
136
+ }
137
+
138
+ export type ModeEntry = {
139
+ type: 'mode'
140
+ sessionId: UUID
141
+ mode: 'coordinator' | 'normal'
142
+ }
143
+
144
+ /**
145
+ * Worktree session state persisted to the transcript for resume.
146
+ * Subset of WorktreeSession from utils/worktree.ts — excludes ephemeral
147
+ * fields (creationDurationMs, usedSparsePaths) that are only used for
148
+ * first-run analytics.
149
+ */
150
+ export type PersistedWorktreeSession = {
151
+ originalCwd: string
152
+ worktreePath: string
153
+ worktreeName: string
154
+ worktreeBranch?: string
155
+ originalBranch?: string
156
+ originalHeadCommit?: string
157
+ sessionId: string
158
+ tmuxSessionName?: string
159
+ hookBased?: boolean
160
+ }
161
+
162
+ /**
163
+ * Records whether the session is currently inside a worktree created by
164
+ * EnterWorktree or --worktree. Last-wins: an enter writes the session,
165
+ * an exit writes null. On --resume, restored only if the worktreePath
166
+ * still exists on disk (the /exit dialog may have removed it).
167
+ */
168
+ export type WorktreeStateEntry = {
169
+ type: 'worktree-state'
170
+ sessionId: UUID
171
+ worktreeSession: PersistedWorktreeSession | null
172
+ }
173
+
174
+ /**
175
+ * Records content blocks whose in-context representation was replaced with a
176
+ * smaller stub (the full content was persisted elsewhere). Replayed on resume
177
+ * for prompt cache stability. Written once per enforcement pass that replaces
178
+ * at least one block. When agentId is set, the record belongs to a subagent
179
+ * sidechain (AgentTool resume reads these); when absent, it's main-thread
180
+ * (/resume reads these).
181
+ */
182
+ export type ContentReplacementEntry = {
183
+ type: 'content-replacement'
184
+ sessionId: UUID
185
+ agentId?: AgentId
186
+ replacements: ContentReplacementRecord[]
187
+ }
188
+
189
+ export type FileHistorySnapshotMessage = {
190
+ type: 'file-history-snapshot'
191
+ messageId: UUID
192
+ snapshot: FileHistorySnapshot
193
+ isSnapshotUpdate: boolean
194
+ }
195
+
196
+ /**
197
+ * Per-file attribution state tracking Claude's character contributions.
198
+ */
199
+ export type FileAttributionState = {
200
+ contentHash: string // SHA-256 hash of file content
201
+ claudeContribution: number // Characters written by Claude
202
+ mtime: number // File modification time
203
+ }
204
+
205
+ /**
206
+ * Attribution snapshot message stored in session transcript.
207
+ * Tracks character-level contributions by Claude for commit attribution.
208
+ */
209
+ export type AttributionSnapshotMessage = {
210
+ type: 'attribution-snapshot'
211
+ messageId: UUID
212
+ surface: string // Client surface (cli, ide, web, api)
213
+ fileStates: Record<string, FileAttributionState>
214
+ promptCount?: number // Total prompts in session
215
+ promptCountAtLastCommit?: number // Prompts at last commit
216
+ permissionPromptCount?: number // Total permission prompts shown
217
+ permissionPromptCountAtLastCommit?: number // Permission prompts at last commit
218
+ escapeCount?: number // Total ESC presses (cancelled permission prompts)
219
+ escapeCountAtLastCommit?: number // ESC presses at last commit
220
+ }
221
+
222
+ export type TranscriptMessage = SerializedMessage & {
223
+ parentUuid: UUID | null
224
+ logicalParentUuid?: UUID | null // Preserves logical parent when parentUuid is nullified for session breaks
225
+ isSidechain: boolean
226
+ gitBranch?: string
227
+ agentId?: string // Agent ID for sidechain transcripts to enable resuming agents
228
+ teamName?: string // Team name if this is a spawned agent session
229
+ agentName?: string // Agent's custom name (from /rename or swarm)
230
+ agentColor?: string // Agent's color (from /rename or swarm)
231
+ promptId?: string // Correlates with OTel prompt.id for user prompt messages
232
+ }
233
+
234
+ export type SpeculationAcceptMessage = {
235
+ type: 'speculation-accept'
236
+ timestamp: string
237
+ timeSavedMs: number
238
+ }
239
+
240
+ /**
241
+ * Persisted context-collapse commit. The archived messages themselves are
242
+ * NOT persisted — they're already in the transcript as ordinary user/
243
+ * assistant messages. We only persist enough to reconstruct the splice
244
+ * instruction (boundary uuids) and the summary placeholder (which is NOT
245
+ * in the transcript because it's never yielded to the REPL).
246
+ *
247
+ * On restore, the store reconstructs CommittedCollapse with archived=[];
248
+ * projectView lazily fills the archive the first time it finds the span.
249
+ *
250
+ * Discriminator is obfuscated to match the gate name. sessionStorage.ts
251
+ * isn't feature-gated (it's the generic transcript plumbing used by every
252
+ * entry type), so a descriptive string here would leak into external builds
253
+ * via the appendEntry dispatch / loadTranscriptFile parser even though
254
+ * nothing in an external build ever writes or reads this entry.
255
+ */
256
+ export type ContextCollapseCommitEntry = {
257
+ type: 'marble-origami-commit'
258
+ sessionId: UUID
259
+ /** 16-digit collapse ID. Max across entries reseeds the ID counter. */
260
+ collapseId: string
261
+ /** The summary placeholder's uuid — registerSummary() needs it. */
262
+ summaryUuid: string
263
+ /** Full <collapsed id="...">text</collapsed> string for the placeholder. */
264
+ summaryContent: string
265
+ /** Plain summary text for ctx_inspect. */
266
+ summary: string
267
+ /** Span boundaries — projectView finds these in the resumed Message[]. */
268
+ firstArchivedUuid: string
269
+ lastArchivedUuid: string
270
+ }
271
+
272
+ /**
273
+ * Snapshot of the staged queue and spawn trigger state. Unlike commits
274
+ * (append-only, replay-all), snapshots are last-wins — only the most
275
+ * recent snapshot entry is applied on restore. Written after every
276
+ * ctx-agent spawn resolves (when staged contents may have changed).
277
+ *
278
+ * Staged boundaries are UUIDs (session-stable), not collapse IDs (which
279
+ * reset with the uuidToId bimap). Restoring a staged span issues fresh
280
+ * collapse IDs for those messages on the next decorate/display, but the
281
+ * span itself resolves correctly.
282
+ */
283
+ export type ContextCollapseSnapshotEntry = {
284
+ type: 'marble-origami-snapshot'
285
+ sessionId: UUID
286
+ staged: Array<{
287
+ startUuid: string
288
+ endUuid: string
289
+ summary: string
290
+ risk: number
291
+ stagedAt: number
292
+ }>
293
+ /** Spawn trigger state — so the +interval clock picks up where it left off. */
294
+ armed: boolean
295
+ lastSpawnTokens: number
296
+ }
297
+
298
+ export type Entry =
299
+ | TranscriptMessage
300
+ | SummaryMessage
301
+ | CustomTitleMessage
302
+ | AiTitleMessage
303
+ | LastPromptMessage
304
+ | TaskSummaryMessage
305
+ | TagMessage
306
+ | AgentNameMessage
307
+ | AgentColorMessage
308
+ | AgentSettingMessage
309
+ | PRLinkMessage
310
+ | FileHistorySnapshotMessage
311
+ | AttributionSnapshotMessage
312
+ | QueueOperationMessage
313
+ | SpeculationAcceptMessage
314
+ | ModeEntry
315
+ | WorktreeStateEntry
316
+ | ContentReplacementEntry
317
+ | ContextCollapseCommitEntry
318
+ | ContextCollapseSnapshotEntry
319
+
320
+ export function sortLogs(logs: LogOption[]): LogOption[] {
321
+ return logs.sort((a, b) => {
322
+ // Sort by modified date (newest first)
323
+ const modifiedDiff = b.modified.getTime() - a.modified.getTime()
324
+ if (modifiedDiff !== 0) {
325
+ return modifiedDiff
326
+ }
327
+
328
+ // If modified dates are equal, sort by created date (newest first)
329
+ return b.created.getTime() - a.created.getTime()
330
+ })
331
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Merged Types - Unified type system for Gizzi + Claude integration
3
+ */
4
+
5
+ export * from "./message"