@shardworks/nexus-core 0.1.20 → 0.1.21

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.
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Session infrastructure — the unified session funnel.
3
+ *
4
+ * ALL sessions (interactive, commissioned, briefed) flow through
5
+ * `launchSession()`. This provides unified logging, events, metrics,
6
+ * workspace lifecycle, and session record persistence.
7
+ *
8
+ * Session providers (e.g. claude-code, claude-api) implement the
9
+ * `SessionProvider` interface and are registered at startup.
10
+ */
11
+ import type { ManifestResult } from './manifest.ts';
12
+ /** What a session provider must implement. */
13
+ export interface SessionProvider {
14
+ /** Provider identifier (e.g. "claude-code", "claude-api", "bedrock"). */
15
+ name: string;
16
+ /** Launch a session and return when it completes. */
17
+ launch(options: SessionProviderLaunchOptions): Promise<SessionProviderResult>;
18
+ }
19
+ /** Options passed to the provider's launch() — provider-specific subset. */
20
+ export interface SessionProviderLaunchOptions {
21
+ /** Guild root path. */
22
+ home: string;
23
+ /** The manifest result — system prompt + resolved tools. */
24
+ manifest: ManifestResult;
25
+ /** The user-facing prompt (commission spec, consultation topic, brief). */
26
+ prompt: string | null;
27
+ /** Whether the session is interactive (human at keyboard) or autonomous. */
28
+ interactive: boolean;
29
+ /** Resolved working directory for the session. */
30
+ cwd: string;
31
+ /** Display name for tracking. */
32
+ name?: string;
33
+ /** Budget cap, if any. */
34
+ maxBudgetUsd?: number;
35
+ }
36
+ /** What comes back from the provider (before the funnel adds its own fields). */
37
+ export interface SessionProviderResult {
38
+ exitCode: number;
39
+ /** Provider-reported token usage, if available. */
40
+ tokenUsage?: {
41
+ inputTokens: number;
42
+ outputTokens: number;
43
+ cacheReadTokens?: number;
44
+ cacheWriteTokens?: number;
45
+ };
46
+ /** Provider-reported cost in USD, if available. */
47
+ costUsd?: number;
48
+ /** Wall-clock duration in milliseconds. */
49
+ durationMs: number;
50
+ /** Session ID from the provider, if available (e.g. claude session ID). */
51
+ providerSessionId?: string;
52
+ /**
53
+ * Full conversation transcript — raw provider output, minimally typed.
54
+ * Stored as-is in the session record; typed normalization deferred.
55
+ */
56
+ transcript?: Record<string, unknown>[];
57
+ }
58
+ /** Everything needed to launch a session through the funnel. */
59
+ export interface SessionLaunchOptions {
60
+ /** Guild root path. */
61
+ home: string;
62
+ /** The manifest result — system prompt + resolved tools. */
63
+ manifest: ManifestResult;
64
+ /** The user-facing prompt (commission spec, consultation topic, brief). */
65
+ prompt: string | null;
66
+ /** Whether the session is interactive (human at keyboard) or autonomous. */
67
+ interactive: boolean;
68
+ /** Workspace context. */
69
+ workspace: ResolvedWorkspace;
70
+ /** What triggered this session. */
71
+ trigger: 'consult' | 'summon' | 'brief';
72
+ /** Display name for tracking. */
73
+ name?: string;
74
+ /** Budget cap, if any. */
75
+ maxBudgetUsd?: number;
76
+ }
77
+ /** What the funnel returns to callers. */
78
+ export interface SessionResult {
79
+ /** Ledger row ID — written by the funnel before provider launch. */
80
+ sessionId: number;
81
+ exitCode: number;
82
+ /** Provider-reported token usage, if available. */
83
+ tokenUsage?: {
84
+ inputTokens: number;
85
+ outputTokens: number;
86
+ cacheReadTokens?: number;
87
+ cacheWriteTokens?: number;
88
+ };
89
+ /** Provider-reported cost in USD, if available. */
90
+ costUsd?: number;
91
+ /** Wall-clock duration in milliseconds. */
92
+ durationMs: number;
93
+ /** Session ID from the provider, if available. */
94
+ providerSessionId?: string;
95
+ /** Raw transcript from the provider. */
96
+ transcript?: Record<string, unknown>[];
97
+ }
98
+ /**
99
+ * Standard optional fields on event payloads. Any event can carry these.
100
+ * The session launcher inspects the triggering event's payload and uses
101
+ * them to determine the working directory for the session.
102
+ */
103
+ export interface WorkspaceContext {
104
+ /** Workshop name — session gets a fresh temporary worktree of main. */
105
+ workshop?: string;
106
+ /** Explicit worktree path — used as-is (caller owns the lifecycle). */
107
+ worktreePath?: string;
108
+ }
109
+ /** The resolved working directory for a session. */
110
+ export type ResolvedWorkspace = {
111
+ kind: 'guildhall';
112
+ } | {
113
+ kind: 'workshop-temp';
114
+ workshop: string;
115
+ worktreePath: string;
116
+ } | {
117
+ kind: 'workshop-managed';
118
+ workshop: string;
119
+ worktreePath: string;
120
+ };
121
+ /** Full session record written to disk as JSON. */
122
+ export interface SessionRecord {
123
+ /** Ledger session row ID (for cross-reference). */
124
+ sessionId: number;
125
+ /** The anima that ran this session, with full composition provenance. */
126
+ anima: {
127
+ id: number;
128
+ name: string;
129
+ roles: string[];
130
+ codex: string;
131
+ roleInstructions: string;
132
+ curriculum: {
133
+ name: string;
134
+ version: string;
135
+ content: string;
136
+ } | null;
137
+ temperament: {
138
+ name: string;
139
+ version: string;
140
+ content: string;
141
+ } | null;
142
+ toolInstructions: Array<{
143
+ toolName: string;
144
+ instructions: string;
145
+ }>;
146
+ };
147
+ /** The final assembled system prompt. */
148
+ systemPrompt: string;
149
+ /** Tools available to the anima. */
150
+ tools: Array<{
151
+ name: string;
152
+ }>;
153
+ /** Tools that were resolved but failed preconditions. */
154
+ unavailableTools: Array<{
155
+ name: string;
156
+ reasons: string[];
157
+ }>;
158
+ /** The user-facing prompt. */
159
+ userPrompt: string | null;
160
+ /** Raw conversation transcript from the provider. */
161
+ transcript: Record<string, unknown>[];
162
+ }
163
+ /**
164
+ * Register a session provider. Called once at startup.
165
+ */
166
+ export declare function registerSessionProvider(provider: SessionProvider): void;
167
+ /** Get the registered session provider. */
168
+ export declare function getSessionProvider(): SessionProvider | null;
169
+ /**
170
+ * Resolve workspace context from an event payload's standard fields.
171
+ */
172
+ export declare function resolveWorkspace(payload: Record<string, unknown> | null): ResolvedWorkspace;
173
+ /**
174
+ * Create a temporary worktree from a workshop's bare repo, checked out to main.
175
+ *
176
+ * Uses a crypto-safe random hash for the directory name. The worktree is
177
+ * a fresh snapshot — no branch management, no merge-back lifecycle.
178
+ *
179
+ * @returns Absolute path to the worktree directory.
180
+ */
181
+ export declare function createTempWorktree(home: string, workshop: string): string;
182
+ /**
183
+ * Remove a temporary worktree.
184
+ *
185
+ * Logs but does not throw on failure — stale worktrees are assumed to be
186
+ * reaped by a separate mechanism.
187
+ */
188
+ export declare function removeTempWorktree(home: string, workshop: string, worktreePath: string): void;
189
+ /**
190
+ * Launch a session through the registered provider.
191
+ *
192
+ * This is THE code path for all sessions. It:
193
+ * 1. If workspace is workshop-temp: create fresh worktree from main
194
+ * 2. Records session.started in the Ledger → gets sessionId
195
+ * 3. Signals session.started event
196
+ * 4. Delegates to the provider (passing resolved cwd)
197
+ * 5. Records session.ended in the Ledger (with metrics)
198
+ * 6. Writes the SessionRecord JSON to .nexus/sessions/{uuid}.json
199
+ * 7. Signals session.ended event (with full metrics + sessionId in payload)
200
+ * 8. If workspace is workshop-temp AND session is autonomous: tear down the worktree
201
+ * (interactive sessions leave the worktree for manual cleanup)
202
+ * 9. Returns the result (including sessionId)
203
+ *
204
+ * Error handling guarantee: Steps 5–8 MUST execute even if the provider
205
+ * throws. The funnel wraps step 4 in try/finally. If the provider crashes,
206
+ * the session row still gets ended_at, exit_code, and the session.ended
207
+ * event still fires (with error details in the payload). If the funnel
208
+ * itself fails during recording (e.g. Ledger locked), it signals
209
+ * session.record-failed as a core event and continues with remaining
210
+ * cleanup steps. Worktree teardown failures are logged but do not throw —
211
+ * stale worktrees are assumed to be reaped by a separate mechanism.
212
+ */
213
+ export declare function launchSession(options: SessionLaunchOptions): Promise<SessionResult>;
214
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,349 @@
1
+ /**
2
+ * Session infrastructure — the unified session funnel.
3
+ *
4
+ * ALL sessions (interactive, commissioned, briefed) flow through
5
+ * `launchSession()`. This provides unified logging, events, metrics,
6
+ * workspace lifecycle, and session record persistence.
7
+ *
8
+ * Session providers (e.g. claude-code, claude-api) implement the
9
+ * `SessionProvider` interface and are registered at startup.
10
+ */
11
+ import crypto from 'node:crypto';
12
+ import { execFileSync } from 'node:child_process';
13
+ import fs from 'node:fs';
14
+ import path from 'node:path';
15
+ import Database from 'better-sqlite3';
16
+ import { ledgerPath, nexusDir, workshopBarePath } from "./nexus-home.js";
17
+ import { signalEvent } from "./events.js";
18
+ // ── Provider Registration ──────────────────────────────────────────────
19
+ let _provider = null;
20
+ /**
21
+ * Register a session provider. Called once at startup.
22
+ */
23
+ export function registerSessionProvider(provider) {
24
+ _provider = provider;
25
+ }
26
+ /** Get the registered session provider. */
27
+ export function getSessionProvider() {
28
+ return _provider;
29
+ }
30
+ // ── Workspace Helpers ──────────────────────────────────────────────────
31
+ /**
32
+ * Resolve workspace context from an event payload's standard fields.
33
+ */
34
+ export function resolveWorkspace(payload) {
35
+ if (!payload)
36
+ return { kind: 'guildhall' };
37
+ const worktreePath = payload.worktreePath;
38
+ const workshop = payload.workshop;
39
+ if (worktreePath && workshop) {
40
+ return { kind: 'workshop-managed', workshop, worktreePath };
41
+ }
42
+ if (workshop) {
43
+ // workshop-temp: worktreePath gets set by createTempWorktree before launch
44
+ // We return a placeholder — the funnel fills in the actual path
45
+ return { kind: 'workshop-temp', workshop, worktreePath: '' };
46
+ }
47
+ return { kind: 'guildhall' };
48
+ }
49
+ /**
50
+ * Create a temporary worktree from a workshop's bare repo, checked out to main.
51
+ *
52
+ * Uses a crypto-safe random hash for the directory name. The worktree is
53
+ * a fresh snapshot — no branch management, no merge-back lifecycle.
54
+ *
55
+ * @returns Absolute path to the worktree directory.
56
+ */
57
+ export function createTempWorktree(home, workshop) {
58
+ const hash = crypto.randomBytes(8).toString('hex');
59
+ const worktreeDir = path.join(nexusDir(home), 'worktrees', workshop, hash);
60
+ const barePath = workshopBarePath(home, workshop);
61
+ if (!fs.existsSync(barePath)) {
62
+ throw new Error(`Workshop "${workshop}" bare repo not found at ${barePath}. ` +
63
+ `Has the workshop been added with 'nsg workshop add'?`);
64
+ }
65
+ fs.mkdirSync(path.dirname(worktreeDir), { recursive: true });
66
+ execFileSync('git', ['worktree', 'add', '--detach', worktreeDir, 'main'], {
67
+ cwd: barePath,
68
+ stdio: 'pipe',
69
+ });
70
+ return worktreeDir;
71
+ }
72
+ /**
73
+ * Remove a temporary worktree.
74
+ *
75
+ * Logs but does not throw on failure — stale worktrees are assumed to be
76
+ * reaped by a separate mechanism.
77
+ */
78
+ export function removeTempWorktree(home, workshop, worktreePath) {
79
+ const barePath = workshopBarePath(home, workshop);
80
+ try {
81
+ execFileSync('git', ['worktree', 'remove', '--force', worktreePath], {
82
+ cwd: barePath,
83
+ stdio: 'pipe',
84
+ });
85
+ }
86
+ catch (err) {
87
+ console.error(`[session] Warning: failed to remove temp worktree ${worktreePath}: ` +
88
+ `${err instanceof Error ? err.message : String(err)}`);
89
+ }
90
+ }
91
+ // ── Session Record Helpers ─────────────────────────────────────────────
92
+ /** Path to the sessions directory. */
93
+ function sessionsDir(home) {
94
+ return path.join(nexusDir(home), 'sessions');
95
+ }
96
+ /**
97
+ * Build a SessionRecord from the manifest and provider result.
98
+ */
99
+ function buildSessionRecord(sessionId, manifest, prompt, providerResult) {
100
+ return {
101
+ sessionId,
102
+ anima: {
103
+ id: manifest.anima.id,
104
+ name: manifest.anima.name,
105
+ roles: manifest.anima.roles,
106
+ codex: manifest.composition.codex,
107
+ roleInstructions: manifest.composition.roleInstructions,
108
+ curriculum: manifest.composition.curriculum,
109
+ temperament: manifest.composition.temperament,
110
+ toolInstructions: manifest.composition.toolInstructions,
111
+ },
112
+ systemPrompt: manifest.systemPrompt,
113
+ tools: manifest.tools.map(t => ({ name: t.name })),
114
+ unavailableTools: manifest.unavailable,
115
+ userPrompt: prompt,
116
+ transcript: providerResult?.transcript ?? [],
117
+ };
118
+ }
119
+ /**
120
+ * Write a session record to disk.
121
+ * @returns The relative record_path (relative to guild root).
122
+ */
123
+ function writeSessionRecord(home, record) {
124
+ const dir = sessionsDir(home);
125
+ fs.mkdirSync(dir, { recursive: true });
126
+ const uuid = crypto.randomUUID();
127
+ const filename = `${uuid}.json`;
128
+ const fullPath = path.join(dir, filename);
129
+ const relativePath = path.relative(home, fullPath);
130
+ fs.writeFileSync(fullPath, JSON.stringify(record, null, 2));
131
+ return relativePath;
132
+ }
133
+ // ── Ledger Helpers ─────────────────────────────────────────────────────
134
+ /**
135
+ * Insert a session.started row in the Ledger.
136
+ * @returns The session row ID.
137
+ */
138
+ function insertSessionRow(home, opts) {
139
+ const db = new Database(ledgerPath(home));
140
+ db.pragma('foreign_keys = ON');
141
+ try {
142
+ const result = db.prepare(`INSERT INTO sessions (anima_id, provider, trigger, workshop, workspace_kind,
143
+ curriculum_name, curriculum_version, temperament_name, temperament_version,
144
+ roles, started_at)
145
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(opts.animaId, opts.provider, opts.trigger, opts.workshop, opts.workspaceKind, opts.curriculumName, opts.curriculumVersion, opts.temperamentName, opts.temperamentVersion, JSON.stringify(opts.roles), opts.startedAt);
146
+ return Number(result.lastInsertRowid);
147
+ }
148
+ finally {
149
+ db.close();
150
+ }
151
+ }
152
+ /**
153
+ * Update a session row with end-of-session data.
154
+ */
155
+ function updateSessionRow(home, sessionId, opts) {
156
+ const db = new Database(ledgerPath(home));
157
+ db.pragma('foreign_keys = ON');
158
+ try {
159
+ db.prepare(`UPDATE sessions SET
160
+ ended_at = ?, exit_code = ?,
161
+ input_tokens = ?, output_tokens = ?,
162
+ cache_read_tokens = ?, cache_write_tokens = ?,
163
+ cost_usd = ?, duration_ms = ?,
164
+ provider_session_id = ?, record_path = ?
165
+ WHERE id = ?`).run(opts.endedAt, opts.exitCode, opts.inputTokens ?? null, opts.outputTokens ?? null, opts.cacheReadTokens ?? null, opts.cacheWriteTokens ?? null, opts.costUsd ?? null, opts.durationMs ?? null, opts.providerSessionId ?? null, opts.recordPath ?? null, sessionId);
166
+ }
167
+ finally {
168
+ db.close();
169
+ }
170
+ }
171
+ // ── The Session Funnel ─────────────────────────────────────────────────
172
+ /**
173
+ * Launch a session through the registered provider.
174
+ *
175
+ * This is THE code path for all sessions. It:
176
+ * 1. If workspace is workshop-temp: create fresh worktree from main
177
+ * 2. Records session.started in the Ledger → gets sessionId
178
+ * 3. Signals session.started event
179
+ * 4. Delegates to the provider (passing resolved cwd)
180
+ * 5. Records session.ended in the Ledger (with metrics)
181
+ * 6. Writes the SessionRecord JSON to .nexus/sessions/{uuid}.json
182
+ * 7. Signals session.ended event (with full metrics + sessionId in payload)
183
+ * 8. If workspace is workshop-temp AND session is autonomous: tear down the worktree
184
+ * (interactive sessions leave the worktree for manual cleanup)
185
+ * 9. Returns the result (including sessionId)
186
+ *
187
+ * Error handling guarantee: Steps 5–8 MUST execute even if the provider
188
+ * throws. The funnel wraps step 4 in try/finally. If the provider crashes,
189
+ * the session row still gets ended_at, exit_code, and the session.ended
190
+ * event still fires (with error details in the payload). If the funnel
191
+ * itself fails during recording (e.g. Ledger locked), it signals
192
+ * session.record-failed as a core event and continues with remaining
193
+ * cleanup steps. Worktree teardown failures are logged but do not throw —
194
+ * stale worktrees are assumed to be reaped by a separate mechanism.
195
+ */
196
+ export async function launchSession(options) {
197
+ if (!_provider) {
198
+ throw new Error('No session provider registered. Call registerSessionProvider() at startup.');
199
+ }
200
+ const { home, manifest, prompt, interactive, trigger, name, maxBudgetUsd } = options;
201
+ let { workspace } = options;
202
+ // Step 1: If workshop-temp, create fresh worktree
203
+ if (workspace.kind === 'workshop-temp') {
204
+ const worktreePath = createTempWorktree(home, workspace.workshop);
205
+ workspace = { ...workspace, worktreePath };
206
+ }
207
+ // Resolve cwd from workspace
208
+ const cwd = workspace.kind === 'guildhall'
209
+ ? home
210
+ : workspace.worktreePath;
211
+ const startedAt = new Date().toISOString();
212
+ // Derive workshop name from workspace
213
+ const workshopName = workspace.kind === 'guildhall' ? null : workspace.workshop;
214
+ // Step 2: Record session.started in the Ledger
215
+ let sessionId;
216
+ try {
217
+ sessionId = insertSessionRow(home, {
218
+ animaId: manifest.anima.id,
219
+ provider: _provider.name,
220
+ trigger,
221
+ workshop: workshopName,
222
+ workspaceKind: workspace.kind,
223
+ curriculumName: manifest.composition.curriculum?.name ?? null,
224
+ curriculumVersion: manifest.composition.curriculum?.version ?? null,
225
+ temperamentName: manifest.composition.temperament?.name ?? null,
226
+ temperamentVersion: manifest.composition.temperament?.version ?? null,
227
+ roles: manifest.anima.roles,
228
+ startedAt,
229
+ });
230
+ }
231
+ catch (err) {
232
+ // If we can't even write the session row, signal failure and abort
233
+ try {
234
+ signalEvent(home, 'session.record-failed', {
235
+ error: err instanceof Error ? err.message : String(err),
236
+ phase: 'insert',
237
+ anima: manifest.anima.name,
238
+ }, 'framework');
239
+ }
240
+ catch { /* swallow — best effort */ }
241
+ throw err;
242
+ }
243
+ // Step 3: Signal session.started event
244
+ try {
245
+ signalEvent(home, 'session.started', {
246
+ sessionId,
247
+ anima: manifest.anima.name,
248
+ trigger,
249
+ workshop: workshopName,
250
+ workspaceKind: workspace.kind,
251
+ }, 'framework');
252
+ }
253
+ catch { /* swallow — event signalling is best-effort */ }
254
+ // Step 4: Delegate to the provider (wrapped in try/finally for guarantees)
255
+ let providerResult = null;
256
+ let providerError = null;
257
+ try {
258
+ providerResult = await _provider.launch({
259
+ home,
260
+ manifest,
261
+ prompt,
262
+ interactive,
263
+ cwd,
264
+ name,
265
+ maxBudgetUsd,
266
+ });
267
+ }
268
+ catch (err) {
269
+ providerError = err instanceof Error ? err : new Error(String(err));
270
+ }
271
+ // Steps 5–8: Always execute, even if the provider threw
272
+ const endedAt = new Date().toISOString();
273
+ const exitCode = providerResult?.exitCode ?? 1;
274
+ const durationMs = providerResult?.durationMs ?? (Date.now() - new Date(startedAt).getTime());
275
+ // Step 5: Update session row in Ledger
276
+ let recordPath;
277
+ try {
278
+ // Step 6: Write SessionRecord JSON
279
+ const record = buildSessionRecord(sessionId, manifest, prompt, providerResult);
280
+ recordPath = writeSessionRecord(home, record);
281
+ }
282
+ catch (err) {
283
+ try {
284
+ signalEvent(home, 'session.record-failed', {
285
+ sessionId,
286
+ error: err instanceof Error ? err.message : String(err),
287
+ phase: 'write-record',
288
+ }, 'framework');
289
+ }
290
+ catch { /* swallow */ }
291
+ }
292
+ try {
293
+ updateSessionRow(home, sessionId, {
294
+ endedAt,
295
+ exitCode,
296
+ inputTokens: providerResult?.tokenUsage?.inputTokens,
297
+ outputTokens: providerResult?.tokenUsage?.outputTokens,
298
+ cacheReadTokens: providerResult?.tokenUsage?.cacheReadTokens,
299
+ cacheWriteTokens: providerResult?.tokenUsage?.cacheWriteTokens,
300
+ costUsd: providerResult?.costUsd,
301
+ durationMs,
302
+ providerSessionId: providerResult?.providerSessionId,
303
+ recordPath,
304
+ });
305
+ }
306
+ catch (err) {
307
+ try {
308
+ signalEvent(home, 'session.record-failed', {
309
+ sessionId,
310
+ error: err instanceof Error ? err.message : String(err),
311
+ phase: 'update-row',
312
+ }, 'framework');
313
+ }
314
+ catch { /* swallow */ }
315
+ }
316
+ // Step 7: Signal session.ended event
317
+ try {
318
+ signalEvent(home, 'session.ended', {
319
+ sessionId,
320
+ anima: manifest.anima.name,
321
+ trigger,
322
+ workshop: workshopName,
323
+ exitCode,
324
+ durationMs,
325
+ costUsd: providerResult?.costUsd ?? null,
326
+ error: providerError?.message ?? null,
327
+ }, 'framework');
328
+ }
329
+ catch { /* swallow */ }
330
+ // Step 8: Teardown temp worktree (autonomous only)
331
+ if (workspace.kind === 'workshop-temp' && !interactive) {
332
+ removeTempWorktree(home, workspace.workshop, workspace.worktreePath);
333
+ }
334
+ // Step 9: Return result
335
+ if (providerError && !providerResult) {
336
+ // Provider threw without returning — re-throw so caller knows
337
+ throw providerError;
338
+ }
339
+ return {
340
+ sessionId,
341
+ exitCode,
342
+ tokenUsage: providerResult?.tokenUsage,
343
+ costUsd: providerResult?.costUsd,
344
+ durationMs,
345
+ providerSessionId: providerResult?.providerSessionId,
346
+ transcript: providerResult?.transcript,
347
+ };
348
+ }
349
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Commission worktree management — creates isolated git worktrees for
3
+ * commission sessions.
4
+ *
5
+ * When an anima is dispatched to work on a commission, this module:
6
+ * 1. Creates a new git branch for the commission
7
+ * 2. Sets up a git worktree pointing at that branch
8
+ * 3. Returns the worktree path so the session can launch in the correct cwd
9
+ *
10
+ * Worktrees provide isolation — each commission gets its own working copy
11
+ * of the repo, so multiple animas can work concurrently without conflicts
12
+ * in the working directory.
13
+ *
14
+ * Absorbed from the former `engine-worktree-setup` package.
15
+ *
16
+ * ## Directory layout
17
+ *
18
+ * Commission worktrees are created from workshop bare clones:
19
+ *
20
+ * GUILD_ROOT/
21
+ * .nexus/
22
+ * workshops/
23
+ * workshop-a.git/ ← bare clone (source for worktrees)
24
+ * worktrees/
25
+ * workshop-a/
26
+ * commission-42/ ← worktree for commission #42
27
+ * workshop-b/
28
+ * commission-17/ ← worktree for commission #17
29
+ */
30
+ export interface WorktreeConfig {
31
+ /** Absolute path to the guild root. */
32
+ home: string;
33
+ /** Workshop name — the bare clone source for the worktree. */
34
+ workshop: string;
35
+ /** Commission ID — used to derive branch name and worktree directory. */
36
+ commissionId: number;
37
+ /** Base branch to create the worktree from (default: 'main'). */
38
+ baseBranch?: string;
39
+ }
40
+ export interface WorktreeResult {
41
+ /** Absolute path to the created worktree. */
42
+ path: string;
43
+ /** Branch name created for the worktree. */
44
+ branch: string;
45
+ /** Commission ID this worktree serves. */
46
+ commissionId: number;
47
+ }
48
+ /**
49
+ * Create a git worktree for a commission session.
50
+ *
51
+ * Creates a new branch from the base branch and sets up a worktree in
52
+ * .nexus/worktrees/{workshop}/commission-{id}/.
53
+ *
54
+ * @throws If the worktree or branch already exists.
55
+ */
56
+ export declare function setupWorktree(config: WorktreeConfig): WorktreeResult;
57
+ /**
58
+ * Remove a worktree after a commission session completes.
59
+ *
60
+ * Removes the worktree directory and prunes it from git's tracking.
61
+ * Does NOT delete the branch — the branch should be kept for history
62
+ * until explicitly merged or pruned.
63
+ */
64
+ export declare function teardownWorktree(home: string, workshop: string, commissionId: number): void;
65
+ /**
66
+ * List active commission worktrees.
67
+ */
68
+ export declare function listWorktrees(home: string, workshop?: string): WorktreeResult[];
69
+ //# sourceMappingURL=worktree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../src/worktree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAOH,MAAM,WAAW,cAAc;IAC7B,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,YAAY,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,YAAY,EAAE,MAAM,CAAC;CACtB;AAMD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAqBpE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAmB3F;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,cAAc,EAAE,CAiC/E"}