@spekn/cli 1.0.1 → 1.0.3
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.
- package/dist/main.js +34856 -29545
- package/dist/prompts/governance-analysis.prompt.md +109 -0
- package/dist/resources/prompts/repo-analysis.prompt.md +28 -136
- package/dist/resources/prompts/repo-sync-analysis.prompt.md +31 -68
- package/dist/tui/app.d.ts +7 -0
- package/dist/tui/app.js +122 -0
- package/dist/tui/args.d.ts +8 -0
- package/dist/tui/args.js +57 -0
- package/dist/tui/capabilities/policy.d.ts +7 -0
- package/dist/tui/capabilities/policy.js +64 -0
- package/dist/tui/chunk-4WEASLXY.mjs +3444 -0
- package/dist/tui/chunk-755CADEG.mjs +3401 -0
- package/dist/tui/chunk-BUJQVTY5.mjs +3409 -0
- package/dist/tui/chunk-BZKKMGFB.mjs +1959 -0
- package/dist/tui/chunk-DJYOBCNM.mjs +3159 -0
- package/dist/tui/chunk-GTFTFDY4.mjs +3417 -0
- package/dist/tui/chunk-IMEBD2KA.mjs +3444 -0
- package/dist/tui/chunk-IX6DR5SW.mjs +3433 -0
- package/dist/tui/chunk-JKFOY4IF.mjs +2003 -0
- package/dist/tui/chunk-OXXZ3O5L.mjs +3378 -0
- package/dist/tui/chunk-SHJNIAAJ.mjs +1697 -0
- package/dist/tui/chunk-V4SNDRUS.mjs +1666 -0
- package/dist/tui/chunk-VXVHNZST.mjs +1666 -0
- package/dist/tui/chunk-WCTSFKTA.mjs +3459 -0
- package/dist/tui/chunk-X2XP5ACW.mjs +3443 -0
- package/dist/tui/chunk-YUYJ7VBG.mjs +2029 -0
- package/dist/tui/chunk-ZM3EI5IA.mjs +3384 -0
- package/dist/tui/chunk-ZYOX64HP.mjs +1653 -0
- package/dist/tui/components/frame.d.ts +8 -0
- package/dist/tui/components/frame.js +8 -0
- package/dist/tui/components/status-bar.d.ts +8 -0
- package/dist/tui/components/status-bar.js +8 -0
- package/dist/tui/index.d.ts +2 -0
- package/dist/tui/index.js +23 -0
- package/dist/tui/index.mjs +6999 -6938
- package/dist/tui/keymap/use-global-keymap.d.ts +19 -0
- package/dist/tui/keymap/use-global-keymap.js +82 -0
- package/dist/tui/navigation/nav-items.d.ts +3 -0
- package/dist/tui/navigation/nav-items.js +18 -0
- package/dist/tui/prompts/spec-creation-system.prompt.md +47 -0
- package/dist/tui/prompts/spec-refinement-system.prompt.md +81 -0
- package/dist/tui/screens/bridge.d.ts +8 -0
- package/dist/tui/screens/bridge.js +19 -0
- package/dist/tui/screens/decisions.d.ts +5 -0
- package/dist/tui/screens/decisions.js +28 -0
- package/dist/tui/screens/export.d.ts +5 -0
- package/dist/tui/screens/export.js +16 -0
- package/dist/tui/screens/home.d.ts +5 -0
- package/dist/tui/screens/home.js +33 -0
- package/dist/tui/screens/locked.d.ts +5 -0
- package/dist/tui/screens/locked.js +9 -0
- package/dist/tui/screens/specs.d.ts +5 -0
- package/dist/tui/screens/specs.js +31 -0
- package/dist/tui/services/client.d.ts +1 -0
- package/dist/tui/services/client.js +18 -0
- package/dist/tui/services/context-service.d.ts +19 -0
- package/dist/tui/services/context-service.js +246 -0
- package/dist/tui/shared-enums.d.ts +16 -0
- package/dist/tui/shared-enums.js +19 -0
- package/dist/tui/state/use-app-state.d.ts +35 -0
- package/dist/tui/state/use-app-state.js +177 -0
- package/dist/tui/types.d.ts +77 -0
- package/dist/tui/types.js +2 -0
- package/dist/tui/use-session-store-63YUGUFA.mjs +8 -0
- package/dist/tui/use-session-store-ACO2SMJC.mjs +8 -0
- package/dist/tui/use-session-store-BVFDAWOB.mjs +8 -0
- package/dist/tui/use-session-store-DJIZ3FQZ.mjs +9 -0
- package/dist/tui/use-session-store-EAIQA4UG.mjs +9 -0
- package/dist/tui/use-session-store-EFBAXC3G.mjs +8 -0
- package/dist/tui/use-session-store-FJOR4KTG.mjs +8 -0
- package/dist/tui/use-session-store-IJE5KVOC.mjs +8 -0
- package/dist/tui/use-session-store-KGAFXCKI.mjs +8 -0
- package/dist/tui/use-session-store-KS4DPNDY.mjs +8 -0
- package/dist/tui/use-session-store-MMHJENNL.mjs +8 -0
- package/dist/tui/use-session-store-OZ6HC4I2.mjs +9 -0
- package/dist/tui/use-session-store-PTMWISNJ.mjs +8 -0
- package/dist/tui/use-session-store-VCDECQMW.mjs +8 -0
- package/dist/tui/use-session-store-VOK5ML5J.mjs +9 -0
- package/package.json +6 -3
|
@@ -0,0 +1,1697 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OrganizationPlan,
|
|
3
|
+
WorkflowPhase,
|
|
4
|
+
__name,
|
|
5
|
+
appendGlobalStructuredLog,
|
|
6
|
+
getClient,
|
|
7
|
+
getService,
|
|
8
|
+
persistProjectContext,
|
|
9
|
+
setClient
|
|
10
|
+
} from "./chunk-YUYJ7VBG.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-VOK5ML5J.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-VOK5ML5J.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-VOK5ML5J.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-VOK5ML5J.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-VOK5ML5J.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
|
+
registerRepository: /* @__PURE__ */ __name(async (options) => {
|
|
1366
|
+
const { boot, appendLog, refresh } = get();
|
|
1367
|
+
const service = getService();
|
|
1368
|
+
if (!boot) {
|
|
1369
|
+
appendLog("[error] repository register unavailable: no active project context");
|
|
1370
|
+
set({
|
|
1371
|
+
statusLine: "Repository register unavailable"
|
|
1372
|
+
});
|
|
1373
|
+
return false;
|
|
1374
|
+
}
|
|
1375
|
+
appendLog("[repo] running register");
|
|
1376
|
+
set({
|
|
1377
|
+
statusLine: "Registering repository..."
|
|
1378
|
+
});
|
|
1379
|
+
const repoPath = options?.path ?? boot.repoPath;
|
|
1380
|
+
const result = await service.registerRepositoryViaCli(boot.organizationId, boot.projectId, repoPath, {
|
|
1381
|
+
primary: options?.primary,
|
|
1382
|
+
analyze: options?.analyze,
|
|
1383
|
+
agent: options?.agent,
|
|
1384
|
+
requestInteraction: options?.requestInteraction,
|
|
1385
|
+
onProgress: /* @__PURE__ */ __name((line) => {
|
|
1386
|
+
appendLog(`[repo] ${line}`);
|
|
1387
|
+
options?.onProgress?.(line);
|
|
1388
|
+
}, "onProgress"),
|
|
1389
|
+
onActivity: /* @__PURE__ */ __name((event) => {
|
|
1390
|
+
options?.onActivity?.(event);
|
|
1391
|
+
}, "onActivity"),
|
|
1392
|
+
signal: options?.signal
|
|
1393
|
+
});
|
|
1394
|
+
if (!result.success) {
|
|
1395
|
+
appendLog(`[error] repository register failed (exit ${result.exitCode})`);
|
|
1396
|
+
set({
|
|
1397
|
+
statusLine: "Repository register failed"
|
|
1398
|
+
});
|
|
1399
|
+
refreshOnAuthenticationError2(result.output);
|
|
1400
|
+
return false;
|
|
1401
|
+
}
|
|
1402
|
+
appendLog("[repo] register completed");
|
|
1403
|
+
set({
|
|
1404
|
+
statusLine: "Repository register completed"
|
|
1405
|
+
});
|
|
1406
|
+
await refresh();
|
|
1407
|
+
return true;
|
|
1408
|
+
}, "registerRepository"),
|
|
1409
|
+
// Onboarding actions
|
|
1410
|
+
selectOnboardingOrganization: /* @__PURE__ */ __name(async (index) => {
|
|
1411
|
+
const { onboarding, appendLog } = get();
|
|
1412
|
+
const service = getService();
|
|
1413
|
+
if (!onboarding) return;
|
|
1414
|
+
if (index < 0 || index >= onboarding.organizations.length) {
|
|
1415
|
+
set((prev) => ({
|
|
1416
|
+
onboarding: prev.onboarding ? {
|
|
1417
|
+
...prev.onboarding,
|
|
1418
|
+
error: `Invalid organization index: ${index + 1}`
|
|
1419
|
+
} : prev.onboarding
|
|
1420
|
+
}));
|
|
1421
|
+
return;
|
|
1422
|
+
}
|
|
1423
|
+
const selectedOrganization = onboarding.organizations[index];
|
|
1424
|
+
set((prev) => ({
|
|
1425
|
+
loading: true,
|
|
1426
|
+
statusLine: "Loading projects...",
|
|
1427
|
+
onboarding: prev.onboarding ? {
|
|
1428
|
+
...prev.onboarding,
|
|
1429
|
+
selectedOrganizationId: selectedOrganization.id,
|
|
1430
|
+
error: void 0
|
|
1431
|
+
} : prev.onboarding
|
|
1432
|
+
}));
|
|
1433
|
+
try {
|
|
1434
|
+
const projects = await service.listProjects(selectedOrganization.id);
|
|
1435
|
+
set((prev) => ({
|
|
1436
|
+
loading: false,
|
|
1437
|
+
statusLine: "Select a project",
|
|
1438
|
+
onboarding: prev.onboarding ? {
|
|
1439
|
+
...prev.onboarding,
|
|
1440
|
+
step: "project",
|
|
1441
|
+
attachCurrentFolder: prev.onboarding.attachCurrentFolder,
|
|
1442
|
+
projects,
|
|
1443
|
+
availableAgents: prev.onboarding?.availableAgents ?? [],
|
|
1444
|
+
canCreateProject: service.canCreateProject(selectedOrganization),
|
|
1445
|
+
selectedOrganizationId: selectedOrganization.id,
|
|
1446
|
+
interaction: void 0,
|
|
1447
|
+
error: projects.length === 0 ? "No projects found in selected organization." : void 0
|
|
1448
|
+
} : prev.onboarding
|
|
1449
|
+
}));
|
|
1450
|
+
} catch (error) {
|
|
1451
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1452
|
+
set((prev) => ({
|
|
1453
|
+
loading: false,
|
|
1454
|
+
statusLine: "Setup error",
|
|
1455
|
+
onboarding: prev.onboarding ? {
|
|
1456
|
+
...prev.onboarding,
|
|
1457
|
+
error: message
|
|
1458
|
+
} : prev.onboarding
|
|
1459
|
+
}));
|
|
1460
|
+
}
|
|
1461
|
+
}, "selectOnboardingOrganization"),
|
|
1462
|
+
registerOnboardingProject: /* @__PURE__ */ __name(async (index) => {
|
|
1463
|
+
const { onboarding, appendLog, refresh } = get();
|
|
1464
|
+
const service = getService();
|
|
1465
|
+
if (!onboarding || !onboarding.selectedOrganizationId) return;
|
|
1466
|
+
if (index < 0 || index >= onboarding.projects.length) {
|
|
1467
|
+
set((prev) => ({
|
|
1468
|
+
onboarding: prev.onboarding ? {
|
|
1469
|
+
...prev.onboarding,
|
|
1470
|
+
error: `Invalid project index: ${index + 1}`
|
|
1471
|
+
} : prev.onboarding
|
|
1472
|
+
}));
|
|
1473
|
+
return;
|
|
1474
|
+
}
|
|
1475
|
+
const selectedProject = onboarding.projects[index];
|
|
1476
|
+
if (onboarding.mode === "switch-context" || !onboarding.attachCurrentFolder) {
|
|
1477
|
+
set((prev) => ({
|
|
1478
|
+
loading: true,
|
|
1479
|
+
statusLine: "Switching context...",
|
|
1480
|
+
onboarding: prev.onboarding ? {
|
|
1481
|
+
...prev.onboarding,
|
|
1482
|
+
error: void 0
|
|
1483
|
+
} : prev.onboarding
|
|
1484
|
+
}));
|
|
1485
|
+
try {
|
|
1486
|
+
service.persistContext(onboarding.selectedOrganizationId, selectedProject.id);
|
|
1487
|
+
appendLog(`[context] switched to ${selectedProject.name}`);
|
|
1488
|
+
await refresh();
|
|
1489
|
+
} catch (error) {
|
|
1490
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1491
|
+
set((prev) => ({
|
|
1492
|
+
loading: false,
|
|
1493
|
+
statusLine: "Context switch failed",
|
|
1494
|
+
onboarding: prev.onboarding ? {
|
|
1495
|
+
...prev.onboarding,
|
|
1496
|
+
step: "project",
|
|
1497
|
+
error: message
|
|
1498
|
+
} : prev.onboarding
|
|
1499
|
+
}));
|
|
1500
|
+
}
|
|
1501
|
+
return;
|
|
1502
|
+
}
|
|
1503
|
+
set((prev) => ({
|
|
1504
|
+
loading: true,
|
|
1505
|
+
statusLine: "Linking repository...",
|
|
1506
|
+
onboarding: prev.onboarding ? {
|
|
1507
|
+
...prev.onboarding,
|
|
1508
|
+
error: void 0
|
|
1509
|
+
} : prev.onboarding
|
|
1510
|
+
}));
|
|
1511
|
+
try {
|
|
1512
|
+
persistProjectContext(process.cwd(), {
|
|
1513
|
+
projectId: selectedProject.id,
|
|
1514
|
+
organizationId: onboarding.selectedOrganizationId
|
|
1515
|
+
});
|
|
1516
|
+
appendLog(`[context] linked to ${selectedProject.name}`);
|
|
1517
|
+
await refresh();
|
|
1518
|
+
} catch (error) {
|
|
1519
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1520
|
+
set((prev) => ({
|
|
1521
|
+
loading: false,
|
|
1522
|
+
statusLine: "Setup error",
|
|
1523
|
+
onboarding: prev.onboarding ? {
|
|
1524
|
+
...prev.onboarding,
|
|
1525
|
+
step: "project",
|
|
1526
|
+
error: message
|
|
1527
|
+
} : prev.onboarding
|
|
1528
|
+
}));
|
|
1529
|
+
}
|
|
1530
|
+
}, "registerOnboardingProject"),
|
|
1531
|
+
createOnboardingProject: /* @__PURE__ */ __name(async (name) => {
|
|
1532
|
+
const { onboarding, appendLog, refresh } = get();
|
|
1533
|
+
const service = getService();
|
|
1534
|
+
if (!onboarding || !onboarding.selectedOrganizationId) return;
|
|
1535
|
+
const trimmed = name.trim();
|
|
1536
|
+
if (!onboarding.canCreateProject) {
|
|
1537
|
+
set((prev) => ({
|
|
1538
|
+
onboarding: prev.onboarding ? {
|
|
1539
|
+
...prev.onboarding,
|
|
1540
|
+
error: "You are not authorized to create projects in this organization."
|
|
1541
|
+
} : prev.onboarding
|
|
1542
|
+
}));
|
|
1543
|
+
return;
|
|
1544
|
+
}
|
|
1545
|
+
if (trimmed.length < 2) {
|
|
1546
|
+
set((prev) => ({
|
|
1547
|
+
onboarding: prev.onboarding ? {
|
|
1548
|
+
...prev.onboarding,
|
|
1549
|
+
error: "Project name must be at least 2 characters."
|
|
1550
|
+
} : prev.onboarding
|
|
1551
|
+
}));
|
|
1552
|
+
return;
|
|
1553
|
+
}
|
|
1554
|
+
set((prev) => ({
|
|
1555
|
+
loading: true,
|
|
1556
|
+
statusLine: "Creating project...",
|
|
1557
|
+
onboarding: prev.onboarding ? {
|
|
1558
|
+
...prev.onboarding,
|
|
1559
|
+
error: void 0
|
|
1560
|
+
} : prev.onboarding
|
|
1561
|
+
}));
|
|
1562
|
+
try {
|
|
1563
|
+
const created = await service.createProject(onboarding.selectedOrganizationId, trimmed);
|
|
1564
|
+
appendLog(`[setup] Created project "${created.name}"`);
|
|
1565
|
+
if (onboarding.mode === "switch-context" || !onboarding.attachCurrentFolder) {
|
|
1566
|
+
service.persistContext(onboarding.selectedOrganizationId, created.id);
|
|
1567
|
+
appendLog(`[context] switched to ${created.name}`);
|
|
1568
|
+
await refresh();
|
|
1569
|
+
return;
|
|
1570
|
+
}
|
|
1571
|
+
const registerStartedAt = Date.now();
|
|
1572
|
+
set((prev) => ({
|
|
1573
|
+
loading: true,
|
|
1574
|
+
statusLine: "Registering repository...",
|
|
1575
|
+
onboarding: prev.onboarding ? {
|
|
1576
|
+
...prev.onboarding,
|
|
1577
|
+
step: "registering",
|
|
1578
|
+
availableAgents: prev.onboarding?.availableAgents ?? [],
|
|
1579
|
+
selectedProjectId: created.id,
|
|
1580
|
+
runLines: [],
|
|
1581
|
+
runStatus: "running",
|
|
1582
|
+
startedAt: registerStartedAt,
|
|
1583
|
+
interaction: void 0,
|
|
1584
|
+
error: void 0
|
|
1585
|
+
} : prev.onboarding
|
|
1586
|
+
}));
|
|
1587
|
+
useOnboardingWindow.getState().setStartedAt(registerStartedAt);
|
|
1588
|
+
await attachRepositoryFromOnboardingZustand({
|
|
1589
|
+
organizationId: onboarding.selectedOrganizationId,
|
|
1590
|
+
projectId: created.id
|
|
1591
|
+
});
|
|
1592
|
+
await refresh();
|
|
1593
|
+
} catch (error) {
|
|
1594
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1595
|
+
set((prev) => ({
|
|
1596
|
+
loading: false,
|
|
1597
|
+
statusLine: "Setup error",
|
|
1598
|
+
onboarding: prev.onboarding ? {
|
|
1599
|
+
...prev.onboarding,
|
|
1600
|
+
error: message
|
|
1601
|
+
} : prev.onboarding
|
|
1602
|
+
}));
|
|
1603
|
+
}
|
|
1604
|
+
}, "createOnboardingProject"),
|
|
1605
|
+
resolveOnboardingInteraction: /* @__PURE__ */ __name((value) => {
|
|
1606
|
+
const resolver = onboardingInteractionResolver;
|
|
1607
|
+
onboardingInteractionResolver = null;
|
|
1608
|
+
set((prev) => ({
|
|
1609
|
+
onboarding: prev.onboarding ? {
|
|
1610
|
+
...prev.onboarding,
|
|
1611
|
+
interaction: void 0
|
|
1612
|
+
} : prev.onboarding
|
|
1613
|
+
}));
|
|
1614
|
+
if (resolver) resolver(value);
|
|
1615
|
+
}, "resolveOnboardingInteraction"),
|
|
1616
|
+
setOnboardingAttachCurrentFolder: /* @__PURE__ */ __name((attach) => {
|
|
1617
|
+
set((prev) => ({
|
|
1618
|
+
onboarding: prev.onboarding ? prev.onboarding.attachCurrentFolder === attach ? prev.onboarding : {
|
|
1619
|
+
...prev.onboarding,
|
|
1620
|
+
attachCurrentFolder: attach
|
|
1621
|
+
} : prev.onboarding
|
|
1622
|
+
}));
|
|
1623
|
+
}, "setOnboardingAttachCurrentFolder")
|
|
1624
|
+
})));
|
|
1625
|
+
async function attachRepositoryFromOnboardingZustand(input) {
|
|
1626
|
+
const service = getService();
|
|
1627
|
+
const { appendLog } = useSessionStore.getState();
|
|
1628
|
+
const result = await service.attachOrSyncCurrentRepository(input.organizationId, input.projectId, (line) => {
|
|
1629
|
+
appendLog(`[setup] ${line}`);
|
|
1630
|
+
useSessionStore.setState((prev) => ({
|
|
1631
|
+
statusLine: line.slice(0, 100),
|
|
1632
|
+
onboarding: prev.onboarding ? {
|
|
1633
|
+
...prev.onboarding,
|
|
1634
|
+
runLines: [
|
|
1635
|
+
...prev.onboarding.runLines ?? [],
|
|
1636
|
+
line
|
|
1637
|
+
].slice(-400)
|
|
1638
|
+
} : prev.onboarding
|
|
1639
|
+
}));
|
|
1640
|
+
}, void 0, requestOnboardingInteraction, (event) => {
|
|
1641
|
+
const { upsertToolCall, setActiveThought } = useOnboardingWindow.getState();
|
|
1642
|
+
if (event.event === "tool_call" || event.event === "tool_call_update") {
|
|
1643
|
+
upsertToolCall(event);
|
|
1644
|
+
} else if (event.event === "agent_thought") {
|
|
1645
|
+
setActiveThought(event.text);
|
|
1646
|
+
} else if (event.event === "agent_chunk" && event.text) {
|
|
1647
|
+
useSessionStore.setState((prev) => {
|
|
1648
|
+
if (!prev.onboarding) return prev;
|
|
1649
|
+
const lines = [
|
|
1650
|
+
...prev.onboarding.runLines ?? []
|
|
1651
|
+
];
|
|
1652
|
+
const parts = event.text.split("\n");
|
|
1653
|
+
if (lines.length === 0) {
|
|
1654
|
+
lines.push(parts[0]);
|
|
1655
|
+
} else {
|
|
1656
|
+
lines[lines.length - 1] += parts[0];
|
|
1657
|
+
}
|
|
1658
|
+
for (let i = 1; i < parts.length; i++) {
|
|
1659
|
+
lines.push(parts[i]);
|
|
1660
|
+
}
|
|
1661
|
+
return {
|
|
1662
|
+
onboarding: {
|
|
1663
|
+
...prev.onboarding,
|
|
1664
|
+
runLines: lines.slice(-400)
|
|
1665
|
+
}
|
|
1666
|
+
};
|
|
1667
|
+
});
|
|
1668
|
+
}
|
|
1669
|
+
});
|
|
1670
|
+
useSessionStore.setState((prev) => ({
|
|
1671
|
+
onboarding: prev.onboarding ? {
|
|
1672
|
+
...prev.onboarding,
|
|
1673
|
+
runStatus: result.warning ? "error" : "success"
|
|
1674
|
+
} : prev.onboarding
|
|
1675
|
+
}));
|
|
1676
|
+
logOnboardingAttachResult(appendLog, result);
|
|
1677
|
+
}
|
|
1678
|
+
__name(attachRepositoryFromOnboardingZustand, "attachRepositoryFromOnboardingZustand");
|
|
1679
|
+
|
|
1680
|
+
export {
|
|
1681
|
+
setInitialScreen,
|
|
1682
|
+
useTuiUiStore,
|
|
1683
|
+
resolveNavPolicy,
|
|
1684
|
+
useOnboardingWindow,
|
|
1685
|
+
buildOnboardingState,
|
|
1686
|
+
useSessionStore,
|
|
1687
|
+
useProjectDataStore,
|
|
1688
|
+
useExportStore,
|
|
1689
|
+
dispatchRefreshComplete,
|
|
1690
|
+
dispatchClearProjectData,
|
|
1691
|
+
refreshOnAuthenticationError,
|
|
1692
|
+
withSessionFeedback,
|
|
1693
|
+
getBootContext,
|
|
1694
|
+
setSessionStatusLine,
|
|
1695
|
+
appendSessionLog,
|
|
1696
|
+
useBridgeStore
|
|
1697
|
+
};
|