@kamilmarzynski/scifi 0.1.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/LICENSE +21 -0
- package/README.md +232 -0
- package/dist/skills/sf-bug/manifest.d.ts +2 -0
- package/dist/skills/sf-bug/manifest.js +6 -0
- package/dist/skills/sf-bug/manifest.js.map +1 -0
- package/dist/skills/sf-change/manifest.d.ts +2 -0
- package/dist/skills/sf-change/manifest.js +6 -0
- package/dist/skills/sf-change/manifest.js.map +1 -0
- package/dist/skills/sf-code-review/manifest.d.ts +2 -0
- package/dist/skills/sf-code-review/manifest.js +5 -0
- package/dist/skills/sf-code-review/manifest.js.map +1 -0
- package/dist/skills/sf-continue/manifest.d.ts +2 -0
- package/dist/skills/sf-continue/manifest.js +6 -0
- package/dist/skills/sf-continue/manifest.js.map +1 -0
- package/dist/skills/sf-feature/manifest.d.ts +2 -0
- package/dist/skills/sf-feature/manifest.js +6 -0
- package/dist/skills/sf-feature/manifest.js.map +1 -0
- package/dist/skills/sf-fix/manifest.d.ts +2 -0
- package/dist/skills/sf-fix/manifest.js +6 -0
- package/dist/skills/sf-fix/manifest.js.map +1 -0
- package/dist/skills/sf-handover/manifest.d.ts +2 -0
- package/dist/skills/sf-handover/manifest.js +5 -0
- package/dist/skills/sf-handover/manifest.js.map +1 -0
- package/dist/skills/sf-implement/manifest.d.ts +2 -0
- package/dist/skills/sf-implement/manifest.js +6 -0
- package/dist/skills/sf-implement/manifest.js.map +1 -0
- package/dist/skills/sf-plan/manifest.d.ts +2 -0
- package/dist/skills/sf-plan/manifest.js +6 -0
- package/dist/skills/sf-plan/manifest.js.map +1 -0
- package/dist/skills/sf-plan-review/manifest.d.ts +2 -0
- package/dist/skills/sf-plan-review/manifest.js +5 -0
- package/dist/skills/sf-plan-review/manifest.js.map +1 -0
- package/dist/skills/sf-receiving-review/manifest.d.ts +2 -0
- package/dist/skills/sf-receiving-review/manifest.js +5 -0
- package/dist/skills/sf-receiving-review/manifest.js.map +1 -0
- package/dist/skills/sf-spec-review/manifest.d.ts +2 -0
- package/dist/skills/sf-spec-review/manifest.js +5 -0
- package/dist/skills/sf-spec-review/manifest.js.map +1 -0
- package/dist/skills/sf-tdd/manifest.d.ts +2 -0
- package/dist/skills/sf-tdd/manifest.js +5 -0
- package/dist/skills/sf-tdd/manifest.js.map +1 -0
- package/dist/skills/sf-verification/manifest.d.ts +2 -0
- package/dist/skills/sf-verification/manifest.js +5 -0
- package/dist/skills/sf-verification/manifest.js.map +1 -0
- package/dist/src/cli/commands/bug.d.ts +2 -0
- package/dist/src/cli/commands/bug.js +58 -0
- package/dist/src/cli/commands/bug.js.map +1 -0
- package/dist/src/cli/commands/finish.d.ts +2 -0
- package/dist/src/cli/commands/finish.js +43 -0
- package/dist/src/cli/commands/finish.js.map +1 -0
- package/dist/src/cli/commands/fix.d.ts +2 -0
- package/dist/src/cli/commands/fix.js +60 -0
- package/dist/src/cli/commands/fix.js.map +1 -0
- package/dist/src/cli/commands/init.d.ts +2 -0
- package/dist/src/cli/commands/init.js +92 -0
- package/dist/src/cli/commands/init.js.map +1 -0
- package/dist/src/cli/commands/list.d.ts +2 -0
- package/dist/src/cli/commands/list.js +52 -0
- package/dist/src/cli/commands/list.js.map +1 -0
- package/dist/src/cli/commands/plan-ready.d.ts +2 -0
- package/dist/src/cli/commands/plan-ready.js +27 -0
- package/dist/src/cli/commands/plan-ready.js.map +1 -0
- package/dist/src/cli/commands/plan.d.ts +2 -0
- package/dist/src/cli/commands/plan.js +43 -0
- package/dist/src/cli/commands/plan.js.map +1 -0
- package/dist/src/cli/commands/spec-ready.d.ts +2 -0
- package/dist/src/cli/commands/spec-ready.js +27 -0
- package/dist/src/cli/commands/spec-ready.js.map +1 -0
- package/dist/src/cli/commands/spec.d.ts +2 -0
- package/dist/src/cli/commands/spec.js +46 -0
- package/dist/src/cli/commands/spec.js.map +1 -0
- package/dist/src/cli/commands/start.d.ts +2 -0
- package/dist/src/cli/commands/start.js +27 -0
- package/dist/src/cli/commands/start.js.map +1 -0
- package/dist/src/cli/commands/status.d.ts +2 -0
- package/dist/src/cli/commands/status.js +62 -0
- package/dist/src/cli/commands/status.js.map +1 -0
- package/dist/src/cli/commands/task.d.ts +2 -0
- package/dist/src/cli/commands/task.js +64 -0
- package/dist/src/cli/commands/task.js.map +1 -0
- package/dist/src/cli/commands/worktree.d.ts +2 -0
- package/dist/src/cli/commands/worktree.js +33 -0
- package/dist/src/cli/commands/worktree.js.map +1 -0
- package/dist/src/cli/index.d.ts +3 -0
- package/dist/src/cli/index.js +106 -0
- package/dist/src/cli/index.js.map +1 -0
- package/dist/src/core/bugs/create.d.ts +13 -0
- package/dist/src/core/bugs/create.js +28 -0
- package/dist/src/core/bugs/create.js.map +1 -0
- package/dist/src/core/bugs/frontmatter.d.ts +7 -0
- package/dist/src/core/bugs/frontmatter.js +65 -0
- package/dist/src/core/bugs/frontmatter.js.map +1 -0
- package/dist/src/core/bugs/id.d.ts +1 -0
- package/dist/src/core/bugs/id.js +4 -0
- package/dist/src/core/bugs/id.js.map +1 -0
- package/dist/src/core/bugs/paths.d.ts +2 -0
- package/dist/src/core/bugs/paths.js +8 -0
- package/dist/src/core/bugs/paths.js.map +1 -0
- package/dist/src/core/bugs/types.d.ts +12 -0
- package/dist/src/core/bugs/types.js +3 -0
- package/dist/src/core/bugs/types.js.map +1 -0
- package/dist/src/core/fixes/create.d.ts +11 -0
- package/dist/src/core/fixes/create.js +43 -0
- package/dist/src/core/fixes/create.js.map +1 -0
- package/dist/src/core/fixes/frontmatter.d.ts +7 -0
- package/dist/src/core/fixes/frontmatter.js +50 -0
- package/dist/src/core/fixes/frontmatter.js.map +1 -0
- package/dist/src/core/fixes/id.d.ts +1 -0
- package/dist/src/core/fixes/id.js +4 -0
- package/dist/src/core/fixes/id.js.map +1 -0
- package/dist/src/core/fixes/list.d.ts +8 -0
- package/dist/src/core/fixes/list.js +43 -0
- package/dist/src/core/fixes/list.js.map +1 -0
- package/dist/src/core/fixes/paths.d.ts +2 -0
- package/dist/src/core/fixes/paths.js +9 -0
- package/dist/src/core/fixes/paths.js.map +1 -0
- package/dist/src/core/fixes/transition.d.ts +9 -0
- package/dist/src/core/fixes/transition.js +26 -0
- package/dist/src/core/fixes/transition.js.map +1 -0
- package/dist/src/core/fixes/types.d.ts +9 -0
- package/dist/src/core/fixes/types.js +2 -0
- package/dist/src/core/fixes/types.js.map +1 -0
- package/dist/src/core/init/config.d.ts +6 -0
- package/dist/src/core/init/config.js +18 -0
- package/dist/src/core/init/config.js.map +1 -0
- package/dist/src/core/init/install-skills.d.ts +8 -0
- package/dist/src/core/init/install-skills.js +14 -0
- package/dist/src/core/init/install-skills.js.map +1 -0
- package/dist/src/core/init/prompt-harness.d.ts +8 -0
- package/dist/src/core/init/prompt-harness.js +19 -0
- package/dist/src/core/init/prompt-harness.js.map +1 -0
- package/dist/src/core/init/scaffold.d.ts +5 -0
- package/dist/src/core/init/scaffold.js +91 -0
- package/dist/src/core/init/scaffold.js.map +1 -0
- package/dist/src/core/init/types.d.ts +5 -0
- package/dist/src/core/init/types.js +2 -0
- package/dist/src/core/init/types.js.map +1 -0
- package/dist/src/core/output/emit.d.ts +8 -0
- package/dist/src/core/output/emit.js +50 -0
- package/dist/src/core/output/emit.js.map +1 -0
- package/dist/src/core/output/errors.d.ts +14 -0
- package/dist/src/core/output/errors.js +36 -0
- package/dist/src/core/output/errors.js.map +1 -0
- package/dist/src/core/output/index.d.ts +4 -0
- package/dist/src/core/output/index.js +4 -0
- package/dist/src/core/output/index.js.map +1 -0
- package/dist/src/core/output/tty.d.ts +1 -0
- package/dist/src/core/output/tty.js +4 -0
- package/dist/src/core/output/tty.js.map +1 -0
- package/dist/src/core/package-root.d.ts +1 -0
- package/dist/src/core/package-root.js +18 -0
- package/dist/src/core/package-root.js.map +1 -0
- package/dist/src/core/skills/catalog.d.ts +6 -0
- package/dist/src/core/skills/catalog.js +69 -0
- package/dist/src/core/skills/catalog.js.map +1 -0
- package/dist/src/core/skills/harness/adapter.d.ts +15 -0
- package/dist/src/core/skills/harness/adapter.js +31 -0
- package/dist/src/core/skills/harness/adapter.js.map +1 -0
- package/dist/src/core/skills/harness/claude-code.d.ts +2 -0
- package/dist/src/core/skills/harness/claude-code.js +37 -0
- package/dist/src/core/skills/harness/claude-code.js.map +1 -0
- package/dist/src/core/skills/harness/register-defaults.d.ts +1 -0
- package/dist/src/core/skills/harness/register-defaults.js +4 -0
- package/dist/src/core/skills/harness/register-defaults.js.map +1 -0
- package/dist/src/core/skills/harness/registry.d.ts +3 -0
- package/dist/src/core/skills/harness/registry.js +22 -0
- package/dist/src/core/skills/harness/registry.js.map +1 -0
- package/dist/src/core/skills/types.d.ts +18 -0
- package/dist/src/core/skills/types.js +9 -0
- package/dist/src/core/skills/types.js.map +1 -0
- package/dist/src/core/slugify.d.ts +2 -0
- package/dist/src/core/slugify.js +13 -0
- package/dist/src/core/slugify.js.map +1 -0
- package/dist/src/core/specs/create.d.ts +11 -0
- package/dist/src/core/specs/create.js +35 -0
- package/dist/src/core/specs/create.js.map +1 -0
- package/dist/src/core/specs/id.d.ts +1 -0
- package/dist/src/core/specs/id.js +4 -0
- package/dist/src/core/specs/id.js.map +1 -0
- package/dist/src/core/specs/lifecycle.d.ts +17 -0
- package/dist/src/core/specs/lifecycle.js +97 -0
- package/dist/src/core/specs/lifecycle.js.map +1 -0
- package/dist/src/core/specs/list.d.ts +6 -0
- package/dist/src/core/specs/list.js +43 -0
- package/dist/src/core/specs/list.js.map +1 -0
- package/dist/src/core/specs/metadata.d.ts +3 -0
- package/dist/src/core/specs/metadata.js +13 -0
- package/dist/src/core/specs/metadata.js.map +1 -0
- package/dist/src/core/specs/paths.d.ts +3 -0
- package/dist/src/core/specs/paths.js +13 -0
- package/dist/src/core/specs/paths.js.map +1 -0
- package/dist/src/core/specs/plan-session.d.ts +18 -0
- package/dist/src/core/specs/plan-session.js +24 -0
- package/dist/src/core/specs/plan-session.js.map +1 -0
- package/dist/src/core/specs/transition.d.ts +8 -0
- package/dist/src/core/specs/transition.js +33 -0
- package/dist/src/core/specs/transition.js.map +1 -0
- package/dist/src/core/specs/types.d.ts +17 -0
- package/dist/src/core/specs/types.js +8 -0
- package/dist/src/core/specs/types.js.map +1 -0
- package/dist/src/core/specs/worktree.d.ts +10 -0
- package/dist/src/core/specs/worktree.js +32 -0
- package/dist/src/core/specs/worktree.js.map +1 -0
- package/dist/src/core/tasks/frontmatter.d.ts +7 -0
- package/dist/src/core/tasks/frontmatter.js +53 -0
- package/dist/src/core/tasks/frontmatter.js.map +1 -0
- package/dist/src/core/tasks/list.d.ts +2 -0
- package/dist/src/core/tasks/list.js +18 -0
- package/dist/src/core/tasks/list.js.map +1 -0
- package/dist/src/core/tasks/paths.d.ts +2 -0
- package/dist/src/core/tasks/paths.js +11 -0
- package/dist/src/core/tasks/paths.js.map +1 -0
- package/dist/src/core/tasks/transition.d.ts +8 -0
- package/dist/src/core/tasks/transition.js +30 -0
- package/dist/src/core/tasks/transition.js.map +1 -0
- package/dist/src/core/tasks/types.d.ts +8 -0
- package/dist/src/core/tasks/types.js +2 -0
- package/dist/src/core/tasks/types.js.map +1 -0
- package/package.json +67 -0
- package/skills/sf-bug/DISPATCH-CODE-REVIEW.md +22 -0
- package/skills/sf-bug/body.md +117 -0
- package/skills/sf-bug/manifest.ts +8 -0
- package/skills/sf-change/body.md +178 -0
- package/skills/sf-change/manifest.ts +8 -0
- package/skills/sf-code-review/body.md +155 -0
- package/skills/sf-code-review/manifest.ts +7 -0
- package/skills/sf-continue/body.md +90 -0
- package/skills/sf-continue/manifest.ts +8 -0
- package/skills/sf-feature/ADR-TEMPLATE.md +16 -0
- package/skills/sf-feature/DISPATCH-SPEC-REVIEW.md +16 -0
- package/skills/sf-feature/SPEC-TEMPLATE.md +37 -0
- package/skills/sf-feature/body.md +145 -0
- package/skills/sf-feature/manifest.ts +8 -0
- package/skills/sf-fix/DISPATCH-CODE-REVIEW.md +25 -0
- package/skills/sf-fix/body.md +174 -0
- package/skills/sf-fix/manifest.ts +8 -0
- package/skills/sf-handover/body.md +67 -0
- package/skills/sf-handover/manifest.ts +7 -0
- package/skills/sf-implement/DISPATCH-CODE-REVIEW.md +19 -0
- package/skills/sf-implement/DISPATCH-HANDOVER.md +19 -0
- package/skills/sf-implement/DISPATCH-IMPLEMENTER.md +36 -0
- package/skills/sf-implement/body.md +147 -0
- package/skills/sf-implement/manifest.ts +8 -0
- package/skills/sf-plan/ADR-TEMPLATE.md +16 -0
- package/skills/sf-plan/DESIGN-TEMPLATE.md +54 -0
- package/skills/sf-plan/DISPATCH-PLAN-REVIEW.md +17 -0
- package/skills/sf-plan/TASK-TEMPLATE.md +30 -0
- package/skills/sf-plan/body.md +162 -0
- package/skills/sf-plan/manifest.ts +8 -0
- package/skills/sf-plan-review/body.md +90 -0
- package/skills/sf-plan-review/manifest.ts +7 -0
- package/skills/sf-receiving-review/body.md +73 -0
- package/skills/sf-receiving-review/manifest.ts +7 -0
- package/skills/sf-spec-review/body.md +83 -0
- package/skills/sf-spec-review/manifest.ts +7 -0
- package/skills/sf-tdd/body.md +120 -0
- package/skills/sf-tdd/manifest.ts +7 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../../../src/core/tasks/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAGrD,SAAS,kBAAkB,CAAC,KAAc;IACxC,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC;AAC9E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,WAAmB,EACnB,WAAmB;IAEnB,MAAM,QAAQ,GAAG,uBAAuB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IAEnE,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QACxF,IAAI,kBAAkB,CAAC,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QACzC,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IAE1F,OAAO,OAAO,CAAC,GAAG,CAChB,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACtB,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAC1E,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { assertSafeSlug } from '../slugify.js';
|
|
3
|
+
import { buildFeatureDirectoryPath } from '../specs/paths.js';
|
|
4
|
+
export function buildTasksDirectoryPath(projectRoot, featureSlug) {
|
|
5
|
+
return join(buildFeatureDirectoryPath(projectRoot, featureSlug), 'tasks');
|
|
6
|
+
}
|
|
7
|
+
export function buildTaskFilePath(projectRoot, featureSlug, taskSlug) {
|
|
8
|
+
assertSafeSlug(taskSlug, 'task slug');
|
|
9
|
+
return join(buildTasksDirectoryPath(projectRoot, featureSlug), `${taskSlug}.md`);
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../../src/core/tasks/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,MAAM,UAAU,uBAAuB,CAAC,WAAmB,EAAE,WAAmB;IAC9E,OAAO,IAAI,CAAC,yBAAyB,CAAC,WAAW,EAAE,WAAW,CAAC,EAAE,OAAO,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,WAAmB,EACnB,WAAmB,EACnB,QAAgB;IAEhB,cAAc,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IACtC,OAAO,IAAI,CAAC,uBAAuB,CAAC,WAAW,EAAE,WAAW,CAAC,EAAE,GAAG,QAAQ,KAAK,CAAC,CAAC;AACnF,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TaskStatus } from './types.js';
|
|
2
|
+
export interface UpdateTaskStatusResult {
|
|
3
|
+
featureSlug: string;
|
|
4
|
+
taskSlug: string;
|
|
5
|
+
previousStatus: TaskStatus;
|
|
6
|
+
newStatus: TaskStatus;
|
|
7
|
+
}
|
|
8
|
+
export declare function updateTaskStatus(projectRoot: string, featureSlug: string, taskSlug: string, targetStatus: TaskStatus): Promise<UpdateTaskStatusResult>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ScifiError } from '../output/errors.js';
|
|
2
|
+
import { readTaskFile, writeTaskFile } from './frontmatter.js';
|
|
3
|
+
import { buildTaskFilePath } from './paths.js';
|
|
4
|
+
function isMissingPathError(error) {
|
|
5
|
+
return error instanceof Error && 'code' in error && error.code === 'ENOENT';
|
|
6
|
+
}
|
|
7
|
+
export async function updateTaskStatus(projectRoot, featureSlug, taskSlug, targetStatus) {
|
|
8
|
+
const filePath = buildTaskFilePath(projectRoot, featureSlug, taskSlug);
|
|
9
|
+
const file = await readTaskFile(filePath).catch((error) => {
|
|
10
|
+
if (isMissingPathError(error)) {
|
|
11
|
+
throw new ScifiError('NOT_FOUND', `Task "${taskSlug}" does not exist in feature "${featureSlug}".`, { hint: 'Run `scifi task list <slug>` to see available tasks.' });
|
|
12
|
+
}
|
|
13
|
+
throw error;
|
|
14
|
+
});
|
|
15
|
+
if (targetStatus === 'done' && file.frontmatter.status !== 'in-progress') {
|
|
16
|
+
throw new ScifiError('PRECONDITION_FAILED', `Cannot mark task ${taskSlug} as done: task is not in-progress (current status: ${file.frontmatter.status}).`, { hint: 'Start it first with `scifi task start <slug> <task>`.' });
|
|
17
|
+
}
|
|
18
|
+
const previousStatus = file.frontmatter.status;
|
|
19
|
+
await writeTaskFile(filePath, {
|
|
20
|
+
...file,
|
|
21
|
+
frontmatter: { ...file.frontmatter, status: targetStatus },
|
|
22
|
+
});
|
|
23
|
+
return {
|
|
24
|
+
featureSlug,
|
|
25
|
+
taskSlug,
|
|
26
|
+
previousStatus,
|
|
27
|
+
newStatus: targetStatus,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=transition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transition.js","sourceRoot":"","sources":["../../../../src/core/tasks/transition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAU/C,SAAS,kBAAkB,CAAC,KAAc;IACxC,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC;AAC9E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,WAAmB,EACnB,WAAmB,EACnB,QAAgB,EAChB,YAAwB;IAExB,MAAM,QAAQ,GAAG,iBAAiB,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IACvE,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAS,EAAE;QACxE,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,UAAU,CAClB,WAAW,EACX,SAAS,QAAQ,gCAAgC,WAAW,IAAI,EAChE,EAAE,IAAI,EAAE,sDAAsD,EAAE,CACjE,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,IAAI,YAAY,KAAK,MAAM,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;QACzE,MAAM,IAAI,UAAU,CAClB,qBAAqB,EACrB,oBAAoB,QAAQ,sDAAsD,IAAI,CAAC,WAAW,CAAC,MAAM,IAAI,EAC7G,EAAE,IAAI,EAAE,uDAAuD,EAAE,CAClE,CAAC;IACJ,CAAC;IAED,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;IAE/C,MAAM,aAAa,CAAC,QAAQ,EAAE;QAC5B,GAAG,IAAI;QACP,WAAW,EAAE,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE;KAC3D,CAAC,CAAC;IAEH,OAAO;QACL,WAAW;QACX,QAAQ;QACR,cAAc;QACd,SAAS,EAAE,YAAY;KACxB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/core/tasks/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,SAAS,EAAE,aAAa,EAAE,MAAM,CAAU,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kamilmarzynski/scifi",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Specification-driven CLI scaffolding for agentic workflows",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"scifi": "./dist/src/cli/index.js"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./dist/src/cli/index.js",
|
|
11
|
+
"./skill-types": {
|
|
12
|
+
"types": "./dist/src/core/skills/types.d.ts",
|
|
13
|
+
"default": "./dist/src/core/skills/types.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"skills"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc -p tsconfig.json && node -e \"const fs=require('node:fs'); const path='dist/src/cli/index.js'; const shebang='#!/usr/bin/env node\\n'; const contents=fs.readFileSync(path, 'utf8'); if (!contents.startsWith(shebang)) { fs.writeFileSync(path, shebang + contents); } fs.chmodSync(path, 0o755);\"",
|
|
22
|
+
"prepack": "npm run build && node -e \"require('node:fs').accessSync('dist/src/cli/index.js')\"",
|
|
23
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
24
|
+
"test": "vitest run",
|
|
25
|
+
"test:watch": "vitest",
|
|
26
|
+
"coverage": "vitest run --coverage",
|
|
27
|
+
"lint": "biome lint .",
|
|
28
|
+
"lint:fix": "biome lint --write .",
|
|
29
|
+
"format": "biome format --write .",
|
|
30
|
+
"check": "biome check .",
|
|
31
|
+
"check:fix": "biome check --write ."
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"cli",
|
|
35
|
+
"scaffolding",
|
|
36
|
+
"specification",
|
|
37
|
+
"typescript"
|
|
38
|
+
],
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "git+https://github.com/KamilMarzynski/sci-fi.git"
|
|
42
|
+
},
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/KamilMarzynski/sci-fi/issues"
|
|
45
|
+
},
|
|
46
|
+
"homepage": "https://github.com/KamilMarzynski/sci-fi",
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=22.0.0"
|
|
49
|
+
},
|
|
50
|
+
"license": "MIT",
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public",
|
|
53
|
+
"provenance": true
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"commander": "^15.0.0",
|
|
57
|
+
"yaml": "^2.9.0",
|
|
58
|
+
"zod": "^4.4.3"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@biomejs/biome": "2.4.16",
|
|
62
|
+
"@types/node": "^24.0.0",
|
|
63
|
+
"@vitest/coverage-v8": "^4.0.0",
|
|
64
|
+
"typescript": "^5.9.0",
|
|
65
|
+
"vitest": "^4.0.0"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Dispatch template: bug-fix code review
|
|
2
|
+
|
|
3
|
+
Dispatch a subagent to review the bug fix before it is accepted. Replace
|
|
4
|
+
`{COMMIT_RANGE}` with the commit(s) the fix produced (a SHA or `<base>..HEAD`)
|
|
5
|
+
and `{CHANGE_BRIEF}` with the root cause and the solution the user agreed to, in
|
|
6
|
+
a sentence or two. There is no feature directory and no task file — this is a
|
|
7
|
+
**fix-mode** review. The criteria and output format live in the `sf-code-review`
|
|
8
|
+
skill — do not restate them here.
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
You are reviewing a bug fix. Load and follow the `sf-code-review` skill.
|
|
12
|
+
|
|
13
|
+
This is a CODE review in FIX MODE (no task file, no feature directory).
|
|
14
|
+
Changes to review: {COMMIT_RANGE}
|
|
15
|
+
Agreed change (the contract): {CHANGE_BRIEF}
|
|
16
|
+
|
|
17
|
+
Judge the change against that brief: it implements the agreed solution and only
|
|
18
|
+
that, a regression test reproduces the bug and now guards it, and no
|
|
19
|
+
non-negotiable is triggered. Use docs/scifi/CONTEXT.md for glossary context if
|
|
20
|
+
it exists. Return your report and verdict exactly as the sf-code-review skill
|
|
21
|
+
defines.
|
|
22
|
+
```
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# sf-bug
|
|
2
|
+
|
|
3
|
+
You run down ONE bug with the user and drive it to a fix. The session has two
|
|
4
|
+
halves: first you investigate *together* until the cause is understood and a fix
|
|
5
|
+
is chosen, then you implement that fix test-first under review. This skill is
|
|
6
|
+
rigid about the seam between them — you do not start fixing until the user has
|
|
7
|
+
agreed on which solution to build.
|
|
8
|
+
|
|
9
|
+
There is no spec and no tracked artifact for a bug. A bug is not a feature: its
|
|
10
|
+
solution emerges from diagnosis, not design. Keep the work in code and tests,
|
|
11
|
+
not in documents.
|
|
12
|
+
|
|
13
|
+
## The Iron Law
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
INVESTIGATE → REPORT → AGREE → FIX. NEVER FIX BEFORE THE USER AGREES.
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The user reported a bug, not a fix. Your job in the first half is to understand
|
|
20
|
+
it well enough to lay out real options; the choice between them is theirs.
|
|
21
|
+
|
|
22
|
+
## Flow
|
|
23
|
+
|
|
24
|
+
### 1. Capture the report
|
|
25
|
+
|
|
26
|
+
- Pin the symptom in the user's words: the error text *verbatim*, the wrong
|
|
27
|
+
output, the failing case. Quote it; do not paraphrase.
|
|
28
|
+
- Note the conditions they hit it under — environment, data, version, steps.
|
|
29
|
+
|
|
30
|
+
Before investigating, create an isolated workspace from the default branch
|
|
31
|
+
(shown as `main` below — substitute your repo's default branch if it differs):
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
git worktree add -b fix/<slug> .worktrees/fix-<slug> main
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Derive `<slug>` from the bug (e.g. `stale-token-refresh`). Work inside it; open
|
|
38
|
+
the PR from it. A bug is untracked, so there is no `scifi` pointer to record.
|
|
39
|
+
|
|
40
|
+
### 2. Investigate
|
|
41
|
+
|
|
42
|
+
Reproduce, then find the root cause. One hypothesis at a time.
|
|
43
|
+
|
|
44
|
+
- **Reproduce** by the smallest path you can. If you cannot make it happen on
|
|
45
|
+
demand, say so and gather more from the user — an unreproducible bug is not
|
|
46
|
+
ready to fix.
|
|
47
|
+
- **Diagnose**: state a single hypothesis about the cause in one sentence,
|
|
48
|
+
confirm or kill it by *reading the code* and adding observation (a log, a
|
|
49
|
+
probe), not by editing a fix and watching the symptom move. When a hypothesis
|
|
50
|
+
is wrong, record what you learned and form the next.
|
|
51
|
+
- You have the root cause when you can trace the full chain from trigger to
|
|
52
|
+
symptom and point at the line that is wrong and say why.
|
|
53
|
+
|
|
54
|
+
Investigate openly with the user — share what you find as you find it. This is a
|
|
55
|
+
debugging session, not a silent report you deliver at the end.
|
|
56
|
+
|
|
57
|
+
### 3. Report and propose (the gate)
|
|
58
|
+
|
|
59
|
+
Stop and bring it back to the user. Present:
|
|
60
|
+
|
|
61
|
+
- **The issue** — the root cause in plain language: what is actually wrong and
|
|
62
|
+
why it produces the symptom. Not the symptom restated.
|
|
63
|
+
- **A few solutions** — typically two or three. For each: what it changes, the
|
|
64
|
+
trade-off, and the blast radius. Be honest about a quick patch vs. a deeper
|
|
65
|
+
fix that removes the cause for good. Recommend one and say why.
|
|
66
|
+
|
|
67
|
+
Then debug it together. The user may push back, add context, or reframe the
|
|
68
|
+
problem — fold that in and re-propose. Do not move on until the user has chosen
|
|
69
|
+
a solution. If diagnosis turns up that this is really a missing feature or a
|
|
70
|
+
design decision, say so and stop — that belongs in `sf-feature`, not here.
|
|
71
|
+
|
|
72
|
+
### 4. Fix, test-first under review
|
|
73
|
+
|
|
74
|
+
Once the user has chosen, implement that solution — and only that solution.
|
|
75
|
+
|
|
76
|
+
- **Hold `sf-tdd`.** The bug becomes its first failing test: write a test that
|
|
77
|
+
reproduces it through the public interface at the smallest scope that captures
|
|
78
|
+
it, watch it fail for the *right* reason (the root cause from step 2), then
|
|
79
|
+
make it pass with the minimal change at the cause. Keep the full suite green.
|
|
80
|
+
- **Review gate.** Dispatch a code-review subagent with `DISPATCH-CODE-REVIEW.md`
|
|
81
|
+
(ships beside this skill) — a fix-mode review: you pass the **change brief**
|
|
82
|
+
(the root cause and the agreed solution), not a task file. Act on its report
|
|
83
|
+
under `sf-receiving-review` with **review type: code**. Re-review until the
|
|
84
|
+
verdict is **Pass** or **With fixes**; a **Fail** re-loops. On **With fixes**,
|
|
85
|
+
address the Minor items (or defer them with the user's ok) before accepting.
|
|
86
|
+
Do not skip it and do not review your own fix.
|
|
87
|
+
|
|
88
|
+
The regression test is the point: it proves the bug existed and guards its
|
|
89
|
+
return.
|
|
90
|
+
|
|
91
|
+
## When you are stuck
|
|
92
|
+
|
|
93
|
+
| Problem | Move |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| Can't reproduce | Shrink the variables: pin env, data, version one at a time. |
|
|
96
|
+
| Many possible causes | Bisect — halve the suspect surface each step, don't scan it. |
|
|
97
|
+
| Symptom moves when you touch it | You patched downstream of the cause. Go upstream. |
|
|
98
|
+
| User picks a patch over the real fix | Build it — but record the leftover cause as known debt. |
|
|
99
|
+
|
|
100
|
+
## Done
|
|
101
|
+
|
|
102
|
+
The bug is done when:
|
|
103
|
+
|
|
104
|
+
- you can state the root cause in one sentence,
|
|
105
|
+
- the user agreed on the solution you built,
|
|
106
|
+
- a test reproduces the bug, which you watched fail then pass,
|
|
107
|
+
- the code review cleared (**Pass**, or **With fixes** with its Minor items
|
|
108
|
+
handled) and the full suite is green.
|
|
109
|
+
|
|
110
|
+
## Hard rules
|
|
111
|
+
|
|
112
|
+
- Never start fixing before the user has chosen a solution.
|
|
113
|
+
- Never present the symptom as the cause.
|
|
114
|
+
- Never ship a fix with no failing test behind it.
|
|
115
|
+
- Never catch or silence the error in place of removing its cause.
|
|
116
|
+
- Never mark done before the code review clears (**Pass**, or **With fixes** with
|
|
117
|
+
its Minor items handled).
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SkillManifest } from "scifi/skill-types";
|
|
2
|
+
|
|
3
|
+
export const manifest: SkillManifest = {
|
|
4
|
+
id: "sf-bug",
|
|
5
|
+
description:
|
|
6
|
+
"Investigate one bug with the user, agree on a solution, then fix it test-first under review. No spec or tracked artifact.",
|
|
7
|
+
argumentHint: "[description]",
|
|
8
|
+
};
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# sf-change
|
|
2
|
+
|
|
3
|
+
The scope of ONE existing feature has changed. Your job is to absorb that
|
|
4
|
+
change cleanly: figure out where the feature currently sits, work out how deep
|
|
5
|
+
the change cuts, update the affected artifacts under the same grilling and
|
|
6
|
+
review gates that produced them, and reset the feature's lifecycle status so it
|
|
7
|
+
never sits *ahead* of the artifacts that back it.
|
|
8
|
+
|
|
9
|
+
You do not re-invent the pipeline. `sf-feature`, `sf-plan`, and `sf-implement`
|
|
10
|
+
already own spec creation, planning, and implementation — each with its own
|
|
11
|
+
grill and its own review gate. Your job is to decide **how far back the change
|
|
12
|
+
rolls the feature**, reset the status to that point, and re-enter the pipeline
|
|
13
|
+
there so the right gate runs again. A change that touches the *what* is not the
|
|
14
|
+
same as one that touches the *how*; getting that judgement right is the work.
|
|
15
|
+
|
|
16
|
+
## The Iron Law
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
IDENTIFY → ASSESS STATE → SCOPE THE CHANGE → DECIDE BLAST RADIUS →
|
|
20
|
+
RESET STATUS → RE-ENTER THE PIPELINE.
|
|
21
|
+
NEVER LET STATUS RUN AHEAD OF THE ARTIFACTS.
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Flow
|
|
25
|
+
|
|
26
|
+
### 1. Identify the feature
|
|
27
|
+
|
|
28
|
+
The change must attach to one feature. Resolve it before anything else.
|
|
29
|
+
|
|
30
|
+
- `/sf-change <slug>` — treat the argument as an exact feature slug.
|
|
31
|
+
- `/sf-change <description>` — you were given prose, not a slug. Discover
|
|
32
|
+
candidates from **both** `scifi list --json` and `git worktree list` (an
|
|
33
|
+
in-flight feature lives on its own `feat/<slug>` branch and will not appear in
|
|
34
|
+
`scifi list` from the default checkout). Match by slug and title. Present your
|
|
35
|
+
best match (or the candidates, if ambiguous) and **confirm the pick with the
|
|
36
|
+
user**. Never guess silently.
|
|
37
|
+
- **Locate the feature's workspace, then confirm it exists.** Run
|
|
38
|
+
`git worktree list`; if `.worktrees/feat-<slug>` (branch `feat/<slug>`) exists,
|
|
39
|
+
enter it and confirm with `scifi status <slug>` from there. Only when *no*
|
|
40
|
+
matching worktree exists **and** `scifi status <slug>` returns `NOT_FOUND` from
|
|
41
|
+
a checkout that would contain it is the feature truly absent — then stop: for
|
|
42
|
+
genuinely new work point the user at `sf-feature`; for a defect rather than a
|
|
43
|
+
scope change, `sf-fix`. A `NOT_FOUND` while a worktree exists just means you
|
|
44
|
+
are in the wrong checkout, not that the feature is gone.
|
|
45
|
+
|
|
46
|
+
### 2. Assess current state
|
|
47
|
+
|
|
48
|
+
Read where the feature is before touching anything:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
scifi status <slug> --json
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Read `status`, the `artifacts` inventory (`artifacts.spec`, `artifacts.design`,
|
|
55
|
+
`artifacts.taskCount`), the per-task statuses in `tasks[]`, and `fixes[]` (each
|
|
56
|
+
carries its own `status`, so filter for the open ones). Then read the artifacts
|
|
57
|
+
themselves —
|
|
58
|
+
`<path>/spec.md`, `<path>/design.md`, the task files under `<path>/tasks/` — and
|
|
59
|
+
grep `docs/scifi/adr/` for decisions touching the area. `<path>` is
|
|
60
|
+
`docs/scifi/specs/<slug>/`. You cannot scope a change without knowing the
|
|
61
|
+
current contract.
|
|
62
|
+
|
|
63
|
+
Enter the feature's worktree (the `worktree` field, fallback
|
|
64
|
+
`.worktrees/feat-<slug>`) before editing any artifact. If the feature was `done`
|
|
65
|
+
and its worktree was cleaned up, recreate one off the default branch
|
|
66
|
+
(`git worktree add -b feat/<slug> .worktrees/feat-<slug> main`, substituting your
|
|
67
|
+
default branch for `main` if it differs) and re-record it
|
|
68
|
+
with `scifi worktree set <slug> --branch feat/<slug> --path
|
|
69
|
+
.worktrees/feat-<slug>`.
|
|
70
|
+
|
|
71
|
+
### 3. Scope the change (grill it)
|
|
72
|
+
|
|
73
|
+
Interrogate the change the same way `sf-feature` interrogates a new idea — one
|
|
74
|
+
question at a time, concrete either/or where possible. Drive toward:
|
|
75
|
+
|
|
76
|
+
- **What actually changes** — a requirement, an acceptance criterion, something
|
|
77
|
+
moving in or out of scope, or only an internal mechanism.
|
|
78
|
+
- **Why now**, and what the change must *not* break.
|
|
79
|
+
- **Confront it against the existing artifacts.** Does it contradict the spec's
|
|
80
|
+
stated scope? A recorded ADR? The agreed design? Surface the conflict; do not
|
|
81
|
+
paper over it.
|
|
82
|
+
|
|
83
|
+
You are ready to act when you can state, in one sentence, exactly what changes
|
|
84
|
+
and which artifact owns it.
|
|
85
|
+
|
|
86
|
+
### 4. Decide the blast radius
|
|
87
|
+
|
|
88
|
+
Classify the change by the deepest artifact it invalidates. This decides how far
|
|
89
|
+
back the feature rolls.
|
|
90
|
+
|
|
91
|
+
| The change touches… | Deepest artifact | Roll back to | Re-enter via |
|
|
92
|
+
| --- | --- | --- | --- |
|
|
93
|
+
| The **what** — a requirement, acceptance criterion, in/out-of-scope line | `spec.md` | `spec-ready` | `sf-feature`'s grill + `sf-spec-review`, then `sf-plan`, then `sf-implement` |
|
|
94
|
+
| The **how** — module shape, seams, task breakdown; spec still holds | `design.md` / tasks | `plan-ready` | `sf-plan`'s grill + `sf-plan-review`, then `sf-implement` |
|
|
95
|
+
| A single in-flight task, within the current design | one task file | stay | `sf-implement` (or finish the task in place) |
|
|
96
|
+
|
|
97
|
+
When in doubt, roll back further, not less. A spec change that you treat as a
|
|
98
|
+
mere task tweak leaves the design and code quietly contradicting the contract —
|
|
99
|
+
exactly the failure this skill exists to prevent.
|
|
100
|
+
|
|
101
|
+
### 5. Reset the status
|
|
102
|
+
|
|
103
|
+
Lower the lifecycle status to the rollback point from step 4, using the CLI
|
|
104
|
+
levers — never by hand-editing metadata:
|
|
105
|
+
|
|
106
|
+
- **Spec-level** → edit `spec.md` first (or re-enter `sf-feature`'s grill for
|
|
107
|
+
the affected sections), then `scifi spec-ready <slug>`. This re-anchors the
|
|
108
|
+
feature at the spec stage; design, tasks, and code are now downstream of a
|
|
109
|
+
changed contract and must be brought back in line.
|
|
110
|
+
- **Design-level** → update `design.md` and the task files, then
|
|
111
|
+
`scifi plan-ready <slug>`.
|
|
112
|
+
- **Task-level** → no status change. `in-progress` stays `in-progress`.
|
|
113
|
+
|
|
114
|
+
Note the one-way gate: `in-progress` is only reachable *from* `plan-ready` via
|
|
115
|
+
`scifi start <slug>`. So a feature you rolled back to `spec-ready` climbs back
|
|
116
|
+
the normal way — `spec-ready → plan-ready → in-progress` — as each gate passes.
|
|
117
|
+
You do not get to jump straight back to where it was.
|
|
118
|
+
|
|
119
|
+
**If the feature was `done`,** a spec- or design-level change reopens it: reset
|
|
120
|
+
the status as above and the feature re-enters the pipeline. Do not leave a `done`
|
|
121
|
+
feature whose contract has changed.
|
|
122
|
+
|
|
123
|
+
### 6. Re-enter the pipeline
|
|
124
|
+
|
|
125
|
+
Hand control to the owning skill for the rollback point — that is where the
|
|
126
|
+
grill and the review gate live:
|
|
127
|
+
|
|
128
|
+
- Rolled to `spec-ready` → run `sf-feature` to settle the changed spec under
|
|
129
|
+
`sf-spec-review`, then `sf-plan`, then `sf-implement`. Each gate re-runs.
|
|
130
|
+
`sf-feature` reopens the *existing* container in this case — it skips its
|
|
131
|
+
`scifi spec` create step, so you keep working against the original feature
|
|
132
|
+
rather than scaffolding a new one.
|
|
133
|
+
- Rolled to `plan-ready` → run `sf-plan` to settle the changed design and tasks
|
|
134
|
+
under `sf-plan-review`, then `sf-implement`.
|
|
135
|
+
- Stayed `in-progress` → run `sf-implement`; it resumes from the next runnable
|
|
136
|
+
task and picks up the added or removed task files.
|
|
137
|
+
|
|
138
|
+
Adding or removing a task means adding or deleting a file under `<path>/tasks/`
|
|
139
|
+
(`sf-plan` owns the task template and the decomposition rules — re-enter it
|
|
140
|
+
rather than hand-rolling task files for anything beyond a trivial edit). The CLI
|
|
141
|
+
tracks task *status* (`scifi task start|done`), not task creation.
|
|
142
|
+
|
|
143
|
+
**Re-open the tasks the change invalidated.** A design change usually rewrites
|
|
144
|
+
tasks that are already `done`, and `sf-implement` *skips* `done` tasks on resume
|
|
145
|
+
— so a changed-but-done task would never be rebuilt. For each existing task the
|
|
146
|
+
change invalidates, run `scifi task start <slug> <task>` to flip it back to
|
|
147
|
+
`in-progress` before re-entering `sf-implement`; it then picks the task up as
|
|
148
|
+
runnable. A brand-new task file already starts `pending`, so it needs no reset.
|
|
149
|
+
|
|
150
|
+
## When you are stuck
|
|
151
|
+
|
|
152
|
+
| Problem | Move |
|
|
153
|
+
| --- | --- |
|
|
154
|
+
| Unsure if it's a spec or design change | Ask: does an *acceptance criterion* move? Yes → spec. No → design. |
|
|
155
|
+
| Change contradicts a recorded ADR | Surface it. The decision may need revisiting before the change lands. |
|
|
156
|
+
| Feature is `done` and change is large | Reopen via `spec-ready`; treat it as a near-fresh pass through the pipeline. |
|
|
157
|
+
| Change turns out to be a defect, not new scope | Stop. Route to `sf-fix`. |
|
|
158
|
+
| Change is really a brand-new feature | Stop. Route to `sf-feature`; don't overload this one. |
|
|
159
|
+
|
|
160
|
+
## Done
|
|
161
|
+
|
|
162
|
+
The change is absorbed when:
|
|
163
|
+
|
|
164
|
+
- the target feature is identified and its current state read,
|
|
165
|
+
- the change is scoped to exactly the artifact it invalidates,
|
|
166
|
+
- that artifact is updated under its own grill and review gate,
|
|
167
|
+
- the lifecycle status is reset to match — never ahead of — the artifacts,
|
|
168
|
+
- and the feature has re-entered the pipeline at the rollback point.
|
|
169
|
+
|
|
170
|
+
## Hard rules
|
|
171
|
+
|
|
172
|
+
- Never change scope silently — grill it and confront it against the artifacts.
|
|
173
|
+
- Never lower a feature past `spec-ready`/`plan-ready` without re-running that
|
|
174
|
+
stage's review gate.
|
|
175
|
+
- Never leave the status ahead of the artifacts: a changed spec means the
|
|
176
|
+
feature is no longer `done`.
|
|
177
|
+
- Never hand-edit lifecycle metadata — use `scifi spec-ready` / `plan-ready`.
|
|
178
|
+
- Never absorb a defect or a new feature here — route to `sf-fix` / `sf-feature`.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SkillManifest } from "scifi/skill-types";
|
|
2
|
+
|
|
3
|
+
export const manifest: SkillManifest = {
|
|
4
|
+
id: "sf-change",
|
|
5
|
+
description:
|
|
6
|
+
"Absorb a scope change to an existing feature: scope it against spec/design, reset lifecycle status to the deepest artifact it invalidates, and re-enter the pipeline so the right review gate runs again.",
|
|
7
|
+
argumentHint: "[feature-slug | description]",
|
|
8
|
+
};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# sf-code-review
|
|
2
|
+
|
|
3
|
+
You are a critic. You were dispatched to review ONE change before it is accepted
|
|
4
|
+
— a planned feature task, or a defect fix. You do not write the code and you do
|
|
5
|
+
not fix it. You read, you judge, you report back to the agent that dispatched
|
|
6
|
+
you.
|
|
7
|
+
|
|
8
|
+
You review by reading only. You do not run the suite or the build — the final
|
|
9
|
+
`sf-handover` subagent owns that. Trust the diff and the files in front of
|
|
10
|
+
you.
|
|
11
|
+
|
|
12
|
+
## Inputs
|
|
13
|
+
|
|
14
|
+
You review in one of two modes; the dispatcher tells you which by what it hands
|
|
15
|
+
you.
|
|
16
|
+
|
|
17
|
+
**Task mode** — dispatched by `sf-implement` to gate one task of a planned
|
|
18
|
+
feature. You get:
|
|
19
|
+
|
|
20
|
+
- `{COMMIT_RANGE}` — the commit(s) the implementer produced (a SHA, or
|
|
21
|
+
`<base>..HEAD`).
|
|
22
|
+
- `{FEATURE_PATH}` — the feature directory (e.g. `docs/scifi/specs/<slug>`).
|
|
23
|
+
- `{TASK_SLUG}` — which task under that feature this change implements.
|
|
24
|
+
|
|
25
|
+
**Fix mode** — dispatched by `sf-bug` or `sf-fix` to gate a defect fix. There is
|
|
26
|
+
no task file, and for an untracked bug no feature directory either. You get:
|
|
27
|
+
|
|
28
|
+
- `{COMMIT_RANGE}` — the commit(s) the fix produced.
|
|
29
|
+
- `{CHANGE_BRIEF}` — the root cause and the solution the user agreed to, in a
|
|
30
|
+
sentence or two. This is the contract the change must match.
|
|
31
|
+
- `{FEATURE_PATH}` *(sf-fix only)* — the owning feature directory, so you can
|
|
32
|
+
judge the fix against its `spec.md` / `design.md` as original intent.
|
|
33
|
+
|
|
34
|
+
In either mode, if `{COMMIT_RANGE}` is empty you cannot see the change — say so
|
|
35
|
+
and stop. In task mode, if `{FEATURE_PATH}/design.md` is missing you have no
|
|
36
|
+
contract to judge against — say so and stop. In fix mode there is no design
|
|
37
|
+
contract; the `{CHANGE_BRIEF}` is the contract.
|
|
38
|
+
|
|
39
|
+
## What to read
|
|
40
|
+
|
|
41
|
+
- The diff — `git show {COMMIT_RANGE}` or `git diff {COMMIT_RANGE}`. Then read
|
|
42
|
+
the touched files in full where the diff alone hides context.
|
|
43
|
+
- **Task mode:** `{FEATURE_PATH}/design.md` (the technical contract) and the task
|
|
44
|
+
file under `{FEATURE_PATH}/tasks/` for `{TASK_SLUG}` — its **Tests first**,
|
|
45
|
+
**Acceptance**, and **Validation** sections.
|
|
46
|
+
- **Fix mode:** the `{CHANGE_BRIEF}`. For `sf-fix`, also `{FEATURE_PATH}/spec.md`
|
|
47
|
+
and `design.md` — the original intent the fix must restore, not contradict.
|
|
48
|
+
- `docs/scifi/CONTEXT.md` — the project's ubiquitous language (canonical
|
|
49
|
+
glossary of domain terms), if it exists.
|
|
50
|
+
|
|
51
|
+
Read everything that applies to your mode before judging. Never invent project
|
|
52
|
+
facts; if something is unknowable from these files, flag it as a question
|
|
53
|
+
instead of assuming.
|
|
54
|
+
|
|
55
|
+
## What to check
|
|
56
|
+
|
|
57
|
+
Go through the diff against this checklist. No fixed priority order — weigh each
|
|
58
|
+
finding by its real impact on the change.
|
|
59
|
+
|
|
60
|
+
- **Acceptance & design** — the change does what it was dispatched to do, and no
|
|
61
|
+
more. *Task mode:* it satisfies the task's acceptance criteria and matches
|
|
62
|
+
`design.md`; an acceptance item with no implementation, or code that
|
|
63
|
+
contradicts the design, is a defect. *Fix mode:* it implements the agreed
|
|
64
|
+
solution from `{CHANGE_BRIEF}` and only that — and, for `sf-fix`, does not
|
|
65
|
+
reintroduce a deviation from the feature's `spec.md` / `design.md`. Behavior
|
|
66
|
+
outside the dispatched scope is a defect in either mode — flag scope creep.
|
|
67
|
+
- **TDD evidence** — the behavior is covered by a test written first. *Task
|
|
68
|
+
mode:* every behavior in the task's **Tests first** has a test. *Fix mode:* a
|
|
69
|
+
regression test reproduces the defect and now guards it. In both, the tests
|
|
70
|
+
exercise the change through its public interface, not by mocking the module
|
|
71
|
+
under test, and assert observable behavior, not shape. Production code with no
|
|
72
|
+
test behind it is a defect (see non-negotiables).
|
|
73
|
+
- **Deep modules** — real behavior behind a narrow interface. Apply the deletion
|
|
74
|
+
test: would removing a unit *concentrate* complexity (keep it) or just
|
|
75
|
+
*scatter* it (inline it)? Flag shallow seams — pass-through wrappers, a class
|
|
76
|
+
that only forwards calls, a "utils" dumping ground, a function extracted solely
|
|
77
|
+
so a test can reach it.
|
|
78
|
+
- **Seam declaration** — new seams (a new boundary, dependency, or
|
|
79
|
+
communication pattern). *Task mode:* they must be declared in `design.md`, not
|
|
80
|
+
introduced silently; judge against the design, not an external architecture
|
|
81
|
+
doc. *Fix mode:* a fix that quietly cuts a new seam is a smell — flag it; it
|
|
82
|
+
usually signals the change outgrew a fix and belongs in a feature.
|
|
83
|
+
- **Simplification (code judo)** — is there a reframing that deletes a whole
|
|
84
|
+
branch, mode, flag, or conditional rather than adding to it? Flag incidental
|
|
85
|
+
complexity the change preserves when a clearly simpler shape exists. Do not
|
|
86
|
+
invent hypothetical rewrites — only call a simplification that is concrete and
|
|
87
|
+
visible.
|
|
88
|
+
- **Spaghetti & types** — new conditionals bolted onto unrelated flows that make
|
|
89
|
+
surrounding code harder to reason about; unjustified casts, optionality, or
|
|
90
|
+
loosely-shaped objects that obscure the real invariant. Prefer explicit typed
|
|
91
|
+
boundaries.
|
|
92
|
+
- **Naming / glossary** — domain terms used in the code or tests that are not in
|
|
93
|
+
`CONTEXT.md` (ubiquitous language) and were not proposed for it. A
|
|
94
|
+
naming-consistency check, not structural.
|
|
95
|
+
- **Placeholders** — any `TBD` / `TODO` / stubbed body / empty implementation
|
|
96
|
+
presented as finished work.
|
|
97
|
+
|
|
98
|
+
## Non-negotiables
|
|
99
|
+
|
|
100
|
+
These are not judgment calls. When the diff contains one, assign at least the
|
|
101
|
+
stated severity regardless of how small it looks. Generalize each rule to the
|
|
102
|
+
project's language — e.g. "type escape" is `any`/`unknown`/an unchecked cast in
|
|
103
|
+
TypeScript, an `interface{}` assertion in Go, a `# type: ignore` in Python.
|
|
104
|
+
|
|
105
|
+
- **Type escape or cast without a justifying comment** → Critical.
|
|
106
|
+
- **Production code with no failing-test origin** (no test exercises it) →
|
|
107
|
+
Critical.
|
|
108
|
+
- **Silent failure** — a swallowed error, an empty catch, a discarded result, a
|
|
109
|
+
fallback that hides a broken invariant → Critical.
|
|
110
|
+
- **Changed public behavior with no doc update** in the same change → Important.
|
|
111
|
+
|
|
112
|
+
## How to report
|
|
113
|
+
|
|
114
|
+
Open with a header that names what this is, so the receiving agent applies the
|
|
115
|
+
right lens: **`Code review of <subject>`** — the task slug in task mode, or a
|
|
116
|
+
short label for the change in fix mode. Then use this exact shape:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
# Code review of <subject>
|
|
120
|
+
|
|
121
|
+
### Strengths
|
|
122
|
+
- <what the change gets right — be specific; accurate praise earns trust>
|
|
123
|
+
|
|
124
|
+
### Issues
|
|
125
|
+
|
|
126
|
+
#### Critical (must fix)
|
|
127
|
+
- Where: <file:line / quoted diff hunk>
|
|
128
|
+
Problem: <what is wrong>
|
|
129
|
+
Fix: <concrete change, or the exact question to ask the user>
|
|
130
|
+
|
|
131
|
+
#### Important (should fix)
|
|
132
|
+
- ...
|
|
133
|
+
|
|
134
|
+
#### Minor (nice to have)
|
|
135
|
+
- ...
|
|
136
|
+
|
|
137
|
+
### Verdict: Pass | Fail | With fixes
|
|
138
|
+
<one-line technical reason>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Calibration:
|
|
142
|
+
|
|
143
|
+
- **Pass** — acceptance (or the agreed fix) met, design matched where one
|
|
144
|
+
exists, tests cover every behavior (or a regression test guards the defect),
|
|
145
|
+
modules are deep, new seams declared, no non-negotiable triggered, no
|
|
146
|
+
placeholders. No Critical or Important issues.
|
|
147
|
+
- **With fixes** — only Minor issues remain; the change is sound enough to land
|
|
148
|
+
once they are addressed.
|
|
149
|
+
- **Fail** — any Critical or Important issue. An uncovered acceptance item,
|
|
150
|
+
untested production code, a triggered non-negotiable, an undeclared new seam,
|
|
151
|
+
or a placeholder is always at least Important.
|
|
152
|
+
|
|
153
|
+
Be specific — quote the line, name the file. The receiving agent acts on your
|
|
154
|
+
list directly, so vague feedback wastes a round trip. Do not mark nitpicks as
|
|
155
|
+
Critical. Do not edit any file yourself.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SkillManifest } from "scifi/skill-types";
|
|
2
|
+
|
|
3
|
+
export const manifest: SkillManifest = {
|
|
4
|
+
id: "sf-code-review",
|
|
5
|
+
description:
|
|
6
|
+
"Read-only critic pass on one change: a feature task against design.md + the task's acceptance, or a bug/fix against the agreed solution. Returns a verdict that gates acceptance.",
|
|
7
|
+
};
|