@agimon-ai/doompi-git 0.0.1-alpha.22 → 0.0.1-alpha.23

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.
@@ -261,11 +261,18 @@ function createWorktreesChannel(options = {}) {
261
261
  git: require_worktreeOperations.createWorktreeGit(),
262
262
  sessionService
263
263
  });
264
+ /** Announces a successful mutation to this session's lifecycle subscribers. */
265
+ const publishLifecycle = (scope, repositoryRoot) => {
266
+ host.directEvents.publish(require_worktreeOperations.GIT_WORKTREE_LIFECYCLE_EVENT, scope.sessionId, {
267
+ version: 1,
268
+ repositoryRoot
269
+ });
270
+ };
264
271
  const unregisterWorktreeProvisioner = sessionService.registerReservedWorktreeProvisioner?.(async ({ reservationId, parentSessionId, signal }) => {
265
272
  const parent = host.sessions().find((scope) => scope.sessionId === parentSessionId);
266
273
  if (parent === void 0) throw new Error("The conversation parent session is unavailable.");
267
274
  const branch = `doompi/conversation-${reservationId.slice(0, 12)}`;
268
- await worktrees.spawn({
275
+ const record = await worktrees.spawn({
269
276
  cwd: parent.cwd,
270
277
  sessionId: parent.sessionId
271
278
  }, {
@@ -275,7 +282,9 @@ function createWorktreesChannel(options = {}) {
275
282
  }, { signal });
276
283
  const reservations = sessionService.reservations;
277
284
  if (reservations === void 0) throw new Error("Conversation reservations are unavailable.");
278
- return reservations.complete(reservationId, parentSessionId);
285
+ const session = await reservations.complete(reservationId, parentSessionId);
286
+ publishLifecycle(parent, record.repositoryRoot);
287
+ return session;
279
288
  });
280
289
  const views = {
281
290
  homeDir: options.homeDir,
@@ -313,13 +322,6 @@ function createWorktreesChannel(options = {}) {
313
322
  });
314
323
  publish(scope, true);
315
324
  };
316
- /** Announces a successful mutation to this session's lifecycle subscribers. */
317
- const publishLifecycle = (scope, repositoryRoot) => {
318
- host.directEvents.publish(require_worktreeOperations.GIT_WORKTREE_LIFECYCLE_EVENT, scope.sessionId, {
319
- version: 1,
320
- repositoryRoot
321
- });
322
- };
323
325
  const run = async (scope, command, generation) => {
324
326
  const context = {
325
327
  cwd: scope.cwd,
@@ -1 +1 @@
1
- {"version":3,"file":"server.cjs","names":["createWorktreeMessageInbox","createWorktreeOperations","createWorktreeGit","readDoomSessionDelivery","readPackageResource","RUN_WORKTREE_TOOL_NAME","RUN_WORKTREE_DESCRIPTION","RunWorktreeToolSchema","validateParams","executeRunWorktreeTool","defineRoot","defineRoot","contribution","DoomGitExpectedError","GIT_WORKTREE_LIFECYCLE_EVENT","createWorktreeOperations","createWorktreeGit","defineRoute","contribution","createWorktreeRegistry","registryFile","DoomGitExpectedError","HubUnavailableError","createWorktreeOperations","createWorktreeGit","GIT_WORKTREE_LIFECYCLE_EVENT","isWorktreeLifecycleEvent","defineChannel","contribution","defineResource","contribution","defineResource","contribution","defineResource","contribution","defineServerTool","defineServerPlugin","apiRoute","channelGitWorktrees","rootSession","composeRootHooks","resourceDoompiGit","resourceDoompiGitReadme","resourceDoompiUseGit","toolRunWorktree"],"sources":["../../src/extensions/workspaces/sessions/(backend)/_lib/root.server.ts","../../src/extensions/workspaces/sessions/(backend)/root.server.ts","../../src/extensions/(backend)/api/_lib/route.server.ts","../../src/extensions/(backend)/api/route.server.ts","../../src/types/webWorktrees.ts","../../src/extensions/(backend)/channel/_lib/git-worktrees.server.ts","../../src/extensions/(backend)/channel/git-worktrees.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiGit.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompiGit.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiGitReadme.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompiGitReadme.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiUseGit.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompiUseGit.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/runWorktree.server.ts","../../generated/server.ts"],"sourcesContent":["import { defineRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport {\n type DoomHeadlessResource,\n type DoomHeadlessTool,\n type DoomHeadlessToolResult,\n} from '@agimon-ai/doompi-core/headless';\nimport { readPackageResource, type DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\nimport { readDoomSessionDelivery } from '@agimon-ai/doompi-session';\n\nimport { RunWorktreeToolSchema, type RunWorktreeToolParams } from '../../../../../schemas/runWorktreeTool';\nimport { createWorktreeGit } from '../../../../../services/gitCli';\nimport {\n executeRunWorktreeTool,\n RUN_WORKTREE_DESCRIPTION,\n RUN_WORKTREE_TOOL_NAME,\n validateParams,\n} from '../../../../../services/runWorktree';\nimport { createWorktreeMessageInbox } from '../../../../../services/worktreeEvents';\nimport { createWorktreeOperations } from '../../../../../services/worktreeOperations';\n\nfunction progressResult(action: RunWorktreeToolParams['action'], label: string): DoomHeadlessToolResult {\n return { content: [{ type: 'text', text: label }], details: { action } };\n}\n\nexport function createGitSession({ context, host: serverHost }: DoomServerPluginContext) {\n if (serverHost.context.directEvents === undefined)\n throw new Error('Git headless facet requires the session direct event bus.');\n if (serverHost.context.sessionId === undefined) throw new Error('Git headless facet requires a session identity.');\n const sessionId = serverHost.context.sessionId;\n const directEvents = serverHost.context.directEvents;\n const messageInbox = createWorktreeMessageInbox(directEvents, sessionId);\n const operations = createWorktreeOperations({\n git: createWorktreeGit(),\n sessionService: serverHost.context.sessionService,\n messageInbox,\n sessionDelivery: () => readDoomSessionDelivery(context),\n });\n const resources: DoomHeadlessResource[] = [\n {\n // The package index is Help-catalog material, not standing instruction, so it\n // only enters the prompt while Help mode is active. Matches the Pi facet,\n // which has always routed this through the Help service.\n when: { state: { 'minor-mode': 'help' }, attribution: { kind: 'minor', mode: 'help' } },\n name: 'doompi-git',\n kind: 'context',\n read: () => readPackageResource(import.meta.url, 'llms.txt'),\n },\n {\n name: 'doompi-use-git',\n kind: 'skill',\n read: () => readPackageResource(import.meta.url, 'src/prompts/doompi-use-git/SKILL.md'),\n },\n ];\n\n const tool: DoomHeadlessTool<typeof RunWorktreeToolSchema> = {\n name: RUN_WORKTREE_TOOL_NAME,\n label: 'Worktree',\n description: RUN_WORKTREE_DESCRIPTION,\n parameters: RunWorktreeToolSchema,\n promptSnippet: 'Create and manage Git worktree sessions',\n executionMode: 'serial',\n async execute(_toolCallId, parameters, signal, onUpdate, execution) {\n const params = validateParams(parameters) as RunWorktreeToolParams;\n return executeRunWorktreeTool(params, operations, execution, {\n ...(signal === undefined ? {} : { signal }),\n onProgress: (label) => onUpdate?.(progressResult(params.action, label)),\n });\n },\n };\n return { value: { resources, tool }, onDispose: () => messageInbox.close() };\n}\n\nconst root = defineRoot(createGitSession);\nexport type GitServerScope = Awaited<ReturnType<typeof root>>['value'];\nexport default root;\n","import { defineRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/root.server';\n\nexport default defineRoot(contribution);\n","import type { DoomApi, DoomApiContext, DoomApiHandler } from '@agimon-ai/doompi-core/packageApi';\n\nimport { DoomGitExpectedError } from '../../../../services/errors';\nimport { createWorktreeGit } from '../../../../services/gitCli';\nimport { GIT_WORKTREE_LIFECYCLE_EVENT } from '../../../../services/worktreeEvents';\nimport { createWorktreeOperations } from '../../../../services/worktreeOperations';\n\n/**\n * The worktree surface the cockpit panel calls.\n *\n * Hub-scoped because worktrees are a property of a repository, not of one\n * session: the panel lists and creates them whether or not the session that\n * made them is focused, and a session-scoped API would disappear with it.\n *\n * The panel names a repository by the hub's opaque id and never by path.\n * `resolveRepository` turns that into an admitted root, so a browser cannot\n * point this at a directory the cockpit was never given.\n */\nfunction badRequest(message: string): Response {\n return Response.json({ error: message }, { status: 400 });\n}\n\nfunction failed(error: unknown): Response {\n if (error instanceof DoomGitExpectedError) {\n return Response.json({ error: error.message, code: error.code }, { status: error.retryable ? 503 : 409 });\n }\n // Never the raw message: a git failure can carry a remote URL with a token.\n return Response.json({ error: 'The worktree operation failed.' }, { status: 500 });\n}\n\nexport const api: DoomApi = {\n basePath: 'git',\n start(context: DoomApiContext): DoomApiHandler {\n if (context.directEvents === undefined) throw new Error('Git hub API requires the direct event bus.');\n const directEvents = context.directEvents;\n const publishLifecycle = (sessionId: string, repositoryRoot: string): void => {\n directEvents.publish(GIT_WORKTREE_LIFECYCLE_EVENT, sessionId, { version: 1 as const, repositoryRoot });\n };\n const operations = createWorktreeOperations({\n git: createWorktreeGit(),\n sessionService: context.sessionService,\n });\n\n /** The admitted root for a request, or a response explaining why not. */\n const rootOf = (url: URL): string | Response => {\n const repositoryId = url.searchParams.get('repositoryId');\n if (repositoryId === null || repositoryId === '') return badRequest('A repositoryId is required.');\n const root = context.resolveRepository?.(repositoryId);\n if (root === undefined) return badRequest('That repository is not admitted to this cockpit.');\n return root;\n };\n\n return {\n async fetch(request) {\n const url = new URL(request.url);\n const root = rootOf(url);\n if (root instanceof Response) return root;\n // The operations layer works from a cwd, and an admitted repository\n // root is one.\n const callerContext = { cwd: root, sessionId: url.searchParams.get('sessionId') ?? '' };\n const isMutation =\n (request.method === 'POST' && url.pathname === '/worktrees') ||\n (request.method === 'DELETE' && /^\\/worktrees\\/[^/]+$/u.test(url.pathname));\n if (isMutation && callerContext.sessionId === '')\n return badRequest('A sessionId is required for worktree mutations.');\n\n try {\n if (request.method === 'GET' && url.pathname === '/worktrees') {\n return Response.json({ worktrees: await operations.list(callerContext) });\n }\n if (request.method === 'POST' && url.pathname === '/worktrees') {\n const body = (await request.json()) as { branch?: string; baseRef?: string; name?: string };\n if (typeof body.branch !== 'string' || body.branch.trim() === '') {\n return badRequest('A branch is required.');\n }\n const record = await operations.spawn(callerContext, {\n branch: body.branch,\n ...(body.baseRef === undefined ? {} : { baseRef: body.baseRef }),\n ...(body.name === undefined ? {} : { name: body.name }),\n });\n publishLifecycle(callerContext.sessionId, record.repositoryRoot);\n return Response.json({ worktree: record }, { status: 201 });\n }\n const closing = /^\\/worktrees\\/([^/]+)$/u.exec(url.pathname);\n if (request.method === 'DELETE' && closing) {\n const record = await operations.close(\n callerContext,\n decodeURIComponent(String(closing[1])),\n url.searchParams.get('force') === 'true',\n );\n publishLifecycle(callerContext.sessionId, record.repositoryRoot);\n return Response.json({ worktree: record });\n }\n return Response.json({ error: 'No such worktree route.' }, { status: 404 });\n } catch (error) {\n context.onNotice(`worktree request failed: ${(error as Error).name}`);\n return failed(error);\n }\n },\n close() {},\n };\n },\n};\n\nexport default api;\n","import { defineRoute } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/route.server';\n\nexport default defineRoute(contribution);\n","/**\n * The cockpit's view of this session's worktrees.\n *\n * DESIGN PATTERNS:\n * - Declarations only. The channel frame type is a constant so the hub and the\n * page cannot drift apart on a string.\n * - A view is the subset of a record the dock needs, not the record. The\n * registry may hold paths and provenance the page has no business rendering.\n *\n * AVOID:\n * - Adding behaviour here. This file is imported by browser code, so it must\n * stay free of node builtins.\n */\n\n/** The data channel carrying one session's worktrees to the page. */\nexport const GIT_WORKTREES_TYPE = 'git_worktrees';\n\n/** One worktree, as the activity dock and its panel render it. */\nexport interface WorktreeView {\n id: string;\n branch: string;\n path: string;\n /** The session the hub started for this worktree, when it is still live. */\n sessionId: string | null;\n /** True once the directory the record names has gone missing. */\n orphaned: boolean;\n /**\n * True when the session that asked for this worktree is gone.\n *\n * An owned worktree is only ever shown to its own session. This flag marks\n * the exception: once the parent is dead nobody would see the worktree at\n * all, so every session in the repository does, and may close it.\n */\n unowned: boolean;\n}\n\n/**\n * What the panel asks the hub channel to do.\n *\n * The dock acts through its own channel rather than through the agent: a\n * worktree made from the panel and one made by the tool take the same\n * `worktreeOperations` path, but the panel no longer has to spend a turn of\n * the conversation to get there.\n */\nexport type GitWorktreesCommand =\n | { action: 'create'; branch: string; baseRef?: string; reservationId?: string }\n | { action: 'close'; id: string; force?: boolean };\n\nexport type WorktreeErrorTarget = { action: 'create' } | { action: 'close'; id: string };\n\nexport interface GitWorktreesPayload {\n worktrees: WorktreeView[];\n /** Label of the operation in flight, absent when the session is idle. */\n pending?: string;\n /** The last failure, cleared when the next command starts. */\n error?: string;\n /** The operation that produced the last failure, when known. */\n errorTarget?: WorktreeErrorTarget;\n}\n","/**\n * The worktrees data channel, and the commands the dock sends back through it.\n *\n * The registry is durable state only. Live lifecycle changes arrive through the\n * hub-owned direct event bus, so this channel never polls or claims files.\n */\nimport type {\n DoomHubChannel,\n DoomHubChannelSource,\n DoomHubSessionScope,\n DoomHubSessionService,\n} from '@agimon-ai/doompi-core/hubChannel';\n\nimport { DoomGitExpectedError, HubUnavailableError } from '../../../../services/errors';\nimport { createWorktreeGit } from '../../../../services/gitCli';\nimport { registryFile } from '../../../../services/paths';\nimport { GIT_WORKTREE_LIFECYCLE_EVENT, isWorktreeLifecycleEvent } from '../../../../services/worktreeEvents';\nimport { createWorktreeOperations, type WorktreeOperations } from '../../../../services/worktreeOperations';\nimport { createWorktreeRegistry } from '../../../../services/worktreeRegistry';\nimport {\n GIT_WORKTREES_TYPE,\n type GitWorktreesCommand,\n type WorktreeErrorTarget,\n type WorktreeView,\n} from '../../../../types/webWorktrees';\n\ninterface SessionState {\n worktrees: WorktreeView[];\n pending: string | undefined;\n error: string | undefined;\n errorTarget: WorktreeErrorTarget | undefined;\n}\n\nfunction payloadOf(state: SessionState): Record<string, unknown> {\n return {\n worktrees: state.worktrees,\n ...(state.pending === undefined ? {} : { pending: state.pending }),\n ...(state.error === undefined ? {} : { error: state.error }),\n ...(state.errorTarget === undefined ? {} : { errorTarget: state.errorTarget }),\n };\n}\n\n/** What the channel needs from its surroundings, injected so tests stay off this machine. */\nexport interface WorktreesChannelOptions {\n operations?: WorktreeOperations;\n homeDir?: string;\n}\n\ninterface ViewDeps {\n homeDir: string | undefined;\n sessionService: DoomHubSessionService;\n}\n\n/** Worktrees visible to this session, using the hub's live session table for ownership. */\nfunction viewsFor(scope: DoomHubSessionScope, deps: ViewDeps): WorktreeView[] {\n try {\n return createWorktreeRegistry(registryFile(scope.cwd, deps.homeDir))\n .list()\n .flatMap((record) => {\n const owned = record.parentSessionId === scope.sessionId;\n const unowned = !owned && !deps.sessionService.isLive(record.parentSessionId);\n if (!owned && !unowned) return [];\n return [\n {\n id: record.id,\n branch: record.branch,\n path: record.path,\n sessionId: record.status === 'orphaned' ? null : record.sessionId,\n orphaned: record.status === 'orphaned',\n unowned,\n },\n ];\n });\n } catch {\n return [];\n }\n}\n\nfunction sameList(left: readonly WorktreeView[], right: readonly WorktreeView[]): boolean {\n if (left.length !== right.length) return false;\n return left.every((entry, index) => {\n const other = right[index];\n return (\n other !== undefined &&\n entry.id === other.id &&\n entry.branch === other.branch &&\n entry.sessionId === other.sessionId &&\n entry.orphaned === other.orphaned &&\n entry.unowned === other.unowned\n );\n });\n}\n\nfunction errorTargetFor(command: GitWorktreesCommand): WorktreeErrorTarget {\n return command.action === 'create' ? { action: 'create' } : { action: 'close', id: command.id };\n}\n\n/** A command the page sent, or undefined when the frame was not one. */\nfunction parseCommand(payload: unknown): GitWorktreesCommand | undefined {\n if (typeof payload !== 'object' || payload === null) return undefined;\n const value = payload as Record<string, unknown>;\n if (value.action === 'create') {\n if (typeof value.branch !== 'string' || value.branch.trim() === '') return undefined;\n if (\n value.reservationId !== undefined &&\n (typeof value.reservationId !== 'string' || !/^[A-Za-z0-9_-]+$/u.test(value.reservationId))\n )\n return undefined;\n return {\n action: 'create',\n branch: value.branch.trim(),\n ...(typeof value.baseRef === 'string' && value.baseRef.trim() !== '' ? { baseRef: value.baseRef.trim() } : {}),\n ...(typeof value.reservationId === 'string' ? { reservationId: value.reservationId } : {}),\n };\n }\n if (value.action === 'close') {\n if (typeof value.id !== 'string' || value.id === '') return undefined;\n return { action: 'close', id: value.id, ...(value.force === true ? { force: true } : {}) };\n }\n return undefined;\n}\n\n/**\n * What the reader is told when a command fails.\n *\n * An expected failure explains itself. Anything else is summarised, never\n * echoed: a git error can carry a remote URL with a token in it.\n */\nfunction failureText(error: unknown): string {\n return error instanceof DoomGitExpectedError ? error.message : 'The worktree operation failed.';\n}\n\n/** Starts one direct-event subscription per managed session. */\nexport function createWorktreesChannel(options: WorktreesChannelOptions = {}): DoomHubChannel {\n // Assigned by start, because receive is reachable only while the channel is\n // running and the command needs the state the direct event subscriptions keep.\n let receiveCommand: ((scope: DoomHubSessionScope, payload: unknown) => void) | undefined;\n\n return {\n frameType: GIT_WORKTREES_TYPE,\n start(host) {\n const sessionService = host.sessionService;\n if (sessionService === undefined) {\n throw new HubUnavailableError('The cockpit session service is unavailable. Start the cockpit and try again.');\n }\n const worktrees =\n options.operations ??\n createWorktreeOperations({\n git: createWorktreeGit(),\n sessionService,\n });\n const unregisterWorktreeProvisioner = sessionService.registerReservedWorktreeProvisioner?.(\n async ({ reservationId, parentSessionId, signal }) => {\n const parent = host.sessions().find((scope) => scope.sessionId === parentSessionId);\n if (parent === undefined) throw new Error('The conversation parent session is unavailable.');\n const branch = `doompi/conversation-${reservationId.slice(0, 12)}`;\n await worktrees.spawn(\n { cwd: parent.cwd, sessionId: parent.sessionId },\n { branch, name: `conversation ${reservationId.slice(0, 8)}`, reservationId },\n { signal },\n );\n const reservations = sessionService.reservations;\n if (reservations === undefined) throw new Error('Conversation reservations are unavailable.');\n return reservations.complete(reservationId, parentSessionId);\n },\n );\n const views: ViewDeps = { homeDir: options.homeDir, sessionService };\n const latest = new Map<string, SessionState>();\n const subscriptions = new Map<string, () => void>();\n const busy = new Set<string>();\n const generations = new Map<string, symbol>();\n const newGeneration = (sessionId: string): symbol => {\n const generation = Symbol(sessionId);\n generations.set(sessionId, generation);\n return generation;\n };\n\n /** Republishes a session, skipping a frame that would say nothing new. */\n const publish = (scope: DoomHubSessionScope, force: boolean): void => {\n const previous = latest.get(scope.sessionId);\n const next: SessionState = {\n worktrees: viewsFor(scope, views),\n pending: previous?.pending,\n error: previous?.error,\n errorTarget: previous?.errorTarget,\n };\n if (\n !force &&\n previous !== undefined &&\n sameList(previous.worktrees, next.worktrees) &&\n previous.pending === next.pending &&\n previous.error === next.error &&\n previous.errorTarget === next.errorTarget\n ) {\n return;\n }\n latest.set(scope.sessionId, next);\n host.publish(scope.sessionId, payloadOf(next));\n };\n\n const mark = (\n scope: DoomHubSessionScope,\n pending: string | undefined,\n error: string | undefined,\n errorTarget: WorktreeErrorTarget | undefined,\n ): void => {\n const previous = latest.get(scope.sessionId);\n latest.set(scope.sessionId, {\n worktrees: previous?.worktrees ?? viewsFor(scope, views),\n pending,\n error,\n errorTarget,\n });\n publish(scope, true);\n };\n\n /** Announces a successful mutation to this session's lifecycle subscribers. */\n const publishLifecycle = (scope: DoomHubSessionScope, repositoryRoot: string): void => {\n host.directEvents.publish(GIT_WORKTREE_LIFECYCLE_EVENT, scope.sessionId, {\n version: 1,\n repositoryRoot,\n });\n };\n\n const run = async (\n scope: DoomHubSessionScope,\n command: GitWorktreesCommand,\n generation: symbol,\n ): Promise<void> => {\n const context = { cwd: scope.cwd, sessionId: scope.sessionId };\n const markCurrent = (\n pending: string | undefined,\n error: string | undefined,\n errorTarget: WorktreeErrorTarget | undefined,\n ): void => {\n if (generations.get(scope.sessionId) !== generation) return;\n mark(scope, pending, error, errorTarget);\n };\n if (command.action === 'create') {\n markCurrent(`creating ${command.branch}…`, undefined, undefined);\n const record = await worktrees.spawn(\n context,\n {\n branch: command.branch,\n ...(command.baseRef === undefined ? {} : { baseRef: command.baseRef }),\n ...(command.reservationId === undefined ? {} : { reservationId: command.reservationId }),\n },\n // Each phase replaces the label, so the panel says what is\n // happening instead of holding one line for the whole wait.\n { onProgress: (label) => markCurrent(label, undefined, undefined) },\n );\n if (generations.get(scope.sessionId) !== generation) return;\n publishLifecycle(scope, record.repositoryRoot);\n return;\n }\n markCurrent(`closing ${command.id}…`, undefined, undefined);\n const record = await worktrees.close(context, command.id, command.force ?? false);\n if (generations.get(scope.sessionId) !== generation) return;\n publishLifecycle(scope, record.repositoryRoot);\n };\n\n const source: DoomHubChannelSource = {\n payloadFor(scope) {\n const state = latest.get(scope.sessionId);\n return state === undefined ? undefined : payloadOf(state);\n },\n sessionAdded(scope) {\n newGeneration(scope.sessionId);\n publish(scope, false);\n const unsubscribe = host.directEvents.subscribe(GIT_WORKTREE_LIFECYCLE_EVENT, scope.sessionId, (payload) => {\n if (!isWorktreeLifecycleEvent(payload)) return;\n let sameRepository = false;\n try {\n sameRepository =\n registryFile(scope.cwd, options.homeDir) === registryFile(payload.repositoryRoot, options.homeDir);\n } catch {\n sameRepository = false;\n }\n if (sameRepository) publish(scope, false);\n });\n subscriptions.set(scope.sessionId, unsubscribe);\n },\n sessionRemoved(sessionId) {\n newGeneration(sessionId);\n subscriptions.get(sessionId)?.();\n subscriptions.delete(sessionId);\n latest.delete(sessionId);\n busy.delete(sessionId);\n },\n close() {\n unregisterWorktreeProvisioner?.();\n for (const unsubscribe of subscriptions.values()) unsubscribe();\n subscriptions.clear();\n latest.clear();\n busy.clear();\n generations.clear();\n },\n };\n receiveCommand = (scope, payload) => {\n const command = parseCommand(payload);\n if (command === undefined) return;\n // One operation per session. A create runs for minutes, and a second\n // click must not start a second worktree behind the first.\n if (busy.has(scope.sessionId)) return;\n const generation = generations.get(scope.sessionId);\n if (generation === undefined) return;\n busy.add(scope.sessionId);\n void run(scope, command, generation)\n .then(() => {\n if (generations.get(scope.sessionId) !== generation) return;\n mark(scope, undefined, undefined, undefined);\n })\n .catch((error: unknown) => {\n if (generations.get(scope.sessionId) !== generation) return;\n host.onNotice(`worktree command failed for ${scope.sessionId} (${failureText(error)})`);\n mark(scope, undefined, failureText(error), errorTargetFor(command));\n })\n .finally(() => {\n if (generations.get(scope.sessionId) === generation) busy.delete(scope.sessionId);\n });\n };\n\n return source;\n },\n receive(scope, payload) {\n receiveCommand?.(scope, payload);\n },\n };\n}\n\nexport default createWorktreesChannel;\n","import { defineChannel } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/git-worktrees.server';\n\nexport default defineChannel(contribution);\n","import type { WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\n\nimport type { GitServerScope } from '../../_lib/root.server';\n\nexport default (context: WithRoot<DoomServerPluginContext, GitServerScope>) => context.root.resources[0]!;\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/doompiGit.server';\n\nexport default defineResource(contribution);\n","import type { WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\n\nimport type { GitServerScope } from '../../_lib/root.server';\n\nexport default (context: WithRoot<DoomServerPluginContext, GitServerScope>) => context.root.resources[2]!;\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/doompiGitReadme.server';\n\nexport default defineResource(contribution);\n","import type { WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\n\nimport type { GitServerScope } from '../../_lib/root.server';\n\nexport default (context: WithRoot<DoomServerPluginContext, GitServerScope>) => context.root.resources[1]!;\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/doompiUseGit.server';\n\nexport default defineResource(contribution);\n","import { defineServerTool, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\n\nimport type { GitServerScope } from '../_lib/root.server';\n\nexport default defineServerTool((context: WithRoot<DoomServerPluginContext, GitServerScope>) => context.root.tool);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineServerPlugin, type DoomServerSessionPlugin } from '@agimon-ai/doompi-core/serverFacet';\nimport { composeRootHooks } from '@agimon-ai/doompi-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.server';\nimport apiRoute from '../src/extensions/(backend)/api/route.server';\nimport channelGitWorktrees from '../src/extensions/(backend)/channel/git-worktrees.server';\nimport resourceDoompiGit from '../src/extensions/workspaces/sessions/(backend)/resource/doompiGit.server';\nimport resourceDoompiGitReadme from '../src/extensions/workspaces/sessions/(backend)/resource/doompiGitReadme.server';\nimport resourceDoompiUseGit from '../src/extensions/workspaces/sessions/(backend)/resource/doompiUseGit.server';\nimport toolRunWorktree from '../src/extensions/workspaces/sessions/(backend)/tool/runWorktree.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const facet = defineServerPlugin({\n name: '@agimon-ai/doompi-git',\n global: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return [at(apiRoute, context)]; },\n get channels(): DoomServerSessionPlugin['channels'] { return [() => via({ frameType: 'git_worktrees' }, channelGitWorktrees())]; },\n }),\n workspace: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return [at(apiRoute, context)]; },\n get channels(): DoomServerSessionPlugin['channels'] { return [() => via({ frameType: 'git_worktrees' }, channelGitWorktrees())]; },\n }),\n session: async (context) => {\n const scopeSession = await rootSession(context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get api(): DoomServerSessionPlugin['api'] { return [at(apiRoute, context)]; },\n get channels(): DoomServerSessionPlugin['channels'] { return [() => via({ frameType: 'git_worktrees' }, channelGitWorktrees())]; },\n get resources(): DoomServerSessionPlugin['resources'] { return [at(resourceDoompiGit, contextSession), at(resourceDoompiGitReadme, contextSession), at(resourceDoompiUseGit, contextSession)]; },\n get tools(): DoomServerSessionPlugin['tools'] { return [via({ name: 'run_worktree' }, at(toolRunWorktree, contextSession))]; },\n services: [...(scopeSession.services ?? [])],\n get activities(): DoomServerSessionPlugin['activities'] { return [...(scopeSession.activities ?? [])]; },\n };\n },\n});\n\nexport default facet;\n"],"mappings":"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"}
1
+ {"version":3,"file":"server.cjs","names":["createWorktreeMessageInbox","createWorktreeOperations","createWorktreeGit","readDoomSessionDelivery","readPackageResource","RUN_WORKTREE_TOOL_NAME","RUN_WORKTREE_DESCRIPTION","RunWorktreeToolSchema","validateParams","executeRunWorktreeTool","defineRoot","defineRoot","contribution","DoomGitExpectedError","GIT_WORKTREE_LIFECYCLE_EVENT","createWorktreeOperations","createWorktreeGit","defineRoute","contribution","createWorktreeRegistry","registryFile","DoomGitExpectedError","HubUnavailableError","createWorktreeOperations","createWorktreeGit","GIT_WORKTREE_LIFECYCLE_EVENT","isWorktreeLifecycleEvent","defineChannel","contribution","defineResource","contribution","defineResource","contribution","defineResource","contribution","defineServerTool","defineServerPlugin","apiRoute","channelGitWorktrees","rootSession","composeRootHooks","resourceDoompiGit","resourceDoompiGitReadme","resourceDoompiUseGit","toolRunWorktree"],"sources":["../../src/extensions/workspaces/sessions/(backend)/_lib/root.server.ts","../../src/extensions/workspaces/sessions/(backend)/root.server.ts","../../src/extensions/(backend)/api/_lib/route.server.ts","../../src/extensions/(backend)/api/route.server.ts","../../src/types/webWorktrees.ts","../../src/extensions/(backend)/channel/_lib/git-worktrees.server.ts","../../src/extensions/(backend)/channel/git-worktrees.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiGit.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompiGit.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiGitReadme.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompiGitReadme.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiUseGit.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompiUseGit.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/runWorktree.server.ts","../../generated/server.ts"],"sourcesContent":["import { defineRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport {\n type DoomHeadlessResource,\n type DoomHeadlessTool,\n type DoomHeadlessToolResult,\n} from '@agimon-ai/doompi-core/headless';\nimport { readPackageResource, type DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\nimport { readDoomSessionDelivery } from '@agimon-ai/doompi-session';\n\nimport { RunWorktreeToolSchema, type RunWorktreeToolParams } from '../../../../../schemas/runWorktreeTool';\nimport { createWorktreeGit } from '../../../../../services/gitCli';\nimport {\n executeRunWorktreeTool,\n RUN_WORKTREE_DESCRIPTION,\n RUN_WORKTREE_TOOL_NAME,\n validateParams,\n} from '../../../../../services/runWorktree';\nimport { createWorktreeMessageInbox } from '../../../../../services/worktreeEvents';\nimport { createWorktreeOperations } from '../../../../../services/worktreeOperations';\n\nfunction progressResult(action: RunWorktreeToolParams['action'], label: string): DoomHeadlessToolResult {\n return { content: [{ type: 'text', text: label }], details: { action } };\n}\n\nexport function createGitSession({ context, host: serverHost }: DoomServerPluginContext) {\n if (serverHost.context.directEvents === undefined)\n throw new Error('Git headless facet requires the session direct event bus.');\n if (serverHost.context.sessionId === undefined) throw new Error('Git headless facet requires a session identity.');\n const sessionId = serverHost.context.sessionId;\n const directEvents = serverHost.context.directEvents;\n const messageInbox = createWorktreeMessageInbox(directEvents, sessionId);\n const operations = createWorktreeOperations({\n git: createWorktreeGit(),\n sessionService: serverHost.context.sessionService,\n messageInbox,\n sessionDelivery: () => readDoomSessionDelivery(context),\n });\n const resources: DoomHeadlessResource[] = [\n {\n // The package index is Help-catalog material, not standing instruction, so it\n // only enters the prompt while Help mode is active. Matches the Pi facet,\n // which has always routed this through the Help service.\n when: { state: { 'minor-mode': 'help' }, attribution: { kind: 'minor', mode: 'help' } },\n name: 'doompi-git',\n kind: 'context',\n read: () => readPackageResource(import.meta.url, 'llms.txt'),\n },\n {\n name: 'doompi-use-git',\n kind: 'skill',\n read: () => readPackageResource(import.meta.url, 'src/prompts/doompi-use-git/SKILL.md'),\n },\n ];\n\n const tool: DoomHeadlessTool<typeof RunWorktreeToolSchema> = {\n name: RUN_WORKTREE_TOOL_NAME,\n label: 'Worktree',\n description: RUN_WORKTREE_DESCRIPTION,\n parameters: RunWorktreeToolSchema,\n promptSnippet: 'Create and manage Git worktree sessions',\n executionMode: 'serial',\n async execute(_toolCallId, parameters, signal, onUpdate, execution) {\n const params = validateParams(parameters) as RunWorktreeToolParams;\n return executeRunWorktreeTool(params, operations, execution, {\n ...(signal === undefined ? {} : { signal }),\n onProgress: (label) => onUpdate?.(progressResult(params.action, label)),\n });\n },\n };\n return { value: { resources, tool }, onDispose: () => messageInbox.close() };\n}\n\nconst root = defineRoot(createGitSession);\nexport type GitServerScope = Awaited<ReturnType<typeof root>>['value'];\nexport default root;\n","import { defineRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/root.server';\n\nexport default defineRoot(contribution);\n","import type { DoomApi, DoomApiContext, DoomApiHandler } from '@agimon-ai/doompi-core/packageApi';\n\nimport { DoomGitExpectedError } from '../../../../services/errors';\nimport { createWorktreeGit } from '../../../../services/gitCli';\nimport { GIT_WORKTREE_LIFECYCLE_EVENT } from '../../../../services/worktreeEvents';\nimport { createWorktreeOperations } from '../../../../services/worktreeOperations';\n\n/**\n * The worktree surface the cockpit panel calls.\n *\n * Hub-scoped because worktrees are a property of a repository, not of one\n * session: the panel lists and creates them whether or not the session that\n * made them is focused, and a session-scoped API would disappear with it.\n *\n * The panel names a repository by the hub's opaque id and never by path.\n * `resolveRepository` turns that into an admitted root, so a browser cannot\n * point this at a directory the cockpit was never given.\n */\nfunction badRequest(message: string): Response {\n return Response.json({ error: message }, { status: 400 });\n}\n\nfunction failed(error: unknown): Response {\n if (error instanceof DoomGitExpectedError) {\n return Response.json({ error: error.message, code: error.code }, { status: error.retryable ? 503 : 409 });\n }\n // Never the raw message: a git failure can carry a remote URL with a token.\n return Response.json({ error: 'The worktree operation failed.' }, { status: 500 });\n}\n\nexport const api: DoomApi = {\n basePath: 'git',\n start(context: DoomApiContext): DoomApiHandler {\n if (context.directEvents === undefined) throw new Error('Git hub API requires the direct event bus.');\n const directEvents = context.directEvents;\n const publishLifecycle = (sessionId: string, repositoryRoot: string): void => {\n directEvents.publish(GIT_WORKTREE_LIFECYCLE_EVENT, sessionId, { version: 1 as const, repositoryRoot });\n };\n const operations = createWorktreeOperations({\n git: createWorktreeGit(),\n sessionService: context.sessionService,\n });\n\n /** The admitted root for a request, or a response explaining why not. */\n const rootOf = (url: URL): string | Response => {\n const repositoryId = url.searchParams.get('repositoryId');\n if (repositoryId === null || repositoryId === '') return badRequest('A repositoryId is required.');\n const root = context.resolveRepository?.(repositoryId);\n if (root === undefined) return badRequest('That repository is not admitted to this cockpit.');\n return root;\n };\n\n return {\n async fetch(request) {\n const url = new URL(request.url);\n const root = rootOf(url);\n if (root instanceof Response) return root;\n // The operations layer works from a cwd, and an admitted repository\n // root is one.\n const callerContext = { cwd: root, sessionId: url.searchParams.get('sessionId') ?? '' };\n const isMutation =\n (request.method === 'POST' && url.pathname === '/worktrees') ||\n (request.method === 'DELETE' && /^\\/worktrees\\/[^/]+$/u.test(url.pathname));\n if (isMutation && callerContext.sessionId === '')\n return badRequest('A sessionId is required for worktree mutations.');\n\n try {\n if (request.method === 'GET' && url.pathname === '/worktrees') {\n return Response.json({ worktrees: await operations.list(callerContext) });\n }\n if (request.method === 'POST' && url.pathname === '/worktrees') {\n const body = (await request.json()) as { branch?: string; baseRef?: string; name?: string };\n if (typeof body.branch !== 'string' || body.branch.trim() === '') {\n return badRequest('A branch is required.');\n }\n const record = await operations.spawn(callerContext, {\n branch: body.branch,\n ...(body.baseRef === undefined ? {} : { baseRef: body.baseRef }),\n ...(body.name === undefined ? {} : { name: body.name }),\n });\n publishLifecycle(callerContext.sessionId, record.repositoryRoot);\n return Response.json({ worktree: record }, { status: 201 });\n }\n const closing = /^\\/worktrees\\/([^/]+)$/u.exec(url.pathname);\n if (request.method === 'DELETE' && closing) {\n const record = await operations.close(\n callerContext,\n decodeURIComponent(String(closing[1])),\n url.searchParams.get('force') === 'true',\n );\n publishLifecycle(callerContext.sessionId, record.repositoryRoot);\n return Response.json({ worktree: record });\n }\n return Response.json({ error: 'No such worktree route.' }, { status: 404 });\n } catch (error) {\n context.onNotice(`worktree request failed: ${(error as Error).name}`);\n return failed(error);\n }\n },\n close() {},\n };\n },\n};\n\nexport default api;\n","import { defineRoute } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/route.server';\n\nexport default defineRoute(contribution);\n","/**\n * The cockpit's view of this session's worktrees.\n *\n * DESIGN PATTERNS:\n * - Declarations only. The channel frame type is a constant so the hub and the\n * page cannot drift apart on a string.\n * - A view is the subset of a record the dock needs, not the record. The\n * registry may hold paths and provenance the page has no business rendering.\n *\n * AVOID:\n * - Adding behaviour here. This file is imported by browser code, so it must\n * stay free of node builtins.\n */\n\n/** The data channel carrying one session's worktrees to the page. */\nexport const GIT_WORKTREES_TYPE = 'git_worktrees';\n\n/** One worktree, as the activity dock and its panel render it. */\nexport interface WorktreeView {\n id: string;\n branch: string;\n path: string;\n /** The session the hub started for this worktree, when it is still live. */\n sessionId: string | null;\n /** True once the directory the record names has gone missing. */\n orphaned: boolean;\n /**\n * True when the session that asked for this worktree is gone.\n *\n * An owned worktree is only ever shown to its own session. This flag marks\n * the exception: once the parent is dead nobody would see the worktree at\n * all, so every session in the repository does, and may close it.\n */\n unowned: boolean;\n}\n\n/**\n * What the panel asks the hub channel to do.\n *\n * The dock acts through its own channel rather than through the agent: a\n * worktree made from the panel and one made by the tool take the same\n * `worktreeOperations` path, but the panel no longer has to spend a turn of\n * the conversation to get there.\n */\nexport type GitWorktreesCommand =\n | { action: 'create'; branch: string; baseRef?: string; reservationId?: string }\n | { action: 'close'; id: string; force?: boolean };\n\nexport type WorktreeErrorTarget = { action: 'create' } | { action: 'close'; id: string };\n\nexport interface GitWorktreesPayload {\n worktrees: WorktreeView[];\n /** Label of the operation in flight, absent when the session is idle. */\n pending?: string;\n /** The last failure, cleared when the next command starts. */\n error?: string;\n /** The operation that produced the last failure, when known. */\n errorTarget?: WorktreeErrorTarget;\n}\n","/**\n * The worktrees data channel, and the commands the dock sends back through it.\n *\n * The registry is durable state only. Live lifecycle changes arrive through the\n * hub-owned direct event bus, so this channel never polls or claims files.\n */\nimport type {\n DoomHubChannel,\n DoomHubChannelSource,\n DoomHubSessionScope,\n DoomHubSessionService,\n} from '@agimon-ai/doompi-core/hubChannel';\n\nimport { DoomGitExpectedError, HubUnavailableError } from '../../../../services/errors';\nimport { createWorktreeGit } from '../../../../services/gitCli';\nimport { registryFile } from '../../../../services/paths';\nimport { GIT_WORKTREE_LIFECYCLE_EVENT, isWorktreeLifecycleEvent } from '../../../../services/worktreeEvents';\nimport { createWorktreeOperations, type WorktreeOperations } from '../../../../services/worktreeOperations';\nimport { createWorktreeRegistry } from '../../../../services/worktreeRegistry';\nimport {\n GIT_WORKTREES_TYPE,\n type GitWorktreesCommand,\n type WorktreeErrorTarget,\n type WorktreeView,\n} from '../../../../types/webWorktrees';\n\ninterface SessionState {\n worktrees: WorktreeView[];\n pending: string | undefined;\n error: string | undefined;\n errorTarget: WorktreeErrorTarget | undefined;\n}\n\nfunction payloadOf(state: SessionState): Record<string, unknown> {\n return {\n worktrees: state.worktrees,\n ...(state.pending === undefined ? {} : { pending: state.pending }),\n ...(state.error === undefined ? {} : { error: state.error }),\n ...(state.errorTarget === undefined ? {} : { errorTarget: state.errorTarget }),\n };\n}\n\n/** What the channel needs from its surroundings, injected so tests stay off this machine. */\nexport interface WorktreesChannelOptions {\n operations?: WorktreeOperations;\n homeDir?: string;\n}\n\ninterface ViewDeps {\n homeDir: string | undefined;\n sessionService: DoomHubSessionService;\n}\n\n/** Worktrees visible to this session, using the hub's live session table for ownership. */\nfunction viewsFor(scope: DoomHubSessionScope, deps: ViewDeps): WorktreeView[] {\n try {\n return createWorktreeRegistry(registryFile(scope.cwd, deps.homeDir))\n .list()\n .flatMap((record) => {\n const owned = record.parentSessionId === scope.sessionId;\n const unowned = !owned && !deps.sessionService.isLive(record.parentSessionId);\n if (!owned && !unowned) return [];\n return [\n {\n id: record.id,\n branch: record.branch,\n path: record.path,\n sessionId: record.status === 'orphaned' ? null : record.sessionId,\n orphaned: record.status === 'orphaned',\n unowned,\n },\n ];\n });\n } catch {\n return [];\n }\n}\n\nfunction sameList(left: readonly WorktreeView[], right: readonly WorktreeView[]): boolean {\n if (left.length !== right.length) return false;\n return left.every((entry, index) => {\n const other = right[index];\n return (\n other !== undefined &&\n entry.id === other.id &&\n entry.branch === other.branch &&\n entry.sessionId === other.sessionId &&\n entry.orphaned === other.orphaned &&\n entry.unowned === other.unowned\n );\n });\n}\n\nfunction errorTargetFor(command: GitWorktreesCommand): WorktreeErrorTarget {\n return command.action === 'create' ? { action: 'create' } : { action: 'close', id: command.id };\n}\n\n/** A command the page sent, or undefined when the frame was not one. */\nfunction parseCommand(payload: unknown): GitWorktreesCommand | undefined {\n if (typeof payload !== 'object' || payload === null) return undefined;\n const value = payload as Record<string, unknown>;\n if (value.action === 'create') {\n if (typeof value.branch !== 'string' || value.branch.trim() === '') return undefined;\n if (\n value.reservationId !== undefined &&\n (typeof value.reservationId !== 'string' || !/^[A-Za-z0-9_-]+$/u.test(value.reservationId))\n )\n return undefined;\n return {\n action: 'create',\n branch: value.branch.trim(),\n ...(typeof value.baseRef === 'string' && value.baseRef.trim() !== '' ? { baseRef: value.baseRef.trim() } : {}),\n ...(typeof value.reservationId === 'string' ? { reservationId: value.reservationId } : {}),\n };\n }\n if (value.action === 'close') {\n if (typeof value.id !== 'string' || value.id === '') return undefined;\n return { action: 'close', id: value.id, ...(value.force === true ? { force: true } : {}) };\n }\n return undefined;\n}\n\n/**\n * What the reader is told when a command fails.\n *\n * An expected failure explains itself. Anything else is summarised, never\n * echoed: a git error can carry a remote URL with a token in it.\n */\nfunction failureText(error: unknown): string {\n return error instanceof DoomGitExpectedError ? error.message : 'The worktree operation failed.';\n}\n\n/** Starts one direct-event subscription per managed session. */\nexport function createWorktreesChannel(options: WorktreesChannelOptions = {}): DoomHubChannel {\n // Assigned by start, because receive is reachable only while the channel is\n // running and the command needs the state the direct event subscriptions keep.\n let receiveCommand: ((scope: DoomHubSessionScope, payload: unknown) => void) | undefined;\n\n return {\n frameType: GIT_WORKTREES_TYPE,\n start(host) {\n const sessionService = host.sessionService;\n if (sessionService === undefined) {\n throw new HubUnavailableError('The cockpit session service is unavailable. Start the cockpit and try again.');\n }\n const worktrees =\n options.operations ??\n createWorktreeOperations({\n git: createWorktreeGit(),\n sessionService,\n });\n /** Announces a successful mutation to this session's lifecycle subscribers. */\n const publishLifecycle = (scope: DoomHubSessionScope, repositoryRoot: string): void => {\n host.directEvents.publish(GIT_WORKTREE_LIFECYCLE_EVENT, scope.sessionId, {\n version: 1,\n repositoryRoot,\n });\n };\n const unregisterWorktreeProvisioner = sessionService.registerReservedWorktreeProvisioner?.(\n async ({ reservationId, parentSessionId, signal }) => {\n const parent = host.sessions().find((scope) => scope.sessionId === parentSessionId);\n if (parent === undefined) throw new Error('The conversation parent session is unavailable.');\n const branch = `doompi/conversation-${reservationId.slice(0, 12)}`;\n const record = await worktrees.spawn(\n { cwd: parent.cwd, sessionId: parent.sessionId },\n { branch, name: `conversation ${reservationId.slice(0, 8)}`, reservationId },\n { signal },\n );\n const reservations = sessionService.reservations;\n if (reservations === undefined) throw new Error('Conversation reservations are unavailable.');\n const session = await reservations.complete(reservationId, parentSessionId);\n publishLifecycle(parent, record.repositoryRoot);\n return session;\n },\n );\n const views: ViewDeps = { homeDir: options.homeDir, sessionService };\n const latest = new Map<string, SessionState>();\n const subscriptions = new Map<string, () => void>();\n const busy = new Set<string>();\n const generations = new Map<string, symbol>();\n const newGeneration = (sessionId: string): symbol => {\n const generation = Symbol(sessionId);\n generations.set(sessionId, generation);\n return generation;\n };\n\n /** Republishes a session, skipping a frame that would say nothing new. */\n const publish = (scope: DoomHubSessionScope, force: boolean): void => {\n const previous = latest.get(scope.sessionId);\n const next: SessionState = {\n worktrees: viewsFor(scope, views),\n pending: previous?.pending,\n error: previous?.error,\n errorTarget: previous?.errorTarget,\n };\n if (\n !force &&\n previous !== undefined &&\n sameList(previous.worktrees, next.worktrees) &&\n previous.pending === next.pending &&\n previous.error === next.error &&\n previous.errorTarget === next.errorTarget\n ) {\n return;\n }\n latest.set(scope.sessionId, next);\n host.publish(scope.sessionId, payloadOf(next));\n };\n\n const mark = (\n scope: DoomHubSessionScope,\n pending: string | undefined,\n error: string | undefined,\n errorTarget: WorktreeErrorTarget | undefined,\n ): void => {\n const previous = latest.get(scope.sessionId);\n latest.set(scope.sessionId, {\n worktrees: previous?.worktrees ?? viewsFor(scope, views),\n pending,\n error,\n errorTarget,\n });\n publish(scope, true);\n };\n\n const run = async (\n scope: DoomHubSessionScope,\n command: GitWorktreesCommand,\n generation: symbol,\n ): Promise<void> => {\n const context = { cwd: scope.cwd, sessionId: scope.sessionId };\n const markCurrent = (\n pending: string | undefined,\n error: string | undefined,\n errorTarget: WorktreeErrorTarget | undefined,\n ): void => {\n if (generations.get(scope.sessionId) !== generation) return;\n mark(scope, pending, error, errorTarget);\n };\n if (command.action === 'create') {\n markCurrent(`creating ${command.branch}…`, undefined, undefined);\n const record = await worktrees.spawn(\n context,\n {\n branch: command.branch,\n ...(command.baseRef === undefined ? {} : { baseRef: command.baseRef }),\n ...(command.reservationId === undefined ? {} : { reservationId: command.reservationId }),\n },\n // Each phase replaces the label, so the panel says what is\n // happening instead of holding one line for the whole wait.\n { onProgress: (label) => markCurrent(label, undefined, undefined) },\n );\n if (generations.get(scope.sessionId) !== generation) return;\n publishLifecycle(scope, record.repositoryRoot);\n return;\n }\n markCurrent(`closing ${command.id}…`, undefined, undefined);\n const record = await worktrees.close(context, command.id, command.force ?? false);\n if (generations.get(scope.sessionId) !== generation) return;\n publishLifecycle(scope, record.repositoryRoot);\n };\n\n const source: DoomHubChannelSource = {\n payloadFor(scope) {\n const state = latest.get(scope.sessionId);\n return state === undefined ? undefined : payloadOf(state);\n },\n sessionAdded(scope) {\n newGeneration(scope.sessionId);\n publish(scope, false);\n const unsubscribe = host.directEvents.subscribe(GIT_WORKTREE_LIFECYCLE_EVENT, scope.sessionId, (payload) => {\n if (!isWorktreeLifecycleEvent(payload)) return;\n let sameRepository = false;\n try {\n sameRepository =\n registryFile(scope.cwd, options.homeDir) === registryFile(payload.repositoryRoot, options.homeDir);\n } catch {\n sameRepository = false;\n }\n if (sameRepository) publish(scope, false);\n });\n subscriptions.set(scope.sessionId, unsubscribe);\n },\n sessionRemoved(sessionId) {\n newGeneration(sessionId);\n subscriptions.get(sessionId)?.();\n subscriptions.delete(sessionId);\n latest.delete(sessionId);\n busy.delete(sessionId);\n },\n close() {\n unregisterWorktreeProvisioner?.();\n for (const unsubscribe of subscriptions.values()) unsubscribe();\n subscriptions.clear();\n latest.clear();\n busy.clear();\n generations.clear();\n },\n };\n receiveCommand = (scope, payload) => {\n const command = parseCommand(payload);\n if (command === undefined) return;\n // One operation per session. A create runs for minutes, and a second\n // click must not start a second worktree behind the first.\n if (busy.has(scope.sessionId)) return;\n const generation = generations.get(scope.sessionId);\n if (generation === undefined) return;\n busy.add(scope.sessionId);\n void run(scope, command, generation)\n .then(() => {\n if (generations.get(scope.sessionId) !== generation) return;\n mark(scope, undefined, undefined, undefined);\n })\n .catch((error: unknown) => {\n if (generations.get(scope.sessionId) !== generation) return;\n host.onNotice(`worktree command failed for ${scope.sessionId} (${failureText(error)})`);\n mark(scope, undefined, failureText(error), errorTargetFor(command));\n })\n .finally(() => {\n if (generations.get(scope.sessionId) === generation) busy.delete(scope.sessionId);\n });\n };\n\n return source;\n },\n receive(scope, payload) {\n receiveCommand?.(scope, payload);\n },\n };\n}\n\nexport default createWorktreesChannel;\n","import { defineChannel } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/git-worktrees.server';\n\nexport default defineChannel(contribution);\n","import type { WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\n\nimport type { GitServerScope } from '../../_lib/root.server';\n\nexport default (context: WithRoot<DoomServerPluginContext, GitServerScope>) => context.root.resources[0]!;\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/doompiGit.server';\n\nexport default defineResource(contribution);\n","import type { WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\n\nimport type { GitServerScope } from '../../_lib/root.server';\n\nexport default (context: WithRoot<DoomServerPluginContext, GitServerScope>) => context.root.resources[2]!;\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/doompiGitReadme.server';\n\nexport default defineResource(contribution);\n","import type { WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\n\nimport type { GitServerScope } from '../../_lib/root.server';\n\nexport default (context: WithRoot<DoomServerPluginContext, GitServerScope>) => context.root.resources[1]!;\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/doompiUseGit.server';\n\nexport default defineResource(contribution);\n","import { defineServerTool, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\n\nimport type { GitServerScope } from '../_lib/root.server';\n\nexport default defineServerTool((context: WithRoot<DoomServerPluginContext, GitServerScope>) => context.root.tool);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineServerPlugin, type DoomServerSessionPlugin } from '@agimon-ai/doompi-core/serverFacet';\nimport { composeRootHooks } from '@agimon-ai/doompi-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.server';\nimport apiRoute from '../src/extensions/(backend)/api/route.server';\nimport channelGitWorktrees from '../src/extensions/(backend)/channel/git-worktrees.server';\nimport resourceDoompiGit from '../src/extensions/workspaces/sessions/(backend)/resource/doompiGit.server';\nimport resourceDoompiGitReadme from '../src/extensions/workspaces/sessions/(backend)/resource/doompiGitReadme.server';\nimport resourceDoompiUseGit from '../src/extensions/workspaces/sessions/(backend)/resource/doompiUseGit.server';\nimport toolRunWorktree from '../src/extensions/workspaces/sessions/(backend)/tool/runWorktree.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const facet = defineServerPlugin({\n name: '@agimon-ai/doompi-git',\n global: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return [at(apiRoute, context)]; },\n get channels(): DoomServerSessionPlugin['channels'] { return [() => via({ frameType: 'git_worktrees' }, channelGitWorktrees())]; },\n }),\n workspace: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return [at(apiRoute, context)]; },\n get channels(): DoomServerSessionPlugin['channels'] { return [() => via({ frameType: 'git_worktrees' }, channelGitWorktrees())]; },\n }),\n session: async (context) => {\n const scopeSession = await rootSession(context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get api(): DoomServerSessionPlugin['api'] { return [at(apiRoute, context)]; },\n get channels(): DoomServerSessionPlugin['channels'] { return [() => via({ frameType: 'git_worktrees' }, channelGitWorktrees())]; },\n get resources(): DoomServerSessionPlugin['resources'] { return [at(resourceDoompiGit, contextSession), at(resourceDoompiGitReadme, contextSession), at(resourceDoompiUseGit, contextSession)]; },\n get tools(): DoomServerSessionPlugin['tools'] { return [via({ name: 'run_worktree' }, at(toolRunWorktree, contextSession))]; },\n services: [...(scopeSession.services ?? [])],\n get activities(): DoomServerSessionPlugin['activities'] { return [...(scopeSession.activities ?? [])]; },\n };\n },\n});\n\nexport default facet;\n"],"mappings":"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"}
@@ -257,11 +257,18 @@ function createWorktreesChannel(options = {}) {
257
257
  git: createWorktreeGit(),
258
258
  sessionService
259
259
  });
260
+ /** Announces a successful mutation to this session's lifecycle subscribers. */
261
+ const publishLifecycle = (scope, repositoryRoot) => {
262
+ host.directEvents.publish(GIT_WORKTREE_LIFECYCLE_EVENT, scope.sessionId, {
263
+ version: 1,
264
+ repositoryRoot
265
+ });
266
+ };
260
267
  const unregisterWorktreeProvisioner = sessionService.registerReservedWorktreeProvisioner?.(async ({ reservationId, parentSessionId, signal }) => {
261
268
  const parent = host.sessions().find((scope) => scope.sessionId === parentSessionId);
262
269
  if (parent === void 0) throw new Error("The conversation parent session is unavailable.");
263
270
  const branch = `doompi/conversation-${reservationId.slice(0, 12)}`;
264
- await worktrees.spawn({
271
+ const record = await worktrees.spawn({
265
272
  cwd: parent.cwd,
266
273
  sessionId: parent.sessionId
267
274
  }, {
@@ -271,7 +278,9 @@ function createWorktreesChannel(options = {}) {
271
278
  }, { signal });
272
279
  const reservations = sessionService.reservations;
273
280
  if (reservations === void 0) throw new Error("Conversation reservations are unavailable.");
274
- return reservations.complete(reservationId, parentSessionId);
281
+ const session = await reservations.complete(reservationId, parentSessionId);
282
+ publishLifecycle(parent, record.repositoryRoot);
283
+ return session;
275
284
  });
276
285
  const views = {
277
286
  homeDir: options.homeDir,
@@ -309,13 +318,6 @@ function createWorktreesChannel(options = {}) {
309
318
  });
310
319
  publish(scope, true);
311
320
  };
312
- /** Announces a successful mutation to this session's lifecycle subscribers. */
313
- const publishLifecycle = (scope, repositoryRoot) => {
314
- host.directEvents.publish(GIT_WORKTREE_LIFECYCLE_EVENT, scope.sessionId, {
315
- version: 1,
316
- repositoryRoot
317
- });
318
- };
319
321
  const run = async (scope, command, generation) => {
320
322
  const context = {
321
323
  cwd: scope.cwd,
@@ -1 +1 @@
1
- {"version":3,"file":"server.mjs","names":["contribution","contribution","contribution","contribution","contribution","contribution","apiRoute","channelGitWorktrees","rootSession","resourceDoompiGit","resourceDoompiGitReadme","resourceDoompiUseGit","toolRunWorktree"],"sources":["../../src/extensions/workspaces/sessions/(backend)/_lib/root.server.ts","../../src/extensions/workspaces/sessions/(backend)/root.server.ts","../../src/extensions/(backend)/api/_lib/route.server.ts","../../src/extensions/(backend)/api/route.server.ts","../../src/types/webWorktrees.ts","../../src/extensions/(backend)/channel/_lib/git-worktrees.server.ts","../../src/extensions/(backend)/channel/git-worktrees.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiGit.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompiGit.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiGitReadme.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompiGitReadme.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiUseGit.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompiUseGit.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/runWorktree.server.ts","../../generated/server.ts"],"sourcesContent":["import { defineRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport {\n type DoomHeadlessResource,\n type DoomHeadlessTool,\n type DoomHeadlessToolResult,\n} from '@agimon-ai/doompi-core/headless';\nimport { readPackageResource, type DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\nimport { readDoomSessionDelivery } from '@agimon-ai/doompi-session';\n\nimport { RunWorktreeToolSchema, type RunWorktreeToolParams } from '../../../../../schemas/runWorktreeTool';\nimport { createWorktreeGit } from '../../../../../services/gitCli';\nimport {\n executeRunWorktreeTool,\n RUN_WORKTREE_DESCRIPTION,\n RUN_WORKTREE_TOOL_NAME,\n validateParams,\n} from '../../../../../services/runWorktree';\nimport { createWorktreeMessageInbox } from '../../../../../services/worktreeEvents';\nimport { createWorktreeOperations } from '../../../../../services/worktreeOperations';\n\nfunction progressResult(action: RunWorktreeToolParams['action'], label: string): DoomHeadlessToolResult {\n return { content: [{ type: 'text', text: label }], details: { action } };\n}\n\nexport function createGitSession({ context, host: serverHost }: DoomServerPluginContext) {\n if (serverHost.context.directEvents === undefined)\n throw new Error('Git headless facet requires the session direct event bus.');\n if (serverHost.context.sessionId === undefined) throw new Error('Git headless facet requires a session identity.');\n const sessionId = serverHost.context.sessionId;\n const directEvents = serverHost.context.directEvents;\n const messageInbox = createWorktreeMessageInbox(directEvents, sessionId);\n const operations = createWorktreeOperations({\n git: createWorktreeGit(),\n sessionService: serverHost.context.sessionService,\n messageInbox,\n sessionDelivery: () => readDoomSessionDelivery(context),\n });\n const resources: DoomHeadlessResource[] = [\n {\n // The package index is Help-catalog material, not standing instruction, so it\n // only enters the prompt while Help mode is active. Matches the Pi facet,\n // which has always routed this through the Help service.\n when: { state: { 'minor-mode': 'help' }, attribution: { kind: 'minor', mode: 'help' } },\n name: 'doompi-git',\n kind: 'context',\n read: () => readPackageResource(import.meta.url, 'llms.txt'),\n },\n {\n name: 'doompi-use-git',\n kind: 'skill',\n read: () => readPackageResource(import.meta.url, 'src/prompts/doompi-use-git/SKILL.md'),\n },\n ];\n\n const tool: DoomHeadlessTool<typeof RunWorktreeToolSchema> = {\n name: RUN_WORKTREE_TOOL_NAME,\n label: 'Worktree',\n description: RUN_WORKTREE_DESCRIPTION,\n parameters: RunWorktreeToolSchema,\n promptSnippet: 'Create and manage Git worktree sessions',\n executionMode: 'serial',\n async execute(_toolCallId, parameters, signal, onUpdate, execution) {\n const params = validateParams(parameters) as RunWorktreeToolParams;\n return executeRunWorktreeTool(params, operations, execution, {\n ...(signal === undefined ? {} : { signal }),\n onProgress: (label) => onUpdate?.(progressResult(params.action, label)),\n });\n },\n };\n return { value: { resources, tool }, onDispose: () => messageInbox.close() };\n}\n\nconst root = defineRoot(createGitSession);\nexport type GitServerScope = Awaited<ReturnType<typeof root>>['value'];\nexport default root;\n","import { defineRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/root.server';\n\nexport default defineRoot(contribution);\n","import type { DoomApi, DoomApiContext, DoomApiHandler } from '@agimon-ai/doompi-core/packageApi';\n\nimport { DoomGitExpectedError } from '../../../../services/errors';\nimport { createWorktreeGit } from '../../../../services/gitCli';\nimport { GIT_WORKTREE_LIFECYCLE_EVENT } from '../../../../services/worktreeEvents';\nimport { createWorktreeOperations } from '../../../../services/worktreeOperations';\n\n/**\n * The worktree surface the cockpit panel calls.\n *\n * Hub-scoped because worktrees are a property of a repository, not of one\n * session: the panel lists and creates them whether or not the session that\n * made them is focused, and a session-scoped API would disappear with it.\n *\n * The panel names a repository by the hub's opaque id and never by path.\n * `resolveRepository` turns that into an admitted root, so a browser cannot\n * point this at a directory the cockpit was never given.\n */\nfunction badRequest(message: string): Response {\n return Response.json({ error: message }, { status: 400 });\n}\n\nfunction failed(error: unknown): Response {\n if (error instanceof DoomGitExpectedError) {\n return Response.json({ error: error.message, code: error.code }, { status: error.retryable ? 503 : 409 });\n }\n // Never the raw message: a git failure can carry a remote URL with a token.\n return Response.json({ error: 'The worktree operation failed.' }, { status: 500 });\n}\n\nexport const api: DoomApi = {\n basePath: 'git',\n start(context: DoomApiContext): DoomApiHandler {\n if (context.directEvents === undefined) throw new Error('Git hub API requires the direct event bus.');\n const directEvents = context.directEvents;\n const publishLifecycle = (sessionId: string, repositoryRoot: string): void => {\n directEvents.publish(GIT_WORKTREE_LIFECYCLE_EVENT, sessionId, { version: 1 as const, repositoryRoot });\n };\n const operations = createWorktreeOperations({\n git: createWorktreeGit(),\n sessionService: context.sessionService,\n });\n\n /** The admitted root for a request, or a response explaining why not. */\n const rootOf = (url: URL): string | Response => {\n const repositoryId = url.searchParams.get('repositoryId');\n if (repositoryId === null || repositoryId === '') return badRequest('A repositoryId is required.');\n const root = context.resolveRepository?.(repositoryId);\n if (root === undefined) return badRequest('That repository is not admitted to this cockpit.');\n return root;\n };\n\n return {\n async fetch(request) {\n const url = new URL(request.url);\n const root = rootOf(url);\n if (root instanceof Response) return root;\n // The operations layer works from a cwd, and an admitted repository\n // root is one.\n const callerContext = { cwd: root, sessionId: url.searchParams.get('sessionId') ?? '' };\n const isMutation =\n (request.method === 'POST' && url.pathname === '/worktrees') ||\n (request.method === 'DELETE' && /^\\/worktrees\\/[^/]+$/u.test(url.pathname));\n if (isMutation && callerContext.sessionId === '')\n return badRequest('A sessionId is required for worktree mutations.');\n\n try {\n if (request.method === 'GET' && url.pathname === '/worktrees') {\n return Response.json({ worktrees: await operations.list(callerContext) });\n }\n if (request.method === 'POST' && url.pathname === '/worktrees') {\n const body = (await request.json()) as { branch?: string; baseRef?: string; name?: string };\n if (typeof body.branch !== 'string' || body.branch.trim() === '') {\n return badRequest('A branch is required.');\n }\n const record = await operations.spawn(callerContext, {\n branch: body.branch,\n ...(body.baseRef === undefined ? {} : { baseRef: body.baseRef }),\n ...(body.name === undefined ? {} : { name: body.name }),\n });\n publishLifecycle(callerContext.sessionId, record.repositoryRoot);\n return Response.json({ worktree: record }, { status: 201 });\n }\n const closing = /^\\/worktrees\\/([^/]+)$/u.exec(url.pathname);\n if (request.method === 'DELETE' && closing) {\n const record = await operations.close(\n callerContext,\n decodeURIComponent(String(closing[1])),\n url.searchParams.get('force') === 'true',\n );\n publishLifecycle(callerContext.sessionId, record.repositoryRoot);\n return Response.json({ worktree: record });\n }\n return Response.json({ error: 'No such worktree route.' }, { status: 404 });\n } catch (error) {\n context.onNotice(`worktree request failed: ${(error as Error).name}`);\n return failed(error);\n }\n },\n close() {},\n };\n },\n};\n\nexport default api;\n","import { defineRoute } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/route.server';\n\nexport default defineRoute(contribution);\n","/**\n * The cockpit's view of this session's worktrees.\n *\n * DESIGN PATTERNS:\n * - Declarations only. The channel frame type is a constant so the hub and the\n * page cannot drift apart on a string.\n * - A view is the subset of a record the dock needs, not the record. The\n * registry may hold paths and provenance the page has no business rendering.\n *\n * AVOID:\n * - Adding behaviour here. This file is imported by browser code, so it must\n * stay free of node builtins.\n */\n\n/** The data channel carrying one session's worktrees to the page. */\nexport const GIT_WORKTREES_TYPE = 'git_worktrees';\n\n/** One worktree, as the activity dock and its panel render it. */\nexport interface WorktreeView {\n id: string;\n branch: string;\n path: string;\n /** The session the hub started for this worktree, when it is still live. */\n sessionId: string | null;\n /** True once the directory the record names has gone missing. */\n orphaned: boolean;\n /**\n * True when the session that asked for this worktree is gone.\n *\n * An owned worktree is only ever shown to its own session. This flag marks\n * the exception: once the parent is dead nobody would see the worktree at\n * all, so every session in the repository does, and may close it.\n */\n unowned: boolean;\n}\n\n/**\n * What the panel asks the hub channel to do.\n *\n * The dock acts through its own channel rather than through the agent: a\n * worktree made from the panel and one made by the tool take the same\n * `worktreeOperations` path, but the panel no longer has to spend a turn of\n * the conversation to get there.\n */\nexport type GitWorktreesCommand =\n | { action: 'create'; branch: string; baseRef?: string; reservationId?: string }\n | { action: 'close'; id: string; force?: boolean };\n\nexport type WorktreeErrorTarget = { action: 'create' } | { action: 'close'; id: string };\n\nexport interface GitWorktreesPayload {\n worktrees: WorktreeView[];\n /** Label of the operation in flight, absent when the session is idle. */\n pending?: string;\n /** The last failure, cleared when the next command starts. */\n error?: string;\n /** The operation that produced the last failure, when known. */\n errorTarget?: WorktreeErrorTarget;\n}\n","/**\n * The worktrees data channel, and the commands the dock sends back through it.\n *\n * The registry is durable state only. Live lifecycle changes arrive through the\n * hub-owned direct event bus, so this channel never polls or claims files.\n */\nimport type {\n DoomHubChannel,\n DoomHubChannelSource,\n DoomHubSessionScope,\n DoomHubSessionService,\n} from '@agimon-ai/doompi-core/hubChannel';\n\nimport { DoomGitExpectedError, HubUnavailableError } from '../../../../services/errors';\nimport { createWorktreeGit } from '../../../../services/gitCli';\nimport { registryFile } from '../../../../services/paths';\nimport { GIT_WORKTREE_LIFECYCLE_EVENT, isWorktreeLifecycleEvent } from '../../../../services/worktreeEvents';\nimport { createWorktreeOperations, type WorktreeOperations } from '../../../../services/worktreeOperations';\nimport { createWorktreeRegistry } from '../../../../services/worktreeRegistry';\nimport {\n GIT_WORKTREES_TYPE,\n type GitWorktreesCommand,\n type WorktreeErrorTarget,\n type WorktreeView,\n} from '../../../../types/webWorktrees';\n\ninterface SessionState {\n worktrees: WorktreeView[];\n pending: string | undefined;\n error: string | undefined;\n errorTarget: WorktreeErrorTarget | undefined;\n}\n\nfunction payloadOf(state: SessionState): Record<string, unknown> {\n return {\n worktrees: state.worktrees,\n ...(state.pending === undefined ? {} : { pending: state.pending }),\n ...(state.error === undefined ? {} : { error: state.error }),\n ...(state.errorTarget === undefined ? {} : { errorTarget: state.errorTarget }),\n };\n}\n\n/** What the channel needs from its surroundings, injected so tests stay off this machine. */\nexport interface WorktreesChannelOptions {\n operations?: WorktreeOperations;\n homeDir?: string;\n}\n\ninterface ViewDeps {\n homeDir: string | undefined;\n sessionService: DoomHubSessionService;\n}\n\n/** Worktrees visible to this session, using the hub's live session table for ownership. */\nfunction viewsFor(scope: DoomHubSessionScope, deps: ViewDeps): WorktreeView[] {\n try {\n return createWorktreeRegistry(registryFile(scope.cwd, deps.homeDir))\n .list()\n .flatMap((record) => {\n const owned = record.parentSessionId === scope.sessionId;\n const unowned = !owned && !deps.sessionService.isLive(record.parentSessionId);\n if (!owned && !unowned) return [];\n return [\n {\n id: record.id,\n branch: record.branch,\n path: record.path,\n sessionId: record.status === 'orphaned' ? null : record.sessionId,\n orphaned: record.status === 'orphaned',\n unowned,\n },\n ];\n });\n } catch {\n return [];\n }\n}\n\nfunction sameList(left: readonly WorktreeView[], right: readonly WorktreeView[]): boolean {\n if (left.length !== right.length) return false;\n return left.every((entry, index) => {\n const other = right[index];\n return (\n other !== undefined &&\n entry.id === other.id &&\n entry.branch === other.branch &&\n entry.sessionId === other.sessionId &&\n entry.orphaned === other.orphaned &&\n entry.unowned === other.unowned\n );\n });\n}\n\nfunction errorTargetFor(command: GitWorktreesCommand): WorktreeErrorTarget {\n return command.action === 'create' ? { action: 'create' } : { action: 'close', id: command.id };\n}\n\n/** A command the page sent, or undefined when the frame was not one. */\nfunction parseCommand(payload: unknown): GitWorktreesCommand | undefined {\n if (typeof payload !== 'object' || payload === null) return undefined;\n const value = payload as Record<string, unknown>;\n if (value.action === 'create') {\n if (typeof value.branch !== 'string' || value.branch.trim() === '') return undefined;\n if (\n value.reservationId !== undefined &&\n (typeof value.reservationId !== 'string' || !/^[A-Za-z0-9_-]+$/u.test(value.reservationId))\n )\n return undefined;\n return {\n action: 'create',\n branch: value.branch.trim(),\n ...(typeof value.baseRef === 'string' && value.baseRef.trim() !== '' ? { baseRef: value.baseRef.trim() } : {}),\n ...(typeof value.reservationId === 'string' ? { reservationId: value.reservationId } : {}),\n };\n }\n if (value.action === 'close') {\n if (typeof value.id !== 'string' || value.id === '') return undefined;\n return { action: 'close', id: value.id, ...(value.force === true ? { force: true } : {}) };\n }\n return undefined;\n}\n\n/**\n * What the reader is told when a command fails.\n *\n * An expected failure explains itself. Anything else is summarised, never\n * echoed: a git error can carry a remote URL with a token in it.\n */\nfunction failureText(error: unknown): string {\n return error instanceof DoomGitExpectedError ? error.message : 'The worktree operation failed.';\n}\n\n/** Starts one direct-event subscription per managed session. */\nexport function createWorktreesChannel(options: WorktreesChannelOptions = {}): DoomHubChannel {\n // Assigned by start, because receive is reachable only while the channel is\n // running and the command needs the state the direct event subscriptions keep.\n let receiveCommand: ((scope: DoomHubSessionScope, payload: unknown) => void) | undefined;\n\n return {\n frameType: GIT_WORKTREES_TYPE,\n start(host) {\n const sessionService = host.sessionService;\n if (sessionService === undefined) {\n throw new HubUnavailableError('The cockpit session service is unavailable. Start the cockpit and try again.');\n }\n const worktrees =\n options.operations ??\n createWorktreeOperations({\n git: createWorktreeGit(),\n sessionService,\n });\n const unregisterWorktreeProvisioner = sessionService.registerReservedWorktreeProvisioner?.(\n async ({ reservationId, parentSessionId, signal }) => {\n const parent = host.sessions().find((scope) => scope.sessionId === parentSessionId);\n if (parent === undefined) throw new Error('The conversation parent session is unavailable.');\n const branch = `doompi/conversation-${reservationId.slice(0, 12)}`;\n await worktrees.spawn(\n { cwd: parent.cwd, sessionId: parent.sessionId },\n { branch, name: `conversation ${reservationId.slice(0, 8)}`, reservationId },\n { signal },\n );\n const reservations = sessionService.reservations;\n if (reservations === undefined) throw new Error('Conversation reservations are unavailable.');\n return reservations.complete(reservationId, parentSessionId);\n },\n );\n const views: ViewDeps = { homeDir: options.homeDir, sessionService };\n const latest = new Map<string, SessionState>();\n const subscriptions = new Map<string, () => void>();\n const busy = new Set<string>();\n const generations = new Map<string, symbol>();\n const newGeneration = (sessionId: string): symbol => {\n const generation = Symbol(sessionId);\n generations.set(sessionId, generation);\n return generation;\n };\n\n /** Republishes a session, skipping a frame that would say nothing new. */\n const publish = (scope: DoomHubSessionScope, force: boolean): void => {\n const previous = latest.get(scope.sessionId);\n const next: SessionState = {\n worktrees: viewsFor(scope, views),\n pending: previous?.pending,\n error: previous?.error,\n errorTarget: previous?.errorTarget,\n };\n if (\n !force &&\n previous !== undefined &&\n sameList(previous.worktrees, next.worktrees) &&\n previous.pending === next.pending &&\n previous.error === next.error &&\n previous.errorTarget === next.errorTarget\n ) {\n return;\n }\n latest.set(scope.sessionId, next);\n host.publish(scope.sessionId, payloadOf(next));\n };\n\n const mark = (\n scope: DoomHubSessionScope,\n pending: string | undefined,\n error: string | undefined,\n errorTarget: WorktreeErrorTarget | undefined,\n ): void => {\n const previous = latest.get(scope.sessionId);\n latest.set(scope.sessionId, {\n worktrees: previous?.worktrees ?? viewsFor(scope, views),\n pending,\n error,\n errorTarget,\n });\n publish(scope, true);\n };\n\n /** Announces a successful mutation to this session's lifecycle subscribers. */\n const publishLifecycle = (scope: DoomHubSessionScope, repositoryRoot: string): void => {\n host.directEvents.publish(GIT_WORKTREE_LIFECYCLE_EVENT, scope.sessionId, {\n version: 1,\n repositoryRoot,\n });\n };\n\n const run = async (\n scope: DoomHubSessionScope,\n command: GitWorktreesCommand,\n generation: symbol,\n ): Promise<void> => {\n const context = { cwd: scope.cwd, sessionId: scope.sessionId };\n const markCurrent = (\n pending: string | undefined,\n error: string | undefined,\n errorTarget: WorktreeErrorTarget | undefined,\n ): void => {\n if (generations.get(scope.sessionId) !== generation) return;\n mark(scope, pending, error, errorTarget);\n };\n if (command.action === 'create') {\n markCurrent(`creating ${command.branch}…`, undefined, undefined);\n const record = await worktrees.spawn(\n context,\n {\n branch: command.branch,\n ...(command.baseRef === undefined ? {} : { baseRef: command.baseRef }),\n ...(command.reservationId === undefined ? {} : { reservationId: command.reservationId }),\n },\n // Each phase replaces the label, so the panel says what is\n // happening instead of holding one line for the whole wait.\n { onProgress: (label) => markCurrent(label, undefined, undefined) },\n );\n if (generations.get(scope.sessionId) !== generation) return;\n publishLifecycle(scope, record.repositoryRoot);\n return;\n }\n markCurrent(`closing ${command.id}…`, undefined, undefined);\n const record = await worktrees.close(context, command.id, command.force ?? false);\n if (generations.get(scope.sessionId) !== generation) return;\n publishLifecycle(scope, record.repositoryRoot);\n };\n\n const source: DoomHubChannelSource = {\n payloadFor(scope) {\n const state = latest.get(scope.sessionId);\n return state === undefined ? undefined : payloadOf(state);\n },\n sessionAdded(scope) {\n newGeneration(scope.sessionId);\n publish(scope, false);\n const unsubscribe = host.directEvents.subscribe(GIT_WORKTREE_LIFECYCLE_EVENT, scope.sessionId, (payload) => {\n if (!isWorktreeLifecycleEvent(payload)) return;\n let sameRepository = false;\n try {\n sameRepository =\n registryFile(scope.cwd, options.homeDir) === registryFile(payload.repositoryRoot, options.homeDir);\n } catch {\n sameRepository = false;\n }\n if (sameRepository) publish(scope, false);\n });\n subscriptions.set(scope.sessionId, unsubscribe);\n },\n sessionRemoved(sessionId) {\n newGeneration(sessionId);\n subscriptions.get(sessionId)?.();\n subscriptions.delete(sessionId);\n latest.delete(sessionId);\n busy.delete(sessionId);\n },\n close() {\n unregisterWorktreeProvisioner?.();\n for (const unsubscribe of subscriptions.values()) unsubscribe();\n subscriptions.clear();\n latest.clear();\n busy.clear();\n generations.clear();\n },\n };\n receiveCommand = (scope, payload) => {\n const command = parseCommand(payload);\n if (command === undefined) return;\n // One operation per session. A create runs for minutes, and a second\n // click must not start a second worktree behind the first.\n if (busy.has(scope.sessionId)) return;\n const generation = generations.get(scope.sessionId);\n if (generation === undefined) return;\n busy.add(scope.sessionId);\n void run(scope, command, generation)\n .then(() => {\n if (generations.get(scope.sessionId) !== generation) return;\n mark(scope, undefined, undefined, undefined);\n })\n .catch((error: unknown) => {\n if (generations.get(scope.sessionId) !== generation) return;\n host.onNotice(`worktree command failed for ${scope.sessionId} (${failureText(error)})`);\n mark(scope, undefined, failureText(error), errorTargetFor(command));\n })\n .finally(() => {\n if (generations.get(scope.sessionId) === generation) busy.delete(scope.sessionId);\n });\n };\n\n return source;\n },\n receive(scope, payload) {\n receiveCommand?.(scope, payload);\n },\n };\n}\n\nexport default createWorktreesChannel;\n","import { defineChannel } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/git-worktrees.server';\n\nexport default defineChannel(contribution);\n","import type { WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\n\nimport type { GitServerScope } from '../../_lib/root.server';\n\nexport default (context: WithRoot<DoomServerPluginContext, GitServerScope>) => context.root.resources[0]!;\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/doompiGit.server';\n\nexport default defineResource(contribution);\n","import type { WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\n\nimport type { GitServerScope } from '../../_lib/root.server';\n\nexport default (context: WithRoot<DoomServerPluginContext, GitServerScope>) => context.root.resources[2]!;\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/doompiGitReadme.server';\n\nexport default defineResource(contribution);\n","import type { WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\n\nimport type { GitServerScope } from '../../_lib/root.server';\n\nexport default (context: WithRoot<DoomServerPluginContext, GitServerScope>) => context.root.resources[1]!;\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/doompiUseGit.server';\n\nexport default defineResource(contribution);\n","import { defineServerTool, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\n\nimport type { GitServerScope } from '../_lib/root.server';\n\nexport default defineServerTool((context: WithRoot<DoomServerPluginContext, GitServerScope>) => context.root.tool);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineServerPlugin, type DoomServerSessionPlugin } from '@agimon-ai/doompi-core/serverFacet';\nimport { composeRootHooks } from '@agimon-ai/doompi-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.server';\nimport apiRoute from '../src/extensions/(backend)/api/route.server';\nimport channelGitWorktrees from '../src/extensions/(backend)/channel/git-worktrees.server';\nimport resourceDoompiGit from '../src/extensions/workspaces/sessions/(backend)/resource/doompiGit.server';\nimport resourceDoompiGitReadme from '../src/extensions/workspaces/sessions/(backend)/resource/doompiGitReadme.server';\nimport resourceDoompiUseGit from '../src/extensions/workspaces/sessions/(backend)/resource/doompiUseGit.server';\nimport toolRunWorktree from '../src/extensions/workspaces/sessions/(backend)/tool/runWorktree.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const facet = defineServerPlugin({\n name: '@agimon-ai/doompi-git',\n global: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return [at(apiRoute, context)]; },\n get channels(): DoomServerSessionPlugin['channels'] { return [() => via({ frameType: 'git_worktrees' }, channelGitWorktrees())]; },\n }),\n workspace: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return [at(apiRoute, context)]; },\n get channels(): DoomServerSessionPlugin['channels'] { return [() => via({ frameType: 'git_worktrees' }, channelGitWorktrees())]; },\n }),\n session: async (context) => {\n const scopeSession = await rootSession(context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get api(): DoomServerSessionPlugin['api'] { return [at(apiRoute, context)]; },\n get channels(): DoomServerSessionPlugin['channels'] { return [() => via({ frameType: 'git_worktrees' }, channelGitWorktrees())]; },\n get resources(): DoomServerSessionPlugin['resources'] { return [at(resourceDoompiGit, contextSession), at(resourceDoompiGitReadme, contextSession), at(resourceDoompiUseGit, contextSession)]; },\n get tools(): DoomServerSessionPlugin['tools'] { return [via({ name: 'run_worktree' }, at(toolRunWorktree, contextSession))]; },\n services: [...(scopeSession.services ?? [])],\n get activities(): DoomServerSessionPlugin['activities'] { return [...(scopeSession.activities ?? [])]; },\n };\n },\n});\n\nexport default facet;\n"],"mappings":"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"}
1
+ {"version":3,"file":"server.mjs","names":["contribution","contribution","contribution","contribution","contribution","contribution","apiRoute","channelGitWorktrees","rootSession","resourceDoompiGit","resourceDoompiGitReadme","resourceDoompiUseGit","toolRunWorktree"],"sources":["../../src/extensions/workspaces/sessions/(backend)/_lib/root.server.ts","../../src/extensions/workspaces/sessions/(backend)/root.server.ts","../../src/extensions/(backend)/api/_lib/route.server.ts","../../src/extensions/(backend)/api/route.server.ts","../../src/types/webWorktrees.ts","../../src/extensions/(backend)/channel/_lib/git-worktrees.server.ts","../../src/extensions/(backend)/channel/git-worktrees.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiGit.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompiGit.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiGitReadme.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompiGitReadme.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiUseGit.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompiUseGit.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/runWorktree.server.ts","../../generated/server.ts"],"sourcesContent":["import { defineRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport {\n type DoomHeadlessResource,\n type DoomHeadlessTool,\n type DoomHeadlessToolResult,\n} from '@agimon-ai/doompi-core/headless';\nimport { readPackageResource, type DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\nimport { readDoomSessionDelivery } from '@agimon-ai/doompi-session';\n\nimport { RunWorktreeToolSchema, type RunWorktreeToolParams } from '../../../../../schemas/runWorktreeTool';\nimport { createWorktreeGit } from '../../../../../services/gitCli';\nimport {\n executeRunWorktreeTool,\n RUN_WORKTREE_DESCRIPTION,\n RUN_WORKTREE_TOOL_NAME,\n validateParams,\n} from '../../../../../services/runWorktree';\nimport { createWorktreeMessageInbox } from '../../../../../services/worktreeEvents';\nimport { createWorktreeOperations } from '../../../../../services/worktreeOperations';\n\nfunction progressResult(action: RunWorktreeToolParams['action'], label: string): DoomHeadlessToolResult {\n return { content: [{ type: 'text', text: label }], details: { action } };\n}\n\nexport function createGitSession({ context, host: serverHost }: DoomServerPluginContext) {\n if (serverHost.context.directEvents === undefined)\n throw new Error('Git headless facet requires the session direct event bus.');\n if (serverHost.context.sessionId === undefined) throw new Error('Git headless facet requires a session identity.');\n const sessionId = serverHost.context.sessionId;\n const directEvents = serverHost.context.directEvents;\n const messageInbox = createWorktreeMessageInbox(directEvents, sessionId);\n const operations = createWorktreeOperations({\n git: createWorktreeGit(),\n sessionService: serverHost.context.sessionService,\n messageInbox,\n sessionDelivery: () => readDoomSessionDelivery(context),\n });\n const resources: DoomHeadlessResource[] = [\n {\n // The package index is Help-catalog material, not standing instruction, so it\n // only enters the prompt while Help mode is active. Matches the Pi facet,\n // which has always routed this through the Help service.\n when: { state: { 'minor-mode': 'help' }, attribution: { kind: 'minor', mode: 'help' } },\n name: 'doompi-git',\n kind: 'context',\n read: () => readPackageResource(import.meta.url, 'llms.txt'),\n },\n {\n name: 'doompi-use-git',\n kind: 'skill',\n read: () => readPackageResource(import.meta.url, 'src/prompts/doompi-use-git/SKILL.md'),\n },\n ];\n\n const tool: DoomHeadlessTool<typeof RunWorktreeToolSchema> = {\n name: RUN_WORKTREE_TOOL_NAME,\n label: 'Worktree',\n description: RUN_WORKTREE_DESCRIPTION,\n parameters: RunWorktreeToolSchema,\n promptSnippet: 'Create and manage Git worktree sessions',\n executionMode: 'serial',\n async execute(_toolCallId, parameters, signal, onUpdate, execution) {\n const params = validateParams(parameters) as RunWorktreeToolParams;\n return executeRunWorktreeTool(params, operations, execution, {\n ...(signal === undefined ? {} : { signal }),\n onProgress: (label) => onUpdate?.(progressResult(params.action, label)),\n });\n },\n };\n return { value: { resources, tool }, onDispose: () => messageInbox.close() };\n}\n\nconst root = defineRoot(createGitSession);\nexport type GitServerScope = Awaited<ReturnType<typeof root>>['value'];\nexport default root;\n","import { defineRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/root.server';\n\nexport default defineRoot(contribution);\n","import type { DoomApi, DoomApiContext, DoomApiHandler } from '@agimon-ai/doompi-core/packageApi';\n\nimport { DoomGitExpectedError } from '../../../../services/errors';\nimport { createWorktreeGit } from '../../../../services/gitCli';\nimport { GIT_WORKTREE_LIFECYCLE_EVENT } from '../../../../services/worktreeEvents';\nimport { createWorktreeOperations } from '../../../../services/worktreeOperations';\n\n/**\n * The worktree surface the cockpit panel calls.\n *\n * Hub-scoped because worktrees are a property of a repository, not of one\n * session: the panel lists and creates them whether or not the session that\n * made them is focused, and a session-scoped API would disappear with it.\n *\n * The panel names a repository by the hub's opaque id and never by path.\n * `resolveRepository` turns that into an admitted root, so a browser cannot\n * point this at a directory the cockpit was never given.\n */\nfunction badRequest(message: string): Response {\n return Response.json({ error: message }, { status: 400 });\n}\n\nfunction failed(error: unknown): Response {\n if (error instanceof DoomGitExpectedError) {\n return Response.json({ error: error.message, code: error.code }, { status: error.retryable ? 503 : 409 });\n }\n // Never the raw message: a git failure can carry a remote URL with a token.\n return Response.json({ error: 'The worktree operation failed.' }, { status: 500 });\n}\n\nexport const api: DoomApi = {\n basePath: 'git',\n start(context: DoomApiContext): DoomApiHandler {\n if (context.directEvents === undefined) throw new Error('Git hub API requires the direct event bus.');\n const directEvents = context.directEvents;\n const publishLifecycle = (sessionId: string, repositoryRoot: string): void => {\n directEvents.publish(GIT_WORKTREE_LIFECYCLE_EVENT, sessionId, { version: 1 as const, repositoryRoot });\n };\n const operations = createWorktreeOperations({\n git: createWorktreeGit(),\n sessionService: context.sessionService,\n });\n\n /** The admitted root for a request, or a response explaining why not. */\n const rootOf = (url: URL): string | Response => {\n const repositoryId = url.searchParams.get('repositoryId');\n if (repositoryId === null || repositoryId === '') return badRequest('A repositoryId is required.');\n const root = context.resolveRepository?.(repositoryId);\n if (root === undefined) return badRequest('That repository is not admitted to this cockpit.');\n return root;\n };\n\n return {\n async fetch(request) {\n const url = new URL(request.url);\n const root = rootOf(url);\n if (root instanceof Response) return root;\n // The operations layer works from a cwd, and an admitted repository\n // root is one.\n const callerContext = { cwd: root, sessionId: url.searchParams.get('sessionId') ?? '' };\n const isMutation =\n (request.method === 'POST' && url.pathname === '/worktrees') ||\n (request.method === 'DELETE' && /^\\/worktrees\\/[^/]+$/u.test(url.pathname));\n if (isMutation && callerContext.sessionId === '')\n return badRequest('A sessionId is required for worktree mutations.');\n\n try {\n if (request.method === 'GET' && url.pathname === '/worktrees') {\n return Response.json({ worktrees: await operations.list(callerContext) });\n }\n if (request.method === 'POST' && url.pathname === '/worktrees') {\n const body = (await request.json()) as { branch?: string; baseRef?: string; name?: string };\n if (typeof body.branch !== 'string' || body.branch.trim() === '') {\n return badRequest('A branch is required.');\n }\n const record = await operations.spawn(callerContext, {\n branch: body.branch,\n ...(body.baseRef === undefined ? {} : { baseRef: body.baseRef }),\n ...(body.name === undefined ? {} : { name: body.name }),\n });\n publishLifecycle(callerContext.sessionId, record.repositoryRoot);\n return Response.json({ worktree: record }, { status: 201 });\n }\n const closing = /^\\/worktrees\\/([^/]+)$/u.exec(url.pathname);\n if (request.method === 'DELETE' && closing) {\n const record = await operations.close(\n callerContext,\n decodeURIComponent(String(closing[1])),\n url.searchParams.get('force') === 'true',\n );\n publishLifecycle(callerContext.sessionId, record.repositoryRoot);\n return Response.json({ worktree: record });\n }\n return Response.json({ error: 'No such worktree route.' }, { status: 404 });\n } catch (error) {\n context.onNotice(`worktree request failed: ${(error as Error).name}`);\n return failed(error);\n }\n },\n close() {},\n };\n },\n};\n\nexport default api;\n","import { defineRoute } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/route.server';\n\nexport default defineRoute(contribution);\n","/**\n * The cockpit's view of this session's worktrees.\n *\n * DESIGN PATTERNS:\n * - Declarations only. The channel frame type is a constant so the hub and the\n * page cannot drift apart on a string.\n * - A view is the subset of a record the dock needs, not the record. The\n * registry may hold paths and provenance the page has no business rendering.\n *\n * AVOID:\n * - Adding behaviour here. This file is imported by browser code, so it must\n * stay free of node builtins.\n */\n\n/** The data channel carrying one session's worktrees to the page. */\nexport const GIT_WORKTREES_TYPE = 'git_worktrees';\n\n/** One worktree, as the activity dock and its panel render it. */\nexport interface WorktreeView {\n id: string;\n branch: string;\n path: string;\n /** The session the hub started for this worktree, when it is still live. */\n sessionId: string | null;\n /** True once the directory the record names has gone missing. */\n orphaned: boolean;\n /**\n * True when the session that asked for this worktree is gone.\n *\n * An owned worktree is only ever shown to its own session. This flag marks\n * the exception: once the parent is dead nobody would see the worktree at\n * all, so every session in the repository does, and may close it.\n */\n unowned: boolean;\n}\n\n/**\n * What the panel asks the hub channel to do.\n *\n * The dock acts through its own channel rather than through the agent: a\n * worktree made from the panel and one made by the tool take the same\n * `worktreeOperations` path, but the panel no longer has to spend a turn of\n * the conversation to get there.\n */\nexport type GitWorktreesCommand =\n | { action: 'create'; branch: string; baseRef?: string; reservationId?: string }\n | { action: 'close'; id: string; force?: boolean };\n\nexport type WorktreeErrorTarget = { action: 'create' } | { action: 'close'; id: string };\n\nexport interface GitWorktreesPayload {\n worktrees: WorktreeView[];\n /** Label of the operation in flight, absent when the session is idle. */\n pending?: string;\n /** The last failure, cleared when the next command starts. */\n error?: string;\n /** The operation that produced the last failure, when known. */\n errorTarget?: WorktreeErrorTarget;\n}\n","/**\n * The worktrees data channel, and the commands the dock sends back through it.\n *\n * The registry is durable state only. Live lifecycle changes arrive through the\n * hub-owned direct event bus, so this channel never polls or claims files.\n */\nimport type {\n DoomHubChannel,\n DoomHubChannelSource,\n DoomHubSessionScope,\n DoomHubSessionService,\n} from '@agimon-ai/doompi-core/hubChannel';\n\nimport { DoomGitExpectedError, HubUnavailableError } from '../../../../services/errors';\nimport { createWorktreeGit } from '../../../../services/gitCli';\nimport { registryFile } from '../../../../services/paths';\nimport { GIT_WORKTREE_LIFECYCLE_EVENT, isWorktreeLifecycleEvent } from '../../../../services/worktreeEvents';\nimport { createWorktreeOperations, type WorktreeOperations } from '../../../../services/worktreeOperations';\nimport { createWorktreeRegistry } from '../../../../services/worktreeRegistry';\nimport {\n GIT_WORKTREES_TYPE,\n type GitWorktreesCommand,\n type WorktreeErrorTarget,\n type WorktreeView,\n} from '../../../../types/webWorktrees';\n\ninterface SessionState {\n worktrees: WorktreeView[];\n pending: string | undefined;\n error: string | undefined;\n errorTarget: WorktreeErrorTarget | undefined;\n}\n\nfunction payloadOf(state: SessionState): Record<string, unknown> {\n return {\n worktrees: state.worktrees,\n ...(state.pending === undefined ? {} : { pending: state.pending }),\n ...(state.error === undefined ? {} : { error: state.error }),\n ...(state.errorTarget === undefined ? {} : { errorTarget: state.errorTarget }),\n };\n}\n\n/** What the channel needs from its surroundings, injected so tests stay off this machine. */\nexport interface WorktreesChannelOptions {\n operations?: WorktreeOperations;\n homeDir?: string;\n}\n\ninterface ViewDeps {\n homeDir: string | undefined;\n sessionService: DoomHubSessionService;\n}\n\n/** Worktrees visible to this session, using the hub's live session table for ownership. */\nfunction viewsFor(scope: DoomHubSessionScope, deps: ViewDeps): WorktreeView[] {\n try {\n return createWorktreeRegistry(registryFile(scope.cwd, deps.homeDir))\n .list()\n .flatMap((record) => {\n const owned = record.parentSessionId === scope.sessionId;\n const unowned = !owned && !deps.sessionService.isLive(record.parentSessionId);\n if (!owned && !unowned) return [];\n return [\n {\n id: record.id,\n branch: record.branch,\n path: record.path,\n sessionId: record.status === 'orphaned' ? null : record.sessionId,\n orphaned: record.status === 'orphaned',\n unowned,\n },\n ];\n });\n } catch {\n return [];\n }\n}\n\nfunction sameList(left: readonly WorktreeView[], right: readonly WorktreeView[]): boolean {\n if (left.length !== right.length) return false;\n return left.every((entry, index) => {\n const other = right[index];\n return (\n other !== undefined &&\n entry.id === other.id &&\n entry.branch === other.branch &&\n entry.sessionId === other.sessionId &&\n entry.orphaned === other.orphaned &&\n entry.unowned === other.unowned\n );\n });\n}\n\nfunction errorTargetFor(command: GitWorktreesCommand): WorktreeErrorTarget {\n return command.action === 'create' ? { action: 'create' } : { action: 'close', id: command.id };\n}\n\n/** A command the page sent, or undefined when the frame was not one. */\nfunction parseCommand(payload: unknown): GitWorktreesCommand | undefined {\n if (typeof payload !== 'object' || payload === null) return undefined;\n const value = payload as Record<string, unknown>;\n if (value.action === 'create') {\n if (typeof value.branch !== 'string' || value.branch.trim() === '') return undefined;\n if (\n value.reservationId !== undefined &&\n (typeof value.reservationId !== 'string' || !/^[A-Za-z0-9_-]+$/u.test(value.reservationId))\n )\n return undefined;\n return {\n action: 'create',\n branch: value.branch.trim(),\n ...(typeof value.baseRef === 'string' && value.baseRef.trim() !== '' ? { baseRef: value.baseRef.trim() } : {}),\n ...(typeof value.reservationId === 'string' ? { reservationId: value.reservationId } : {}),\n };\n }\n if (value.action === 'close') {\n if (typeof value.id !== 'string' || value.id === '') return undefined;\n return { action: 'close', id: value.id, ...(value.force === true ? { force: true } : {}) };\n }\n return undefined;\n}\n\n/**\n * What the reader is told when a command fails.\n *\n * An expected failure explains itself. Anything else is summarised, never\n * echoed: a git error can carry a remote URL with a token in it.\n */\nfunction failureText(error: unknown): string {\n return error instanceof DoomGitExpectedError ? error.message : 'The worktree operation failed.';\n}\n\n/** Starts one direct-event subscription per managed session. */\nexport function createWorktreesChannel(options: WorktreesChannelOptions = {}): DoomHubChannel {\n // Assigned by start, because receive is reachable only while the channel is\n // running and the command needs the state the direct event subscriptions keep.\n let receiveCommand: ((scope: DoomHubSessionScope, payload: unknown) => void) | undefined;\n\n return {\n frameType: GIT_WORKTREES_TYPE,\n start(host) {\n const sessionService = host.sessionService;\n if (sessionService === undefined) {\n throw new HubUnavailableError('The cockpit session service is unavailable. Start the cockpit and try again.');\n }\n const worktrees =\n options.operations ??\n createWorktreeOperations({\n git: createWorktreeGit(),\n sessionService,\n });\n /** Announces a successful mutation to this session's lifecycle subscribers. */\n const publishLifecycle = (scope: DoomHubSessionScope, repositoryRoot: string): void => {\n host.directEvents.publish(GIT_WORKTREE_LIFECYCLE_EVENT, scope.sessionId, {\n version: 1,\n repositoryRoot,\n });\n };\n const unregisterWorktreeProvisioner = sessionService.registerReservedWorktreeProvisioner?.(\n async ({ reservationId, parentSessionId, signal }) => {\n const parent = host.sessions().find((scope) => scope.sessionId === parentSessionId);\n if (parent === undefined) throw new Error('The conversation parent session is unavailable.');\n const branch = `doompi/conversation-${reservationId.slice(0, 12)}`;\n const record = await worktrees.spawn(\n { cwd: parent.cwd, sessionId: parent.sessionId },\n { branch, name: `conversation ${reservationId.slice(0, 8)}`, reservationId },\n { signal },\n );\n const reservations = sessionService.reservations;\n if (reservations === undefined) throw new Error('Conversation reservations are unavailable.');\n const session = await reservations.complete(reservationId, parentSessionId);\n publishLifecycle(parent, record.repositoryRoot);\n return session;\n },\n );\n const views: ViewDeps = { homeDir: options.homeDir, sessionService };\n const latest = new Map<string, SessionState>();\n const subscriptions = new Map<string, () => void>();\n const busy = new Set<string>();\n const generations = new Map<string, symbol>();\n const newGeneration = (sessionId: string): symbol => {\n const generation = Symbol(sessionId);\n generations.set(sessionId, generation);\n return generation;\n };\n\n /** Republishes a session, skipping a frame that would say nothing new. */\n const publish = (scope: DoomHubSessionScope, force: boolean): void => {\n const previous = latest.get(scope.sessionId);\n const next: SessionState = {\n worktrees: viewsFor(scope, views),\n pending: previous?.pending,\n error: previous?.error,\n errorTarget: previous?.errorTarget,\n };\n if (\n !force &&\n previous !== undefined &&\n sameList(previous.worktrees, next.worktrees) &&\n previous.pending === next.pending &&\n previous.error === next.error &&\n previous.errorTarget === next.errorTarget\n ) {\n return;\n }\n latest.set(scope.sessionId, next);\n host.publish(scope.sessionId, payloadOf(next));\n };\n\n const mark = (\n scope: DoomHubSessionScope,\n pending: string | undefined,\n error: string | undefined,\n errorTarget: WorktreeErrorTarget | undefined,\n ): void => {\n const previous = latest.get(scope.sessionId);\n latest.set(scope.sessionId, {\n worktrees: previous?.worktrees ?? viewsFor(scope, views),\n pending,\n error,\n errorTarget,\n });\n publish(scope, true);\n };\n\n const run = async (\n scope: DoomHubSessionScope,\n command: GitWorktreesCommand,\n generation: symbol,\n ): Promise<void> => {\n const context = { cwd: scope.cwd, sessionId: scope.sessionId };\n const markCurrent = (\n pending: string | undefined,\n error: string | undefined,\n errorTarget: WorktreeErrorTarget | undefined,\n ): void => {\n if (generations.get(scope.sessionId) !== generation) return;\n mark(scope, pending, error, errorTarget);\n };\n if (command.action === 'create') {\n markCurrent(`creating ${command.branch}…`, undefined, undefined);\n const record = await worktrees.spawn(\n context,\n {\n branch: command.branch,\n ...(command.baseRef === undefined ? {} : { baseRef: command.baseRef }),\n ...(command.reservationId === undefined ? {} : { reservationId: command.reservationId }),\n },\n // Each phase replaces the label, so the panel says what is\n // happening instead of holding one line for the whole wait.\n { onProgress: (label) => markCurrent(label, undefined, undefined) },\n );\n if (generations.get(scope.sessionId) !== generation) return;\n publishLifecycle(scope, record.repositoryRoot);\n return;\n }\n markCurrent(`closing ${command.id}…`, undefined, undefined);\n const record = await worktrees.close(context, command.id, command.force ?? false);\n if (generations.get(scope.sessionId) !== generation) return;\n publishLifecycle(scope, record.repositoryRoot);\n };\n\n const source: DoomHubChannelSource = {\n payloadFor(scope) {\n const state = latest.get(scope.sessionId);\n return state === undefined ? undefined : payloadOf(state);\n },\n sessionAdded(scope) {\n newGeneration(scope.sessionId);\n publish(scope, false);\n const unsubscribe = host.directEvents.subscribe(GIT_WORKTREE_LIFECYCLE_EVENT, scope.sessionId, (payload) => {\n if (!isWorktreeLifecycleEvent(payload)) return;\n let sameRepository = false;\n try {\n sameRepository =\n registryFile(scope.cwd, options.homeDir) === registryFile(payload.repositoryRoot, options.homeDir);\n } catch {\n sameRepository = false;\n }\n if (sameRepository) publish(scope, false);\n });\n subscriptions.set(scope.sessionId, unsubscribe);\n },\n sessionRemoved(sessionId) {\n newGeneration(sessionId);\n subscriptions.get(sessionId)?.();\n subscriptions.delete(sessionId);\n latest.delete(sessionId);\n busy.delete(sessionId);\n },\n close() {\n unregisterWorktreeProvisioner?.();\n for (const unsubscribe of subscriptions.values()) unsubscribe();\n subscriptions.clear();\n latest.clear();\n busy.clear();\n generations.clear();\n },\n };\n receiveCommand = (scope, payload) => {\n const command = parseCommand(payload);\n if (command === undefined) return;\n // One operation per session. A create runs for minutes, and a second\n // click must not start a second worktree behind the first.\n if (busy.has(scope.sessionId)) return;\n const generation = generations.get(scope.sessionId);\n if (generation === undefined) return;\n busy.add(scope.sessionId);\n void run(scope, command, generation)\n .then(() => {\n if (generations.get(scope.sessionId) !== generation) return;\n mark(scope, undefined, undefined, undefined);\n })\n .catch((error: unknown) => {\n if (generations.get(scope.sessionId) !== generation) return;\n host.onNotice(`worktree command failed for ${scope.sessionId} (${failureText(error)})`);\n mark(scope, undefined, failureText(error), errorTargetFor(command));\n })\n .finally(() => {\n if (generations.get(scope.sessionId) === generation) busy.delete(scope.sessionId);\n });\n };\n\n return source;\n },\n receive(scope, payload) {\n receiveCommand?.(scope, payload);\n },\n };\n}\n\nexport default createWorktreesChannel;\n","import { defineChannel } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/git-worktrees.server';\n\nexport default defineChannel(contribution);\n","import type { WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\n\nimport type { GitServerScope } from '../../_lib/root.server';\n\nexport default (context: WithRoot<DoomServerPluginContext, GitServerScope>) => context.root.resources[0]!;\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/doompiGit.server';\n\nexport default defineResource(contribution);\n","import type { WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\n\nimport type { GitServerScope } from '../../_lib/root.server';\n\nexport default (context: WithRoot<DoomServerPluginContext, GitServerScope>) => context.root.resources[2]!;\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/doompiGitReadme.server';\n\nexport default defineResource(contribution);\n","import type { WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\n\nimport type { GitServerScope } from '../../_lib/root.server';\n\nexport default (context: WithRoot<DoomServerPluginContext, GitServerScope>) => context.root.resources[1]!;\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/doompiUseGit.server';\n\nexport default defineResource(contribution);\n","import { defineServerTool, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\n\nimport type { GitServerScope } from '../_lib/root.server';\n\nexport default defineServerTool((context: WithRoot<DoomServerPluginContext, GitServerScope>) => context.root.tool);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineServerPlugin, type DoomServerSessionPlugin } from '@agimon-ai/doompi-core/serverFacet';\nimport { composeRootHooks } from '@agimon-ai/doompi-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.server';\nimport apiRoute from '../src/extensions/(backend)/api/route.server';\nimport channelGitWorktrees from '../src/extensions/(backend)/channel/git-worktrees.server';\nimport resourceDoompiGit from '../src/extensions/workspaces/sessions/(backend)/resource/doompiGit.server';\nimport resourceDoompiGitReadme from '../src/extensions/workspaces/sessions/(backend)/resource/doompiGitReadme.server';\nimport resourceDoompiUseGit from '../src/extensions/workspaces/sessions/(backend)/resource/doompiUseGit.server';\nimport toolRunWorktree from '../src/extensions/workspaces/sessions/(backend)/tool/runWorktree.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const facet = defineServerPlugin({\n name: '@agimon-ai/doompi-git',\n global: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return [at(apiRoute, context)]; },\n get channels(): DoomServerSessionPlugin['channels'] { return [() => via({ frameType: 'git_worktrees' }, channelGitWorktrees())]; },\n }),\n workspace: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return [at(apiRoute, context)]; },\n get channels(): DoomServerSessionPlugin['channels'] { return [() => via({ frameType: 'git_worktrees' }, channelGitWorktrees())]; },\n }),\n session: async (context) => {\n const scopeSession = await rootSession(context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get api(): DoomServerSessionPlugin['api'] { return [at(apiRoute, context)]; },\n get channels(): DoomServerSessionPlugin['channels'] { return [() => via({ frameType: 'git_worktrees' }, channelGitWorktrees())]; },\n get resources(): DoomServerSessionPlugin['resources'] { return [at(resourceDoompiGit, contextSession), at(resourceDoompiGitReadme, contextSession), at(resourceDoompiUseGit, contextSession)]; },\n get tools(): DoomServerSessionPlugin['tools'] { return [via({ name: 'run_worktree' }, at(toolRunWorktree, contextSession))]; },\n services: [...(scopeSession.services ?? [])],\n get activities(): DoomServerSessionPlugin['activities'] { return [...(scopeSession.activities ?? [])]; },\n };\n },\n});\n\nexport default facet;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agimon-ai/doompi-git",
3
- "version": "0.0.1-alpha.22",
3
+ "version": "0.0.1-alpha.23",
4
4
  "description": "Git worktree sessions for DoomPi: spawn an isolated worktree with its own session and manage it from the parent",
5
5
  "keywords": [
6
6
  "ai",
@@ -67,17 +67,17 @@
67
67
  "access": "public"
68
68
  },
69
69
  "dependencies": {
70
- "@agimon-ai/doompi-core": "0.0.1-alpha.86",
71
- "@agimon-ai/doompi-session": "0.0.1-alpha.10",
72
- "@agimon-ai/doompi-web-components": "0.0.1-alpha.44",
70
+ "@agimon-ai/doompi-core": "0.0.1-alpha.87",
71
+ "@agimon-ai/doompi-session": "0.0.1-alpha.11",
72
+ "@agimon-ai/doompi-web-components": "0.0.1-alpha.45",
73
73
  "@deepseek-ai/cordis": "4.0.2",
74
74
  "@tanstack/react-store": "0.11.1",
75
75
  "@tanstack/store": "0.11.1",
76
76
  "typebox": "1.3.34"
77
77
  },
78
78
  "devDependencies": {
79
- "@agimon-ai/doompi-build": "0.0.1-alpha.12",
80
- "@agimon-ai/vibe-lint-plugin-doom-extension": "0.0.1-alpha.78",
79
+ "@agimon-ai/doompi-build": "0.0.1-alpha.13",
80
+ "@agimon-ai/vibe-lint-plugin-doom-extension": "0.0.1-alpha.79",
81
81
  "@earendil-works/pi-agent-core": "0.87.1",
82
82
  "@earendil-works/pi-coding-agent": "0.87.1",
83
83
  "@types/node": "26.6.1",