@context-forge/cli 0.8.5 → 0.8.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/arch.d.ts +7 -0
- package/dist/commands/arch.d.ts.map +1 -0
- package/dist/commands/arch.js +160 -0
- package/dist/commands/arch.js.map +1 -0
- package/dist/commands/backup.d.ts +3 -0
- package/dist/commands/backup.d.ts.map +1 -0
- package/dist/commands/backup.js +27 -0
- package/dist/commands/backup.js.map +1 -0
- package/dist/commands/build.d.ts +24 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +146 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/check.d.ts +3 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +211 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/commandInstaller.d.ts +28 -0
- package/dist/commands/commandInstaller.d.ts.map +1 -0
- package/dist/commands/commandInstaller.js +136 -0
- package/dist/commands/commandInstaller.js.map +1 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +69 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/future.d.ts +3 -0
- package/dist/commands/future.d.ts.map +1 -0
- package/dist/commands/future.js +96 -0
- package/dist/commands/future.js.map +1 -0
- package/dist/commands/guides.d.ts +9 -0
- package/dist/commands/guides.d.ts.map +1 -0
- package/dist/commands/guides.js +156 -0
- package/dist/commands/guides.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +124 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +93 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/next.d.ts +3 -0
- package/dist/commands/next.d.ts.map +1 -0
- package/dist/commands/next.js +51 -0
- package/dist/commands/next.js.map +1 -0
- package/dist/commands/plan.d.ts +7 -0
- package/dist/commands/plan.d.ts.map +1 -0
- package/dist/commands/plan.js +102 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/project.d.ts +25 -0
- package/dist/commands/project.d.ts.map +1 -0
- package/dist/commands/project.js +550 -0
- package/dist/commands/project.js.map +1 -0
- package/dist/commands/prompt.d.ts +3 -0
- package/dist/commands/prompt.d.ts.map +1 -0
- package/dist/commands/prompt.js +112 -0
- package/dist/commands/prompt.js.map +1 -0
- package/dist/commands/setup-ide.d.ts +15 -0
- package/dist/commands/setup-ide.d.ts.map +1 -0
- package/dist/commands/setup-ide.js +250 -0
- package/dist/commands/setup-ide.js.map +1 -0
- package/dist/commands/slice.d.ts +6 -0
- package/dist/commands/slice.d.ts.map +1 -0
- package/dist/commands/slice.js +100 -0
- package/dist/commands/slice.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +209 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/task.d.ts +12 -0
- package/dist/commands/task.d.ts.map +1 -0
- package/dist/commands/task.js +185 -0
- package/dist/commands/task.js.map +1 -0
- package/dist/commands/update.d.ts +27 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +172 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/workflow.d.ts +3 -0
- package/dist/commands/workflow.d.ts.map +1 -0
- package/dist/commands/workflow.js +204 -0
- package/dist/commands/workflow.js.map +1 -0
- package/dist/commands/worktree.d.ts +3 -0
- package/dist/commands/worktree.d.ts.map +1 -0
- package/dist/commands/worktree.js +371 -0
- package/dist/commands/worktree.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +167 -0
- package/dist/index.js.map +1 -0
- package/dist/options.d.ts +16 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +29 -0
- package/dist/options.js.map +1 -0
- package/dist/output/formatter.d.ts +6 -0
- package/dist/output/formatter.d.ts.map +1 -0
- package/dist/output/formatter.js +9 -0
- package/dist/output/formatter.js.map +1 -0
- package/dist/output/styles.d.ts +15 -0
- package/dist/output/styles.d.ts.map +1 -0
- package/dist/output/styles.js +16 -0
- package/dist/output/styles.js.map +1 -0
- package/dist/output/tables.d.ts +6 -0
- package/dist/output/tables.d.ts.map +1 -0
- package/dist/output/tables.js +45 -0
- package/dist/output/tables.js.map +1 -0
- package/dist/utils/breaking-changes.d.ts +14 -0
- package/dist/utils/breaking-changes.d.ts.map +1 -0
- package/dist/utils/breaking-changes.js +11 -0
- package/dist/utils/breaking-changes.js.map +1 -0
- package/dist/utils/commandCatalog.d.ts +25 -0
- package/dist/utils/commandCatalog.d.ts.map +1 -0
- package/dist/utils/commandCatalog.js +32 -0
- package/dist/utils/commandCatalog.js.map +1 -0
- package/dist/utils/confirm.d.ts +3 -0
- package/dist/utils/confirm.d.ts.map +1 -0
- package/dist/utils/confirm.js +12 -0
- package/dist/utils/confirm.js.map +1 -0
- package/dist/utils/errors.d.ts +22 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +63 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/phaseShorthand.d.ts +23 -0
- package/dist/utils/phaseShorthand.d.ts.map +1 -0
- package/dist/utils/phaseShorthand.js +68 -0
- package/dist/utils/phaseShorthand.js.map +1 -0
- package/dist/utils/project.d.ts +60 -0
- package/dist/utils/project.d.ts.map +1 -0
- package/dist/utils/project.js +140 -0
- package/dist/utils/project.js.map +1 -0
- package/dist/utils/worktree-overlay.d.ts +31 -0
- package/dist/utils/worktree-overlay.d.ts.map +1 -0
- package/dist/utils/worktree-overlay.js +63 -0
- package/dist/utils/worktree-overlay.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { FileProjectStore, WorkflowNavigator, GitWorktreeDiscovery, parseSlicePlan, resolveArtifactPath } from '@context-forge/core/node';
|
|
3
|
+
import { resolveProject } from '@context-forge/core';
|
|
4
|
+
import { resolveProjectWorktree, findWorktreeByNameOrId } from '../utils/project.js';
|
|
5
|
+
import { applyWorktreeOverlay } from '../utils/worktree-overlay.js';
|
|
6
|
+
import { handleError, UserError } from '../utils/errors.js';
|
|
7
|
+
import { withJsonOption, withProjectOption } from '../options.js';
|
|
8
|
+
import { printJson } from '../output/formatter.js';
|
|
9
|
+
import { renderTable } from '../output/tables.js';
|
|
10
|
+
import { label, value as valueStyle, success, dim, warn } from '../output/styles.js';
|
|
11
|
+
export function registerStatusCommand(program) {
|
|
12
|
+
const statusCmd = program
|
|
13
|
+
.command('status')
|
|
14
|
+
.description('Show workflow status for the active project');
|
|
15
|
+
withJsonOption(statusCmd);
|
|
16
|
+
withProjectOption(statusCmd);
|
|
17
|
+
statusCmd
|
|
18
|
+
.option('--worktree <name>', 'Show status for a specific worktree')
|
|
19
|
+
.option('--worktrees', 'Show summary of all worktrees');
|
|
20
|
+
statusCmd.action(async (opts) => {
|
|
21
|
+
try {
|
|
22
|
+
if (opts.worktree && opts.worktrees) {
|
|
23
|
+
throw new UserError('--worktree and --worktrees are mutually exclusive.');
|
|
24
|
+
}
|
|
25
|
+
const store = new FileProjectStore();
|
|
26
|
+
const { id, source, worktreeId: cwdWorktreeId } = await resolveProjectWorktree({ project: opts.project }, store);
|
|
27
|
+
const rawProject = await store.getById(id);
|
|
28
|
+
if (!rawProject) {
|
|
29
|
+
throw new UserError(`Project not found: '${id}'. Run cf project list to see available projects.`);
|
|
30
|
+
}
|
|
31
|
+
// ── --worktrees dashboard ──────────────────────────────────────────
|
|
32
|
+
if (opts.worktrees) {
|
|
33
|
+
const worktrees = rawProject.worktrees ?? [];
|
|
34
|
+
if (worktrees.length === 0) {
|
|
35
|
+
if (opts.json) {
|
|
36
|
+
printJson([]);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
console.log(dim('No worktrees configured.'));
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const summaries = await Promise.all(worktrees.map(async (wt) => {
|
|
44
|
+
const overlaid = applyWorktreeOverlay(rawProject, wt.id);
|
|
45
|
+
let sliceProgress = '—';
|
|
46
|
+
const wtPath = wt.worktreePath ?? rawProject.projectPath;
|
|
47
|
+
if (overlaid.fileSlicePlan && wtPath) {
|
|
48
|
+
const planRelPath = resolveArtifactPath('fileSlicePlan', overlaid.fileSlicePlan);
|
|
49
|
+
if (planRelPath) {
|
|
50
|
+
try {
|
|
51
|
+
const planPath = join(wtPath, planRelPath);
|
|
52
|
+
const plan = await parseSlicePlan(planPath);
|
|
53
|
+
sliceProgress = `${plan.completedSlices}/${plan.totalSlices} slices`;
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Plan file may not exist on disk
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const isActive = wt.id === cwdWorktreeId;
|
|
61
|
+
return {
|
|
62
|
+
id: wt.id,
|
|
63
|
+
name: wt.name,
|
|
64
|
+
range: wt.indexRange ? `${wt.indexRange[0]}-${wt.indexRange[1]}` : '—',
|
|
65
|
+
phase: overlaid.developmentPhase || '—',
|
|
66
|
+
slice: overlaid.fileSlice || '—',
|
|
67
|
+
progress: sliceProgress,
|
|
68
|
+
isActive,
|
|
69
|
+
};
|
|
70
|
+
}));
|
|
71
|
+
if (opts.json) {
|
|
72
|
+
printJson(summaries);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
console.log(label('Project: ') + valueStyle(rawProject.name));
|
|
76
|
+
console.log('');
|
|
77
|
+
const rows = summaries.map((s) => {
|
|
78
|
+
const activeSuffix = s.isActive ? success(' ← active') : '';
|
|
79
|
+
return [s.name + activeSuffix, s.range, s.phase, s.slice, s.progress];
|
|
80
|
+
});
|
|
81
|
+
console.log(label('Worktrees'));
|
|
82
|
+
console.log(renderTable(['Name', 'Range', 'Phase', 'Slice', 'Progress'], rows));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// ── Single worktree / default status ───────────────────────────────
|
|
86
|
+
// Resolve worktree: explicit --worktree flag takes priority over CWD resolution
|
|
87
|
+
let resolvedWorktreeId = cwdWorktreeId;
|
|
88
|
+
if (opts.worktree) {
|
|
89
|
+
const wt = await findWorktreeByNameOrId(id, opts.worktree, store);
|
|
90
|
+
if (!wt) {
|
|
91
|
+
throw new UserError(`Worktree '${opts.worktree}' not found. Run cf worktree list to see available worktrees.`);
|
|
92
|
+
}
|
|
93
|
+
resolvedWorktreeId = wt.id;
|
|
94
|
+
}
|
|
95
|
+
// Apply worktree overlay so navigator and display use correct fields
|
|
96
|
+
const project = await resolveProject(store, id, resolvedWorktreeId);
|
|
97
|
+
if (!project) {
|
|
98
|
+
throw new UserError(`Project not found: '${id}'.`);
|
|
99
|
+
}
|
|
100
|
+
const worktreeCtx = resolvedWorktreeId
|
|
101
|
+
? (rawProject.worktrees ?? []).find((w) => w.id === resolvedWorktreeId)
|
|
102
|
+
: undefined;
|
|
103
|
+
const nav = new WorkflowNavigator();
|
|
104
|
+
const status = await nav.getStatus(project);
|
|
105
|
+
if (opts.json) {
|
|
106
|
+
printJson({ ...status, resolutionSource: source, ...(worktreeCtx ? { worktree: worktreeCtx } : {}) });
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const sourceLabels = {
|
|
110
|
+
flag: '(--project flag)',
|
|
111
|
+
cwd: '(from CWD)',
|
|
112
|
+
worktree: '(from CWD)',
|
|
113
|
+
default: '(default)',
|
|
114
|
+
none: '',
|
|
115
|
+
};
|
|
116
|
+
// When worktree is resolved, show a dedicated Worktree line instead of
|
|
117
|
+
// embedding worktree info in the Project line's source label.
|
|
118
|
+
const sourceLabel = sourceLabels[source];
|
|
119
|
+
const projectLine = sourceLabel
|
|
120
|
+
? `${valueStyle(status.project)} ${dim(sourceLabel)}`
|
|
121
|
+
: valueStyle(status.project);
|
|
122
|
+
console.log(label('Project: ') + projectLine);
|
|
123
|
+
if (worktreeCtx) {
|
|
124
|
+
const range = worktreeCtx.indexRange
|
|
125
|
+
? ` [${worktreeCtx.indexRange[0]}-${worktreeCtx.indexRange[1]}]`
|
|
126
|
+
: '';
|
|
127
|
+
console.log(label('Worktree: ') + valueStyle(`${worktreeCtx.name}${range}`));
|
|
128
|
+
}
|
|
129
|
+
console.log(label('Date: ') + valueStyle(project.dateProject || 'Not set'));
|
|
130
|
+
console.log(label('Phase: ') + valueStyle(status.phase ?? 'Not set'));
|
|
131
|
+
console.log(label('Arch: ') + valueStyle(project.fileArch || 'Not set'));
|
|
132
|
+
console.log(label('Plan: ') + valueStyle(project.fileSlicePlan || 'Not set'));
|
|
133
|
+
console.log(label('Slice: ') + valueStyle(project.fileSlice || 'Not set'));
|
|
134
|
+
console.log(label('Tasks: ') + valueStyle(project.fileTasks || 'Not set'));
|
|
135
|
+
if (status.activeSlice?.taskProgress) {
|
|
136
|
+
const { completed, total, inferredStatus } = status.activeSlice.taskProgress;
|
|
137
|
+
console.log(label('Progress: ') + valueStyle(`${completed}/${total} tasks (${inferredStatus})`));
|
|
138
|
+
}
|
|
139
|
+
if (status.activeSlice && status.activeSlice.status !== 'no-active-slice') {
|
|
140
|
+
console.log(label('Status: ') + valueStyle(status.activeSlice.status));
|
|
141
|
+
}
|
|
142
|
+
if (status.slicePlan) {
|
|
143
|
+
console.log('');
|
|
144
|
+
console.log(label('Slice Plan'));
|
|
145
|
+
console.log(dim(` ${status.slicePlan.completed}/${status.slicePlan.total} slices complete`));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch (err) {
|
|
149
|
+
// First-run messaging: suggest cf worktree init if CWD is a git worktree of a known project
|
|
150
|
+
if (err instanceof UserError) {
|
|
151
|
+
const shown = await showWorktreeSuggestion();
|
|
152
|
+
if (shown)
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
handleError(err);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* When project resolution fails, check if CWD is a git worktree of a known project.
|
|
161
|
+
* If so, display a helpful suggestion to create a worktree context.
|
|
162
|
+
* Returns true if a suggestion was displayed.
|
|
163
|
+
*/
|
|
164
|
+
async function showWorktreeSuggestion() {
|
|
165
|
+
try {
|
|
166
|
+
const discovery = new GitWorktreeDiscovery();
|
|
167
|
+
const gitWorktrees = await discovery.listWorktrees(process.cwd());
|
|
168
|
+
if (gitWorktrees.length === 0)
|
|
169
|
+
return false;
|
|
170
|
+
// Main worktree is the first entry from git worktree list
|
|
171
|
+
const mainWorktreePath = gitWorktrees[0].path;
|
|
172
|
+
// Check if main worktree path matches a registered project
|
|
173
|
+
const store = new FileProjectStore();
|
|
174
|
+
const projects = await store.getAll();
|
|
175
|
+
const matchingProject = projects.find((p) => p.projectPath === mainWorktreePath);
|
|
176
|
+
if (!matchingProject)
|
|
177
|
+
return false;
|
|
178
|
+
// Derive suggested name from current git branch
|
|
179
|
+
const currentBranch = gitWorktrees.find((wt) => {
|
|
180
|
+
const cwd = process.cwd();
|
|
181
|
+
return wt.path === cwd || cwd.startsWith(wt.path + '/');
|
|
182
|
+
})?.branch;
|
|
183
|
+
let suggestedName = 'my-worktree';
|
|
184
|
+
if (currentBranch) {
|
|
185
|
+
// Strip refs/heads/ and common prefixes like feature/, bugfix/
|
|
186
|
+
suggestedName = currentBranch
|
|
187
|
+
.replace(/^refs\/heads\//, '')
|
|
188
|
+
.replace(/^(feature|bugfix|hotfix|fix|chore|refactor)\//, '');
|
|
189
|
+
}
|
|
190
|
+
// Suggest next available 100-block range
|
|
191
|
+
const existingWorktrees = matchingProject.worktrees ?? [];
|
|
192
|
+
let maxEnd = 99;
|
|
193
|
+
for (const wt of existingWorktrees) {
|
|
194
|
+
if (wt.indexRange[1] > maxEnd)
|
|
195
|
+
maxEnd = wt.indexRange[1];
|
|
196
|
+
}
|
|
197
|
+
const rangeStart = Math.ceil((maxEnd + 1) / 100) * 100;
|
|
198
|
+
const rangeEnd = rangeStart + 99;
|
|
199
|
+
console.log('');
|
|
200
|
+
console.log(warn(`This directory appears to be a git worktree of project '${matchingProject.name}'.`));
|
|
201
|
+
console.log(`Create a worktree context: ${dim(`cf worktree init --name '${suggestedName}' --range ${rangeStart}-${rangeEnd}`)}`);
|
|
202
|
+
console.log('');
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Shared action handler for listing task files. */
|
|
2
|
+
export declare function taskListAction(opts: {
|
|
3
|
+
json?: boolean;
|
|
4
|
+
all?: boolean;
|
|
5
|
+
project?: string;
|
|
6
|
+
}): Promise<void>;
|
|
7
|
+
/** Shared action handler for listing task items from the active task file. */
|
|
8
|
+
export declare function taskItemsAction(opts: {
|
|
9
|
+
json?: boolean;
|
|
10
|
+
project?: string;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
//# sourceMappingURL=task.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../../src/commands/task.ts"],"names":[],"mappings":"AAgBA,oDAAoD;AACpD,wBAAsB,cAAc,CAAC,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA4B7G;AAED,8EAA8E;AAC9E,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB/F"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { readdir } from 'node:fs/promises';
|
|
3
|
+
import { FileProjectStore, resolveArtifactPath, extractSliceIndex, parseSlicePlan, parseTaskFile, } from '@context-forge/core/node';
|
|
4
|
+
import { resolveProjectWorktree } from '../utils/project.js';
|
|
5
|
+
import { resolveProject } from '@context-forge/core';
|
|
6
|
+
import { resolveOperationPath, getWorktreeIndexRange, isInIndexRange, resolveAllOperationPaths } from '../utils/worktree-overlay.js';
|
|
7
|
+
import { UserError } from '../utils/errors.js';
|
|
8
|
+
import { printJson } from '../output/formatter.js';
|
|
9
|
+
import { label, success, dim } from '../output/styles.js';
|
|
10
|
+
/** Shared action handler for listing task files. */
|
|
11
|
+
export async function taskListAction(opts) {
|
|
12
|
+
const store = new FileProjectStore();
|
|
13
|
+
const { id, worktreeId } = await resolveProjectWorktree({ project: opts.project }, store);
|
|
14
|
+
const rawProject = await store.getById(id);
|
|
15
|
+
if (!rawProject) {
|
|
16
|
+
throw new UserError(`Project not found: '${id}'.`);
|
|
17
|
+
}
|
|
18
|
+
const project = await resolveProject(store, id, worktreeId);
|
|
19
|
+
if (!project) {
|
|
20
|
+
throw new UserError(`Project not found: '${id}'.`);
|
|
21
|
+
}
|
|
22
|
+
if (!project.projectPath) {
|
|
23
|
+
throw new UserError('No projectPath configured. Set one with: cf set projectPath /path/to/project');
|
|
24
|
+
}
|
|
25
|
+
if (opts.all && rawProject.worktrees?.length) {
|
|
26
|
+
const paths = resolveAllOperationPaths(rawProject);
|
|
27
|
+
await listTaskFiles(project, paths, undefined, opts.json);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
const operationPath = resolveOperationPath(project, worktreeId) ?? project.projectPath;
|
|
31
|
+
const indexRange = getWorktreeIndexRange(rawProject, worktreeId);
|
|
32
|
+
await listTaskFiles(project, [operationPath], indexRange, opts.json);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** Shared action handler for listing task items from the active task file. */
|
|
36
|
+
export async function taskItemsAction(opts) {
|
|
37
|
+
const store = new FileProjectStore();
|
|
38
|
+
const { id, worktreeId } = await resolveProjectWorktree({ project: opts.project }, store);
|
|
39
|
+
const project = await resolveProject(store, id, worktreeId);
|
|
40
|
+
if (!project) {
|
|
41
|
+
throw new UserError(`Project not found: '${id}'.`);
|
|
42
|
+
}
|
|
43
|
+
if (!project.projectPath) {
|
|
44
|
+
throw new UserError('No projectPath configured. Set one with: cf set projectPath /path/to/project');
|
|
45
|
+
}
|
|
46
|
+
const operationPath = resolveOperationPath(project, worktreeId) ?? project.projectPath;
|
|
47
|
+
await listTaskItems(project, operationPath, opts.json);
|
|
48
|
+
}
|
|
49
|
+
async function listTaskItems(project, operationPath, json) {
|
|
50
|
+
if (!project.fileTasks) {
|
|
51
|
+
throw new UserError('No task file configured. Set one with: cf set tasks <filename>');
|
|
52
|
+
}
|
|
53
|
+
const taskRelPath = resolveArtifactPath('fileTasks', project.fileTasks);
|
|
54
|
+
if (!taskRelPath) {
|
|
55
|
+
throw new UserError('Could not resolve task file path.');
|
|
56
|
+
}
|
|
57
|
+
// Detect split task files via index
|
|
58
|
+
const sliceIndex = extractSliceIndex(project.fileSlice);
|
|
59
|
+
let taskPaths;
|
|
60
|
+
if (sliceIndex !== null) {
|
|
61
|
+
const tasksDir = join(operationPath, 'project-documents/user/tasks');
|
|
62
|
+
try {
|
|
63
|
+
const files = await readdir(tasksDir);
|
|
64
|
+
const matching = files
|
|
65
|
+
.filter((f) => f.startsWith(`${sliceIndex}-tasks.`) && f.endsWith('.md'))
|
|
66
|
+
.sort()
|
|
67
|
+
.map((f) => join(tasksDir, f));
|
|
68
|
+
taskPaths = matching.length > 0 ? matching : [join(operationPath, taskRelPath)];
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
taskPaths = [join(operationPath, taskRelPath)];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
taskPaths = [join(operationPath, taskRelPath)];
|
|
76
|
+
}
|
|
77
|
+
const taskResult = await parseTaskFile(taskPaths);
|
|
78
|
+
if (json) {
|
|
79
|
+
printJson(taskResult);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const fileName = project.fileTasks.split('/').pop() ?? project.fileTasks;
|
|
83
|
+
console.log(label(`\nTasks: ${fileName}`) +
|
|
84
|
+
dim(` (${taskResult.completedTasks}/${taskResult.totalTasks} complete)`));
|
|
85
|
+
for (const item of taskResult.items) {
|
|
86
|
+
const icon = item.done ? success(' ✓ ') : dim(' ○ ');
|
|
87
|
+
const text = item.done ? dim(item.name) : item.name;
|
|
88
|
+
console.log(icon + text);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async function listTaskFiles(project, operationPaths, indexRange, json) {
|
|
92
|
+
if (!project.fileSlicePlan) {
|
|
93
|
+
throw new UserError('No slice plan configured. Set one with: cf set slicePlan <path>');
|
|
94
|
+
}
|
|
95
|
+
const planRelPath = resolveArtifactPath('fileSlicePlan', project.fileSlicePlan);
|
|
96
|
+
if (!planRelPath) {
|
|
97
|
+
throw new UserError('Could not resolve slice plan path.');
|
|
98
|
+
}
|
|
99
|
+
// Try to find the plan file across operation paths
|
|
100
|
+
let plan;
|
|
101
|
+
for (const op of operationPaths) {
|
|
102
|
+
try {
|
|
103
|
+
plan = await parseSlicePlan(join(op, planRelPath));
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (!plan) {
|
|
111
|
+
throw new UserError('Could not resolve slice plan path.');
|
|
112
|
+
}
|
|
113
|
+
const activeIndex = extractSliceIndex(project.fileSlice);
|
|
114
|
+
// Collect task files from all operation paths, deduplicate by filename
|
|
115
|
+
const fileMap = new Map(); // filename -> full path to tasks dir
|
|
116
|
+
for (const op of operationPaths) {
|
|
117
|
+
const tasksDir = join(op, 'project-documents/user/tasks');
|
|
118
|
+
try {
|
|
119
|
+
const files = await readdir(tasksDir);
|
|
120
|
+
for (const f of files) {
|
|
121
|
+
if (!fileMap.has(f))
|
|
122
|
+
fileMap.set(f, tasksDir);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (fileMap.size === 0) {
|
|
130
|
+
if (json) {
|
|
131
|
+
console.log(JSON.stringify([]));
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
console.log('No task files found.');
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const summaries = [];
|
|
138
|
+
// Skip range filtering when the plan itself is outside the range
|
|
139
|
+
const planBaseIndex = /^(\d+)-/.exec(project.fileSlicePlan ?? '')?.[1];
|
|
140
|
+
const planOutsideRange = planBaseIndex && indexRange && !isInIndexRange(parseInt(planBaseIndex, 10), indexRange);
|
|
141
|
+
const filteredEntries = planOutsideRange
|
|
142
|
+
? plan.entries
|
|
143
|
+
: plan.entries.filter((e) => isInIndexRange(e.index, indexRange));
|
|
144
|
+
for (const entry of filteredEntries) {
|
|
145
|
+
const matching = [...fileMap.entries()]
|
|
146
|
+
.filter(([f]) => f.startsWith(`${entry.index}-tasks.`) && f.endsWith('.md'))
|
|
147
|
+
.sort(([a], [b]) => a.localeCompare(b));
|
|
148
|
+
if (matching.length === 0)
|
|
149
|
+
continue;
|
|
150
|
+
const paths = matching.map(([f, dir]) => join(dir, f));
|
|
151
|
+
try {
|
|
152
|
+
const result = await parseTaskFile(paths);
|
|
153
|
+
summaries.push({
|
|
154
|
+
index: entry.index,
|
|
155
|
+
name: entry.name,
|
|
156
|
+
files: matching.map(([f]) => f),
|
|
157
|
+
completed: result.completedTasks,
|
|
158
|
+
total: result.totalTasks,
|
|
159
|
+
isActive: entry.index === activeIndex,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
summaries.push({
|
|
164
|
+
index: entry.index,
|
|
165
|
+
name: entry.name,
|
|
166
|
+
files: matching.map(([f]) => f),
|
|
167
|
+
completed: 0,
|
|
168
|
+
total: 0,
|
|
169
|
+
isActive: entry.index === activeIndex,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (json) {
|
|
174
|
+
printJson(summaries);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
console.log(label('\nTask Files'));
|
|
178
|
+
for (const s of summaries) {
|
|
179
|
+
const active = s.isActive ? success(' ← active') : '';
|
|
180
|
+
const progress = s.total > 0 ? dim(` (${s.completed}/${s.total})`) : dim(' (empty)');
|
|
181
|
+
const icon = s.total > 0 && s.completed === s.total ? success(' ✓ ') : dim(' ○ ');
|
|
182
|
+
console.log(icon + `${s.index} ${s.name}` + progress + active);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=task.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task.js","sourceRoot":"","sources":["../../src/commands/task.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* Compare two semver strings (major.minor.patch).
|
|
4
|
+
* Returns -1 if a < b, 0 if equal, 1 if a > b.
|
|
5
|
+
*/
|
|
6
|
+
export declare function compareSemver(a: string, b: string): number;
|
|
7
|
+
/**
|
|
8
|
+
* Fetch the latest published version of a package from the npm registry.
|
|
9
|
+
* Returns null on any failure (network, non-200, malformed JSON).
|
|
10
|
+
*/
|
|
11
|
+
export declare function fetchLatestVersion(packageName: string): Promise<string | null>;
|
|
12
|
+
/**
|
|
13
|
+
* Detect how cf was installed globally.
|
|
14
|
+
* Returns the package manager method and whether this is a local/dev install.
|
|
15
|
+
*/
|
|
16
|
+
export declare function detectInstallMethod(): {
|
|
17
|
+
method: 'npm' | 'pnpm' | 'unknown';
|
|
18
|
+
isLocal: boolean;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Run the global install command to update the CLI package.
|
|
22
|
+
* Uses execSync so the user sees output directly. Throws on failure.
|
|
23
|
+
*/
|
|
24
|
+
export declare function runUpdate(method: 'npm' | 'pnpm'): void;
|
|
25
|
+
/** Register the `cf update` command. */
|
|
26
|
+
export declare function registerUpdateCommand(program: Command): void;
|
|
27
|
+
//# sourceMappingURL=update.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAU1D;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAgBpF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI;IAAE,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CA4B9F;AAcD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,IAAI,CAKtD;AAED,wCAAwC;AACxC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA4E5D"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { execSync } from 'node:child_process';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import { dirname, join, resolve } from 'node:path';
|
|
5
|
+
import { handleError } from '../utils/errors.js';
|
|
6
|
+
import { withJsonOption, withYesOption } from '../options.js';
|
|
7
|
+
import { askConfirmation } from '../utils/confirm.js';
|
|
8
|
+
import { printJson } from '../output/formatter.js';
|
|
9
|
+
import { label, value, dim, success, warn } from '../output/styles.js';
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
11
|
+
const { version: currentVersion } = require('../../package.json');
|
|
12
|
+
/**
|
|
13
|
+
* Compare two semver strings (major.minor.patch).
|
|
14
|
+
* Returns -1 if a < b, 0 if equal, 1 if a > b.
|
|
15
|
+
*/
|
|
16
|
+
export function compareSemver(a, b) {
|
|
17
|
+
const partsA = a.split('.').map(Number);
|
|
18
|
+
const partsB = b.split('.').map(Number);
|
|
19
|
+
for (let i = 0; i < 3; i++) {
|
|
20
|
+
const segA = partsA[i] ?? 0;
|
|
21
|
+
const segB = partsB[i] ?? 0;
|
|
22
|
+
if (segA < segB)
|
|
23
|
+
return -1;
|
|
24
|
+
if (segA > segB)
|
|
25
|
+
return 1;
|
|
26
|
+
}
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Fetch the latest published version of a package from the npm registry.
|
|
31
|
+
* Returns null on any failure (network, non-200, malformed JSON).
|
|
32
|
+
*/
|
|
33
|
+
export async function fetchLatestVersion(packageName) {
|
|
34
|
+
try {
|
|
35
|
+
const response = await globalThis.fetch(`https://registry.npmjs.org/${packageName}/latest`, { signal: AbortSignal.timeout(10_000) });
|
|
36
|
+
if (!response.ok)
|
|
37
|
+
return null;
|
|
38
|
+
const data = await response.json();
|
|
39
|
+
if (typeof data === 'object' && data !== null && 'version' in data) {
|
|
40
|
+
const ver = data.version;
|
|
41
|
+
if (typeof ver === 'string')
|
|
42
|
+
return ver;
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Detect how cf was installed globally.
|
|
52
|
+
* Returns the package manager method and whether this is a local/dev install.
|
|
53
|
+
*/
|
|
54
|
+
export function detectInstallMethod() {
|
|
55
|
+
const scriptPath = process.argv[1] ?? '';
|
|
56
|
+
// pnpm global install (check first — pnpm global paths also contain node_modules)
|
|
57
|
+
if (scriptPath.includes('.pnpm') || scriptPath.includes('pnpm/global')) {
|
|
58
|
+
return { method: 'pnpm', isLocal: false };
|
|
59
|
+
}
|
|
60
|
+
// Check for global npm install (system-level node_modules)
|
|
61
|
+
const isGlobalNpm = /\/(usr|opt)\/(local\/)?lib\/node_modules\//.test(scriptPath)
|
|
62
|
+
|| /\/lib\/node_modules\//.test(scriptPath);
|
|
63
|
+
if (isGlobalNpm) {
|
|
64
|
+
return { method: 'npm', isLocal: false };
|
|
65
|
+
}
|
|
66
|
+
// Local/dev install: project-local node_modules or relative path
|
|
67
|
+
if (scriptPath.includes('node_modules') || !scriptPath.startsWith('/')) {
|
|
68
|
+
return { method: 'unknown', isLocal: true };
|
|
69
|
+
}
|
|
70
|
+
// Heuristic: if a package.json exists in the script's ancestor directories
|
|
71
|
+
// (within 4 levels), this is likely a local dev install (e.g., `node packages/cli/dist/index.js`)
|
|
72
|
+
if (isLocalDevPath(scriptPath)) {
|
|
73
|
+
return { method: 'unknown', isLocal: true };
|
|
74
|
+
}
|
|
75
|
+
// Default to npm global (absolute path not matching known patterns)
|
|
76
|
+
return { method: 'npm', isLocal: false };
|
|
77
|
+
}
|
|
78
|
+
/** Check if the script path is under a local project by looking for package.json nearby. */
|
|
79
|
+
function isLocalDevPath(scriptPath) {
|
|
80
|
+
let dir = dirname(resolve(scriptPath));
|
|
81
|
+
for (let i = 0; i < 4; i++) {
|
|
82
|
+
if (existsSync(join(dir, 'package.json')))
|
|
83
|
+
return true;
|
|
84
|
+
const parent = dirname(dir);
|
|
85
|
+
if (parent === dir)
|
|
86
|
+
break;
|
|
87
|
+
dir = parent;
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Run the global install command to update the CLI package.
|
|
93
|
+
* Uses execSync so the user sees output directly. Throws on failure.
|
|
94
|
+
*/
|
|
95
|
+
export function runUpdate(method) {
|
|
96
|
+
const cmd = method === 'pnpm'
|
|
97
|
+
? 'pnpm add -g @context-forge/cli@latest'
|
|
98
|
+
: 'npm install -g @context-forge/cli@latest';
|
|
99
|
+
execSync(cmd, { stdio: 'inherit' });
|
|
100
|
+
}
|
|
101
|
+
/** Register the `cf update` command. */
|
|
102
|
+
export function registerUpdateCommand(program) {
|
|
103
|
+
const updateCmd = program
|
|
104
|
+
.command('update')
|
|
105
|
+
.description('Check for updates and install the latest version');
|
|
106
|
+
withYesOption(updateCmd);
|
|
107
|
+
withJsonOption(updateCmd);
|
|
108
|
+
updateCmd.action(async (opts) => {
|
|
109
|
+
try {
|
|
110
|
+
const install = detectInstallMethod();
|
|
111
|
+
// Local/dev install — skip update
|
|
112
|
+
if (install.isLocal) {
|
|
113
|
+
console.log(warn('Local development install detected — skipping self-update.'));
|
|
114
|
+
console.log(dim(' To update, pull the latest changes and rebuild.'));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
// Fetch latest version from npm
|
|
118
|
+
const latest = await fetchLatestVersion('@context-forge/cli');
|
|
119
|
+
if (!latest) {
|
|
120
|
+
handleError(new Error('Could not reach npm registry — check your network connection.'));
|
|
121
|
+
}
|
|
122
|
+
const cmp = compareSemver(currentVersion, latest);
|
|
123
|
+
// JSON output — no side effects
|
|
124
|
+
if (opts.json) {
|
|
125
|
+
printJson({
|
|
126
|
+
current: currentVersion,
|
|
127
|
+
latest,
|
|
128
|
+
updateAvailable: cmp < 0,
|
|
129
|
+
installMethod: install.method,
|
|
130
|
+
});
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
// Already up to date
|
|
134
|
+
if (cmp >= 0) {
|
|
135
|
+
console.log(success(`@context-forge/cli v${currentVersion} is up to date.`));
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
// Update available
|
|
139
|
+
console.log(`${label('Update available:')} ${value(currentVersion)} → ${value(latest)}`);
|
|
140
|
+
console.log('');
|
|
141
|
+
const isTTY = process.stdin.isTTY;
|
|
142
|
+
if (opts.yes) {
|
|
143
|
+
// --yes: proceed without prompt
|
|
144
|
+
}
|
|
145
|
+
else if (isTTY) {
|
|
146
|
+
// Interactive: prompt
|
|
147
|
+
const confirmed = await askConfirmation('Install now? (y/N) ');
|
|
148
|
+
if (!confirmed) {
|
|
149
|
+
console.log(dim('Update skipped.'));
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
// Non-TTY without --yes: inform and exit
|
|
155
|
+
console.log(dim('Run with --yes to install non-interactively.'));
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (install.method === 'unknown') {
|
|
159
|
+
console.log(warn('Could not determine install method. Run manually:'));
|
|
160
|
+
console.log(dim(' npm install -g @context-forge/cli@latest'));
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
runUpdate(install.method);
|
|
164
|
+
console.log('');
|
|
165
|
+
console.log(success(`✓ Updated @context-forge/cli to ${latest}`));
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
handleError(err);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=update.js.map
|