@spekn/cli 1.0.3 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/main.js +29015 -56113
  2. package/dist/resources/prompts/repo-sync-analysis.prompt.md +1 -1
  3. package/dist/tui/index.mjs +4746 -538
  4. package/package.json +3 -8
  5. package/dist/tui/chunk-4WEASLXY.mjs +0 -3444
  6. package/dist/tui/chunk-755CADEG.mjs +0 -3401
  7. package/dist/tui/chunk-BUJQVTY5.mjs +0 -3409
  8. package/dist/tui/chunk-BZKKMGFB.mjs +0 -1959
  9. package/dist/tui/chunk-DJYOBCNM.mjs +0 -3159
  10. package/dist/tui/chunk-GTFTFDY4.mjs +0 -3417
  11. package/dist/tui/chunk-IMEBD2KA.mjs +0 -3444
  12. package/dist/tui/chunk-IX6DR5SW.mjs +0 -3433
  13. package/dist/tui/chunk-JKFOY4IF.mjs +0 -2003
  14. package/dist/tui/chunk-OXXZ3O5L.mjs +0 -3378
  15. package/dist/tui/chunk-SHJNIAAJ.mjs +0 -1697
  16. package/dist/tui/chunk-V4SNDRUS.mjs +0 -1666
  17. package/dist/tui/chunk-VXVHNZST.mjs +0 -1666
  18. package/dist/tui/chunk-WCTSFKTA.mjs +0 -3459
  19. package/dist/tui/chunk-X2XP5ACW.mjs +0 -3443
  20. package/dist/tui/chunk-YUYJ7VBG.mjs +0 -2029
  21. package/dist/tui/chunk-ZM3EI5IA.mjs +0 -3384
  22. package/dist/tui/chunk-ZYOX64HP.mjs +0 -1653
  23. package/dist/tui/use-session-store-63YUGUFA.mjs +0 -8
  24. package/dist/tui/use-session-store-ACO2SMJC.mjs +0 -8
  25. package/dist/tui/use-session-store-BVFDAWOB.mjs +0 -8
  26. package/dist/tui/use-session-store-DJIZ3FQZ.mjs +0 -9
  27. package/dist/tui/use-session-store-EAIQA4UG.mjs +0 -9
  28. package/dist/tui/use-session-store-EFBAXC3G.mjs +0 -8
  29. package/dist/tui/use-session-store-FJOR4KTG.mjs +0 -8
  30. package/dist/tui/use-session-store-IJE5KVOC.mjs +0 -8
  31. package/dist/tui/use-session-store-KGAFXCKI.mjs +0 -8
  32. package/dist/tui/use-session-store-KS4DPNDY.mjs +0 -8
  33. package/dist/tui/use-session-store-MMHJENNL.mjs +0 -8
  34. package/dist/tui/use-session-store-OZ6HC4I2.mjs +0 -9
  35. package/dist/tui/use-session-store-PTMWISNJ.mjs +0 -8
  36. package/dist/tui/use-session-store-VCDECQMW.mjs +0 -8
  37. package/dist/tui/use-session-store-VOK5ML5J.mjs +0 -9
