@eunjae/il 0.0.1 → 1.0.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/dist/scripts/il.d.mts +1 -0
- package/dist/scripts/il.mjs +977 -0
- package/package.json +10 -3
- package/dist/lib/__tests__/aliasRepo.test.js +0 -17
- package/dist/lib/__tests__/edit.test.js +0 -32
- package/dist/lib/__tests__/fsm.test.js +0 -22
- package/dist/lib/__tests__/id.test.js +0 -25
- package/dist/lib/__tests__/schema.test.js +0 -37
- package/dist/lib/__tests__/taskOperations.test.js +0 -33
- package/dist/lib/aliasReconcile.js +0 -28
- package/dist/lib/aliasRepo.js +0 -58
- package/dist/lib/config.js +0 -35
- package/dist/lib/constants.js +0 -6
- package/dist/lib/edit.js +0 -47
- package/dist/lib/format.js +0 -52
- package/dist/lib/fsm.js +0 -25
- package/dist/lib/gitignore.js +0 -21
- package/dist/lib/id.js +0 -30
- package/dist/lib/json.js +0 -10
- package/dist/lib/lock.js +0 -25
- package/dist/lib/pr.js +0 -64
- package/dist/lib/schema.js +0 -64
- package/dist/lib/search.js +0 -17
- package/dist/lib/taskFactory.js +0 -19
- package/dist/lib/taskOperations.js +0 -57
- package/dist/lib/taskRepo.js +0 -67
- package/dist/lib/taskResolver.js +0 -31
- package/dist/lib/taskStore.js +0 -9
- package/dist/lib/time.js +0 -18
- package/dist/lib/types.js +0 -3
- package/dist/lib/workspace.js +0 -58
- package/dist/scripts/il.js +0 -396
- package/dist/scripts/suivi.js +0 -396
package/dist/scripts/il.js
DELETED
|
@@ -1,396 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { Command } from 'commander';
|
|
4
|
-
import { readAliases } from '../lib/aliasRepo';
|
|
5
|
-
import { reconcileAliases } from '../lib/aliasReconcile';
|
|
6
|
-
import { resolveGithubToken } from '../lib/config';
|
|
7
|
-
import { APP_DIR } from '../lib/constants';
|
|
8
|
-
import { applyTaskEdit } from '../lib/edit';
|
|
9
|
-
import { formatTaskDetails, formatTaskListLine, buildAliasLookup } from '../lib/format';
|
|
10
|
-
import { ensureLockIgnored } from '../lib/gitignore';
|
|
11
|
-
import { withWorkspaceLock } from '../lib/lock';
|
|
12
|
-
import { buildPrAttachment, fetchGitHubPr, parseGitHubPrUrl } from '../lib/pr';
|
|
13
|
-
import { taskSchema } from '../lib/schema';
|
|
14
|
-
import { taskMatchesQuery } from '../lib/search';
|
|
15
|
-
import { buildTask } from '../lib/taskFactory';
|
|
16
|
-
import { appendDayAssignment, appendLog, applyTransition, isAssignedOnDate } from '../lib/taskOperations';
|
|
17
|
-
import { createTaskInStore } from '../lib/taskStore';
|
|
18
|
-
import { listAllTasks, listTasksByStatus, moveTaskFile, saveTask } from '../lib/taskRepo';
|
|
19
|
-
import { resolveTask } from '../lib/taskResolver';
|
|
20
|
-
import { nowIso, todayDate } from '../lib/time';
|
|
21
|
-
import { taskStatuses, taskTypes } from '../lib/types';
|
|
22
|
-
import { ensureWorkspaceLayout, findGitRoot, resolveWorkspace } from '../lib/workspace';
|
|
23
|
-
const program = new Command();
|
|
24
|
-
const handleAction = (fn) => async (...args) => {
|
|
25
|
-
try {
|
|
26
|
-
await fn(...args);
|
|
27
|
-
}
|
|
28
|
-
catch (error) {
|
|
29
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
30
|
-
process.stderr.write(`${message}\n`);
|
|
31
|
-
process.exitCode = 1;
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
const resolveWorkspaceFor = async (ensure) => {
|
|
35
|
-
const opts = program.opts();
|
|
36
|
-
const workspace = await resolveWorkspace({
|
|
37
|
-
store: opts.store,
|
|
38
|
-
global: opts.global,
|
|
39
|
-
repo: opts.repo
|
|
40
|
-
});
|
|
41
|
-
if (ensure) {
|
|
42
|
-
await ensureWorkspaceLayout(workspace.root);
|
|
43
|
-
}
|
|
44
|
-
return workspace.root;
|
|
45
|
-
};
|
|
46
|
-
const printLines = (lines) => {
|
|
47
|
-
if (lines.length === 0) {
|
|
48
|
-
process.stdout.write('No tasks.\n');
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
process.stdout.write(`${lines.join('\n')}\n`);
|
|
52
|
-
};
|
|
53
|
-
const isTaskStatus = (value) => {
|
|
54
|
-
return taskStatuses.includes(value);
|
|
55
|
-
};
|
|
56
|
-
program
|
|
57
|
-
.name('il')
|
|
58
|
-
.description('Terminal task manager')
|
|
59
|
-
.option('--store <path>', 'explicit workspace path')
|
|
60
|
-
.option('--global', 'use global workspace')
|
|
61
|
-
.option('--repo', 'use repo workspace');
|
|
62
|
-
program
|
|
63
|
-
.command('init')
|
|
64
|
-
.description('initialize repo workspace')
|
|
65
|
-
.action(handleAction(async () => {
|
|
66
|
-
const repoRoot = await findGitRoot(process.cwd());
|
|
67
|
-
if (!repoRoot) {
|
|
68
|
-
throw new Error('Not inside a git repository');
|
|
69
|
-
}
|
|
70
|
-
const workspaceRoot = path.join(repoRoot, APP_DIR);
|
|
71
|
-
await ensureWorkspaceLayout(workspaceRoot);
|
|
72
|
-
await ensureLockIgnored(repoRoot);
|
|
73
|
-
process.stdout.write(`Initialized workspace at ${workspaceRoot}\n`);
|
|
74
|
-
}));
|
|
75
|
-
program
|
|
76
|
-
.command('where')
|
|
77
|
-
.description('show resolved workspace')
|
|
78
|
-
.action(handleAction(async () => {
|
|
79
|
-
const opts = program.opts();
|
|
80
|
-
const workspace = await resolveWorkspace({
|
|
81
|
-
store: opts.store,
|
|
82
|
-
global: opts.global,
|
|
83
|
-
repo: opts.repo
|
|
84
|
-
});
|
|
85
|
-
process.stdout.write(`${workspace.root} (${workspace.kind})\n`);
|
|
86
|
-
}));
|
|
87
|
-
program
|
|
88
|
-
.command('add')
|
|
89
|
-
.description('add a task')
|
|
90
|
-
.argument('[title]', 'task title')
|
|
91
|
-
.option('--type <type>', 'regular|pr_review', 'regular')
|
|
92
|
-
.option('--url <url>', 'attach URL')
|
|
93
|
-
.option('--pr <url>', 'attach PR URL')
|
|
94
|
-
.action(handleAction(async (title, options, command) => {
|
|
95
|
-
const taskType = options.type;
|
|
96
|
-
if (!taskTypes.includes(taskType)) {
|
|
97
|
-
throw new Error(`Invalid type: ${taskType}`);
|
|
98
|
-
}
|
|
99
|
-
if (taskType === 'pr_review' && !options.pr) {
|
|
100
|
-
throw new Error('PR review tasks require --pr');
|
|
101
|
-
}
|
|
102
|
-
const workspaceRoot = await resolveWorkspaceFor(true);
|
|
103
|
-
await withWorkspaceLock(workspaceRoot, async () => {
|
|
104
|
-
let prAttachment;
|
|
105
|
-
let prTitle;
|
|
106
|
-
if (options.pr) {
|
|
107
|
-
const parsed = parseGitHubPrUrl(options.pr);
|
|
108
|
-
if (!parsed) {
|
|
109
|
-
throw new Error('Invalid PR URL');
|
|
110
|
-
}
|
|
111
|
-
const token = await resolveGithubToken(workspaceRoot);
|
|
112
|
-
const fetched = await fetchGitHubPr(parsed, token);
|
|
113
|
-
prAttachment = buildPrAttachment(parsed, fetched ?? undefined);
|
|
114
|
-
prTitle = fetched?.title ?? `PR #${parsed.number} ${parsed.repo.owner}/${parsed.repo.name}`;
|
|
115
|
-
}
|
|
116
|
-
const isExplicitTitle = Boolean(title);
|
|
117
|
-
let finalTitle = title ?? prTitle;
|
|
118
|
-
if (!finalTitle) {
|
|
119
|
-
throw new Error('Title is required when no PR URL is provided');
|
|
120
|
-
}
|
|
121
|
-
if (taskType === 'pr_review' && !isExplicitTitle) {
|
|
122
|
-
finalTitle = `Review: ${finalTitle}`;
|
|
123
|
-
}
|
|
124
|
-
const metadata = {
|
|
125
|
-
url: options.url,
|
|
126
|
-
pr: prAttachment
|
|
127
|
-
};
|
|
128
|
-
const task = buildTask({
|
|
129
|
-
type: taskType,
|
|
130
|
-
title: finalTitle,
|
|
131
|
-
metadata
|
|
132
|
-
});
|
|
133
|
-
taskSchema.parse(task);
|
|
134
|
-
const created = await createTaskInStore(workspaceRoot, task);
|
|
135
|
-
process.stdout.write(`Created ${created.alias} ${created.task.ref} ${created.task.title}\n`);
|
|
136
|
-
});
|
|
137
|
-
}));
|
|
138
|
-
program
|
|
139
|
-
.command('list')
|
|
140
|
-
.description('list tasks')
|
|
141
|
-
.argument('[status]', 'task status')
|
|
142
|
-
.action(handleAction(async (status, command) => {
|
|
143
|
-
const workspaceRoot = await resolveWorkspaceFor(true);
|
|
144
|
-
const aliases = await readAliases(workspaceRoot);
|
|
145
|
-
const aliasLookup = buildAliasLookup(aliases);
|
|
146
|
-
if (status && !isTaskStatus(status)) {
|
|
147
|
-
throw new Error(`Invalid status: ${status}`);
|
|
148
|
-
}
|
|
149
|
-
const statuses = status ? [status] : [...taskStatuses];
|
|
150
|
-
const lines = [];
|
|
151
|
-
for (const currentStatus of statuses) {
|
|
152
|
-
const stored = await listTasksByStatus(workspaceRoot, currentStatus);
|
|
153
|
-
for (const entry of stored) {
|
|
154
|
-
const alias = aliasLookup.get(entry.task.id);
|
|
155
|
-
let line = formatTaskListLine(entry.task, alias);
|
|
156
|
-
if (entry.task.metadata.pr?.fetched?.state) {
|
|
157
|
-
line += ` PR:${entry.task.metadata.pr.fetched.state}`;
|
|
158
|
-
}
|
|
159
|
-
lines.push(line);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
printLines(lines);
|
|
163
|
-
}));
|
|
164
|
-
program
|
|
165
|
-
.command('show')
|
|
166
|
-
.description('show a task')
|
|
167
|
-
.argument('<id>', 'task identifier')
|
|
168
|
-
.action(handleAction(async (identifier, command) => {
|
|
169
|
-
const workspaceRoot = await resolveWorkspaceFor(true);
|
|
170
|
-
const stored = await resolveTask(workspaceRoot, identifier);
|
|
171
|
-
const aliases = await readAliases(workspaceRoot);
|
|
172
|
-
const aliasLookup = buildAliasLookup(aliases);
|
|
173
|
-
const alias = aliasLookup.get(stored.task.id);
|
|
174
|
-
process.stdout.write(`${formatTaskDetails(stored.task, alias)}\n`);
|
|
175
|
-
}));
|
|
176
|
-
const addTransitionCommand = (name) => {
|
|
177
|
-
program
|
|
178
|
-
.command(name)
|
|
179
|
-
.description(`${name} a task`)
|
|
180
|
-
.argument('<id>', 'task identifier')
|
|
181
|
-
.option('-m, --message <message>', 'custom log message')
|
|
182
|
-
.action(handleAction(async (identifier, options, command) => {
|
|
183
|
-
const workspaceRoot = await resolveWorkspaceFor(true);
|
|
184
|
-
await withWorkspaceLock(workspaceRoot, async () => {
|
|
185
|
-
const stored = await resolveTask(workspaceRoot, identifier);
|
|
186
|
-
const { task: updated, nextStatus } = applyTransition(stored.task, name, options.message);
|
|
187
|
-
await saveTask(workspaceRoot, stored.status, updated);
|
|
188
|
-
await moveTaskFile(workspaceRoot, updated.id, stored.status, nextStatus);
|
|
189
|
-
process.stdout.write(`Updated ${updated.ref} -> ${nextStatus}\n`);
|
|
190
|
-
});
|
|
191
|
-
}));
|
|
192
|
-
};
|
|
193
|
-
addTransitionCommand('start');
|
|
194
|
-
addTransitionCommand('pause');
|
|
195
|
-
addTransitionCommand('complete');
|
|
196
|
-
addTransitionCommand('cancel');
|
|
197
|
-
program
|
|
198
|
-
.command('log')
|
|
199
|
-
.description('append a log entry')
|
|
200
|
-
.argument('<id>', 'task identifier')
|
|
201
|
-
.argument('<message>', 'log message')
|
|
202
|
-
.option('--status <status>', 'include status in log entry')
|
|
203
|
-
.action(handleAction(async (identifier, message, options, command) => {
|
|
204
|
-
const workspaceRoot = await resolveWorkspaceFor(true);
|
|
205
|
-
const status = options.status;
|
|
206
|
-
if (status && !taskStatuses.includes(status)) {
|
|
207
|
-
throw new Error(`Invalid status: ${status}`);
|
|
208
|
-
}
|
|
209
|
-
await withWorkspaceLock(workspaceRoot, async () => {
|
|
210
|
-
const stored = await resolveTask(workspaceRoot, identifier);
|
|
211
|
-
const updated = appendLog(stored.task, message, status);
|
|
212
|
-
await saveTask(workspaceRoot, stored.status, updated);
|
|
213
|
-
process.stdout.write(`Logged on ${updated.ref}\n`);
|
|
214
|
-
});
|
|
215
|
-
}));
|
|
216
|
-
program
|
|
217
|
-
.command('edit')
|
|
218
|
-
.description('edit a task field')
|
|
219
|
-
.argument('<id>', 'task identifier')
|
|
220
|
-
.argument('<path>', 'dotted path')
|
|
221
|
-
.argument('<value>', 'new value')
|
|
222
|
-
.action(handleAction(async (identifier, dottedPath, value, command) => {
|
|
223
|
-
const workspaceRoot = await resolveWorkspaceFor(true);
|
|
224
|
-
await withWorkspaceLock(workspaceRoot, async () => {
|
|
225
|
-
const stored = await resolveTask(workspaceRoot, identifier);
|
|
226
|
-
const updated = applyTaskEdit(stored.task, dottedPath, value);
|
|
227
|
-
await saveTask(workspaceRoot, stored.status, updated);
|
|
228
|
-
process.stdout.write(`Updated ${updated.ref}\n`);
|
|
229
|
-
});
|
|
230
|
-
}));
|
|
231
|
-
program
|
|
232
|
-
.command('search')
|
|
233
|
-
.description('search tasks')
|
|
234
|
-
.argument('<query>', 'search query')
|
|
235
|
-
.action(handleAction(async (query, command) => {
|
|
236
|
-
const workspaceRoot = await resolveWorkspaceFor(true);
|
|
237
|
-
const aliases = await readAliases(workspaceRoot);
|
|
238
|
-
const aliasLookup = buildAliasLookup(aliases);
|
|
239
|
-
const tasks = await listAllTasks(workspaceRoot);
|
|
240
|
-
const lines = tasks
|
|
241
|
-
.filter((stored) => taskMatchesQuery(stored.task, query))
|
|
242
|
-
.map((stored) => {
|
|
243
|
-
const alias = aliasLookup.get(stored.task.id);
|
|
244
|
-
let line = formatTaskListLine(stored.task, alias);
|
|
245
|
-
if (stored.task.metadata.pr?.fetched?.state) {
|
|
246
|
-
line += ` PR:${stored.task.metadata.pr.fetched.state}`;
|
|
247
|
-
}
|
|
248
|
-
return line;
|
|
249
|
-
});
|
|
250
|
-
printLines(lines);
|
|
251
|
-
}));
|
|
252
|
-
program
|
|
253
|
-
.command('today')
|
|
254
|
-
.description('assign or list today tasks')
|
|
255
|
-
.argument('[id]', 'task identifier')
|
|
256
|
-
.option('--date <date>', 'YYYY-MM-DD')
|
|
257
|
-
.option('-m, --message <message>', 'assignment message')
|
|
258
|
-
.action(handleAction(async (identifier, options, command) => {
|
|
259
|
-
const workspaceRoot = await resolveWorkspaceFor(true);
|
|
260
|
-
const date = todayDate(options.date);
|
|
261
|
-
if (!identifier) {
|
|
262
|
-
const aliases = await readAliases(workspaceRoot);
|
|
263
|
-
const aliasLookup = buildAliasLookup(aliases);
|
|
264
|
-
const tasks = await listAllTasks(workspaceRoot);
|
|
265
|
-
const assigned = tasks.filter((stored) => isAssignedOnDate(stored.task, date));
|
|
266
|
-
const lines = assigned.map((stored) => formatTaskListLine(stored.task, aliasLookup.get(stored.task.id)));
|
|
267
|
-
printLines(lines);
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
await withWorkspaceLock(workspaceRoot, async () => {
|
|
271
|
-
const stored = await resolveTask(workspaceRoot, identifier);
|
|
272
|
-
if (isAssignedOnDate(stored.task, date)) {
|
|
273
|
-
process.stdout.write(`Already assigned ${stored.task.ref} to ${date}\n`);
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
const updated = appendDayAssignment(stored.task, date, 'assign', options.message);
|
|
277
|
-
await saveTask(workspaceRoot, stored.status, updated);
|
|
278
|
-
process.stdout.write(`Assigned ${updated.ref} to ${date}\n`);
|
|
279
|
-
});
|
|
280
|
-
}));
|
|
281
|
-
program
|
|
282
|
-
.command('untoday')
|
|
283
|
-
.description('unassign a task from today')
|
|
284
|
-
.argument('<id>', 'task identifier')
|
|
285
|
-
.option('--date <date>', 'YYYY-MM-DD')
|
|
286
|
-
.action(handleAction(async (identifier, options, command) => {
|
|
287
|
-
const workspaceRoot = await resolveWorkspaceFor(true);
|
|
288
|
-
const date = todayDate(options.date);
|
|
289
|
-
await withWorkspaceLock(workspaceRoot, async () => {
|
|
290
|
-
const stored = await resolveTask(workspaceRoot, identifier);
|
|
291
|
-
if (!isAssignedOnDate(stored.task, date)) {
|
|
292
|
-
process.stdout.write(`Already unassigned ${stored.task.ref} from ${date}\n`);
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
const updated = appendDayAssignment(stored.task, date, 'unassign');
|
|
296
|
-
await saveTask(workspaceRoot, stored.status, updated);
|
|
297
|
-
process.stdout.write(`Unassigned ${updated.ref} from ${date}\n`);
|
|
298
|
-
});
|
|
299
|
-
}));
|
|
300
|
-
program
|
|
301
|
-
.command('attach-pr')
|
|
302
|
-
.description('attach PR metadata to a task')
|
|
303
|
-
.argument('<id>', 'task identifier')
|
|
304
|
-
.argument('<url>', 'PR URL')
|
|
305
|
-
.option('-m, --message <message>', 'log message')
|
|
306
|
-
.action(handleAction(async (identifier, url, options, command) => {
|
|
307
|
-
const workspaceRoot = await resolveWorkspaceFor(true);
|
|
308
|
-
await withWorkspaceLock(workspaceRoot, async () => {
|
|
309
|
-
const parsed = parseGitHubPrUrl(url);
|
|
310
|
-
if (!parsed) {
|
|
311
|
-
throw new Error('Invalid PR URL');
|
|
312
|
-
}
|
|
313
|
-
const token = await resolveGithubToken(workspaceRoot);
|
|
314
|
-
const fetched = await fetchGitHubPr(parsed, token);
|
|
315
|
-
const stored = await resolveTask(workspaceRoot, identifier);
|
|
316
|
-
const updated = {
|
|
317
|
-
...stored.task,
|
|
318
|
-
metadata: {
|
|
319
|
-
...stored.task.metadata,
|
|
320
|
-
pr: buildPrAttachment(parsed, fetched ?? stored.task.metadata.pr?.fetched)
|
|
321
|
-
},
|
|
322
|
-
updated_at: nowIso()
|
|
323
|
-
};
|
|
324
|
-
const logMessage = options.message ?? `Attached PR ${url}`;
|
|
325
|
-
const next = appendLog(updated, logMessage);
|
|
326
|
-
await saveTask(workspaceRoot, stored.status, next);
|
|
327
|
-
process.stdout.write(`Attached PR to ${next.ref}\n`);
|
|
328
|
-
});
|
|
329
|
-
}));
|
|
330
|
-
program
|
|
331
|
-
.command('refresh')
|
|
332
|
-
.description('refresh PR metadata')
|
|
333
|
-
.argument('<id>', 'task identifier')
|
|
334
|
-
.option('-m, --message <message>', 'log message')
|
|
335
|
-
.action(handleAction(async (identifier, options, command) => {
|
|
336
|
-
const workspaceRoot = await resolveWorkspaceFor(true);
|
|
337
|
-
await withWorkspaceLock(workspaceRoot, async () => {
|
|
338
|
-
const stored = await resolveTask(workspaceRoot, identifier);
|
|
339
|
-
const prUrl = stored.task.metadata.pr?.url;
|
|
340
|
-
if (!prUrl) {
|
|
341
|
-
process.stdout.write('No PR attached.\n');
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
const parsed = parseGitHubPrUrl(prUrl);
|
|
345
|
-
if (!parsed) {
|
|
346
|
-
throw new Error('Invalid PR URL');
|
|
347
|
-
}
|
|
348
|
-
const token = await resolveGithubToken(workspaceRoot);
|
|
349
|
-
const fetched = await fetchGitHubPr(parsed, token);
|
|
350
|
-
if (!fetched) {
|
|
351
|
-
throw new Error('No GitHub token configured');
|
|
352
|
-
}
|
|
353
|
-
const baseUpdated = {
|
|
354
|
-
...stored.task,
|
|
355
|
-
metadata: {
|
|
356
|
-
...stored.task.metadata,
|
|
357
|
-
pr: buildPrAttachment(parsed, fetched)
|
|
358
|
-
},
|
|
359
|
-
updated_at: nowIso()
|
|
360
|
-
};
|
|
361
|
-
const previousState = stored.task.metadata.pr?.fetched?.state;
|
|
362
|
-
const nextState = fetched.state;
|
|
363
|
-
const isTerminal = stored.task.status === 'completed' || stored.task.status === 'cancelled';
|
|
364
|
-
let finalTask = baseUpdated;
|
|
365
|
-
let nextStatus = stored.status;
|
|
366
|
-
if (!isTerminal && previousState !== nextState) {
|
|
367
|
-
if (nextState === 'merged') {
|
|
368
|
-
const result = applyTransition(baseUpdated, 'complete', options.message ?? 'PR merged');
|
|
369
|
-
finalTask = result.task;
|
|
370
|
-
nextStatus = result.nextStatus;
|
|
371
|
-
}
|
|
372
|
-
else if (nextState === 'closed') {
|
|
373
|
-
const result = applyTransition(baseUpdated, 'cancel', options.message ?? 'PR closed without merge');
|
|
374
|
-
finalTask = result.task;
|
|
375
|
-
nextStatus = result.nextStatus;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
await saveTask(workspaceRoot, stored.status, finalTask);
|
|
379
|
-
if (nextStatus !== stored.status) {
|
|
380
|
-
await moveTaskFile(workspaceRoot, finalTask.id, stored.status, nextStatus);
|
|
381
|
-
}
|
|
382
|
-
process.stdout.write(`Refreshed ${finalTask.ref}\n`);
|
|
383
|
-
});
|
|
384
|
-
}));
|
|
385
|
-
const aliasCommand = program.command('alias').description('alias helpers');
|
|
386
|
-
aliasCommand
|
|
387
|
-
.command('reconcile')
|
|
388
|
-
.description('reconcile alias mapping')
|
|
389
|
-
.action(handleAction(async (command) => {
|
|
390
|
-
const workspaceRoot = await resolveWorkspaceFor(true);
|
|
391
|
-
await withWorkspaceLock(workspaceRoot, async () => {
|
|
392
|
-
await reconcileAliases(workspaceRoot);
|
|
393
|
-
process.stdout.write('Aliases reconciled.\n');
|
|
394
|
-
});
|
|
395
|
-
}));
|
|
396
|
-
program.parseAsync(process.argv);
|