logwork-cli 1.1.1 → 1.3.0
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/README.md +53 -25
- package/RELEASE.md +4 -2
- package/bin/logwork.mjs +2 -2
- package/commands/commits.mjs +128 -13
- package/commands/history.mjs +0 -4
- package/commands/mcp.mjs +266 -0
- package/commands/quick.mjs +38 -23
- package/commands/reminder.mjs +41 -2
- package/commands/setup.mjs +197 -42
- package/commands/tui.mjs +1 -0
- package/docs/advanced.md +18 -7
- package/docs/mcp-setup.md +120 -26
- package/docs/operations-guide.md +50 -2
- package/docs/recipes.md +40 -0
- package/docs/security.md +23 -2
- package/examples/mcp/antigravity.mcp_config.json +2 -2
- package/examples/mcp/codex.config.toml +2 -2
- package/examples/mcp/copilot.mcp.json +2 -2
- package/lib/api-auth-forms.mjs +393 -0
- package/lib/api-auth-http.mjs +184 -0
- package/lib/api-auth-support.mjs +101 -0
- package/lib/api-auth-tokens.mjs +129 -0
- package/lib/api-auth.mjs +39 -813
- package/lib/api.mjs +38 -1422
- package/lib/apply-ledger.mjs +1 -1
- package/lib/batch-workflow.mjs +187 -2
- package/lib/commit-workflow.mjs +345 -23
- package/lib/config.mjs +7 -0
- package/lib/diagnostics.mjs +116 -4
- package/lib/jira-api.mjs +25 -3
- package/lib/jira-workflow.mjs +36 -6
- package/lib/launcher.mjs +303 -0
- package/lib/logwork-config.mjs +64 -13
- package/lib/manual-apply-state.mjs +15 -0
- package/lib/manual-commands.mjs +2 -2
- package/lib/manual-ink-app.mjs +142 -1282
- package/lib/manual-ink-draft-actions.mjs +227 -0
- package/lib/manual-ink-interaction.mjs +318 -0
- package/lib/manual-ink-session.mjs +41 -0
- package/lib/manual-ink-task-editor.mjs +338 -0
- package/lib/manual-ink-ui.mjs +38 -0
- package/lib/manual-ink-wizard.mjs +520 -0
- package/lib/manual-mcp.mjs +78 -20
- package/lib/manual-repl.mjs +171 -22
- package/lib/mcp-install.mjs +930 -0
- package/lib/mcp-server.mjs +51 -20
- package/lib/node-runtime.mjs +155 -0
- package/lib/paths.mjs +7 -0
- package/lib/project-mapping-workflow.mjs +32 -27
- package/lib/query-workflow.mjs +19 -1
- package/lib/reconciliation-workflow.mjs +1 -1
- package/lib/reminder-config.mjs +38 -2
- package/lib/reminder-scheduler.mjs +85 -18
- package/lib/reminder-service.mjs +42 -3
- package/lib/reminder-workflow.mjs +118 -22
- package/lib/repo-project-suggestions.mjs +285 -0
- package/lib/ro-api-diagnostics.mjs +109 -0
- package/lib/ro-api-entries.mjs +359 -0
- package/lib/ro-api-fields.mjs +290 -0
- package/lib/ro-api-http.mjs +68 -0
- package/lib/ro-api-projects.mjs +137 -0
- package/lib/ro-api-tasks.mjs +50 -0
- package/lib/ro-api-timesheet.mjs +413 -0
- package/lib/ro-delete-workflow.mjs +2 -1
- package/lib/ro-entry-reader.mjs +11 -6
- package/lib/ro-resubmit-workflow.mjs +2 -1
- package/lib/terminal-auth-prompts.mjs +7 -4
- package/lib/ui.mjs +121 -56
- package/package.json +11 -4
- package/skills/logwork/SKILL.md +10 -4
package/lib/manual-ink-app.mjs
CHANGED
|
@@ -6,65 +6,31 @@ import React, {
|
|
|
6
6
|
} from 'react';
|
|
7
7
|
import { Box, render, useApp } from 'ink';
|
|
8
8
|
import { isAuthRequiredError } from './auth-errors.mjs';
|
|
9
|
+
import { isDryRun } from './config.mjs';
|
|
9
10
|
import { isJiraAuthRequiredError } from './jira-auth.mjs';
|
|
10
|
-
import {
|
|
11
|
-
buildLogworkText,
|
|
12
|
-
buildCurrentWeekDateOptions,
|
|
13
|
-
buildProjectOverrides,
|
|
14
|
-
buildProjectOptions,
|
|
15
|
-
buildWeekDateOptions,
|
|
16
|
-
canApplyPreview,
|
|
17
|
-
formatDraftPreview,
|
|
18
|
-
parseTaskLine,
|
|
19
|
-
removeDraftTasks,
|
|
20
|
-
replaceDraftTask,
|
|
21
|
-
toggleTaskSelection
|
|
22
|
-
} from './manual-logwork-wizard.mjs';
|
|
23
11
|
import {
|
|
24
12
|
getCommandSuggestions,
|
|
25
13
|
TASK_COMMANDS
|
|
26
14
|
} from './manual-commands.mjs';
|
|
15
|
+
import { jiraLoginInstruction } from './manual-targets.mjs';
|
|
27
16
|
import {
|
|
28
|
-
AUTH_TARGETS,
|
|
29
|
-
BOTH_TARGET,
|
|
30
|
-
jiraLoginInstruction,
|
|
31
|
-
JIRA_TARGET,
|
|
32
|
-
LOGWORK_TARGETS,
|
|
33
|
-
previewTargets,
|
|
34
|
-
RO_TARGET,
|
|
35
|
-
targetLabel
|
|
36
|
-
} from './manual-targets.mjs';
|
|
37
|
-
import {
|
|
38
|
-
deleteManualDraft,
|
|
39
|
-
formatManualDraftLabel,
|
|
40
|
-
loadManualDrafts,
|
|
41
|
-
saveManualDraft
|
|
42
|
-
} from './manual-drafts.mjs';
|
|
43
|
-
import { enrichRoPreviewWithJiraProjects } from './project-mapping-workflow.mjs';
|
|
44
|
-
import {
|
|
45
|
-
CommandInput,
|
|
46
|
-
ConfirmDialog,
|
|
47
17
|
completeCommandValue,
|
|
48
18
|
CurrentPanel,
|
|
49
|
-
DatePicker,
|
|
50
|
-
DraftPicker,
|
|
51
|
-
formatTaskHours,
|
|
52
19
|
HeaderBar,
|
|
53
20
|
LoadingLine,
|
|
54
21
|
loadingMessageForCommand,
|
|
55
|
-
McpClientPicker,
|
|
56
22
|
panelTitleForCommand,
|
|
57
|
-
|
|
58
|
-
sameProjectIdentity,
|
|
59
|
-
StatusBar,
|
|
60
|
-
TargetPicker,
|
|
61
|
-
TaskEditPicker,
|
|
62
|
-
TaskRemovePicker
|
|
23
|
+
StatusBar
|
|
63
24
|
} from './manual-ink-ui.mjs';
|
|
25
|
+
import { createInkCredentialProvider } from './manual-ink-auth.mjs';
|
|
64
26
|
import {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
} from './manual-ink-
|
|
27
|
+
activeSessionPreview,
|
|
28
|
+
hasSessionPreview
|
|
29
|
+
} from './manual-ink-session.mjs';
|
|
30
|
+
import { useLogworkWizard } from './manual-ink-wizard.mjs';
|
|
31
|
+
import { useDraftActions } from './manual-ink-draft-actions.mjs';
|
|
32
|
+
import { useTaskEditorActions } from './manual-ink-task-editor.mjs';
|
|
33
|
+
import { renderManualInteraction } from './manual-ink-interaction.mjs';
|
|
68
34
|
|
|
69
35
|
export {
|
|
70
36
|
CommandInput,
|
|
@@ -78,6 +44,7 @@ export {
|
|
|
78
44
|
OutputPanel,
|
|
79
45
|
ProjectChart,
|
|
80
46
|
ProjectPicker,
|
|
47
|
+
SelectPrompt,
|
|
81
48
|
SelectionList,
|
|
82
49
|
SlashMenu,
|
|
83
50
|
StatusBar,
|
|
@@ -102,50 +69,6 @@ export {
|
|
|
102
69
|
} from './manual-ink-auth.mjs';
|
|
103
70
|
|
|
104
71
|
const h = React.createElement;
|
|
105
|
-
const RECONCILIATION_PERIOD_OPTIONS = [
|
|
106
|
-
{ key: 'today', label: 'Today', description: 'Compare today' },
|
|
107
|
-
{ key: 'yesterday', label: 'Yesterday', description: 'Compare yesterday' },
|
|
108
|
-
{ key: 'this_week', label: 'This week', description: 'Compare Monday through Sunday' },
|
|
109
|
-
{ key: 'last_week', label: 'Last week', description: 'Compare the previous week' },
|
|
110
|
-
{ key: 'this_month', label: 'This month', description: 'Compare the current month' },
|
|
111
|
-
{ key: 'last_month', label: 'Last month', description: 'Compare the previous month' }
|
|
112
|
-
];
|
|
113
|
-
|
|
114
|
-
function setSessionPreview(session, target, preview) {
|
|
115
|
-
session.activeTarget = target;
|
|
116
|
-
session.previews = {
|
|
117
|
-
...(session.previews || {}),
|
|
118
|
-
[target]: preview
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function clearSessionPreview(session, target) {
|
|
123
|
-
if (session.previews) {
|
|
124
|
-
session.previews[target] = null;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function clearSessionPreviews(session) {
|
|
129
|
-
session.previews = {
|
|
130
|
-
[RO_TARGET]: null,
|
|
131
|
-
[JIRA_TARGET]: null
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function sessionPreview(session, target) {
|
|
136
|
-
return session.previews?.[target] || null;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function hasSessionPreview(session) {
|
|
140
|
-
return Boolean(session.previews?.[RO_TARGET] || session.previews?.[JIRA_TARGET]);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function activeSessionPreview(session) {
|
|
144
|
-
if (session.activeTarget === JIRA_TARGET) {
|
|
145
|
-
return sessionPreview(session, JIRA_TARGET);
|
|
146
|
-
}
|
|
147
|
-
return sessionPreview(session, RO_TARGET);
|
|
148
|
-
}
|
|
149
72
|
|
|
150
73
|
export async function runManualInkApp({
|
|
151
74
|
input,
|
|
@@ -180,6 +103,7 @@ export function ManualApp({
|
|
|
180
103
|
const { exit } = useApp();
|
|
181
104
|
const sessionRef = useRef(controller.createManualSession());
|
|
182
105
|
const confirmResolverRef = useRef(null);
|
|
106
|
+
const selectResolverRef = useRef(null);
|
|
183
107
|
const authResolverRef = useRef(null);
|
|
184
108
|
const authRejecterRef = useRef(null);
|
|
185
109
|
const [inputValue, setInputValue] = useState('');
|
|
@@ -193,6 +117,7 @@ export function ManualApp({
|
|
|
193
117
|
}));
|
|
194
118
|
const [loading, setLoading] = useState('');
|
|
195
119
|
const [pendingConfirm, setPendingConfirm] = useState(null);
|
|
120
|
+
const [pendingSelect, setPendingSelect] = useState(null);
|
|
196
121
|
const [authPrompt, setAuthPrompt] = useState(null);
|
|
197
122
|
const [authActive, setAuthActive] = useState(false);
|
|
198
123
|
const [wizard, setWizard] = useState(null);
|
|
@@ -206,9 +131,35 @@ export function ManualApp({
|
|
|
206
131
|
initialValue
|
|
207
132
|
});
|
|
208
133
|
});
|
|
134
|
+
},
|
|
135
|
+
// { message, options: [{ value, label, hint }], initialValue } -> the
|
|
136
|
+
// chosen value, or null on Escape.
|
|
137
|
+
select({ message, options = [], initialValue }) {
|
|
138
|
+
return new Promise((resolveValue) => {
|
|
139
|
+
selectResolverRef.current = resolveValue;
|
|
140
|
+
const initialIndex = Math.max(0, options.findIndex((option) => option.value === initialValue));
|
|
141
|
+
setPendingSelect({
|
|
142
|
+
message,
|
|
143
|
+
options,
|
|
144
|
+
selectedIndex: initialIndex
|
|
145
|
+
});
|
|
146
|
+
});
|
|
209
147
|
}
|
|
210
148
|
}), []);
|
|
211
149
|
|
|
150
|
+
const changeSelect = useCallback((index) => {
|
|
151
|
+
setPendingSelect((current) => (current ? { ...current, selectedIndex: index } : current));
|
|
152
|
+
}, []);
|
|
153
|
+
|
|
154
|
+
const resolveSelect = useCallback((value) => {
|
|
155
|
+
const resolver = selectResolverRef.current;
|
|
156
|
+
selectResolverRef.current = null;
|
|
157
|
+
setPendingSelect(null);
|
|
158
|
+
if (resolver) {
|
|
159
|
+
resolver(value ?? null);
|
|
160
|
+
}
|
|
161
|
+
}, []);
|
|
162
|
+
|
|
212
163
|
const resolveConfirm = useCallback((value) => {
|
|
213
164
|
const resolver = confirmResolverRef.current;
|
|
214
165
|
confirmResolverRef.current = null;
|
|
@@ -346,958 +297,82 @@ export function ManualApp({
|
|
|
346
297
|
}
|
|
347
298
|
}, [controller, cwd, exit, inkWorkflows, prompts, setCommandPanel]);
|
|
348
299
|
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
});
|
|
360
|
-
try {
|
|
361
|
-
const weekly = target === JIRA_TARGET
|
|
362
|
-
? null
|
|
363
|
-
: await runWithInlineAuth(() => inkWorkflows.queryLogwork({
|
|
364
|
-
period: 'this_week',
|
|
365
|
-
cwd,
|
|
366
|
-
includeEntries: false
|
|
367
|
-
}));
|
|
368
|
-
const dateOptions = weekly ? buildWeekDateOptions(weekly) : buildCurrentWeekDateOptions();
|
|
369
|
-
if (!dateOptions.length) {
|
|
370
|
-
throw new Error('Unable to build week date options.');
|
|
371
|
-
}
|
|
372
|
-
const todayIndex = dateOptions.findIndex((option) => option.isToday);
|
|
373
|
-
setWizard({
|
|
374
|
-
step: 'select_date',
|
|
375
|
-
target,
|
|
376
|
-
weekly,
|
|
377
|
-
dateOptions,
|
|
378
|
-
dateIndex: todayIndex >= 0 ? todayIndex : 0,
|
|
379
|
-
projectsResult: null,
|
|
380
|
-
projectOptions: [],
|
|
381
|
-
projectIndex: 0,
|
|
382
|
-
selectedDate: null,
|
|
383
|
-
selectedProject: null,
|
|
384
|
-
tasks: [],
|
|
385
|
-
preview: null,
|
|
386
|
-
activeDraftId: null
|
|
387
|
-
});
|
|
388
|
-
setActivePanel({
|
|
389
|
-
kind: 'logwork',
|
|
390
|
-
title: 'Select Date',
|
|
391
|
-
text: `Choose a day for this ${targetLabel(target)} logwork session.`
|
|
392
|
-
});
|
|
393
|
-
} catch (error) {
|
|
394
|
-
setActivePanel({
|
|
395
|
-
kind: 'error',
|
|
396
|
-
title: 'Logwork Error',
|
|
397
|
-
text: error.message
|
|
398
|
-
});
|
|
399
|
-
} finally {
|
|
400
|
-
setLoading('');
|
|
401
|
-
}
|
|
402
|
-
}, [cwd, inkWorkflows, runWithInlineAuth, runWithJiraAuthInstruction]);
|
|
403
|
-
|
|
404
|
-
const startLogworkTargetPicker = useCallback(() => {
|
|
405
|
-
setInputValue('');
|
|
406
|
-
setSelectedIndex(0);
|
|
407
|
-
setWizard({
|
|
408
|
-
step: 'select_logwork_target',
|
|
409
|
-
targetIndex: 0
|
|
410
|
-
});
|
|
411
|
-
setActivePanel({
|
|
412
|
-
kind: 'logwork',
|
|
413
|
-
title: 'Select Logwork Target',
|
|
414
|
-
text: 'Choose where this logwork session should write.'
|
|
415
|
-
});
|
|
416
|
-
}, []);
|
|
417
|
-
|
|
418
|
-
const startAuthTargetPicker = useCallback(() => {
|
|
419
|
-
setInputValue('');
|
|
420
|
-
setSelectedIndex(0);
|
|
421
|
-
setWizard({
|
|
422
|
-
step: 'select_auth_target',
|
|
423
|
-
targetIndex: 0
|
|
424
|
-
});
|
|
425
|
-
setActivePanel({
|
|
426
|
-
kind: 'auth',
|
|
427
|
-
title: 'Select Auth Target',
|
|
428
|
-
text: 'Choose which service to authenticate.'
|
|
429
|
-
});
|
|
430
|
-
}, []);
|
|
431
|
-
|
|
432
|
-
const startReconciliationPeriodPicker = useCallback(() => {
|
|
433
|
-
setInputValue('');
|
|
434
|
-
setSelectedIndex(0);
|
|
435
|
-
setWizard({
|
|
436
|
-
step: 'select_reconciliation_period',
|
|
437
|
-
periodIndex: 2
|
|
438
|
-
});
|
|
439
|
-
setActivePanel({
|
|
440
|
-
kind: 'output',
|
|
441
|
-
title: 'RO / Jira Reconciliation',
|
|
442
|
-
text: 'Choose a preset period to compare.'
|
|
443
|
-
});
|
|
444
|
-
}, []);
|
|
445
|
-
|
|
446
|
-
const startLogworkWizard = useCallback(async (target) => {
|
|
447
|
-
if (!target) {
|
|
448
|
-
startLogworkTargetPicker();
|
|
449
|
-
return;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
if (target !== RO_TARGET) {
|
|
453
|
-
await startNewLogworkWizard(target);
|
|
454
|
-
return;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
setInputValue('');
|
|
458
|
-
setSelectedIndex(0);
|
|
459
|
-
setLoading('Loading saved drafts...');
|
|
460
|
-
try {
|
|
461
|
-
const drafts = await loadManualDrafts({ cwd });
|
|
462
|
-
if (drafts.length) {
|
|
463
|
-
setWizard({
|
|
464
|
-
step: 'select_draft',
|
|
465
|
-
target: RO_TARGET,
|
|
466
|
-
drafts,
|
|
467
|
-
draftIndex: 0,
|
|
468
|
-
draftSource: 'start',
|
|
469
|
-
weekly: null,
|
|
470
|
-
dateOptions: [],
|
|
471
|
-
dateIndex: 0,
|
|
472
|
-
projectsResult: null,
|
|
473
|
-
projectOptions: [],
|
|
474
|
-
projectIndex: 0,
|
|
475
|
-
selectedDate: null,
|
|
476
|
-
selectedProject: null,
|
|
477
|
-
tasks: [],
|
|
478
|
-
preview: null,
|
|
479
|
-
activeDraftId: null
|
|
480
|
-
});
|
|
481
|
-
setActivePanel({
|
|
482
|
-
kind: 'logwork',
|
|
483
|
-
title: 'Saved Drafts',
|
|
484
|
-
text: 'Resume a saved draft, delete one, or start a new logwork session.'
|
|
485
|
-
});
|
|
486
|
-
return;
|
|
487
|
-
}
|
|
488
|
-
await startNewLogworkWizard(RO_TARGET);
|
|
489
|
-
} catch (error) {
|
|
490
|
-
setActivePanel({
|
|
491
|
-
kind: 'error',
|
|
492
|
-
title: 'Draft Error',
|
|
493
|
-
text: error.message
|
|
494
|
-
});
|
|
495
|
-
} finally {
|
|
496
|
-
setLoading('');
|
|
497
|
-
}
|
|
498
|
-
}, [cwd, startLogworkTargetPicker, startNewLogworkWizard]);
|
|
499
|
-
|
|
500
|
-
const startMcpClientPicker = useCallback(() => {
|
|
501
|
-
setInputValue('');
|
|
502
|
-
setSelectedIndex(0);
|
|
503
|
-
setWizard({
|
|
504
|
-
step: 'select_mcp_client',
|
|
505
|
-
mcpClientIndex: 0
|
|
506
|
-
});
|
|
507
|
-
setActivePanel({
|
|
508
|
-
kind: 'output',
|
|
509
|
-
title: 'MCP Setup',
|
|
510
|
-
text: 'Choose an MCP client to print copy-ready setup.'
|
|
511
|
-
});
|
|
512
|
-
}, []);
|
|
513
|
-
|
|
514
|
-
const cancelMcpClientPicker = useCallback(() => {
|
|
515
|
-
setWizard(null);
|
|
516
|
-
setActivePanel({
|
|
517
|
-
kind: 'idle',
|
|
518
|
-
title: 'Ready',
|
|
519
|
-
text: 'Type / for commands.'
|
|
520
|
-
});
|
|
521
|
-
}, []);
|
|
522
|
-
|
|
523
|
-
const selectWizardDate = useCallback(async (dateOption) => {
|
|
524
|
-
const target = wizard?.target || RO_TARGET;
|
|
525
|
-
if (target === JIRA_TARGET) {
|
|
526
|
-
const draft = {
|
|
527
|
-
target,
|
|
528
|
-
date: dateOption.date,
|
|
529
|
-
project: null,
|
|
530
|
-
tasks: [],
|
|
531
|
-
preview: null
|
|
532
|
-
};
|
|
533
|
-
sessionRef.current.logworkDraft = draft;
|
|
534
|
-
clearSessionPreviews(sessionRef.current);
|
|
535
|
-
sessionRef.current.activeTarget = target;
|
|
536
|
-
setWizard((current) => ({
|
|
537
|
-
...current,
|
|
538
|
-
step: 'edit_tasks',
|
|
539
|
-
selectedDate: dateOption.date,
|
|
540
|
-
selectedProject: null,
|
|
541
|
-
tasks: [],
|
|
542
|
-
preview: null,
|
|
543
|
-
previews: {}
|
|
544
|
-
}));
|
|
545
|
-
setActivePanel({
|
|
546
|
-
kind: 'logwork',
|
|
547
|
-
title: 'Jira Worklog Draft',
|
|
548
|
-
text: [
|
|
549
|
-
formatDraftPreview(draft),
|
|
550
|
-
'',
|
|
551
|
-
'Enter tasks one per line: +2 Feature Development | check ui/ux (SCB-213)',
|
|
552
|
-
'Empty Enter applies after preview is ready.',
|
|
553
|
-
'Type / for task commands. Esc cancels.'
|
|
554
|
-
].join('\n')
|
|
555
|
-
});
|
|
556
|
-
return;
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
setLoading('Fetching project memberships...');
|
|
560
|
-
setActivePanel({
|
|
561
|
-
kind: 'logwork',
|
|
562
|
-
title: 'Select Project',
|
|
563
|
-
text: `Loading projects for ${dateOption.date}...`
|
|
564
|
-
});
|
|
565
|
-
try {
|
|
566
|
-
const projectsResult = await runWithInlineAuth(() => inkWorkflows.listLogworkProjects({ cwd }));
|
|
567
|
-
const projectOptions = buildProjectOptions({
|
|
568
|
-
projectsResult,
|
|
569
|
-
weekly: wizard.weekly,
|
|
570
|
-
date: dateOption.date
|
|
571
|
-
});
|
|
572
|
-
if (!projectOptions.length) {
|
|
573
|
-
throw new Error('No Resource Optimiser project memberships found.');
|
|
574
|
-
}
|
|
575
|
-
setWizard((current) => ({
|
|
576
|
-
...current,
|
|
577
|
-
step: 'select_project',
|
|
578
|
-
target,
|
|
579
|
-
selectedDate: dateOption.date,
|
|
580
|
-
projectsResult,
|
|
581
|
-
projectOptions,
|
|
582
|
-
projectIndex: 0,
|
|
583
|
-
selectedProject: null,
|
|
584
|
-
tasks: [],
|
|
585
|
-
preview: null
|
|
586
|
-
}));
|
|
587
|
-
setActivePanel({
|
|
588
|
-
kind: 'logwork',
|
|
589
|
-
title: 'Select Project',
|
|
590
|
-
text: `Choose a project for ${dateOption.date}.`
|
|
591
|
-
});
|
|
592
|
-
} catch (error) {
|
|
593
|
-
setActivePanel({
|
|
594
|
-
kind: 'error',
|
|
595
|
-
title: 'Project Error',
|
|
596
|
-
text: error.message
|
|
597
|
-
});
|
|
598
|
-
} finally {
|
|
599
|
-
setLoading('');
|
|
600
|
-
}
|
|
601
|
-
}, [cwd, inkWorkflows, runWithInlineAuth, wizard]);
|
|
602
|
-
|
|
603
|
-
const selectWizardProject = useCallback((project) => {
|
|
604
|
-
const target = wizard?.target || RO_TARGET;
|
|
605
|
-
const draft = {
|
|
606
|
-
target,
|
|
607
|
-
date: wizard.selectedDate,
|
|
608
|
-
project,
|
|
609
|
-
tasks: [],
|
|
610
|
-
preview: null
|
|
611
|
-
};
|
|
612
|
-
sessionRef.current.logworkDraft = draft;
|
|
613
|
-
clearSessionPreviews(sessionRef.current);
|
|
614
|
-
sessionRef.current.activeTarget = target;
|
|
615
|
-
setWizard((current) => ({
|
|
616
|
-
...current,
|
|
617
|
-
step: 'edit_tasks',
|
|
618
|
-
target,
|
|
619
|
-
selectedProject: project,
|
|
620
|
-
tasks: [],
|
|
621
|
-
preview: null,
|
|
622
|
-
previews: {}
|
|
623
|
-
}));
|
|
624
|
-
setActivePanel({
|
|
625
|
-
kind: 'logwork',
|
|
626
|
-
title: target === BOTH_TARGET ? 'RO + Jira Draft' : 'Logwork Draft',
|
|
627
|
-
text: [
|
|
628
|
-
formatDraftPreview(draft),
|
|
629
|
-
'',
|
|
630
|
-
target === BOTH_TARGET ? 'Enter tasks one per line: +2 Feature Development | check ui/ux (SCB-213)' : 'Enter tasks one per line: +2 Feature Development | check ui/ux',
|
|
631
|
-
'Empty Enter applies after preview is ready.',
|
|
632
|
-
'Type / for task commands. Esc cancels.'
|
|
633
|
-
].join('\n')
|
|
634
|
-
});
|
|
635
|
-
}, [wizard]);
|
|
636
|
-
|
|
637
|
-
const previewDraft = useCallback(async (nextWizard) => {
|
|
638
|
-
const target = nextWizard.target || RO_TARGET;
|
|
639
|
-
const draft = {
|
|
640
|
-
target,
|
|
641
|
-
date: nextWizard.selectedDate,
|
|
642
|
-
project: nextWizard.selectedProject,
|
|
643
|
-
tasks: nextWizard.tasks
|
|
644
|
-
};
|
|
645
|
-
|
|
646
|
-
if (!draft.tasks.length) {
|
|
647
|
-
sessionRef.current.logworkDraft = draft;
|
|
648
|
-
clearSessionPreviews(sessionRef.current);
|
|
649
|
-
sessionRef.current.activeTarget = target;
|
|
650
|
-
setWizard(nextWizard);
|
|
651
|
-
setActivePanel({
|
|
652
|
-
kind: 'logwork',
|
|
653
|
-
title: target === JIRA_TARGET ? 'Jira Worklog Draft' : target === BOTH_TARGET ? 'RO + Jira Draft' : 'Logwork Draft',
|
|
654
|
-
text: [
|
|
655
|
-
formatDraftPreview(draft),
|
|
656
|
-
'',
|
|
657
|
-
target === RO_TARGET ? 'Enter tasks one per line: +2 Feature Development | check ui/ux' : 'Enter tasks one per line: +2 Feature Development | check ui/ux (SCB-213)',
|
|
658
|
-
'Empty Enter applies after preview is ready.'
|
|
659
|
-
].join('\n')
|
|
660
|
-
});
|
|
661
|
-
return;
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
setLoading('Building live preview...');
|
|
665
|
-
try {
|
|
666
|
-
const text = buildLogworkText({
|
|
667
|
-
date: draft.date,
|
|
668
|
-
tasks: draft.tasks
|
|
669
|
-
});
|
|
670
|
-
const previews = {};
|
|
671
|
-
if (previewTargets(target).includes(RO_TARGET)) {
|
|
672
|
-
const projectOverrides = buildProjectOverrides({
|
|
673
|
-
date: draft.date,
|
|
674
|
-
tasks: draft.tasks,
|
|
675
|
-
projectMemberId: draft.project.projectMemberId
|
|
676
|
-
});
|
|
677
|
-
previews[RO_TARGET] = await runWithInlineAuth(() => inkWorkflows.previewLogworkBatch({
|
|
678
|
-
text,
|
|
679
|
-
projectOverrides,
|
|
680
|
-
cwd
|
|
681
|
-
}));
|
|
682
|
-
}
|
|
683
|
-
if (previewTargets(target).includes(JIRA_TARGET)) {
|
|
684
|
-
previews[JIRA_TARGET] = await runWithJiraAuthInstruction(() => inkWorkflows.previewJiraWorklogBatch({
|
|
685
|
-
text
|
|
686
|
-
}));
|
|
687
|
-
}
|
|
688
|
-
if (target === BOTH_TARGET && previews[RO_TARGET] && previews[JIRA_TARGET]) {
|
|
689
|
-
previews[RO_TARGET] = enrichRoPreviewWithJiraProjects(previews[RO_TARGET], previews[JIRA_TARGET]);
|
|
690
|
-
}
|
|
691
|
-
const preview = target === JIRA_TARGET ? previews[JIRA_TARGET] : previews[RO_TARGET];
|
|
692
|
-
const withPreview = {
|
|
693
|
-
...draft,
|
|
694
|
-
preview,
|
|
695
|
-
previews
|
|
696
|
-
};
|
|
697
|
-
sessionRef.current.logworkDraft = withPreview;
|
|
698
|
-
sessionRef.current.activeTarget = target;
|
|
699
|
-
for (const previewTarget of previewTargets(target)) {
|
|
700
|
-
setSessionPreview(sessionRef.current, previewTarget, previews[previewTarget] || null);
|
|
701
|
-
}
|
|
702
|
-
setWizard({
|
|
703
|
-
...nextWizard,
|
|
704
|
-
target,
|
|
705
|
-
preview,
|
|
706
|
-
previews
|
|
707
|
-
});
|
|
708
|
-
const hasBlockedJira = previews[JIRA_TARGET]?.entries?.some((entry) => entry.status !== 'ready');
|
|
709
|
-
setActivePanel({
|
|
710
|
-
kind: preview?.unresolvedEntries?.length || preview?.errors?.length || hasBlockedJira ? 'error' : 'logwork',
|
|
711
|
-
title: target === JIRA_TARGET ? 'Jira Worklog Preview' : target === BOTH_TARGET ? 'RO + Jira Preview' : 'Logwork Preview',
|
|
712
|
-
text: [
|
|
713
|
-
formatDraftPreview(withPreview),
|
|
714
|
-
'',
|
|
715
|
-
'Empty Enter applies this preview.',
|
|
716
|
-
'Type another +hours task to add more.',
|
|
717
|
-
'/remove selects tasks to delete.'
|
|
718
|
-
].join('\n')
|
|
719
|
-
});
|
|
720
|
-
return preview;
|
|
721
|
-
} catch (error) {
|
|
722
|
-
setActivePanel({
|
|
723
|
-
kind: 'error',
|
|
724
|
-
title: 'Preview Error',
|
|
725
|
-
text: error.message
|
|
726
|
-
});
|
|
727
|
-
} finally {
|
|
728
|
-
setLoading('');
|
|
729
|
-
}
|
|
730
|
-
}, [cwd, inkWorkflows, runWithInlineAuth, runWithJiraAuthInstruction]);
|
|
731
|
-
|
|
732
|
-
const saveCurrentDraft = useCallback(async () => {
|
|
733
|
-
if (wizard?.target === JIRA_TARGET) {
|
|
734
|
-
setActivePanel({
|
|
735
|
-
kind: 'logwork',
|
|
736
|
-
title: 'Save Draft',
|
|
737
|
-
text: 'Saved drafts are only supported for Resource Optimiser logwork in this version.'
|
|
738
|
-
});
|
|
739
|
-
return null;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
if (!wizard?.selectedDate || !wizard?.selectedProject || !wizard?.tasks?.length) {
|
|
743
|
-
setActivePanel({
|
|
744
|
-
kind: 'logwork',
|
|
745
|
-
title: 'Save Draft',
|
|
746
|
-
text: 'Add at least one task before saving a draft.'
|
|
747
|
-
});
|
|
748
|
-
return null;
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
try {
|
|
752
|
-
const saved = await saveManualDraft({
|
|
753
|
-
id: wizard.activeDraftId,
|
|
754
|
-
cwd,
|
|
755
|
-
date: wizard.selectedDate,
|
|
756
|
-
project: wizard.selectedProject,
|
|
757
|
-
tasks: wizard.tasks,
|
|
758
|
-
latestPreviewStatus: wizard.preview?.status
|
|
759
|
-
}, { cwd });
|
|
760
|
-
setWizard((current) => ({
|
|
761
|
-
...current,
|
|
762
|
-
activeDraftId: saved.id
|
|
763
|
-
}));
|
|
764
|
-
setActivePanel({
|
|
765
|
-
kind: 'success',
|
|
766
|
-
title: 'Draft Saved',
|
|
767
|
-
text: [
|
|
768
|
-
`Saved ${saved.tasks.length} task${saved.tasks.length === 1 ? '' : 's'} locally.`,
|
|
769
|
-
formatManualDraftLabel(saved),
|
|
770
|
-
'',
|
|
771
|
-
'Continue editing, press empty Enter to apply, or type /drafts.'
|
|
772
|
-
].join('\n')
|
|
773
|
-
});
|
|
774
|
-
return saved;
|
|
775
|
-
} catch (error) {
|
|
776
|
-
setActivePanel({
|
|
777
|
-
kind: 'error',
|
|
778
|
-
title: 'Save Draft Error',
|
|
779
|
-
text: error.message
|
|
780
|
-
});
|
|
781
|
-
return null;
|
|
782
|
-
}
|
|
783
|
-
}, [cwd, wizard]);
|
|
784
|
-
|
|
785
|
-
const openDraftPicker = useCallback(async (source = 'editor') => {
|
|
786
|
-
setLoading('Loading saved drafts...');
|
|
787
|
-
try {
|
|
788
|
-
const drafts = await loadManualDrafts({ cwd });
|
|
789
|
-
if (!drafts.length) {
|
|
790
|
-
setActivePanel({
|
|
791
|
-
kind: 'logwork',
|
|
792
|
-
title: 'Saved Drafts',
|
|
793
|
-
text: 'No saved drafts found.'
|
|
794
|
-
});
|
|
795
|
-
return;
|
|
796
|
-
}
|
|
797
|
-
setWizard((current) => ({
|
|
798
|
-
...current,
|
|
799
|
-
step: 'select_draft',
|
|
800
|
-
drafts,
|
|
801
|
-
draftIndex: 0,
|
|
802
|
-
draftSource: source
|
|
803
|
-
}));
|
|
804
|
-
setActivePanel({
|
|
805
|
-
kind: 'logwork',
|
|
806
|
-
title: 'Saved Drafts',
|
|
807
|
-
text: 'Enter resumes · d deletes · Esc returns.'
|
|
808
|
-
});
|
|
809
|
-
} catch (error) {
|
|
810
|
-
setActivePanel({
|
|
811
|
-
kind: 'error',
|
|
812
|
-
title: 'Draft Error',
|
|
813
|
-
text: error.message
|
|
814
|
-
});
|
|
815
|
-
} finally {
|
|
816
|
-
setLoading('');
|
|
817
|
-
}
|
|
818
|
-
}, [cwd]);
|
|
819
|
-
|
|
820
|
-
const resumeManualDraft = useCallback(async (draft) => {
|
|
821
|
-
setLoading('Resuming saved draft...');
|
|
822
|
-
try {
|
|
823
|
-
const weekly = await runWithInlineAuth(() => inkWorkflows.queryLogwork({
|
|
824
|
-
period: 'this_week',
|
|
825
|
-
cwd,
|
|
826
|
-
includeEntries: false
|
|
827
|
-
}));
|
|
828
|
-
const dateOptions = buildWeekDateOptions(weekly);
|
|
829
|
-
const projectsResult = await runWithInlineAuth(() => inkWorkflows.listLogworkProjects({ cwd }));
|
|
830
|
-
const projectOptions = buildProjectOptions({
|
|
831
|
-
projectsResult,
|
|
832
|
-
weekly,
|
|
833
|
-
date: draft.date
|
|
834
|
-
});
|
|
835
|
-
const selectedProject = projectOptions.find((project) => sameProjectIdentity(project, draft.project)) || draft.project;
|
|
836
|
-
const nextWizard = {
|
|
837
|
-
step: 'edit_tasks',
|
|
838
|
-
target: RO_TARGET,
|
|
839
|
-
weekly,
|
|
840
|
-
dateOptions,
|
|
841
|
-
dateIndex: Math.max(0, dateOptions.findIndex((option) => option.date === draft.date)),
|
|
842
|
-
projectsResult,
|
|
843
|
-
projectOptions,
|
|
844
|
-
projectIndex: Math.max(0, projectOptions.findIndex((project) => sameProjectIdentity(project, selectedProject))),
|
|
845
|
-
selectedDate: draft.date,
|
|
846
|
-
selectedProject,
|
|
847
|
-
tasks: draft.tasks,
|
|
848
|
-
preview: null,
|
|
849
|
-
activeDraftId: draft.id
|
|
850
|
-
};
|
|
851
|
-
sessionRef.current.logworkDraft = {
|
|
852
|
-
target: RO_TARGET,
|
|
853
|
-
date: draft.date,
|
|
854
|
-
project: selectedProject,
|
|
855
|
-
tasks: draft.tasks,
|
|
856
|
-
preview: null
|
|
857
|
-
};
|
|
858
|
-
clearSessionPreviews(sessionRef.current);
|
|
859
|
-
sessionRef.current.activeTarget = RO_TARGET;
|
|
860
|
-
await previewDraft(nextWizard);
|
|
861
|
-
} catch (error) {
|
|
862
|
-
setActivePanel({
|
|
863
|
-
kind: 'error',
|
|
864
|
-
title: 'Resume Draft Error',
|
|
865
|
-
text: error.message
|
|
866
|
-
});
|
|
867
|
-
} finally {
|
|
868
|
-
setLoading('');
|
|
869
|
-
}
|
|
870
|
-
}, [cwd, inkWorkflows, previewDraft, runWithInlineAuth]);
|
|
871
|
-
|
|
872
|
-
const deleteSavedDraft = useCallback(async (draft) => {
|
|
873
|
-
const ok = await prompts.confirm(`Delete saved draft "${formatManualDraftLabel(draft)}"?`, false);
|
|
874
|
-
if (!ok) {
|
|
875
|
-
return;
|
|
876
|
-
}
|
|
877
|
-
await deleteManualDraft(draft.id);
|
|
878
|
-
const drafts = await loadManualDrafts({ cwd });
|
|
879
|
-
setWizard((current) => ({
|
|
880
|
-
...current,
|
|
881
|
-
drafts,
|
|
882
|
-
draftIndex: 0
|
|
883
|
-
}));
|
|
884
|
-
setActivePanel({
|
|
885
|
-
kind: 'success',
|
|
886
|
-
title: 'Draft Deleted',
|
|
887
|
-
text: drafts.length ? 'Draft deleted. Choose another saved draft or start new.' : 'Draft deleted. No saved drafts remain.'
|
|
888
|
-
});
|
|
889
|
-
}, [cwd, prompts]);
|
|
890
|
-
|
|
891
|
-
const returnFromDraftPicker = useCallback(() => {
|
|
892
|
-
if (wizard?.draftSource === 'start') {
|
|
893
|
-
startNewLogworkWizard(RO_TARGET);
|
|
894
|
-
return;
|
|
895
|
-
}
|
|
896
|
-
setWizard((current) => ({
|
|
897
|
-
...current,
|
|
898
|
-
step: 'edit_tasks',
|
|
899
|
-
draftSource: undefined
|
|
900
|
-
}));
|
|
901
|
-
const draft = {
|
|
902
|
-
target: wizard?.target || RO_TARGET,
|
|
903
|
-
date: wizard?.selectedDate,
|
|
904
|
-
project: wizard?.selectedProject,
|
|
905
|
-
tasks: wizard?.tasks || [],
|
|
906
|
-
preview: wizard?.preview
|
|
907
|
-
};
|
|
908
|
-
setActivePanel({
|
|
909
|
-
kind: 'logwork',
|
|
910
|
-
title: wizard?.preview ? 'Logwork Preview' : 'Logwork Draft',
|
|
911
|
-
text: [
|
|
912
|
-
formatDraftPreview(draft),
|
|
913
|
-
'',
|
|
914
|
-
'Type / for task commands. Empty Enter applies when ready.'
|
|
915
|
-
].join('\n')
|
|
916
|
-
});
|
|
917
|
-
}, [startNewLogworkWizard, wizard]);
|
|
918
|
-
|
|
919
|
-
const cancelCurrentLogwork = useCallback(async () => {
|
|
920
|
-
if (wizard?.tasks?.length) {
|
|
921
|
-
const ok = await prompts.confirm('Discard this unsaved logwork session?', false);
|
|
922
|
-
if (!ok) {
|
|
923
|
-
return;
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
sessionRef.current.logworkDraft = null;
|
|
927
|
-
clearSessionPreviews(sessionRef.current);
|
|
928
|
-
setWizard(null);
|
|
929
|
-
setActivePanel({
|
|
930
|
-
kind: 'idle',
|
|
931
|
-
title: 'Ready',
|
|
932
|
-
text: 'Logwork session discarded. Type / for commands.'
|
|
933
|
-
});
|
|
934
|
-
}, [prompts, wizard]);
|
|
935
|
-
|
|
936
|
-
const applyWizardPreview = useCallback(async () => {
|
|
937
|
-
const target = wizard.target || RO_TARGET;
|
|
938
|
-
if (!wizard.tasks.length) {
|
|
939
|
-
setActivePanel({
|
|
940
|
-
kind: 'logwork',
|
|
941
|
-
title: 'Logwork Draft',
|
|
942
|
-
text: target === RO_TARGET ? 'Enter a task like +2 Feature Development | check ui/ux.' : 'Enter a task like +2 Feature Development | check ui/ux (SCB-213).'
|
|
943
|
-
});
|
|
944
|
-
return;
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
const targets = previewTargets(target);
|
|
948
|
-
const missingPreview = targets.some((previewTarget) => !sessionPreview(sessionRef.current, previewTarget));
|
|
949
|
-
if (missingPreview) {
|
|
950
|
-
await previewDraft(wizard);
|
|
951
|
-
return;
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
for (const previewTarget of targets) {
|
|
955
|
-
const applyState = canApplyPreview(sessionPreview(sessionRef.current, previewTarget), { target: previewTarget });
|
|
956
|
-
if (!applyState.ok) {
|
|
957
|
-
setActivePanel({
|
|
958
|
-
kind: 'error',
|
|
959
|
-
title: 'Apply Blocked',
|
|
960
|
-
text: `${targetLabel(previewTarget)}: ${applyState.reason}`
|
|
961
|
-
});
|
|
962
|
-
return;
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
await executeCommand({ type: 'apply', target });
|
|
967
|
-
if (!hasSessionPreview(sessionRef.current)) {
|
|
968
|
-
setWizard(null);
|
|
969
|
-
}
|
|
970
|
-
}, [executeCommand, previewDraft, wizard]);
|
|
971
|
-
|
|
972
|
-
const restoreTaskEditorPanel = useCallback((nextWizard = wizard) => {
|
|
973
|
-
const target = nextWizard.target || RO_TARGET;
|
|
974
|
-
const draft = {
|
|
975
|
-
target,
|
|
976
|
-
date: nextWizard.selectedDate,
|
|
977
|
-
project: nextWizard.selectedProject,
|
|
978
|
-
tasks: nextWizard.tasks,
|
|
979
|
-
preview: nextWizard.preview,
|
|
980
|
-
previews: nextWizard.previews
|
|
981
|
-
};
|
|
982
|
-
setActivePanel({
|
|
983
|
-
kind: 'logwork',
|
|
984
|
-
title: nextWizard.preview ? `${targetLabel(target)} Preview` : `${targetLabel(target)} Draft`,
|
|
985
|
-
text: [
|
|
986
|
-
formatDraftPreview(draft),
|
|
987
|
-
'',
|
|
988
|
-
nextWizard.preview ? 'Empty Enter applies this preview.' : target === RO_TARGET ? 'Enter tasks one per line: +2 Feature Development | check ui/ux' : 'Enter tasks one per line: +2 Feature Development | check ui/ux (SCB-213)',
|
|
989
|
-
nextWizard.preview ? 'Type another +hours task to add more.' : 'Empty Enter applies after preview is ready.',
|
|
990
|
-
'Type / for task commands. Esc cancels.'
|
|
991
|
-
].join('\n')
|
|
992
|
-
});
|
|
993
|
-
}, [wizard]);
|
|
994
|
-
|
|
995
|
-
const cancelRemoveTasks = useCallback(() => {
|
|
996
|
-
setWizard((current) => ({
|
|
997
|
-
...current,
|
|
998
|
-
step: 'edit_tasks',
|
|
999
|
-
removeIndex: 0,
|
|
1000
|
-
removeSelectedIndexes: []
|
|
1001
|
-
}));
|
|
1002
|
-
restoreTaskEditorPanel();
|
|
1003
|
-
}, [restoreTaskEditorPanel]);
|
|
1004
|
-
|
|
1005
|
-
const confirmRemoveTasks = useCallback(async (selectedIndexes) => {
|
|
1006
|
-
if (!selectedIndexes.length) {
|
|
1007
|
-
setActivePanel({
|
|
1008
|
-
kind: 'logwork',
|
|
1009
|
-
title: 'Remove Tasks',
|
|
1010
|
-
text: 'No tasks selected. Use Space to select tasks, Enter to remove, Esc to cancel.'
|
|
1011
|
-
});
|
|
1012
|
-
return;
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
const ok = await prompts.confirm(`Remove ${selectedIndexes.length} selected task${selectedIndexes.length === 1 ? '' : 's'}?`);
|
|
1016
|
-
if (!ok) {
|
|
1017
|
-
cancelRemoveTasks();
|
|
1018
|
-
return;
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
await previewDraft({
|
|
1022
|
-
...wizard,
|
|
1023
|
-
step: 'edit_tasks',
|
|
1024
|
-
tasks: removeDraftTasks(wizard.tasks, selectedIndexes),
|
|
1025
|
-
preview: null,
|
|
1026
|
-
removeIndex: 0,
|
|
1027
|
-
removeSelectedIndexes: []
|
|
1028
|
-
});
|
|
1029
|
-
}, [cancelRemoveTasks, previewDraft, prompts, wizard]);
|
|
1030
|
-
|
|
1031
|
-
const submitWizardTaskInput = useCallback(async (value) => {
|
|
1032
|
-
const text = String(value || '').trim();
|
|
1033
|
-
setInputValue('');
|
|
1034
|
-
|
|
1035
|
-
if (!text) {
|
|
1036
|
-
await applyWizardPreview();
|
|
1037
|
-
return;
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
if (text === '/diagnostics') {
|
|
1041
|
-
await executeCommand({ type: 'diagnostics' });
|
|
1042
|
-
return;
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
if (text === '/cancel' || text === '/discard') {
|
|
1046
|
-
await cancelCurrentLogwork();
|
|
1047
|
-
return;
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
if (text === '/back') {
|
|
1051
|
-
sessionRef.current.logworkDraft = null;
|
|
1052
|
-
clearSessionPreviews(sessionRef.current);
|
|
1053
|
-
if (wizard.target === JIRA_TARGET) {
|
|
1054
|
-
setWizard((current) => ({
|
|
1055
|
-
...current,
|
|
1056
|
-
step: 'select_date',
|
|
1057
|
-
selectedDate: null,
|
|
1058
|
-
tasks: [],
|
|
1059
|
-
preview: null,
|
|
1060
|
-
previews: {}
|
|
1061
|
-
}));
|
|
1062
|
-
setActivePanel({
|
|
1063
|
-
kind: 'logwork',
|
|
1064
|
-
title: 'Select Date',
|
|
1065
|
-
text: 'Choose a day for this Jira worklog session.'
|
|
1066
|
-
});
|
|
1067
|
-
} else {
|
|
1068
|
-
setWizard((current) => ({
|
|
1069
|
-
...current,
|
|
1070
|
-
step: 'select_project',
|
|
1071
|
-
selectedProject: null,
|
|
1072
|
-
tasks: [],
|
|
1073
|
-
preview: null,
|
|
1074
|
-
previews: {}
|
|
1075
|
-
}));
|
|
1076
|
-
setActivePanel({
|
|
1077
|
-
kind: 'logwork',
|
|
1078
|
-
title: 'Select Project',
|
|
1079
|
-
text: `Choose a project for ${wizard.selectedDate}.`
|
|
1080
|
-
});
|
|
1081
|
-
}
|
|
1082
|
-
return;
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
|
-
if (text === '/clear') {
|
|
1086
|
-
const ok = !wizard.tasks.length || await prompts.confirm('Clear all current tasks?', false);
|
|
1087
|
-
if (!ok) {
|
|
1088
|
-
restoreTaskEditorPanel();
|
|
1089
|
-
return;
|
|
1090
|
-
}
|
|
1091
|
-
await previewDraft({
|
|
1092
|
-
...wizard,
|
|
1093
|
-
tasks: [],
|
|
1094
|
-
preview: null
|
|
1095
|
-
});
|
|
1096
|
-
return;
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
|
-
if (text === '/save') {
|
|
1100
|
-
await saveCurrentDraft();
|
|
1101
|
-
return;
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
|
-
if (text === '/drafts') {
|
|
1105
|
-
await openDraftPicker('editor');
|
|
1106
|
-
return;
|
|
1107
|
-
}
|
|
1108
|
-
|
|
1109
|
-
if (text === '/edit') {
|
|
1110
|
-
if (!wizard.tasks.length) {
|
|
1111
|
-
setActivePanel({
|
|
1112
|
-
kind: 'error',
|
|
1113
|
-
title: 'Edit Task',
|
|
1114
|
-
text: 'No tasks to edit.'
|
|
1115
|
-
});
|
|
1116
|
-
return;
|
|
1117
|
-
}
|
|
1118
|
-
setWizard((current) => ({
|
|
1119
|
-
...current,
|
|
1120
|
-
step: 'edit_task_select',
|
|
1121
|
-
editIndex: 0,
|
|
1122
|
-
replacementError: ''
|
|
1123
|
-
}));
|
|
1124
|
-
setActivePanel({
|
|
1125
|
-
kind: 'logwork',
|
|
1126
|
-
title: 'Edit Task',
|
|
1127
|
-
text: 'Select a task to replace. Esc returns to the editor.'
|
|
1128
|
-
});
|
|
1129
|
-
return;
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
if (text === '/remove') {
|
|
1133
|
-
if (!wizard.tasks.length) {
|
|
1134
|
-
setActivePanel({
|
|
1135
|
-
kind: 'error',
|
|
1136
|
-
title: 'Remove Task',
|
|
1137
|
-
text: 'No tasks to remove.'
|
|
1138
|
-
});
|
|
1139
|
-
return;
|
|
1140
|
-
}
|
|
1141
|
-
setWizard((current) => ({
|
|
1142
|
-
...current,
|
|
1143
|
-
step: 'remove_tasks',
|
|
1144
|
-
removeIndex: 0,
|
|
1145
|
-
removeSelectedIndexes: []
|
|
1146
|
-
}));
|
|
1147
|
-
setActivePanel({
|
|
1148
|
-
kind: 'logwork',
|
|
1149
|
-
title: 'Remove Tasks',
|
|
1150
|
-
text: 'Select tasks to remove. Space toggles, Enter confirms, Esc cancels.'
|
|
1151
|
-
});
|
|
1152
|
-
return;
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
if (text.startsWith('/remove ')) {
|
|
1156
|
-
const index = Number(text.slice('/remove '.length).trim());
|
|
1157
|
-
if (!Number.isInteger(index)) {
|
|
1158
|
-
setActivePanel({
|
|
1159
|
-
kind: 'error',
|
|
1160
|
-
title: 'Remove Task',
|
|
1161
|
-
text: 'Usage: /remove <task number>'
|
|
1162
|
-
});
|
|
1163
|
-
return;
|
|
1164
|
-
}
|
|
1165
|
-
if (index < 1 || index > wizard.tasks.length) {
|
|
1166
|
-
setActivePanel({
|
|
1167
|
-
kind: 'error',
|
|
1168
|
-
title: 'Remove Task',
|
|
1169
|
-
text: `No task found at index ${index}.`
|
|
1170
|
-
});
|
|
1171
|
-
return;
|
|
1172
|
-
}
|
|
1173
|
-
await previewDraft({
|
|
1174
|
-
...wizard,
|
|
1175
|
-
tasks: wizard.tasks.filter((_, currentIndex) => currentIndex !== index - 1),
|
|
1176
|
-
preview: null
|
|
1177
|
-
});
|
|
1178
|
-
return;
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
if (text === '/done') {
|
|
1182
|
-
if (!wizard.tasks.length) {
|
|
1183
|
-
setActivePanel({
|
|
1184
|
-
kind: 'error',
|
|
1185
|
-
title: 'Logwork Draft',
|
|
1186
|
-
text: 'Add at least one task before /done.'
|
|
1187
|
-
});
|
|
1188
|
-
return;
|
|
1189
|
-
}
|
|
1190
|
-
await previewDraft(wizard);
|
|
1191
|
-
return;
|
|
1192
|
-
}
|
|
1193
|
-
|
|
1194
|
-
if (text === '/apply') {
|
|
1195
|
-
await applyWizardPreview();
|
|
1196
|
-
return;
|
|
1197
|
-
}
|
|
1198
|
-
|
|
1199
|
-
if (text.startsWith('/')) {
|
|
1200
|
-
setActivePanel({
|
|
1201
|
-
kind: 'error',
|
|
1202
|
-
title: 'Logwork Draft',
|
|
1203
|
-
text: `Unknown logwork command: ${text}`
|
|
1204
|
-
});
|
|
1205
|
-
return;
|
|
1206
|
-
}
|
|
1207
|
-
|
|
1208
|
-
try {
|
|
1209
|
-
const task = parseTaskLine(text);
|
|
1210
|
-
await previewDraft({
|
|
1211
|
-
...wizard,
|
|
1212
|
-
tasks: [...wizard.tasks, task],
|
|
1213
|
-
preview: null
|
|
1214
|
-
});
|
|
1215
|
-
} catch (error) {
|
|
1216
|
-
setActivePanel({
|
|
1217
|
-
kind: 'error',
|
|
1218
|
-
title: 'Task Error',
|
|
1219
|
-
text: error.message
|
|
1220
|
-
});
|
|
1221
|
-
}
|
|
1222
|
-
}, [
|
|
1223
|
-
applyWizardPreview,
|
|
300
|
+
const {
|
|
301
|
+
startNewLogworkWizard,
|
|
302
|
+
startAuthTargetPicker,
|
|
303
|
+
startReconciliationPeriodPicker,
|
|
304
|
+
startLogworkWizard,
|
|
305
|
+
startMcpClientPicker,
|
|
306
|
+
cancelMcpClientPicker,
|
|
307
|
+
selectWizardDate,
|
|
308
|
+
selectWizardProject,
|
|
309
|
+
previewDraft,
|
|
1224
310
|
cancelCurrentLogwork,
|
|
1225
|
-
|
|
311
|
+
applyWizardPreview,
|
|
312
|
+
restoreTaskEditorPanel
|
|
313
|
+
} = useLogworkWizard({
|
|
314
|
+
cwd,
|
|
315
|
+
sessionRef,
|
|
316
|
+
wizard,
|
|
317
|
+
setWizard,
|
|
318
|
+
setActivePanel,
|
|
319
|
+
setLoading,
|
|
320
|
+
setInputValue,
|
|
321
|
+
setSelectedIndex,
|
|
322
|
+
inkWorkflows,
|
|
323
|
+
prompts,
|
|
324
|
+
runWithInlineAuth,
|
|
325
|
+
runWithJiraAuthInstruction,
|
|
326
|
+
executeCommand
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
const {
|
|
330
|
+
saveCurrentDraft,
|
|
1226
331
|
openDraftPicker,
|
|
332
|
+
resumeManualDraft,
|
|
333
|
+
deleteSavedDraft,
|
|
334
|
+
returnFromDraftPicker
|
|
335
|
+
} = useDraftActions({
|
|
336
|
+
cwd,
|
|
337
|
+
sessionRef,
|
|
338
|
+
wizard,
|
|
339
|
+
setWizard,
|
|
340
|
+
setActivePanel,
|
|
341
|
+
setLoading,
|
|
342
|
+
inkWorkflows,
|
|
343
|
+
prompts,
|
|
344
|
+
runWithInlineAuth,
|
|
1227
345
|
previewDraft,
|
|
346
|
+
startNewLogworkWizard
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
const {
|
|
350
|
+
cancelRemoveTasks,
|
|
351
|
+
confirmRemoveTasks,
|
|
352
|
+
submitWizardTaskInput,
|
|
353
|
+
selectTaskForEdit,
|
|
354
|
+
submitTaskReplacement
|
|
355
|
+
} = useTaskEditorActions({
|
|
356
|
+
sessionRef,
|
|
357
|
+
wizard,
|
|
358
|
+
setWizard,
|
|
359
|
+
setActivePanel,
|
|
360
|
+
setInputValue,
|
|
1228
361
|
prompts,
|
|
362
|
+
executeCommand,
|
|
363
|
+
previewDraft,
|
|
364
|
+
applyWizardPreview,
|
|
365
|
+
cancelCurrentLogwork,
|
|
1229
366
|
restoreTaskEditorPanel,
|
|
1230
367
|
saveCurrentDraft,
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
const selectTaskForEdit = useCallback((index) => {
|
|
1235
|
-
const task = wizard.tasks[index];
|
|
1236
|
-
setInputValue('');
|
|
1237
|
-
setWizard((current) => ({
|
|
1238
|
-
...current,
|
|
1239
|
-
step: 'edit_task_replace',
|
|
1240
|
-
editIndex: index,
|
|
1241
|
-
replacementError: ''
|
|
1242
|
-
}));
|
|
1243
|
-
setActivePanel({
|
|
1244
|
-
kind: 'logwork',
|
|
1245
|
-
title: 'Replace Task',
|
|
1246
|
-
text: [
|
|
1247
|
-
`Replacing ${index + 1}. +${formatTaskHours(task.hours)} ${task.taskName}`,
|
|
1248
|
-
'Enter replacement line using format: +2 Feature Development | check ui/ux',
|
|
1249
|
-
'Esc returns without changing the task.'
|
|
1250
|
-
].join('\n')
|
|
1251
|
-
});
|
|
1252
|
-
}, [wizard]);
|
|
1253
|
-
|
|
1254
|
-
const submitTaskReplacement = useCallback(async (value) => {
|
|
1255
|
-
const text = String(value || '').trim();
|
|
1256
|
-
setInputValue('');
|
|
1257
|
-
if (!text) {
|
|
1258
|
-
setActivePanel({
|
|
1259
|
-
kind: 'error',
|
|
1260
|
-
title: 'Replace Task',
|
|
1261
|
-
text: 'Replacement task is empty. Use format: +2 Feature Development | check ui/ux'
|
|
1262
|
-
});
|
|
1263
|
-
return;
|
|
1264
|
-
}
|
|
1265
|
-
if (text === '/cancel') {
|
|
1266
|
-
setWizard((current) => ({
|
|
1267
|
-
...current,
|
|
1268
|
-
step: 'edit_tasks',
|
|
1269
|
-
replacementError: ''
|
|
1270
|
-
}));
|
|
1271
|
-
restoreTaskEditorPanel();
|
|
1272
|
-
return;
|
|
1273
|
-
}
|
|
1274
|
-
try {
|
|
1275
|
-
const task = parseTaskLine(text);
|
|
1276
|
-
await previewDraft({
|
|
1277
|
-
...wizard,
|
|
1278
|
-
step: 'edit_tasks',
|
|
1279
|
-
tasks: replaceDraftTask(wizard.tasks, wizard.editIndex, task),
|
|
1280
|
-
preview: null,
|
|
1281
|
-
replacementError: ''
|
|
1282
|
-
});
|
|
1283
|
-
} catch (error) {
|
|
1284
|
-
setWizard((current) => ({
|
|
1285
|
-
...current,
|
|
1286
|
-
replacementError: error.message
|
|
1287
|
-
}));
|
|
1288
|
-
setActivePanel({
|
|
1289
|
-
kind: 'error',
|
|
1290
|
-
title: 'Replace Task',
|
|
1291
|
-
text: error.message
|
|
1292
|
-
});
|
|
1293
|
-
}
|
|
1294
|
-
}, [previewDraft, restoreTaskEditorPanel, wizard]);
|
|
368
|
+
openDraftPicker
|
|
369
|
+
});
|
|
1295
370
|
|
|
1296
371
|
const submitInput = useCallback((value) => {
|
|
1297
372
|
const text = String(value || '');
|
|
1298
373
|
const trimmed = text.trim();
|
|
1299
374
|
|
|
1300
|
-
if (pendingConfirm) {
|
|
375
|
+
if (pendingConfirm || pendingSelect) {
|
|
1301
376
|
return;
|
|
1302
377
|
}
|
|
1303
378
|
|
|
@@ -1375,6 +450,7 @@ export function ManualApp({
|
|
|
1375
450
|
executeCommand,
|
|
1376
451
|
inputValue,
|
|
1377
452
|
pendingConfirm,
|
|
453
|
+
pendingSelect,
|
|
1378
454
|
authActive,
|
|
1379
455
|
authPrompt,
|
|
1380
456
|
selectedIndex,
|
|
@@ -1396,259 +472,43 @@ export function ManualApp({
|
|
|
1396
472
|
loading ? h(LoadingLine, { message: loading }) : null,
|
|
1397
473
|
h(StatusBar, {
|
|
1398
474
|
preview: activeSessionPreview(sessionRef.current),
|
|
1399
|
-
dryRun:
|
|
475
|
+
dryRun: isDryRun(),
|
|
1400
476
|
wizard,
|
|
1401
477
|
authPrompt: authPrompt || (authActive ? { step: 'working' } : null)
|
|
1402
478
|
}),
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
targets: LOGWORK_TARGETS,
|
|
1439
|
-
selectedIndex: wizard.targetIndex || 0,
|
|
1440
|
-
onChange(index) {
|
|
1441
|
-
setWizard((current) => ({
|
|
1442
|
-
...current,
|
|
1443
|
-
targetIndex: index
|
|
1444
|
-
}));
|
|
1445
|
-
},
|
|
1446
|
-
onSelect(target) {
|
|
1447
|
-
startLogworkWizard(target.key);
|
|
1448
|
-
},
|
|
1449
|
-
onCancel() {
|
|
1450
|
-
setWizard(null);
|
|
1451
|
-
setActivePanel({
|
|
1452
|
-
kind: 'idle',
|
|
1453
|
-
title: 'Ready',
|
|
1454
|
-
text: 'Type / for commands.'
|
|
1455
|
-
});
|
|
1456
|
-
}
|
|
1457
|
-
})
|
|
1458
|
-
: wizard?.step === 'select_auth_target'
|
|
1459
|
-
? h(TargetPicker, {
|
|
1460
|
-
title: 'Pick auth target',
|
|
1461
|
-
targets: AUTH_TARGETS,
|
|
1462
|
-
selectedIndex: wizard.targetIndex || 0,
|
|
1463
|
-
onChange(index) {
|
|
1464
|
-
setWizard((current) => ({
|
|
1465
|
-
...current,
|
|
1466
|
-
targetIndex: index
|
|
1467
|
-
}));
|
|
1468
|
-
},
|
|
1469
|
-
onSelect(target) {
|
|
1470
|
-
executeCommand({
|
|
1471
|
-
type: 'auth',
|
|
1472
|
-
target: target.key
|
|
1473
|
-
});
|
|
1474
|
-
},
|
|
1475
|
-
onCancel() {
|
|
1476
|
-
setWizard(null);
|
|
1477
|
-
setActivePanel({
|
|
1478
|
-
kind: 'idle',
|
|
1479
|
-
title: 'Ready',
|
|
1480
|
-
text: 'Type / for commands.'
|
|
1481
|
-
});
|
|
1482
|
-
}
|
|
1483
|
-
})
|
|
1484
|
-
: wizard?.step === 'select_reconciliation_period'
|
|
1485
|
-
? h(TargetPicker, {
|
|
1486
|
-
title: 'Pick reconciliation period',
|
|
1487
|
-
targets: RECONCILIATION_PERIOD_OPTIONS,
|
|
1488
|
-
selectedIndex: wizard.periodIndex || 0,
|
|
1489
|
-
onChange(index) {
|
|
1490
|
-
setWizard((current) => ({
|
|
1491
|
-
...current,
|
|
1492
|
-
periodIndex: index
|
|
1493
|
-
}));
|
|
1494
|
-
},
|
|
1495
|
-
onSelect(period) {
|
|
1496
|
-
executeCommand({
|
|
1497
|
-
type: 'reconcile',
|
|
1498
|
-
period: period.key
|
|
1499
|
-
});
|
|
1500
|
-
},
|
|
1501
|
-
onCancel() {
|
|
1502
|
-
setWizard(null);
|
|
1503
|
-
setActivePanel({
|
|
1504
|
-
kind: 'idle',
|
|
1505
|
-
title: 'Ready',
|
|
1506
|
-
text: 'Type / for commands.'
|
|
1507
|
-
});
|
|
1508
|
-
}
|
|
1509
|
-
})
|
|
1510
|
-
: wizard?.step === 'select_draft'
|
|
1511
|
-
? h(DraftPicker, {
|
|
1512
|
-
drafts: wizard.drafts || [],
|
|
1513
|
-
selectedIndex: wizard.draftIndex || 0,
|
|
1514
|
-
includeStartNew: wizard.draftSource === 'start',
|
|
1515
|
-
onChange(index) {
|
|
1516
|
-
setWizard((current) => ({
|
|
1517
|
-
...current,
|
|
1518
|
-
draftIndex: index
|
|
1519
|
-
}));
|
|
1520
|
-
},
|
|
1521
|
-
onResume(draft) {
|
|
1522
|
-
resumeManualDraft(draft);
|
|
1523
|
-
},
|
|
1524
|
-
onDelete(draft) {
|
|
1525
|
-
deleteSavedDraft(draft);
|
|
1526
|
-
},
|
|
1527
|
-
onStartNew() {
|
|
1528
|
-
startNewLogworkWizard(RO_TARGET);
|
|
1529
|
-
},
|
|
1530
|
-
onCancel() {
|
|
1531
|
-
returnFromDraftPicker();
|
|
1532
|
-
}
|
|
1533
|
-
})
|
|
1534
|
-
: wizard?.step === 'select_date'
|
|
1535
|
-
? h(DatePicker, {
|
|
1536
|
-
options: wizard.dateOptions,
|
|
1537
|
-
selectedIndex: wizard.dateIndex,
|
|
1538
|
-
onChange(index) {
|
|
1539
|
-
setWizard((current) => ({
|
|
1540
|
-
...current,
|
|
1541
|
-
dateIndex: index
|
|
1542
|
-
}));
|
|
1543
|
-
},
|
|
1544
|
-
onSelect(option) {
|
|
1545
|
-
selectWizardDate(option);
|
|
1546
|
-
}
|
|
1547
|
-
})
|
|
1548
|
-
: wizard?.step === 'select_project'
|
|
1549
|
-
? h(ProjectPicker, {
|
|
1550
|
-
options: wizard.projectOptions,
|
|
1551
|
-
selectedIndex: wizard.projectIndex,
|
|
1552
|
-
onChange(index) {
|
|
1553
|
-
setWizard((current) => ({
|
|
1554
|
-
...current,
|
|
1555
|
-
projectIndex: index
|
|
1556
|
-
}));
|
|
1557
|
-
},
|
|
1558
|
-
onSelect(project) {
|
|
1559
|
-
selectWizardProject(project);
|
|
1560
|
-
}
|
|
1561
|
-
})
|
|
1562
|
-
: wizard?.step === 'select_mcp_client'
|
|
1563
|
-
? h(McpClientPicker, {
|
|
1564
|
-
selectedIndex: wizard.mcpClientIndex || 0,
|
|
1565
|
-
onChange(index) {
|
|
1566
|
-
setWizard((current) => ({
|
|
1567
|
-
...current,
|
|
1568
|
-
mcpClientIndex: index
|
|
1569
|
-
}));
|
|
1570
|
-
},
|
|
1571
|
-
onSelect(client) {
|
|
1572
|
-
executeCommand({
|
|
1573
|
-
type: 'mcp',
|
|
1574
|
-
client: client.key
|
|
1575
|
-
});
|
|
1576
|
-
},
|
|
1577
|
-
onCancel() {
|
|
1578
|
-
cancelMcpClientPicker();
|
|
1579
|
-
}
|
|
1580
|
-
})
|
|
1581
|
-
: wizard?.step === 'remove_tasks'
|
|
1582
|
-
? h(TaskRemovePicker, {
|
|
1583
|
-
tasks: wizard.tasks,
|
|
1584
|
-
selectedIndex: wizard.removeIndex || 0,
|
|
1585
|
-
selectedIndexes: wizard.removeSelectedIndexes || [],
|
|
1586
|
-
onChange(index) {
|
|
1587
|
-
setWizard((current) => ({
|
|
1588
|
-
...current,
|
|
1589
|
-
removeIndex: index
|
|
1590
|
-
}));
|
|
1591
|
-
},
|
|
1592
|
-
onToggle(index) {
|
|
1593
|
-
setWizard((current) => ({
|
|
1594
|
-
...current,
|
|
1595
|
-
removeSelectedIndexes: toggleTaskSelection(current.removeSelectedIndexes || [], index)
|
|
1596
|
-
}));
|
|
1597
|
-
},
|
|
1598
|
-
onSubmit(indexes) {
|
|
1599
|
-
confirmRemoveTasks(indexes);
|
|
1600
|
-
},
|
|
1601
|
-
onCancel() {
|
|
1602
|
-
cancelRemoveTasks();
|
|
1603
|
-
}
|
|
1604
|
-
})
|
|
1605
|
-
: wizard?.step === 'edit_task_select'
|
|
1606
|
-
? h(TaskEditPicker, {
|
|
1607
|
-
tasks: wizard.tasks,
|
|
1608
|
-
selectedIndex: wizard.editIndex || 0,
|
|
1609
|
-
onChange(index) {
|
|
1610
|
-
setWizard((current) => ({
|
|
1611
|
-
...current,
|
|
1612
|
-
editIndex: index
|
|
1613
|
-
}));
|
|
1614
|
-
},
|
|
1615
|
-
onSelect(index) {
|
|
1616
|
-
selectTaskForEdit(index);
|
|
1617
|
-
},
|
|
1618
|
-
onCancel() {
|
|
1619
|
-
setWizard((current) => ({
|
|
1620
|
-
...current,
|
|
1621
|
-
step: 'edit_tasks'
|
|
1622
|
-
}));
|
|
1623
|
-
restoreTaskEditorPanel();
|
|
1624
|
-
}
|
|
1625
|
-
})
|
|
1626
|
-
: h(CommandInput, {
|
|
1627
|
-
value: inputValue,
|
|
1628
|
-
onChange(value) {
|
|
1629
|
-
setInputValue(value);
|
|
1630
|
-
setSelectedIndex(0);
|
|
1631
|
-
},
|
|
1632
|
-
onSubmit: submitInput,
|
|
1633
|
-
selectedIndex,
|
|
1634
|
-
setSelectedIndex,
|
|
1635
|
-
mode: wizard?.step === 'edit_tasks' ? 'task' : wizard?.step === 'edit_task_replace' ? 'task-edit' : 'command',
|
|
1636
|
-
onEscape() {
|
|
1637
|
-
if (!wizard) {
|
|
1638
|
-
exit();
|
|
1639
|
-
return;
|
|
1640
|
-
}
|
|
1641
|
-
if (wizard?.step === 'edit_tasks') {
|
|
1642
|
-
cancelCurrentLogwork();
|
|
1643
|
-
return;
|
|
1644
|
-
}
|
|
1645
|
-
if (wizard?.step === 'edit_task_replace') {
|
|
1646
|
-
setWizard((current) => ({
|
|
1647
|
-
...current,
|
|
1648
|
-
step: 'edit_tasks'
|
|
1649
|
-
}));
|
|
1650
|
-
restoreTaskEditorPanel();
|
|
1651
|
-
}
|
|
1652
|
-
}
|
|
1653
|
-
}));
|
|
479
|
+
renderManualInteraction({
|
|
480
|
+
authPrompt,
|
|
481
|
+
authActive,
|
|
482
|
+
pendingConfirm,
|
|
483
|
+
pendingSelect,
|
|
484
|
+
wizard,
|
|
485
|
+
inputValue,
|
|
486
|
+
selectedIndex,
|
|
487
|
+
setInputValue,
|
|
488
|
+
setSelectedIndex,
|
|
489
|
+
setAuthPrompt,
|
|
490
|
+
setWizard,
|
|
491
|
+
setActivePanel,
|
|
492
|
+
resolveAuthPrompt,
|
|
493
|
+
rejectAuthPrompt,
|
|
494
|
+
resolveConfirm,
|
|
495
|
+
changeSelect,
|
|
496
|
+
resolveSelect,
|
|
497
|
+
exit,
|
|
498
|
+
executeCommand,
|
|
499
|
+
submitInput,
|
|
500
|
+
startLogworkWizard,
|
|
501
|
+
startNewLogworkWizard,
|
|
502
|
+
selectWizardDate,
|
|
503
|
+
selectWizardProject,
|
|
504
|
+
cancelMcpClientPicker,
|
|
505
|
+
cancelCurrentLogwork,
|
|
506
|
+
restoreTaskEditorPanel,
|
|
507
|
+
resumeManualDraft,
|
|
508
|
+
deleteSavedDraft,
|
|
509
|
+
returnFromDraftPicker,
|
|
510
|
+
confirmRemoveTasks,
|
|
511
|
+
cancelRemoveTasks,
|
|
512
|
+
selectTaskForEdit
|
|
513
|
+
}));
|
|
1654
514
|
}
|