sidecar-cli 0.1.5-beta.2 → 0.1.6-beta.1
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 +20 -8
- package/dist/cli.js +61 -2
- package/dist/services/capabilities-service.js +7 -0
- package/dist/services/task-status-service.js +33 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -79,6 +79,18 @@ Run locally in dev mode:
|
|
|
79
79
|
npm run dev -- --help
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
+
## Release channels
|
|
83
|
+
|
|
84
|
+
Sidecar ships features through `beta` → `rc` → `stable` as version bumps — there are no per-feature channel flags. Install `@beta` to try new features early; install default (stable) for the latest promoted release.
|
|
85
|
+
|
|
86
|
+
| Channel | Current version | Notes |
|
|
87
|
+
| --- | --- | --- |
|
|
88
|
+
| stable (`latest`) | `0.1.4` | Promoted releases. Homebrew tracks this channel. |
|
|
89
|
+
| rc | _none newer than stable_ | Release candidates published only when preparing a stable cut. |
|
|
90
|
+
| beta | `0.1.5-beta.2` | Dual-runner pipelines, run replay, ambient capture via Claude Code hooks, typed validation + auto-approve, freestanding prompt specs, `sidecar demo`. |
|
|
91
|
+
|
|
92
|
+
Per-version release notes live at [github.com/karlhills/sidecar-cli/releases](https://github.com/karlhills/sidecar-cli/releases).
|
|
93
|
+
|
|
82
94
|
## Quick start
|
|
83
95
|
|
|
84
96
|
1. Initialize in a project directory:
|
|
@@ -188,9 +200,9 @@ Notes, decisions, worklogs:
|
|
|
188
200
|
|
|
189
201
|
Tasks:
|
|
190
202
|
|
|
191
|
-
- `sidecar task
|
|
192
|
-
- `sidecar task
|
|
193
|
-
- `sidecar task list [--status
|
|
203
|
+
- `sidecar task create --title "<title>" --summary "<summary>" --goal "<goal>" [--type feature|bug|chore|research] [--status draft|ready|queued|running|review|blocked|done] [--priority low|medium|high] [--json]`
|
|
204
|
+
- `sidecar task set-status <task-id> --to draft|ready|queued|running|review|blocked|done --reason "<text>" [--by human|agent] [--session <id>] [--json]`
|
|
205
|
+
- `sidecar task list [--status draft|ready|queued|running|review|blocked|done|all] [--json]`
|
|
194
206
|
|
|
195
207
|
Sessions:
|
|
196
208
|
|
|
@@ -422,7 +434,7 @@ sidecar context --format markdown
|
|
|
422
434
|
sidecar session start --actor agent --name codex
|
|
423
435
|
sidecar decision record --title "Use SQLite" --summary "Local-first persistence"
|
|
424
436
|
sidecar worklog record --goal "init flow" --done "Implemented schema and command surface" --files src/cli.ts,src/db/schema.ts
|
|
425
|
-
sidecar task
|
|
437
|
+
sidecar task create --title "Add integration tests" --summary "Add integration coverage for init flow" --goal "Ensure init flow has regression coverage" --priority medium
|
|
426
438
|
sidecar summary refresh
|
|
427
439
|
sidecar session end --summary "Initialization and recording flow implemented"
|
|
428
440
|
```
|
|
@@ -437,7 +449,7 @@ Required minimum for any code change:
|
|
|
437
449
|
1. `sidecar context --format markdown`
|
|
438
450
|
2. `sidecar worklog record --done "<what changed>" --files <paths> --by agent`
|
|
439
451
|
3. if behavior/design changed: `sidecar decision record ...`
|
|
440
|
-
4. if follow-up exists: `sidecar task
|
|
452
|
+
4. if follow-up exists: `sidecar task create ...`
|
|
441
453
|
5. `sidecar summary refresh`
|
|
442
454
|
|
|
443
455
|
Optional local enforcement:
|
|
@@ -477,7 +489,7 @@ When changes are made in this repo, document them in Sidecar:
|
|
|
477
489
|
1. `sidecar context --format markdown`
|
|
478
490
|
2. `sidecar worklog record --done "<what changed>" --files <paths> --by human|agent`
|
|
479
491
|
3. `sidecar decision record ...` when behavior/design changes
|
|
480
|
-
4. `sidecar task
|
|
492
|
+
4. `sidecar task create ...` for follow-up work
|
|
481
493
|
5. `sidecar summary refresh`
|
|
482
494
|
|
|
483
495
|
## Local storage details
|
|
@@ -567,7 +579,7 @@ Standard JSON envelope:
|
|
|
567
579
|
{
|
|
568
580
|
"ok": true,
|
|
569
581
|
"version": "1.0",
|
|
570
|
-
"command": "task
|
|
582
|
+
"command": "task create",
|
|
571
583
|
"data": {},
|
|
572
584
|
"errors": []
|
|
573
585
|
}
|
|
@@ -579,7 +591,7 @@ Failure envelope:
|
|
|
579
591
|
{
|
|
580
592
|
"ok": false,
|
|
581
593
|
"version": "1.0",
|
|
582
|
-
"command": "task
|
|
594
|
+
"command": "task create",
|
|
583
595
|
"data": null,
|
|
584
596
|
"errors": ["..."]
|
|
585
597
|
}
|
package/dist/cli.js
CHANGED
|
@@ -22,7 +22,7 @@ import { refreshSummaryFile } from './services/summary-service.js';
|
|
|
22
22
|
import { buildContext } from './services/context-service.js';
|
|
23
23
|
import { getCapabilitiesManifest } from './services/capabilities-service.js';
|
|
24
24
|
import { addArtifact, listArtifacts } from './services/artifact-service.js';
|
|
25
|
-
import { addDecision, addNote, addWorklog, getActiveSessionId, listRecentEvents } from './services/event-service.js';
|
|
25
|
+
import { addDecision, addNote, addWorklog, createEvent, getActiveSessionId, listRecentEvents } from './services/event-service.js';
|
|
26
26
|
import { currentSession, endSession, startSession, verifySessionHygiene } from './services/session-service.js';
|
|
27
27
|
import { HOOK_EVENTS, handleHookEvent, hookEventSchema, hookPayloadSchema } from './services/hook-service.js';
|
|
28
28
|
import { loadPromptSpec } from './prompts/prompt-spec.js';
|
|
@@ -39,6 +39,7 @@ import { compileTaskPrompt } from './prompts/prompt-service.js';
|
|
|
39
39
|
import { runPipelineExecution, runTaskExecution } from './services/run-orchestrator-service.js';
|
|
40
40
|
import { loadRunnerPreferences } from './runners/config.js';
|
|
41
41
|
import { assignTask, queueReadyTasks } from './services/task-orchestration-service.js';
|
|
42
|
+
import { transitionTaskStatus } from './services/task-status-service.js';
|
|
42
43
|
import { buildReviewSummary, createFollowupTaskFromRun, reviewRun } from './services/run-review-service.js';
|
|
43
44
|
const pkg = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
|
|
44
45
|
const actorSchema = z.enum(['human', 'agent']);
|
|
@@ -1100,7 +1101,7 @@ task
|
|
|
1100
1101
|
.description('List task packets')
|
|
1101
1102
|
.option('--status <status>', 'draft|ready|queued|running|review|blocked|done|all', 'all')
|
|
1102
1103
|
.option('--json', 'Print machine-readable JSON output')
|
|
1103
|
-
.addHelpText('after', '\nExamples:\n $ sidecar task list\n $ sidecar task list --status
|
|
1104
|
+
.addHelpText('after', '\nExamples:\n $ sidecar task list\n $ sidecar task list --status draft\n $ sidecar task list --json')
|
|
1104
1105
|
.action((opts) => {
|
|
1105
1106
|
const command = 'task list';
|
|
1106
1107
|
try {
|
|
@@ -1158,6 +1159,64 @@ task
|
|
|
1158
1159
|
handleCommandError(command, Boolean(opts.json), err);
|
|
1159
1160
|
}
|
|
1160
1161
|
});
|
|
1162
|
+
task
|
|
1163
|
+
.command('set-status <task-id>')
|
|
1164
|
+
.description('Transition task packet status with validation and an audit note')
|
|
1165
|
+
.requiredOption('--to <status>', 'draft|ready|queued|running|review|blocked|done')
|
|
1166
|
+
.requiredOption('--reason <text>', 'Why this manual transition is needed')
|
|
1167
|
+
.option('--by <actor>', 'human|agent', 'human')
|
|
1168
|
+
.option('--session <session-id>', 'Session id override')
|
|
1169
|
+
.option('--json', 'Print machine-readable JSON output')
|
|
1170
|
+
.addHelpText('after', '\nExamples:\n $ sidecar task set-status T-001 --to ready --reason "Ready to queue"\n $ sidecar task set-status T-001 --to done --reason "Administrative cleanup" --by agent --json')
|
|
1171
|
+
.action((taskIdText, opts) => {
|
|
1172
|
+
const command = 'task set-status';
|
|
1173
|
+
try {
|
|
1174
|
+
const taskId = taskIdText.trim().toUpperCase();
|
|
1175
|
+
const toStatus = taskPacketStatusSchema.parse(opts.to);
|
|
1176
|
+
const reason = String(opts.reason ?? '').trim();
|
|
1177
|
+
if (!reason)
|
|
1178
|
+
fail('Reason is required');
|
|
1179
|
+
const by = actorSchema.parse(opts.by);
|
|
1180
|
+
const { db, projectId } = requireInitialized();
|
|
1181
|
+
const sessionId = maybeSessionId(db, projectId, opts.session);
|
|
1182
|
+
const result = transitionTaskStatus(resolveProjectRoot(), taskId, toStatus);
|
|
1183
|
+
const eventId = createEvent(db, {
|
|
1184
|
+
projectId,
|
|
1185
|
+
type: 'note',
|
|
1186
|
+
title: `Task ${result.task_id} status changed`,
|
|
1187
|
+
summary: `${result.from_status} -> ${result.to_status}: ${reason}`,
|
|
1188
|
+
details: {
|
|
1189
|
+
task_id: result.task_id,
|
|
1190
|
+
from_status: result.from_status,
|
|
1191
|
+
to_status: result.to_status,
|
|
1192
|
+
reason,
|
|
1193
|
+
command: 'task set-status',
|
|
1194
|
+
},
|
|
1195
|
+
createdBy: by,
|
|
1196
|
+
sessionId,
|
|
1197
|
+
});
|
|
1198
|
+
db.close();
|
|
1199
|
+
respondSuccess(command, Boolean(opts.json), {
|
|
1200
|
+
task: result,
|
|
1201
|
+
event: {
|
|
1202
|
+
id: eventId,
|
|
1203
|
+
type: 'note',
|
|
1204
|
+
title: `Task ${result.task_id} status changed`,
|
|
1205
|
+
summary: `${result.from_status} -> ${result.to_status}: ${reason}`,
|
|
1206
|
+
created_by: by,
|
|
1207
|
+
session_id: sessionId,
|
|
1208
|
+
created_at: nowIso(),
|
|
1209
|
+
},
|
|
1210
|
+
}, [
|
|
1211
|
+
`Updated ${result.task_id}: ${result.from_status} -> ${result.to_status}.`,
|
|
1212
|
+
`Reason: ${reason}`,
|
|
1213
|
+
`Recorded note event #${eventId}.`,
|
|
1214
|
+
]);
|
|
1215
|
+
}
|
|
1216
|
+
catch (err) {
|
|
1217
|
+
handleCommandError(command, Boolean(opts.json), err);
|
|
1218
|
+
}
|
|
1219
|
+
});
|
|
1161
1220
|
task
|
|
1162
1221
|
.command('create-followup <run-id>')
|
|
1163
1222
|
.description('Create a follow-up task packet from a run report')
|
|
@@ -222,6 +222,13 @@ export function getCapabilitiesManifest(version) {
|
|
|
222
222
|
arguments: ['<task-id>'],
|
|
223
223
|
options: ['--agent-role planner|builder-ui|builder-app|reviewer|tester', '--runner codex|claude', '--json'],
|
|
224
224
|
},
|
|
225
|
+
{
|
|
226
|
+
name: 'set-status',
|
|
227
|
+
description: 'Transition task packet status with validation',
|
|
228
|
+
json_output: true,
|
|
229
|
+
arguments: ['<task-id>'],
|
|
230
|
+
options: ['--to draft|ready|queued|running|review|blocked|done', '--reason <text>', '--by human|agent', '--session <id>', '--json'],
|
|
231
|
+
},
|
|
225
232
|
{
|
|
226
233
|
name: 'create-followup',
|
|
227
234
|
description: 'Create follow-up task from run report',
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { SidecarError } from '../lib/errors.js';
|
|
2
|
+
import { getTaskPacket, saveTaskPacket } from '../tasks/task-service.js';
|
|
3
|
+
const TASK_STATUS_TRANSITIONS = {
|
|
4
|
+
draft: ['ready', 'blocked', 'done'],
|
|
5
|
+
ready: ['draft', 'queued', 'blocked', 'done'],
|
|
6
|
+
queued: ['ready', 'running', 'blocked'],
|
|
7
|
+
running: ['ready', 'review', 'blocked'],
|
|
8
|
+
review: ['ready', 'blocked', 'done'],
|
|
9
|
+
blocked: ['ready', 'done'],
|
|
10
|
+
done: ['review'],
|
|
11
|
+
};
|
|
12
|
+
export function allowedTaskStatusTransitions(fromStatus) {
|
|
13
|
+
return TASK_STATUS_TRANSITIONS[fromStatus];
|
|
14
|
+
}
|
|
15
|
+
export function transitionTaskStatus(rootPath, taskId, toStatus) {
|
|
16
|
+
const task = getTaskPacket(rootPath, taskId);
|
|
17
|
+
const fromStatus = task.status;
|
|
18
|
+
if (fromStatus === toStatus) {
|
|
19
|
+
throw new SidecarError(`Task ${task.task_id} is already '${toStatus}'`);
|
|
20
|
+
}
|
|
21
|
+
const allowed = allowedTaskStatusTransitions(fromStatus);
|
|
22
|
+
if (!allowed.includes(toStatus)) {
|
|
23
|
+
throw new SidecarError(`Invalid status transition for ${task.task_id}: ${fromStatus} -> ${toStatus}. Allowed: ${allowed.join(', ')}`);
|
|
24
|
+
}
|
|
25
|
+
const updated = { ...task, status: toStatus };
|
|
26
|
+
const filePath = saveTaskPacket(rootPath, updated);
|
|
27
|
+
return {
|
|
28
|
+
task_id: task.task_id,
|
|
29
|
+
from_status: fromStatus,
|
|
30
|
+
to_status: toStatus,
|
|
31
|
+
path: filePath,
|
|
32
|
+
};
|
|
33
|
+
}
|