@@ -1,1653 +0,0 @@
1
- import {
2
- OrganizationPlan,
3
- WorkflowPhase,
4
- __name,
5
- appendGlobalStructuredLog,
6
- getClient,
7
- getService,
8
- persistProjectContext,
9
- setClient
10
- } from "./chunk-BZKKMGFB.mjs";
11
-
12
- // src/store/use-session-store.ts
13
- import { create as create6 } from "zustand";
14
- import { subscribeWithSelector as subscribeWithSelector6 } from "zustand/middleware";
15
-
16
- // src/store/use-tui-ui-store.ts
17
- import { create } from "zustand";
18
- import { subscribeWithSelector } from "zustand/middleware";
19
- var _initialScreen = "home";
20
- function setInitialScreen(screen) {
21
- _initialScreen = screen;
22
- }
23
- __name(setInitialScreen, "setInitialScreen");
24
- var initialState = {
25
- screen: _initialScreen,
26
- showHelp: false,
27
- commandMode: false,
28
- searchQuery: "",
29
- navMode: "content",
30
- cursorSpec: null,
31
- cursorDecision: null,
32
- openedSpecId: void 0,
33
- editorMenuOpen: false,
34
- statusMenuOpen: false,
35
- aiRefineMenuOpen: false,
36
- editorLaunching: false,
37
- selectedEditor: "",
38
- selectedOrganizationIndex: void 0,
39
- selectedProjectIndex: void 0,
40
- newProjectName: void 0,
41
- generationPanelOpen: false,
42
- generationPanelSpecId: void 0,
43
- selectedAnalysisAgent: "auto"
44
- };
45
- var useTuiUiStore = create()(subscribeWithSelector((set) => ({
46
- ...initialState,
47
- screen: _initialScreen,
48
- setScreen: /* @__PURE__ */ __name((screen) => set({
49
- screen
50
- }), "setScreen"),
51
- toggleHelp: /* @__PURE__ */ __name(() => set((prev) => ({
52
- showHelp: !prev.showHelp
53
- })), "toggleHelp"),
54
- setShowHelp: /* @__PURE__ */ __name((show) => set({
55
- showHelp: show
56
- }), "setShowHelp"),
57
- setCommandMode: /* @__PURE__ */ __name((enabled) => set({
58
- commandMode: enabled
59
- }), "setCommandMode"),
60
- setSearchQuery: /* @__PURE__ */ __name((query) => set({
61
- searchQuery: query
62
- }), "setSearchQuery"),
63
- setNavMode: /* @__PURE__ */ __name((mode) => set({
64
- navMode: mode
65
- }), "setNavMode"),
66
- setCursorSpec: /* @__PURE__ */ __name((spec) => set({
67
- cursorSpec: spec
68
- }), "setCursorSpec"),
69
- setCursorDecision: /* @__PURE__ */ __name((decision) => set({
70
- cursorDecision: decision
71
- }), "setCursorDecision"),
72
- setOpenedSpecId: /* @__PURE__ */ __name((specId) => set({
73
- openedSpecId: specId
74
- }), "setOpenedSpecId"),
75
- setSelectedEditor: /* @__PURE__ */ __name((editor) => set({
76
- selectedEditor: editor
77
- }), "setSelectedEditor"),
78
- setEditorMenuOpen: /* @__PURE__ */ __name((open) => set({
79
- editorMenuOpen: open
80
- }), "setEditorMenuOpen"),
81
- setStatusMenuOpen: /* @__PURE__ */ __name((open) => set({
82
- statusMenuOpen: open
83
- }), "setStatusMenuOpen"),
84
- setAiRefineMenuOpen: /* @__PURE__ */ __name((open) => set({
85
- aiRefineMenuOpen: open
86
- }), "setAiRefineMenuOpen"),
87
- setEditorLaunching: /* @__PURE__ */ __name((launching) => set({
88
- editorLaunching: launching
89
- }), "setEditorLaunching"),
90
- openEditorMenuForSpec: /* @__PURE__ */ __name((specId, editor) => set({
91
- openedSpecId: specId,
92
- selectedEditor: editor,
93
- editorMenuOpen: true
94
- }), "openEditorMenuForSpec"),
95
- resetSpecsUi: /* @__PURE__ */ __name(() => set({
96
- openedSpecId: void 0,
97
- cursorSpec: null,
98
- editorMenuOpen: false,
99
- statusMenuOpen: false,
100
- aiRefineMenuOpen: false,
101
- editorLaunching: false,
102
- generationPanelOpen: false,
103
- generationPanelSpecId: void 0
104
- }), "resetSpecsUi"),
105
- setSelectedOrganizationIndex: /* @__PURE__ */ __name((index) => set({
106
- selectedOrganizationIndex: index
107
- }), "setSelectedOrganizationIndex"),
108
- setSelectedProjectIndex: /* @__PURE__ */ __name((index) => set({
109
- selectedProjectIndex: index
110
- }), "setSelectedProjectIndex"),
111
- setNewProjectName: /* @__PURE__ */ __name((name) => set({
112
- newProjectName: name
113
- }), "setNewProjectName"),
114
- setSelectedAnalysisAgent: /* @__PURE__ */ __name((agent) => set({
115
- selectedAnalysisAgent: agent
116
- }), "setSelectedAnalysisAgent"),
117
- resetOnboardingUi: /* @__PURE__ */ __name(() => set({
118
- selectedOrganizationIndex: void 0,
119
- selectedProjectIndex: void 0,
120
- newProjectName: void 0,
121
- selectedAnalysisAgent: "auto"
122
- }), "resetOnboardingUi"),
123
- setGenerationPanelOpen: /* @__PURE__ */ __name((open, specId) => set({
124
- generationPanelOpen: open,
125
- generationPanelSpecId: specId
126
- }), "setGenerationPanelOpen"),
127
- showTooltip: /* @__PURE__ */ __name((message, duration = 3e3) => set((state) => {
128
- if (state.tooltipTimeout) {
129
- clearTimeout(state.tooltipTimeout);
130
- }
131
- const timeout = setTimeout(() => {
132
- useTuiUiStore.getState().clearTooltip();
133
- }, duration);
134
- return {
135
- tooltip: message,
136
- tooltipTimeout: timeout
137
- };
138
- }), "showTooltip"),
139
- clearTooltip: /* @__PURE__ */ __name(() => set((state) => {
140
- if (state.tooltipTimeout) {
141
- clearTimeout(state.tooltipTimeout);
142
- }
143
- return {
144
- tooltip: void 0,
145
- tooltipTimeout: void 0
146
- };
147
- }), "clearTooltip")
148
- })));
149
-
150
- // src/capabilities/policy.ts
151
- var TIER_ORDER = {
152
- [OrganizationPlan.FREE]: 0,
153
- [OrganizationPlan.PRO]: 1,
154
- [OrganizationPlan.TEAM]: 2,
155
- [OrganizationPlan.ENTERPRISE]: 3
156
- };
157
- var NAV_DEFINITIONS = [
158
- {
159
- id: "home",
160
- label: "Home",
161
- description: "Next actions and workflow pulse",
162
- requiredPlan: OrganizationPlan.FREE
163
- },
164
- {
165
- id: "specs",
166
- label: "Specs",
167
- description: "Manage governed specifications",
168
- requiredPlan: OrganizationPlan.FREE
169
- },
170
- {
171
- id: "decisions",
172
- label: "Decision Log",
173
- description: "Review decisions and rationale",
174
- requiredPlan: OrganizationPlan.FREE
175
- },
176
- {
177
- id: "export",
178
- label: "Export",
179
- description: "Generate AGENTS.md / CLAUDE.md / .cursorrules",
180
- requiredPlan: OrganizationPlan.FREE
181
- },
182
- {
183
- id: "bridge",
184
- label: "Local Bridge",
185
- description: "Bridge status and controls",
186
- requiredPlan: OrganizationPlan.FREE
187
- },
188
- {
189
- id: "active-runs",
190
- label: "Active Runs",
191
- description: "Realtime orchestration dashboard",
192
- requiredPlan: OrganizationPlan.TEAM
193
- },
194
- {
195
- id: "phase-gates",
196
- label: "Phase Gates",
197
- description: "Approve and unblock workflow phases",
198
- requiredPlan: OrganizationPlan.TEAM
199
- },
200
- {
201
- id: "skills-marketplace",
202
- label: "Skills Marketplace",
203
- description: "Manage shared managed skills",
204
- requiredPlan: OrganizationPlan.TEAM
205
- },
206
- {
207
- id: "org-governance",
208
- label: "Org Governance",
209
- description: "Compliance, policy, deployment gates",
210
- requiredPlan: OrganizationPlan.ENTERPRISE
211
- }
212
- ];
213
- var GATE_DISABLED_PHASES = [
214
- WorkflowPhase.SPECIFY,
215
- WorkflowPhase.CLARIFY
216
- ];
217
- function meetsMinimumTier(current, required) {
218
- return TIER_ORDER[current] >= TIER_ORDER[required];
219
- }
220
- __name(meetsMinimumTier, "meetsMinimumTier");
221
- function resolveNavPolicy(ctx) {
222
- return NAV_DEFINITIONS.map((item) => {
223
- if (!meetsMinimumTier(ctx.plan, item.requiredPlan)) {
224
- return {
225
- ...item,
226
- state: "locked",
227
- reason: `Requires ${item.requiredPlan.toUpperCase()} tier`
228
- };
229
- }
230
- if (item.id === "phase-gates" && ctx.role === "viewer") {
231
- return {
232
- ...item,
233
- state: "disabled",
234
- reason: "Viewer role cannot approve gates"
235
- };
236
- }
237
- if (item.id === "phase-gates" && ctx.workflowPhase && GATE_DISABLED_PHASES.includes(ctx.workflowPhase)) {
238
- return {
239
- ...item,
240
- state: "disabled",
241
- reason: `Gate approvals are unavailable in ${ctx.workflowPhase} phase`
242
- };
243
- }
244
- return {
245
- ...item,
246
- state: "enabled"
247
- };
248
- });
249
- }
250
- __name(resolveNavPolicy, "resolveNavPolicy");
251
-
252
- // src/state/onboarding-utils.ts
253
- function logOnboardingAttachResult(appendLog, result) {
254
- if (result.warning) {
255
- appendLog(`[warn] ${result.warning}`);
256
- }
257
- if (result.analyzed) {
258
- appendLog("[setup] Repository attached and analysis complete.");
259
- } else if (result.warning) {
260
- appendLog("[setup] Repository attached; analysis did not fully complete.");
261
- } else {
262
- appendLog("[setup] Repository already attached. Metadata sync complete (analysis skipped).");
263
- }
264
- }
265
- __name(logOnboardingAttachResult, "logOnboardingAttachResult");
266
-
267
- // src/store/windows/use-onboarding-window.ts
268
- import { create as create2 } from "zustand";
269
- import { subscribeWithSelector as subscribeWithSelector2 } from "zustand/middleware";
270
- var useOnboardingWindow = create2()(subscribeWithSelector2((set) => ({
271
- mode: "initial-setup",
272
- step: "organization",
273
- attachCurrentFolder: true,
274
- runLines: [],
275
- runStatus: "running",
276
- startedAt: null,
277
- availableAgents: [],
278
- canCreateProject: false,
279
- toolCalls: {},
280
- setMode: /* @__PURE__ */ __name((mode) => set({
281
- mode
282
- }), "setMode"),
283
- setStep: /* @__PURE__ */ __name((step) => set({
284
- step
285
- }), "setStep"),
286
- setSelectedOrganizationIndex: /* @__PURE__ */ __name((index) => set({
287
- selectedOrganizationIndex: index
288
- }), "setSelectedOrganizationIndex"),
289
- setSelectedProjectIndex: /* @__PURE__ */ __name((index) => set({
290
- selectedProjectIndex: index
291
- }), "setSelectedProjectIndex"),
292
- setNewProjectName: /* @__PURE__ */ __name((name) => set({
293
- newProjectName: name
294
- }), "setNewProjectName"),
295
- setAttachCurrentFolder: /* @__PURE__ */ __name((attach) => set({
296
- attachCurrentFolder: attach
297
- }), "setAttachCurrentFolder"),
298
- setRunLines: /* @__PURE__ */ __name((lines) => set({
299
- runLines: lines
300
- }), "setRunLines"),
301
- addRunLine: /* @__PURE__ */ __name((line) => set((state) => ({
302
- runLines: [
303
- ...state.runLines,
304
- line
305
- ].slice(-400)
306
- })), "addRunLine"),
307
- setRunStatus: /* @__PURE__ */ __name((status) => set({
308
- runStatus: status
309
- }), "setRunStatus"),
310
- setStartedAt: /* @__PURE__ */ __name((ts) => set({
311
- startedAt: ts
312
- }), "setStartedAt"),
313
- setInteraction: /* @__PURE__ */ __name((interaction) => set({
314
- interaction
315
- }), "setInteraction"),
316
- setError: /* @__PURE__ */ __name((error) => set({
317
- error
318
- }), "setError"),
319
- setSelectedOrganizationId: /* @__PURE__ */ __name((id) => set({
320
- selectedOrganizationId: id
321
- }), "setSelectedOrganizationId"),
322
- setSelectedProjectId: /* @__PURE__ */ __name((id) => set({
323
- selectedProjectId: id
324
- }), "setSelectedProjectId"),
325
- setAvailableAgents: /* @__PURE__ */ __name((agents) => set({
326
- availableAgents: agents
327
- }), "setAvailableAgents"),
328
- setCanCreateProject: /* @__PURE__ */ __name((canCreate) => set({
329
- canCreateProject: canCreate
330
- }), "setCanCreateProject"),
331
- upsertToolCall: /* @__PURE__ */ __name((event) => set((state) => {
332
- const id = event.toolCallId ?? `tc-${Date.now()}`;
333
- const existing = state.toolCalls[id];
334
- const updated = existing ? {
335
- ...existing,
336
- status: event.status ?? existing.status,
337
- title: event.title ?? existing.title,
338
- locations: event.locations ?? existing.locations,
339
- completedAt: event.status === "completed" || event.status === "failed" ? Date.now() : existing.completedAt
340
- } : {
341
- toolCallId: id,
342
- title: event.title ?? event.toolName ?? "Tool call",
343
- toolName: event.toolName,
344
- kind: event.kind ?? "other",
345
- status: event.status ?? "in_progress",
346
- locations: event.locations ?? [],
347
- startedAt: Date.now()
348
- };
349
- return {
350
- toolCalls: {
351
- ...state.toolCalls,
352
- [id]: updated
353
- }
354
- };
355
- }), "upsertToolCall"),
356
- setActiveThought: /* @__PURE__ */ __name((text) => set({
357
- activeThought: text
358
- }), "setActiveThought"),
359
- reset: /* @__PURE__ */ __name(() => set({
360
- mode: "initial-setup",
361
- step: "organization",
362
- selectedOrganizationIndex: void 0,
363
- selectedProjectIndex: void 0,
364
- newProjectName: void 0,
365
- attachCurrentFolder: true,
366
- runLines: [],
367
- runStatus: "running",
368
- startedAt: null,
369
- interaction: void 0,
370
- error: void 0,
371
- selectedOrganizationId: void 0,
372
- selectedProjectId: void 0,
373
- availableAgents: [],
374
- canCreateProject: false,
375
- toolCalls: {},
376
- activeThought: void 0
377
- }), "reset")
378
- })));
379
-
380
- // src/store/auth-utils.ts
381
- function isAuthenticationError(message) {
382
- const normalized = message.toLowerCase();
383
- return normalized.includes("authentication required") || normalized.includes("no valid credentials") || normalized.includes("unauthorized") || normalized.includes("forbidden") || normalized.includes("invalid token") || normalized.includes("token expired") || normalized.includes("auth");
384
- }
385
- __name(isAuthenticationError, "isAuthenticationError");
386
-
387
- // src/store/use-project-data-store.ts
388
- import { create as create3 } from "zustand";
389
- import { subscribeWithSelector as subscribeWithSelector3 } from "zustand/middleware";
390
- var EMPTY_WORKFLOW = {
391
- currentPhase: null,
392
- blockedCount: 0,
393
- hasPlanningArtifacts: false,
394
- hasVerificationEvidence: false
395
- };
396
- var useProjectDataStore = create3()(subscribeWithSelector3((set, get) => ({
397
- specs: [],
398
- decisions: [],
399
- workflow: EMPTY_WORKFLOW,
400
- navPolicy: [],
401
- specGenerations: {},
402
- activeGenerationId: null,
403
- setProjectData: /* @__PURE__ */ __name((specs, decisions, workflow, navPolicy) => set({
404
- specs,
405
- decisions,
406
- workflow,
407
- navPolicy
408
- }), "setProjectData"),
409
- setPollingData: /* @__PURE__ */ __name((workflow, navPolicy) => set({
410
- workflow,
411
- navPolicy
412
- }), "setPollingData"),
413
- clearProjectData: /* @__PURE__ */ __name(() => set({
414
- specs: [],
415
- decisions: [],
416
- workflow: EMPTY_WORKFLOW,
417
- navPolicy: [],
418
- specGenerations: {},
419
- activeGenerationId: null
420
- }), "clearProjectData"),
421
- updateSpecificationContent: /* @__PURE__ */ __name(async (specificationId, content) => {
422
- const client = getClient();
423
- const boot = getBootContext();
424
- if (!client || !boot) return;
425
- await withSessionFeedback({
426
- statusLine: "Saving specification...",
427
- action: /* @__PURE__ */ __name(() => getService().updateSpecificationContent(client, boot.projectId, specificationId, content), "action"),
428
- successLog: "[specs] saved specification changes",
429
- failureLog: "[error] save failed",
430
- failureStatusLine: "Save failed"
431
- });
432
- }, "updateSpecificationContent"),
433
- updateSpecificationStatus: /* @__PURE__ */ __name(async (specificationId, status, options) => {
434
- const client = getClient();
435
- const boot = getBootContext();
436
- if (!client || !boot) return;
437
- setSessionStatusLine(`Updating status to ${status}...`);
438
- try {
439
- await getService().updateSpecificationStatus(client, boot.projectId, specificationId, status);
440
- appendSessionLog(`[specs] status updated to ${status}`);
441
- if (options?.refresh !== false) {
442
- const { useSessionStore: useSessionStore2 } = await import("./use-session-store-OZ6HC4I2.mjs");
443
- await useSessionStore2.getState().refresh();
444
- }
445
- } catch (error) {
446
- const message = error instanceof Error ? error.message : String(error);
447
- appendSessionLog(`[error] status update failed: ${message}`);
448
- setSessionStatusLine("Status update failed");
449
- refreshOnAuthenticationError(message);
450
- }
451
- }, "updateSpecificationStatus"),
452
- deleteSpecification: /* @__PURE__ */ __name(async (specificationId, mode = "archive", options) => {
453
- const client = getClient();
454
- const boot = getBootContext();
455
- if (!client || !boot) return;
456
- setSessionStatusLine(mode === "delete" ? "Deleting specification permanently..." : "Archiving specification...");
457
- try {
458
- await getService().deleteSpecification(client, boot.projectId, specificationId, mode);
459
- appendSessionLog(mode === "delete" ? "[specs] specification deleted permanently" : "[specs] specification archived");
460
- if (options?.refresh !== false) {
461
- const { useSessionStore: useSessionStore2 } = await import("./use-session-store-OZ6HC4I2.mjs");
462
- await useSessionStore2.getState().refresh();
463
- }
464
- } catch (error) {
465
- const message = error instanceof Error ? error.message : String(error);
466
- appendSessionLog(`[error] specification ${mode === "delete" ? "delete" : "archive"} failed: ${message}`);
467
- setSessionStatusLine(mode === "delete" ? "Permanent delete failed" : "Archive failed");
468
- refreshOnAuthenticationError(message);
469
- }
470
- }, "deleteSpecification"),
471
- refineSpecificationWithAi: /* @__PURE__ */ __name(async (specificationId, userMessage) => {
472
- const client = getClient();
473
- const boot = getBootContext();
474
- const { specs } = get();
475
- if (!client || !boot) return;
476
- const spec = specs.find((item) => item.id === specificationId);
477
- if (!spec) {
478
- appendSessionLog("[error] refine failed: specification not found in current list");
479
- setSessionStatusLine("Refinement failed");
480
- return;
481
- }
482
- const specContent = (spec.content ?? "").trim();
483
- if (!specContent) {
484
- appendSessionLog("[error] refine failed: selected specification has no content");
485
- setSessionStatusLine("Refinement failed");
486
- return;
487
- }
488
- setSessionStatusLine("Refining specification with AI...");
489
- const service = getService();
490
- try {
491
- const refinedContent = await service.refineSpecificationWithAi(client, {
492
- projectId: boot.projectId,
493
- specContent,
494
- userMessage,
495
- agentType: "codex"
496
- });
497
- await service.updateSpecificationContent(client, boot.projectId, specificationId, refinedContent);
498
- appendSessionLog("[specs] AI refinement applied and saved");
499
- const { useSessionStore: useSessionStore2 } = await import("./use-session-store-OZ6HC4I2.mjs");
500
- await useSessionStore2.getState().refresh();
501
- } catch (error) {
502
- const message = error instanceof Error ? error.message : String(error);
503
- appendSessionLog(`[error] AI refinement failed: ${message}`);
504
- setSessionStatusLine("AI refinement failed");
505
- refreshOnAuthenticationError(message);
506
- }
507
- }, "refineSpecificationWithAi"),
508
- resolveDecision: /* @__PURE__ */ __name(async (decisionId, status, reason, existingRationale, options) => {
509
- const client = getClient();
510
- const boot = getBootContext();
511
- if (!client || !boot) {
512
- throw new Error("Decision update unavailable: project context is not initialized.");
513
- }
514
- setSessionStatusLine(`Resolving decision as ${status}...`);
515
- try {
516
- await getService().resolveDecision(client, boot.projectId, decisionId, status, reason, existingRationale);
517
- appendSessionLog(`[decisions] ${decisionId} -> ${status}`);
518
- if (options?.refresh !== false) {
519
- const { useSessionStore: useSessionStore2 } = await import("./use-session-store-OZ6HC4I2.mjs");
520
- await useSessionStore2.getState().refresh();
521
- }
522
- } catch (error) {
523
- const message = error instanceof Error ? error.message : String(error);
524
- appendSessionLog(`[error] decision resolution failed: ${message}`);
525
- setSessionStatusLine("Decision resolution failed");
526
- refreshOnAuthenticationError(message);
527
- throw error;
528
- }
529
- }, "resolveDecision"),
530
- deleteDecision: /* @__PURE__ */ __name(async (decisionId, mode = "archive", options) => {
531
- const client = getClient();
532
- const boot = getBootContext();
533
- if (!client || !boot) {
534
- throw new Error("Decision delete unavailable: project context is not initialized.");
535
- }
536
- setSessionStatusLine(mode === "delete" ? "Deleting decision permanently..." : "Archiving decision...");
537
- try {
538
- await getService().deleteDecision(client, boot.projectId, decisionId, mode);
539
- appendSessionLog(mode === "delete" ? `[decisions] ${decisionId} deleted permanently` : `[decisions] ${decisionId} archived`);
540
- if (options?.refresh !== false) {
541
- const { useSessionStore: useSessionStore2 } = await import("./use-session-store-OZ6HC4I2.mjs");
542
- await useSessionStore2.getState().refresh();
543
- }
544
- } catch (error) {
545
- const message = error instanceof Error ? error.message : String(error);
546
- appendSessionLog(`[error] decision ${mode === "delete" ? "delete" : "archive"} failed: ${message}`);
547
- setSessionStatusLine(mode === "delete" ? "Permanent delete failed" : "Archive failed");
548
- refreshOnAuthenticationError(message);
549
- throw error;
550
- }
551
- }, "deleteDecision"),
552
- loadGenerations: /* @__PURE__ */ __name(async (specId) => {
553
- const client = getClient();
554
- const boot = getBootContext();
555
- if (!client || !boot) return;
556
- try {
557
- const gens = await getService().listGenerations(client, boot.projectId, specId);
558
- set((state) => ({
559
- specGenerations: {
560
- ...state.specGenerations,
561
- [specId]: gens.map((g) => ({
562
- id: g.id,
563
- generationNumber: g.generationNumber,
564
- status: g.status,
565
- createdBy: g.createdBy ?? "",
566
- createdAt: g.createdAt ?? "",
567
- lockedBy: g.lockedBy,
568
- lockedAt: g.lockedAt,
569
- qualityScore: g.qualityScore,
570
- qualityGrade: g.qualityGrade,
571
- content: g.content
572
- }))
573
- }
574
- }));
575
- } catch (error) {
576
- const message = error instanceof Error ? error.message : String(error);
577
- appendSessionLog(`[specs] failed to load generations: ${message}`);
578
- refreshOnAuthenticationError(message);
579
- }
580
- }, "loadGenerations"),
581
- setActiveGenerationId: /* @__PURE__ */ __name((genId) => set({
582
- activeGenerationId: genId
583
- }), "setActiveGenerationId")
584
- })));
585
-
586
- // src/store/use-export-store.ts
587
- import { create as create4 } from "zustand";
588
- import { subscribeWithSelector as subscribeWithSelector4 } from "zustand/middleware";
589
-
590
- // src/utils/clipboard.ts
591
- import { spawnSync } from "child_process";
592
- function clipboardAttempts() {
593
- if (process.platform === "darwin") {
594
- return [
595
- {
596
- cmd: "pbcopy",
597
- args: []
598
- }
599
- ];
600
- }
601
- if (process.platform === "win32") {
602
- return [
603
- {
604
- cmd: "clip",
605
- args: []
606
- }
607
- ];
608
- }
609
- return [
610
- {
611
- cmd: "wl-copy",
612
- args: []
613
- },
614
- {
615
- cmd: "xclip",
616
- args: [
617
- "-selection",
618
- "clipboard"
619
- ]
620
- },
621
- {
622
- cmd: "xsel",
623
- args: [
624
- "--clipboard",
625
- "--input"
626
- ]
627
- }
628
- ];
629
- }
630
- __name(clipboardAttempts, "clipboardAttempts");
631
- function copyTextToClipboard(text) {
632
- const attempts = clipboardAttempts();
633
- let lastError = "No clipboard command available.";
634
- for (const attempt of attempts) {
635
- const result = spawnSync(attempt.cmd, attempt.args, {
636
- input: text,
637
- encoding: "utf8",
638
- stdio: [
639
- "pipe",
640
- "ignore",
641
- "pipe"
642
- ]
643
- });
644
- if (!result.error && result.status === 0) {
645
- return {
646
- ok: true
647
- };
648
- }
649
- lastError = (result.error?.message ?? result.stderr?.trim()) || `${attempt.cmd} exited with status ${result.status}`;
650
- }
651
- return {
652
- ok: false,
653
- error: lastError
654
- };
655
- }
656
- __name(copyTextToClipboard, "copyTextToClipboard");
657
-
658
- // src/store/use-export-store.ts
659
- var EMPTY_EXPORT_JOB = {
660
- action: null,
661
- status: "idle"
662
- };
663
- async function runExport(action) {
664
- const state = useExportStore.getState();
665
- const boot = getBootContext();
666
- if (!boot) return;
667
- if (state.exportInFlight) {
668
- appendSessionLog("[warn] Export already in progress");
669
- return;
670
- }
671
- const format = state.exportFormat;
672
- useExportStore.setState({
673
- exportInFlight: true,
674
- exportJob: {
675
- action,
676
- status: "running",
677
- format
678
- }
679
- });
680
- setSessionStatusLine(action === "preview" ? "Previewing export..." : "Generating export...");
681
- const service = getService();
682
- const client = getClient();
683
- try {
684
- if (action === "status") {
685
- const status = await service.exportStatus(boot.projectId, format, {
686
- mode: state.exportMode,
687
- scopePath: state.exportScopePath || void 0,
688
- organizationId: boot.organizationId
689
- });
690
- useExportStore.setState({
691
- exportStatus: status,
692
- exportJob: {
693
- action,
694
- status: "success",
695
- format
696
- }
697
- });
698
- setSessionStatusLine(`Export status: ${status.overall}`);
699
- appendSessionLog(`[export] Status ${format}: ${status.overall}`);
700
- return;
701
- }
702
- if (action === "commit" || action === "pr") {
703
- const delivery = action === "commit" ? "commit" : "pr";
704
- const result = await service.deliverExport(boot.projectId, format, delivery, {
705
- mode: state.exportMode,
706
- scopePath: state.exportScopePath || void 0,
707
- organizationId: boot.organizationId
708
- });
709
- useExportStore.setState({
710
- exportJob: {
711
- action,
712
- status: "success",
713
- format
714
- }
715
- });
716
- setSessionStatusLine(result.message);
717
- appendSessionLog(`[export] ${result.message}`);
718
- return;
719
- }
720
- const output = action === "preview" ? await service.previewExport(client, boot.projectId, format) : await service.generateExport(client, boot.projectId, format);
721
- useExportStore.setState({
722
- exportPreview: output,
723
- exportJob: {
724
- action,
725
- status: "success",
726
- format
727
- }
728
- });
729
- setSessionStatusLine(action === "preview" ? "Export preview ready" : "Export generated");
730
- const verb = action === "preview" ? "Previewed" : "Generated";
731
- appendSessionLog(`[export] ${verb} ${format} (${output.anchorCount} anchors)`);
732
- } catch (error) {
733
- const message = error instanceof Error ? error.message : String(error);
734
- useExportStore.setState({
735
- exportJob: {
736
- action,
737
- status: "error",
738
- format,
739
- error: message
740
- }
741
- });
742
- setSessionStatusLine(action === "preview" ? "Export preview failed" : "Export generation failed");
743
- appendSessionLog(`[error] Export ${action} failed: ${message}`);
744
- refreshOnAuthenticationError(message);
745
- } finally {
746
- useExportStore.setState({
747
- exportInFlight: false
748
- });
749
- }
750
- }
751
- __name(runExport, "runExport");
752
- var useExportStore = create4()(subscribeWithSelector4((set, get) => ({
753
- exportFormat: "agents-md",
754
- exportMode: "global",
755
- exportScopePath: "",
756
- exportDelivery: "download",
757
- exportCapabilities: null,
758
- exportPreview: null,
759
- exportStatus: null,
760
- exportValidation: {
761
- open: false
762
- },
763
- exportJob: EMPTY_EXPORT_JOB,
764
- exportInFlight: false,
765
- setCapabilities: /* @__PURE__ */ __name((capabilities) => {
766
- set((prev) => {
767
- const discoveredFormats = capabilities?.formats?.map((f) => f.id) ?? [];
768
- const discoveredModes = capabilities?.modes ?? [];
769
- const resolvedFormat = discoveredFormats.length > 0 ? discoveredFormats.includes(prev.exportFormat) ? prev.exportFormat : discoveredFormats[0] : prev.exportFormat;
770
- const resolvedMode = discoveredModes.length > 0 ? discoveredModes.includes(prev.exportMode) ? prev.exportMode : discoveredModes[0] : prev.exportMode;
771
- return {
772
- exportCapabilities: capabilities,
773
- exportFormat: resolvedFormat,
774
- exportMode: resolvedMode
775
- };
776
- });
777
- }, "setCapabilities"),
778
- setExportFormat: /* @__PURE__ */ __name((format) => {
779
- set((prev) => {
780
- const allowedFormats = prev.exportCapabilities?.formats.map((f) => f.id) ?? [];
781
- if (allowedFormats.length > 0 && !allowedFormats.includes(format)) {
782
- setSessionStatusLine(`Export format unavailable: ${format}`);
783
- return prev;
784
- }
785
- if (prev.exportFormat === format) return prev;
786
- setSessionStatusLine(`Export format set to ${format}`);
787
- return {
788
- exportFormat: format,
789
- exportPreview: null,
790
- exportStatus: null,
791
- exportValidation: {
792
- open: false
793
- },
794
- exportJob: EMPTY_EXPORT_JOB
795
- };
796
- });
797
- }, "setExportFormat"),
798
- setExportMode: /* @__PURE__ */ __name((mode) => {
799
- set((prev) => {
800
- const allowedModes = prev.exportCapabilities?.modes ?? [];
801
- if (allowedModes.length > 0 && !allowedModes.includes(mode)) {
802
- setSessionStatusLine(`Export mode unavailable: ${mode}`);
803
- return prev;
804
- }
805
- setSessionStatusLine(`Export mode set to ${mode}`);
806
- return {
807
- exportMode: mode
808
- };
809
- });
810
- }, "setExportMode"),
811
- setExportScopePath: /* @__PURE__ */ __name((scopePath) => {
812
- setSessionStatusLine("Updated export scope path");
813
- set({
814
- exportScopePath: scopePath
815
- });
816
- }, "setExportScopePath"),
817
- setExportDelivery: /* @__PURE__ */ __name((delivery) => {
818
- setSessionStatusLine(`Export delivery set to ${delivery}`);
819
- set({
820
- exportDelivery: delivery
821
- });
822
- }, "setExportDelivery"),
823
- previewExport: /* @__PURE__ */ __name(async () => {
824
- await runExport("preview");
825
- }, "previewExport"),
826
- generateExport: /* @__PURE__ */ __name(async () => {
827
- setSessionStatusLine("Confirm export validation to write files to disk");
828
- set({
829
- exportValidation: {
830
- open: true
831
- }
832
- });
833
- }, "generateExport"),
834
- validateAndWriteExport: /* @__PURE__ */ __name(async () => {
835
- const state = get();
836
- const boot = getBootContext();
837
- if (!boot) return;
838
- if (state.exportInFlight) {
839
- appendSessionLog("[warn] Export already in progress");
840
- return;
841
- }
842
- const format = state.exportFormat;
843
- set({
844
- exportInFlight: true,
845
- exportValidation: {
846
- open: false
847
- },
848
- exportJob: {
849
- action: "generate",
850
- status: "running",
851
- format
852
- }
853
- });
854
- setSessionStatusLine("Validating export and writing files...");
855
- const service = getService();
856
- try {
857
- const result = await service.deliverExport(boot.projectId, format, "download", {
858
- mode: state.exportMode,
859
- scopePath: state.exportScopePath || void 0,
860
- organizationId: boot.organizationId
861
- });
862
- set((prev) => ({
863
- exportStatus: result.localStatus ?? prev.exportStatus,
864
- exportJob: {
865
- action: "generate",
866
- status: "success",
867
- format
868
- }
869
- }));
870
- setSessionStatusLine(result.message);
871
- appendSessionLog(`[export] ${result.message}`);
872
- } catch (error) {
873
- const message = error instanceof Error ? error.message : String(error);
874
- set({
875
- exportJob: {
876
- action: "generate",
877
- status: "error",
878
- format,
879
- error: message
880
- }
881
- });
882
- setSessionStatusLine("Export validation/write failed");
883
- appendSessionLog(`[error] Export validate/write failed: ${message}`);
884
- refreshOnAuthenticationError(message);
885
- } finally {
886
- set({
887
- exportInFlight: false
888
- });
889
- }
890
- }, "validateAndWriteExport"),
891
- cancelExportValidation: /* @__PURE__ */ __name(() => {
892
- setSessionStatusLine("Export validation cancelled");
893
- set({
894
- exportValidation: {
895
- open: false
896
- }
897
- });
898
- }, "cancelExportValidation"),
899
- statusExport: /* @__PURE__ */ __name(async () => {
900
- await runExport("status");
901
- }, "statusExport"),
902
- commitExport: /* @__PURE__ */ __name(async () => {
903
- await runExport("commit");
904
- }, "commitExport"),
905
- createPrExport: /* @__PURE__ */ __name(async () => {
906
- await runExport("pr");
907
- }, "createPrExport"),
908
- copyExportPreview: /* @__PURE__ */ __name(() => {
909
- const { exportPreview, exportJob } = get();
910
- const hasGeneratedPreview = exportJob.status === "success" && (exportJob.action === "preview" || exportJob.action === "generate");
911
- if (!exportPreview?.content || !hasGeneratedPreview) {
912
- setSessionStatusLine("No generated preview to copy. Run p or g first.");
913
- appendSessionLog("[warn] export copy requested before preview/generate completed");
914
- return;
915
- }
916
- const copied = copyTextToClipboard(exportPreview.content);
917
- if (copied.ok) {
918
- setSessionStatusLine("Copied preview to clipboard");
919
- appendSessionLog("[export] copied preview to clipboard");
920
- return;
921
- }
922
- setSessionStatusLine("Clipboard copy failed");
923
- appendSessionLog(`[error] clipboard copy failed: ${copied.error}`);
924
- }, "copyExportPreview")
925
- })));
926
-
927
- // src/store/use-bridge-store.ts
928
- import { create as create5 } from "zustand";
929
- import { subscribeWithSelector as subscribeWithSelector5 } from "zustand/middleware";
930
- var useBridgeStore = create5()(subscribeWithSelector5((set, get) => ({
931
- bridge: null,
932
- localBridge: null,
933
- bridgeLogs: [],
934
- bridgeLogsSince: 0,
935
- startedByTui: false,
936
- webmcpChannels: [],
937
- setBridgeData: /* @__PURE__ */ __name((bridge, localBridge) => set({
938
- bridge,
939
- localBridge
940
- }), "setBridgeData"),
941
- setLocalBridge: /* @__PURE__ */ __name((localBridge) => set({
942
- localBridge
943
- }), "setLocalBridge"),
944
- setBridgeLogs: /* @__PURE__ */ __name((logs) => {
945
- if (logs.length === 0) return;
946
- const lastTimestamp = logs[logs.length - 1].timestamp;
947
- set((prev) => ({
948
- bridgeLogs: [
949
- ...prev.bridgeLogs,
950
- ...logs
951
- ].slice(-200),
952
- bridgeLogsSince: lastTimestamp
953
- }));
954
- }, "setBridgeLogs"),
955
- clearBridgeLogs: /* @__PURE__ */ __name(() => set({
956
- bridgeLogs: []
957
- }), "clearBridgeLogs"),
958
- setWebMcpChannels: /* @__PURE__ */ __name((channels) => set({
959
- webmcpChannels: channels
960
- }), "setWebMcpChannels"),
961
- bridgeStart: /* @__PURE__ */ __name(() => {
962
- const service = getService();
963
- service.startLocalBridgeDetached();
964
- set({
965
- startedByTui: true
966
- });
967
- appendSessionLog("[bridge] Started local bridge process (detached)");
968
- setSessionStatusLine("Bridge start triggered (detached)");
969
- }, "bridgeStart"),
970
- bridgeStop: /* @__PURE__ */ __name(async () => {
971
- const service = getService();
972
- const { localBridge } = get();
973
- await service.stopLocalBridge(localBridge?.port);
974
- if (localBridge) {
975
- set({
976
- localBridge: {
977
- ...localBridge,
978
- running: false,
979
- uptimeSec: 0
980
- },
981
- webmcpChannels: []
982
- });
983
- }
984
- appendSessionLog("[bridge] Stop signal sent");
985
- setSessionStatusLine("Bridge stop signal sent");
986
- }, "bridgeStop")
987
- })));
988
-
989
- // src/store/store-effects.ts
990
- function dispatchRefreshComplete(data) {
991
- useProjectDataStore.getState().setProjectData(data.specs, data.decisions, data.workflow, data.navPolicy);
992
- useExportStore.getState().setCapabilities(data.exportCapabilities);
993
- useBridgeStore.getState().setBridgeData(data.bridge, data.localBridge);
994
- }
995
- __name(dispatchRefreshComplete, "dispatchRefreshComplete");
996
- function dispatchClearProjectData() {
997
- useProjectDataStore.getState().clearProjectData();
998
- }
999
- __name(dispatchClearProjectData, "dispatchClearProjectData");
1000
- function refreshOnAuthenticationError(message) {
1001
- if (!isAuthenticationError(message)) return;
1002
- const { appendLog, refresh } = useSessionStore.getState();
1003
- useSessionStore.setState({
1004
- statusLine: "Authentication required. Refreshing context..."
1005
- });
1006
- appendLog("[auth] action requires authentication, refreshing context");
1007
- void refresh();
1008
- }
1009
- __name(refreshOnAuthenticationError, "refreshOnAuthenticationError");
1010
- async function withSessionFeedback(opts) {
1011
- const { appendLog, refresh } = useSessionStore.getState();
1012
- useSessionStore.setState({
1013
- statusLine: opts.statusLine
1014
- });
1015
- try {
1016
- const result = await opts.action();
1017
- appendLog(opts.successLog);
1018
- if (opts.refresh !== false) {
1019
- await refresh();
1020
- }
1021
- return result;
1022
- } catch (error) {
1023
- const message = error instanceof Error ? error.message : String(error);
1024
- appendLog(`${opts.failureLog}: ${message}`);
1025
- useSessionStore.setState({
1026
- statusLine: opts.failureStatusLine
1027
- });
1028
- refreshOnAuthenticationError(message);
1029
- throw error;
1030
- }
1031
- }
1032
- __name(withSessionFeedback, "withSessionFeedback");
1033
- function getBootContext() {
1034
- return useSessionStore.getState().boot;
1035
- }
1036
- __name(getBootContext, "getBootContext");
1037
- function setSessionStatusLine(line) {
1038
- useSessionStore.setState({
1039
- statusLine: line
1040
- });
1041
- }
1042
- __name(setSessionStatusLine, "setSessionStatusLine");
1043
- function appendSessionLog(entry) {
1044
- useSessionStore.getState().appendLog(entry);
1045
- }
1046
- __name(appendSessionLog, "appendSessionLog");
1047
-
1048
- // src/store/use-session-store.ts
1049
- var onboardingInteractionResolver = null;
1050
- function requestOnboardingInteraction(request) {
1051
- return new Promise((resolve) => {
1052
- onboardingInteractionResolver = resolve;
1053
- useSessionStore.setState((prev) => ({
1054
- onboarding: prev.onboarding ? {
1055
- ...prev.onboarding,
1056
- interaction: request
1057
- } : prev.onboarding
1058
- }));
1059
- });
1060
- }
1061
- __name(requestOnboardingInteraction, "requestOnboardingInteraction");
1062
- function refreshOnAuthenticationError2(message) {
1063
- if (!isAuthenticationError(message)) return;
1064
- const { appendLog, refresh } = useSessionStore.getState();
1065
- useSessionStore.setState({
1066
- statusLine: "Authentication required. Refreshing context..."
1067
- });
1068
- appendLog("[auth] action requires authentication, refreshing context");
1069
- void refresh();
1070
- }
1071
- __name(refreshOnAuthenticationError2, "refreshOnAuthenticationError");
1072
- async function buildOnboardingState(mode) {
1073
- const service = getService();
1074
- const boot = useSessionStore.getState().boot;
1075
- const organizations = await service.listOrganizations();
1076
- if (organizations.length === 0) {
1077
- return {
1078
- mode,
1079
- step: "create-organization",
1080
- attachCurrentFolder: mode === "initial-setup",
1081
- organizations: [],
1082
- projects: [],
1083
- availableAgents: [],
1084
- canCreateProject: false,
1085
- error: void 0
1086
- };
1087
- }
1088
- const preferredOrganizationId = boot?.organizationId;
1089
- const selectedOrganization = organizations.find((org) => org.id === preferredOrganizationId) ?? organizations[0];
1090
- const projects = await service.listProjects(selectedOrganization.id);
1091
- return {
1092
- mode,
1093
- step: organizations.length === 1 ? "project" : "organization",
1094
- attachCurrentFolder: mode === "initial-setup",
1095
- organizations,
1096
- projects,
1097
- availableAgents: [],
1098
- canCreateProject: service.canCreateProject(selectedOrganization),
1099
- selectedOrganizationId: selectedOrganization.id,
1100
- interaction: void 0,
1101
- error: void 0
1102
- };
1103
- }
1104
- __name(buildOnboardingState, "buildOnboardingState");
1105
- var useSessionStore = create6()(subscribeWithSelector6((set, get) => ({
1106
- boot: null,
1107
- auth: null,
1108
- onboarding: null,
1109
- loading: true,
1110
- error: null,
1111
- statusLine: "Bootstrapping...",
1112
- logs: [],
1113
- appendLog: /* @__PURE__ */ __name((entry) => {
1114
- const screen = useTuiUiStore.getState().screen;
1115
- const level = entry.startsWith("[error]") ? "error" : entry.startsWith("[warn]") ? "warn" : "info";
1116
- appendGlobalStructuredLog({
1117
- source: "tui.event-log",
1118
- level,
1119
- message: entry,
1120
- details: {
1121
- screen
1122
- }
1123
- });
1124
- set((prev) => ({
1125
- logs: [
1126
- entry,
1127
- ...prev.logs
1128
- ].slice(0, 40)
1129
- }));
1130
- }, "appendLog"),
1131
- setStatusLine: /* @__PURE__ */ __name((line) => set({
1132
- statusLine: line
1133
- }), "setStatusLine"),
1134
- setLoading: /* @__PURE__ */ __name((loading) => set({
1135
- loading
1136
- }), "setLoading"),
1137
- setError: /* @__PURE__ */ __name((error) => set({
1138
- error
1139
- }), "setError"),
1140
- authenticate: /* @__PURE__ */ __name(async () => {
1141
- const { appendLog } = get();
1142
- const service = getService();
1143
- set({
1144
- loading: false,
1145
- auth: {
1146
- status: "authenticating"
1147
- },
1148
- statusLine: "Starting browser login flow..."
1149
- });
1150
- appendLog("[auth] starting login flow");
1151
- const ok = await service.authenticateViaCli((line) => {
1152
- appendLog(`[auth] ${line}`);
1153
- });
1154
- if (!ok) {
1155
- set({
1156
- auth: {
1157
- status: "auth_failed",
1158
- error: "Authentication failed. Check logs and try again."
1159
- },
1160
- statusLine: "Authentication failed"
1161
- });
1162
- appendLog("[auth] login flow failed");
1163
- return;
1164
- }
1165
- appendLog("[auth] login flow completed");
1166
- await get().refresh();
1167
- }, "authenticate"),
1168
- refresh: /* @__PURE__ */ __name(async (projectId) => {
1169
- const service = getService();
1170
- set((prev) => ({
1171
- loading: prev.boot ? false : true,
1172
- statusLine: "Loading context..."
1173
- }));
1174
- try {
1175
- const token = await service.checkAuthentication();
1176
- if (!token) {
1177
- set({
1178
- loading: false,
1179
- error: null,
1180
- auth: {
1181
- status: "unauthenticated",
1182
- error: "No valid credentials. Please run `spekn auth login` to authenticate."
1183
- },
1184
- statusLine: "Authentication required"
1185
- });
1186
- return;
1187
- }
1188
- set({
1189
- auth: {
1190
- status: "authenticated",
1191
- userEmail: service.extractUserEmail(token),
1192
- tokenExpiresAt: service.extractTokenExpiry(token)
1193
- }
1194
- });
1195
- if (!projectId && !service.hasLocalProjectContext()) {
1196
- const onboarding = await buildOnboardingState("initial-setup");
1197
- set({
1198
- loading: false,
1199
- error: null,
1200
- onboarding,
1201
- statusLine: "Project setup required"
1202
- });
1203
- return;
1204
- }
1205
- let bootstrapResult;
1206
- try {
1207
- bootstrapResult = await service.bootstrap(projectId);
1208
- } catch (bootstrapError) {
1209
- if (bootstrapError instanceof Error && bootstrapError.message === "ONBOARDING_REQUIRED") {
1210
- const onboarding = await buildOnboardingState("initial-setup");
1211
- set({
1212
- loading: false,
1213
- error: null,
1214
- onboarding,
1215
- statusLine: "Project setup required"
1216
- });
1217
- return;
1218
- }
1219
- throw bootstrapError;
1220
- }
1221
- const { boot, client } = bootstrapResult;
1222
- setClient(client);
1223
- const [specs, decisions, workflow, bridge, localBridge, exportCapabilities] = await Promise.all([
1224
- service.loadSpecs(client, boot.projectId),
1225
- service.loadDecisions(client, boot.projectId),
1226
- service.loadWorkflowSummary(client, boot.projectId),
1227
- service.loadBridgeSummary(client),
1228
- service.loadLocalBridgeSummary(),
1229
- service.discoverExportCapabilities(boot.projectId, boot.organizationId).catch(() => null)
1230
- ]);
1231
- const capabilityContext = {
1232
- plan: boot.plan,
1233
- role: boot.role,
1234
- workflowPhase: workflow.currentPhase,
1235
- permissions: boot.permissions
1236
- };
1237
- const navPolicy = resolveNavPolicy(capabilityContext);
1238
- dispatchRefreshComplete({
1239
- specs,
1240
- decisions,
1241
- workflow,
1242
- navPolicy,
1243
- exportCapabilities,
1244
- bridge,
1245
- localBridge
1246
- });
1247
- set({
1248
- boot,
1249
- loading: false,
1250
- error: null,
1251
- onboarding: null,
1252
- statusLine: "Ready"
1253
- });
1254
- } catch (error) {
1255
- const message = error instanceof Error ? error.message : String(error);
1256
- let authStatus = null;
1257
- if (message.includes("credentials") || message.includes("auth") || message.includes("token")) {
1258
- authStatus = {
1259
- status: "auth_failed",
1260
- error: message
1261
- };
1262
- }
1263
- set((prev) => ({
1264
- loading: false,
1265
- error: message,
1266
- auth: authStatus || prev.auth,
1267
- statusLine: "Error"
1268
- }));
1269
- get().appendLog(`[error] ${message}`);
1270
- }
1271
- }, "refresh"),
1272
- switchContext: /* @__PURE__ */ __name(async () => {
1273
- const { appendLog } = get();
1274
- set({
1275
- loading: true,
1276
- error: null,
1277
- statusLine: "Loading organizations..."
1278
- });
1279
- try {
1280
- const onboarding = await buildOnboardingState("switch-context");
1281
- set({
1282
- loading: false,
1283
- onboarding,
1284
- statusLine: "Switch organization/project"
1285
- });
1286
- appendLog("[context] switch mode opened");
1287
- } catch (error) {
1288
- const message = error instanceof Error ? error.message : String(error);
1289
- set({
1290
- loading: false,
1291
- statusLine: "Context switch failed",
1292
- error: message
1293
- });
1294
- appendLog(`[error] context switch failed: ${message}`);
1295
- refreshOnAuthenticationError2(message);
1296
- }
1297
- }, "switchContext"),
1298
- detachRepoContext: /* @__PURE__ */ __name(async () => {
1299
- const { boot, appendLog, refresh } = get();
1300
- const service = getService();
1301
- const result = await service.detachContextViaCli(boot?.projectId, process.cwd());
1302
- if (!result.success) {
1303
- appendLog(`[error] Failed to detach context: ${result.output}`);
1304
- set({
1305
- statusLine: "Context detach failed"
1306
- });
1307
- return;
1308
- }
1309
- if (result.output) {
1310
- appendLog(`[context] ${result.output}`);
1311
- }
1312
- appendLog("[context] Detached repository from local project context");
1313
- set({
1314
- boot: null,
1315
- statusLine: "Repository detached. Select a project to attach."
1316
- });
1317
- dispatchClearProjectData();
1318
- await refresh();
1319
- }, "detachRepoContext"),
1320
- syncRepository: /* @__PURE__ */ __name(async (options) => {
1321
- const { boot, appendLog, refresh } = get();
1322
- const service = getService();
1323
- if (!boot) {
1324
- appendLog("[error] repository sync unavailable: no active project context");
1325
- set({
1326
- statusLine: "Repository sync unavailable"
1327
- });
1328
- return false;
1329
- }
1330
- appendLog("[repo] running sync (metadata + drift analysis)");
1331
- set({
1332
- statusLine: "Syncing repository..."
1333
- });
1334
- const result = await service.syncRepositoryViaCli(boot.organizationId, boot.projectId, boot.repoPath, {
1335
- analyze: options?.analyze ?? true,
1336
- importToProject: options?.importToProject,
1337
- maxFiles: options?.maxFiles,
1338
- analysisEngine: options?.analysisEngine,
1339
- agent: options?.agent,
1340
- requestInteraction: options?.requestInteraction,
1341
- onProgress: /* @__PURE__ */ __name((line) => {
1342
- appendLog(`[repo] ${line}`);
1343
- options?.onProgress?.(line);
1344
- }, "onProgress"),
1345
- onActivity: /* @__PURE__ */ __name((event) => {
1346
- options?.onActivity?.(event);
1347
- }, "onActivity"),
1348
- signal: options?.signal
1349
- });
1350
- if (!result.success) {
1351
- appendLog(`[error] repository sync failed (exit ${result.exitCode})`);
1352
- set({
1353
- statusLine: "Repository sync failed"
1354
- });
1355
- refreshOnAuthenticationError2(result.output);
1356
- return false;
1357
- }
1358
- appendLog("[repo] sync completed");
1359
- set({
1360
- statusLine: "Repository sync completed"
1361
- });
1362
- await refresh();
1363
- return true;
1364
- }, "syncRepository"),
1365
- // Onboarding actions
1366
- selectOnboardingOrganization: /* @__PURE__ */ __name(async (index) => {
1367
- const { onboarding, appendLog } = get();
1368
- const service = getService();
1369
- if (!onboarding) return;
1370
- if (index < 0 || index >= onboarding.organizations.length) {
1371
- set((prev) => ({
1372
- onboarding: prev.onboarding ? {
1373
- ...prev.onboarding,
1374
- error: `Invalid organization index: ${index + 1}`
1375
- } : prev.onboarding
1376
- }));
1377
- return;
1378
- }
1379
- const selectedOrganization = onboarding.organizations[index];
1380
- set((prev) => ({
1381
- loading: true,
1382
- statusLine: "Loading projects...",
1383
- onboarding: prev.onboarding ? {
1384
- ...prev.onboarding,
1385
- selectedOrganizationId: selectedOrganization.id,
1386
- error: void 0
1387
- } : prev.onboarding
1388
- }));
1389
- try {
1390
- const projects = await service.listProjects(selectedOrganization.id);
1391
- set((prev) => ({
1392
- loading: false,
1393
- statusLine: "Select a project",
1394
- onboarding: prev.onboarding ? {
1395
- ...prev.onboarding,
1396
- step: "project",
1397
- attachCurrentFolder: prev.onboarding.attachCurrentFolder,
1398
- projects,
1399
- availableAgents: prev.onboarding?.availableAgents ?? [],
1400
- canCreateProject: service.canCreateProject(selectedOrganization),
1401
- selectedOrganizationId: selectedOrganization.id,
1402
- interaction: void 0,
1403
- error: projects.length === 0 ? "No projects found in selected organization." : void 0
1404
- } : prev.onboarding
1405
- }));
1406
- } catch (error) {
1407
- const message = error instanceof Error ? error.message : String(error);
1408
- set((prev) => ({
1409
- loading: false,
1410
- statusLine: "Setup error",
1411
- onboarding: prev.onboarding ? {
1412
- ...prev.onboarding,
1413
- error: message
1414
- } : prev.onboarding
1415
- }));
1416
- }
1417
- }, "selectOnboardingOrganization"),
1418
- registerOnboardingProject: /* @__PURE__ */ __name(async (index) => {
1419
- const { onboarding, appendLog, refresh } = get();
1420
- const service = getService();
1421
- if (!onboarding || !onboarding.selectedOrganizationId) return;
1422
- if (index < 0 || index >= onboarding.projects.length) {
1423
- set((prev) => ({
1424
- onboarding: prev.onboarding ? {
1425
- ...prev.onboarding,
1426
- error: `Invalid project index: ${index + 1}`
1427
- } : prev.onboarding
1428
- }));
1429
- return;
1430
- }
1431
- const selectedProject = onboarding.projects[index];
1432
- if (onboarding.mode === "switch-context" || !onboarding.attachCurrentFolder) {
1433
- set((prev) => ({
1434
- loading: true,
1435
- statusLine: "Switching context...",
1436
- onboarding: prev.onboarding ? {
1437
- ...prev.onboarding,
1438
- error: void 0
1439
- } : prev.onboarding
1440
- }));
1441
- try {
1442
- service.persistContext(onboarding.selectedOrganizationId, selectedProject.id);
1443
- appendLog(`[context] switched to ${selectedProject.name}`);
1444
- await refresh();
1445
- } catch (error) {
1446
- const message = error instanceof Error ? error.message : String(error);
1447
- set((prev) => ({
1448
- loading: false,
1449
- statusLine: "Context switch failed",
1450
- onboarding: prev.onboarding ? {
1451
- ...prev.onboarding,
1452
- step: "project",
1453
- error: message
1454
- } : prev.onboarding
1455
- }));
1456
- }
1457
- return;
1458
- }
1459
- set((prev) => ({
1460
- loading: true,
1461
- statusLine: "Linking repository...",
1462
- onboarding: prev.onboarding ? {
1463
- ...prev.onboarding,
1464
- error: void 0
1465
- } : prev.onboarding
1466
- }));
1467
- try {
1468
- persistProjectContext(process.cwd(), {
1469
- projectId: selectedProject.id,
1470
- organizationId: onboarding.selectedOrganizationId
1471
- });
1472
- appendLog(`[context] linked to ${selectedProject.name}`);
1473
- await refresh();
1474
- } catch (error) {
1475
- const message = error instanceof Error ? error.message : String(error);
1476
- set((prev) => ({
1477
- loading: false,
1478
- statusLine: "Setup error",
1479
- onboarding: prev.onboarding ? {
1480
- ...prev.onboarding,
1481
- step: "project",
1482
- error: message
1483
- } : prev.onboarding
1484
- }));
1485
- }
1486
- }, "registerOnboardingProject"),
1487
- createOnboardingProject: /* @__PURE__ */ __name(async (name) => {
1488
- const { onboarding, appendLog, refresh } = get();
1489
- const service = getService();
1490
- if (!onboarding || !onboarding.selectedOrganizationId) return;
1491
- const trimmed = name.trim();
1492
- if (!onboarding.canCreateProject) {
1493
- set((prev) => ({
1494
- onboarding: prev.onboarding ? {
1495
- ...prev.onboarding,
1496
- error: "You are not authorized to create projects in this organization."
1497
- } : prev.onboarding
1498
- }));
1499
- return;
1500
- }
1501
- if (trimmed.length < 2) {
1502
- set((prev) => ({
1503
- onboarding: prev.onboarding ? {
1504
- ...prev.onboarding,
1505
- error: "Project name must be at least 2 characters."
1506
- } : prev.onboarding
1507
- }));
1508
- return;
1509
- }
1510
- set((prev) => ({
1511
- loading: true,
1512
- statusLine: "Creating project...",
1513
- onboarding: prev.onboarding ? {
1514
- ...prev.onboarding,
1515
- error: void 0
1516
- } : prev.onboarding
1517
- }));
1518
- try {
1519
- const created = await service.createProject(onboarding.selectedOrganizationId, trimmed);
1520
- appendLog(`[setup] Created project "${created.name}"`);
1521
- if (onboarding.mode === "switch-context" || !onboarding.attachCurrentFolder) {
1522
- service.persistContext(onboarding.selectedOrganizationId, created.id);
1523
- appendLog(`[context] switched to ${created.name}`);
1524
- await refresh();
1525
- return;
1526
- }
1527
- const registerStartedAt = Date.now();
1528
- set((prev) => ({
1529
- loading: true,
1530
- statusLine: "Registering repository...",
1531
- onboarding: prev.onboarding ? {
1532
- ...prev.onboarding,
1533
- step: "registering",
1534
- availableAgents: prev.onboarding?.availableAgents ?? [],
1535
- selectedProjectId: created.id,
1536
- runLines: [],
1537
- runStatus: "running",
1538
- startedAt: registerStartedAt,
1539
- interaction: void 0,
1540
- error: void 0
1541
- } : prev.onboarding
1542
- }));
1543
- useOnboardingWindow.getState().setStartedAt(registerStartedAt);
1544
- await attachRepositoryFromOnboardingZustand({
1545
- organizationId: onboarding.selectedOrganizationId,
1546
- projectId: created.id
1547
- });
1548
- await refresh();
1549
- } catch (error) {
1550
- const message = error instanceof Error ? error.message : String(error);
1551
- set((prev) => ({
1552
- loading: false,
1553
- statusLine: "Setup error",
1554
- onboarding: prev.onboarding ? {
1555
- ...prev.onboarding,
1556
- error: message
1557
- } : prev.onboarding
1558
- }));
1559
- }
1560
- }, "createOnboardingProject"),
1561
- resolveOnboardingInteraction: /* @__PURE__ */ __name((value) => {
1562
- const resolver = onboardingInteractionResolver;
1563
- onboardingInteractionResolver = null;
1564
- set((prev) => ({
1565
- onboarding: prev.onboarding ? {
1566
- ...prev.onboarding,
1567
- interaction: void 0
1568
- } : prev.onboarding
1569
- }));
1570
- if (resolver) resolver(value);
1571
- }, "resolveOnboardingInteraction"),
1572
- setOnboardingAttachCurrentFolder: /* @__PURE__ */ __name((attach) => {
1573
- set((prev) => ({
1574
- onboarding: prev.onboarding ? prev.onboarding.attachCurrentFolder === attach ? prev.onboarding : {
1575
- ...prev.onboarding,
1576
- attachCurrentFolder: attach
1577
- } : prev.onboarding
1578
- }));
1579
- }, "setOnboardingAttachCurrentFolder")
1580
- })));
1581
- async function attachRepositoryFromOnboardingZustand(input) {
1582
- const service = getService();
1583
- const { appendLog } = useSessionStore.getState();
1584
- const result = await service.attachOrSyncCurrentRepository(input.organizationId, input.projectId, (line) => {
1585
- appendLog(`[setup] ${line}`);
1586
- useSessionStore.setState((prev) => ({
1587
- statusLine: line.slice(0, 100),
1588
- onboarding: prev.onboarding ? {
1589
- ...prev.onboarding,
1590
- runLines: [
1591
- ...prev.onboarding.runLines ?? [],
1592
- line
1593
- ].slice(-400)
1594
- } : prev.onboarding
1595
- }));
1596
- }, void 0, requestOnboardingInteraction, (event) => {
1597
- const { upsertToolCall, setActiveThought } = useOnboardingWindow.getState();
1598
- if (event.event === "tool_call" || event.event === "tool_call_update") {
1599
- upsertToolCall(event);
1600
- } else if (event.event === "agent_thought") {
1601
- setActiveThought(event.text);
1602
- } else if (event.event === "agent_chunk" && event.text) {
1603
- useSessionStore.setState((prev) => {
1604
- if (!prev.onboarding) return prev;
1605
- const lines = [
1606
- ...prev.onboarding.runLines ?? []
1607
- ];
1608
- const parts = event.text.split("\n");
1609
- if (lines.length === 0) {
1610
- lines.push(parts[0]);
1611
- } else {
1612
- lines[lines.length - 1] += parts[0];
1613
- }
1614
- for (let i = 1; i < parts.length; i++) {
1615
- lines.push(parts[i]);
1616
- }
1617
- return {
1618
- onboarding: {
1619
- ...prev.onboarding,
1620
- runLines: lines.slice(-400)
1621
- }
1622
- };
1623
- });
1624
- }
1625
- });
1626
- useSessionStore.setState((prev) => ({
1627
- onboarding: prev.onboarding ? {
1628
- ...prev.onboarding,
1629
- runStatus: result.warning ? "error" : "success"
1630
- } : prev.onboarding
1631
- }));
1632
- logOnboardingAttachResult(appendLog, result);
1633
- }
1634
- __name(attachRepositoryFromOnboardingZustand, "attachRepositoryFromOnboardingZustand");
1635
-
1636
- export {
1637
- setInitialScreen,
1638
- useTuiUiStore,
1639
- resolveNavPolicy,
1640
- useOnboardingWindow,
1641
- buildOnboardingState,
1642
- useSessionStore,
1643
- useProjectDataStore,
1644
- useExportStore,
1645
- dispatchRefreshComplete,
1646
- dispatchClearProjectData,
1647
- refreshOnAuthenticationError,
1648
- withSessionFeedback,
1649
- getBootContext,
1650
- setSessionStatusLine,
1651
- appendSessionLog,
1652
- useBridgeStore
1653
- };