@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,33 @@
|
|
|
1
|
+
import { cwd } from 'node:process';
|
|
2
|
+
import { emitError, emitSuccess, jsonMode } from '../../core/output/index.js';
|
|
3
|
+
import { setFeatureWorktree } from '../../core/specs/worktree.js';
|
|
4
|
+
export function registerWorktreeCommand(program) {
|
|
5
|
+
const worktree = program
|
|
6
|
+
.command('worktree')
|
|
7
|
+
.description('Manage the git branch + worktree pointer recorded on a feature');
|
|
8
|
+
worktree
|
|
9
|
+
.command('set')
|
|
10
|
+
.description('Record the git branch and worktree path backing a feature')
|
|
11
|
+
.argument('<slug>', 'feature folder slug')
|
|
12
|
+
.requiredOption('--branch <branch>', 'git branch backing the feature')
|
|
13
|
+
.requiredOption('--path <path>', 'worktree path backing the feature')
|
|
14
|
+
.option('--json', 'output as structured JSON')
|
|
15
|
+
.action(async (slug, options, command) => {
|
|
16
|
+
const json = jsonMode(command);
|
|
17
|
+
try {
|
|
18
|
+
const result = await setFeatureWorktree(cwd(), slug, {
|
|
19
|
+
branch: options.branch,
|
|
20
|
+
path: options.path,
|
|
21
|
+
});
|
|
22
|
+
emitSuccess({ action: 'worktree-set', ...result }, json, [
|
|
23
|
+
`feature ${result.slug}: worktree recorded`,
|
|
24
|
+
` branch: ${result.branch}`,
|
|
25
|
+
` worktree: ${result.worktreePath}`,
|
|
26
|
+
]);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
emitError(error, json);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=worktree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../../../src/cli/commands/worktree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAElE,MAAM,UAAU,uBAAuB,CAAC,OAAgB;IACtD,MAAM,QAAQ,GAAG,OAAO;SACrB,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,gEAAgE,CAAC,CAAC;IAEjF,QAAQ;SACL,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,2DAA2D,CAAC;SACxE,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,CAAC;SACzC,cAAc,CAAC,mBAAmB,EAAE,gCAAgC,CAAC;SACrE,cAAc,CAAC,eAAe,EAAE,mCAAmC,CAAC;SACpE,MAAM,CAAC,QAAQ,EAAE,2BAA2B,CAAC;SAC7C,MAAM,CACL,KAAK,EACH,IAAY,EACZ,OAAyD,EACzD,OAAgB,EAChB,EAAE;QACF,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC/B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE;gBACnD,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,IAAI,EAAE,OAAO,CAAC,IAAI;aACnB,CAAC,CAAC;YACH,WAAW,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,EAAE,EAAE,IAAI,EAAE;gBACvD,WAAW,MAAM,CAAC,IAAI,qBAAqB;gBAC3C,eAAe,MAAM,CAAC,MAAM,EAAE;gBAC9B,eAAe,MAAM,CAAC,YAAY,EAAE;aACrC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACzB,CAAC;IACH,CAAC,CACF,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync, realpathSync } from 'node:fs';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
import { join, resolve } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { Command, CommanderError } from 'commander';
|
|
7
|
+
import { ScifiError } from '../core/output/errors.js';
|
|
8
|
+
import { emitError } from '../core/output/index.js';
|
|
9
|
+
import { findPackageRoot } from '../core/package-root.js';
|
|
10
|
+
import { registerFinishCommand } from './commands/finish.js';
|
|
11
|
+
import { registerFixCommand } from './commands/fix.js';
|
|
12
|
+
import { registerInitCommand } from './commands/init.js';
|
|
13
|
+
import { registerListCommand } from './commands/list.js';
|
|
14
|
+
import { registerPlanCommand } from './commands/plan.js';
|
|
15
|
+
import { registerPlanReadyCommand } from './commands/plan-ready.js';
|
|
16
|
+
import { registerSpecCommand } from './commands/spec.js';
|
|
17
|
+
import { registerSpecReadyCommand } from './commands/spec-ready.js';
|
|
18
|
+
import { registerStartCommand } from './commands/start.js';
|
|
19
|
+
import { registerStatusCommand } from './commands/status.js';
|
|
20
|
+
import { registerTaskCommand } from './commands/task.js';
|
|
21
|
+
import { registerWorktreeCommand } from './commands/worktree.js';
|
|
22
|
+
const require = createRequire(import.meta.url);
|
|
23
|
+
const packageJson = require(join(findPackageRoot(import.meta.url), 'package.json'));
|
|
24
|
+
function readPackageVersion(value) {
|
|
25
|
+
if (typeof value === 'object' &&
|
|
26
|
+
value !== null &&
|
|
27
|
+
'version' in value &&
|
|
28
|
+
typeof value.version === 'string') {
|
|
29
|
+
return value.version;
|
|
30
|
+
}
|
|
31
|
+
throw new Error('Unable to read version from package.json');
|
|
32
|
+
}
|
|
33
|
+
export function buildProgram() {
|
|
34
|
+
const program = new Command();
|
|
35
|
+
program
|
|
36
|
+
.name('scifi')
|
|
37
|
+
.description('Specification-driven CLI scaffolding for agentic workflows')
|
|
38
|
+
.version(readPackageVersion(packageJson))
|
|
39
|
+
.exitOverride();
|
|
40
|
+
registerInitCommand(program);
|
|
41
|
+
registerSpecCommand(program);
|
|
42
|
+
registerSpecReadyCommand(program);
|
|
43
|
+
registerPlanCommand(program);
|
|
44
|
+
registerPlanReadyCommand(program);
|
|
45
|
+
registerStartCommand(program);
|
|
46
|
+
registerFinishCommand(program);
|
|
47
|
+
registerListCommand(program);
|
|
48
|
+
registerStatusCommand(program);
|
|
49
|
+
registerTaskCommand(program);
|
|
50
|
+
registerFixCommand(program);
|
|
51
|
+
registerWorktreeCommand(program);
|
|
52
|
+
applyExitOverride(program);
|
|
53
|
+
return program;
|
|
54
|
+
}
|
|
55
|
+
function applyExitOverride(command) {
|
|
56
|
+
// Suppress Commander's own "error: ..." line so usage failures surface only
|
|
57
|
+
// through the structured emitError output (avoids double-printing).
|
|
58
|
+
command.configureOutput({ writeErr: () => { } });
|
|
59
|
+
for (const child of command.commands) {
|
|
60
|
+
child.exitOverride();
|
|
61
|
+
applyExitOverride(child);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export function isDirectExecution(moduleUrl, argv) {
|
|
65
|
+
const scriptPath = argv[1];
|
|
66
|
+
if (scriptPath === undefined) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return normalizeExecutionPath(fileURLToPath(moduleUrl)) === normalizeExecutionPath(scriptPath);
|
|
70
|
+
}
|
|
71
|
+
function normalizeExecutionPath(path) {
|
|
72
|
+
const resolvedPath = resolve(path);
|
|
73
|
+
if (!existsSync(resolvedPath)) {
|
|
74
|
+
return resolvedPath;
|
|
75
|
+
}
|
|
76
|
+
return realpathSync(resolvedPath);
|
|
77
|
+
}
|
|
78
|
+
function handleCliError(error, argv) {
|
|
79
|
+
const json = argv.includes('--json');
|
|
80
|
+
if (error instanceof CommanderError) {
|
|
81
|
+
// Help/version requests exit cleanly; Commander already wrote output.
|
|
82
|
+
if (error.exitCode === 0) {
|
|
83
|
+
process.exitCode = 0;
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const message = error.message.replace(/^error:\s*/i, '');
|
|
87
|
+
emitError(new ScifiError('INVALID_ARGUMENT', message, {
|
|
88
|
+
hint: 'Run `scifi --help` (or `<command> --help`) for usage.',
|
|
89
|
+
cause: error,
|
|
90
|
+
}), json);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
emitError(error, json);
|
|
94
|
+
}
|
|
95
|
+
async function runCli(argv) {
|
|
96
|
+
try {
|
|
97
|
+
await buildProgram().parseAsync(argv);
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
handleCliError(error, argv);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (isDirectExecution(import.meta.url, process.argv)) {
|
|
104
|
+
await runCli(process.argv);
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { BugSeverity } from './types.js';
|
|
2
|
+
export interface CreateBugOptions {
|
|
3
|
+
projectRoot: string;
|
|
4
|
+
description: string;
|
|
5
|
+
relatedFeature?: string;
|
|
6
|
+
severity?: BugSeverity;
|
|
7
|
+
now: string;
|
|
8
|
+
}
|
|
9
|
+
export interface CreateBugResult {
|
|
10
|
+
id: string;
|
|
11
|
+
filePath: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function createBug(options: CreateBugOptions): Promise<CreateBugResult>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { mkdir, readdir } from 'node:fs/promises';
|
|
2
|
+
import { slugify } from '../slugify.js';
|
|
3
|
+
import { writeBugFile } from './frontmatter.js';
|
|
4
|
+
import { formatBugId } from './id.js';
|
|
5
|
+
import { buildBugFilePath, buildBugsRootPath } from './paths.js';
|
|
6
|
+
export async function createBug(options) {
|
|
7
|
+
const { projectRoot, description, relatedFeature, severity, now } = options;
|
|
8
|
+
const bugsRoot = buildBugsRootPath(projectRoot);
|
|
9
|
+
await mkdir(bugsRoot, { recursive: true });
|
|
10
|
+
const existing = await readdir(bugsRoot, { withFileTypes: true });
|
|
11
|
+
const mdCount = existing.filter((e) => e.isFile() && e.name.endsWith('.md')).length;
|
|
12
|
+
const id = formatBugId(mdCount + 1);
|
|
13
|
+
const slug = slugify(description);
|
|
14
|
+
const filePath = buildBugFilePath(projectRoot, id, slug);
|
|
15
|
+
await writeBugFile(filePath, {
|
|
16
|
+
frontmatter: {
|
|
17
|
+
id,
|
|
18
|
+
slug,
|
|
19
|
+
status: 'open',
|
|
20
|
+
...(severity !== undefined && { severity }),
|
|
21
|
+
...(relatedFeature !== undefined && { 'related-feature': relatedFeature }),
|
|
22
|
+
created: now,
|
|
23
|
+
},
|
|
24
|
+
body: `# ${description}\n`,
|
|
25
|
+
});
|
|
26
|
+
return { id, filePath };
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../../../src/core/bugs/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAgBjE,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAyB;IACvD,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;IAC5E,MAAM,QAAQ,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAEhD,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE3C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAClE,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IAEpF,MAAM,EAAE,GAAG,WAAW,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,WAAW,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;IAEzD,MAAM,YAAY,CAAC,QAAQ,EAAE;QAC3B,WAAW,EAAE;YACX,EAAE;YACF,IAAI;YACJ,MAAM,EAAE,MAAM;YACd,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,CAAC;YAC3C,GAAG,CAAC,cAAc,KAAK,SAAS,IAAI,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAC;YAC1E,OAAO,EAAE,GAAG;SACb;QACD,IAAI,EAAE,KAAK,WAAW,IAAI;KAC3B,CAAC,CAAC;IAEH,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type BugFrontmatter } from './types.js';
|
|
2
|
+
export interface BugFile {
|
|
3
|
+
frontmatter: BugFrontmatter;
|
|
4
|
+
body: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function readBugFile(filePath: string): Promise<BugFile>;
|
|
7
|
+
export declare function writeBugFile(filePath: string, file: BugFile): Promise<void>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
|
|
3
|
+
import { BUG_SEVERITY_VALUES, BUG_STATUS_VALUES, } from './types.js';
|
|
4
|
+
const FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/;
|
|
5
|
+
function isValidBugStatus(value) {
|
|
6
|
+
return typeof value === 'string' && BUG_STATUS_VALUES.includes(value);
|
|
7
|
+
}
|
|
8
|
+
function isValidBugSeverity(value) {
|
|
9
|
+
return typeof value === 'string' && BUG_SEVERITY_VALUES.includes(value);
|
|
10
|
+
}
|
|
11
|
+
function isValidRawBugFrontmatter(raw) {
|
|
12
|
+
if (typeof raw !== 'object' || raw === null)
|
|
13
|
+
return false;
|
|
14
|
+
const obj = raw;
|
|
15
|
+
return (typeof obj.id === 'string' &&
|
|
16
|
+
typeof obj.slug === 'string' &&
|
|
17
|
+
isValidBugStatus(obj.status) &&
|
|
18
|
+
(obj.severity === undefined || isValidBugSeverity(obj.severity)) &&
|
|
19
|
+
(typeof obj['related-feature'] === 'string' || obj['related-feature'] === undefined) &&
|
|
20
|
+
typeof obj.created === 'string');
|
|
21
|
+
}
|
|
22
|
+
export async function readBugFile(filePath) {
|
|
23
|
+
const content = await readFile(filePath, 'utf8');
|
|
24
|
+
const match = FRONTMATTER_PATTERN.exec(content);
|
|
25
|
+
if (!match) {
|
|
26
|
+
throw new Error(`Bug file at ${filePath} is missing YAML frontmatter.`);
|
|
27
|
+
}
|
|
28
|
+
const raw = parseYaml(match[1] ?? '');
|
|
29
|
+
if (!isValidRawBugFrontmatter(raw)) {
|
|
30
|
+
throw new Error(`Bug file at ${filePath} has invalid frontmatter.`);
|
|
31
|
+
}
|
|
32
|
+
const frontmatter = {
|
|
33
|
+
id: raw.id,
|
|
34
|
+
slug: raw.slug,
|
|
35
|
+
status: raw.status,
|
|
36
|
+
created: raw.created,
|
|
37
|
+
};
|
|
38
|
+
if (raw.severity !== undefined) {
|
|
39
|
+
frontmatter.severity = raw.severity;
|
|
40
|
+
}
|
|
41
|
+
if (raw['related-feature'] !== undefined) {
|
|
42
|
+
frontmatter['related-feature'] = raw['related-feature'];
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
frontmatter,
|
|
46
|
+
body: match[2] ?? '',
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export async function writeBugFile(filePath, file) {
|
|
50
|
+
const rawFrontmatter = {
|
|
51
|
+
id: file.frontmatter.id,
|
|
52
|
+
slug: file.frontmatter.slug,
|
|
53
|
+
status: file.frontmatter.status,
|
|
54
|
+
...(file.frontmatter.severity !== undefined && {
|
|
55
|
+
severity: file.frontmatter.severity,
|
|
56
|
+
}),
|
|
57
|
+
...(file.frontmatter['related-feature'] !== undefined && {
|
|
58
|
+
'related-feature': file.frontmatter['related-feature'],
|
|
59
|
+
}),
|
|
60
|
+
created: file.frontmatter.created,
|
|
61
|
+
};
|
|
62
|
+
const content = `---\n${stringifyYaml(rawFrontmatter)}---\n${file.body}`;
|
|
63
|
+
await writeFile(filePath, content, 'utf8');
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=frontmatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../../../src/core/bugs/frontmatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,SAAS,IAAI,aAAa,EAAE,MAAM,MAAM,CAAC;AACtE,OAAO,EACL,mBAAmB,EACnB,iBAAiB,GAGlB,MAAM,YAAY,CAAC;AAOpB,MAAM,mBAAmB,GAAG,4CAA4C,CAAC;AAEzE,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,iBAAuC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC/F,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAc;IACxC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,mBAAyC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACjG,CAAC;AAED,SAAS,wBAAwB,CAAC,GAAY;IAC5C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC1D,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,OAAO,CACL,OAAO,GAAG,CAAC,EAAE,KAAK,QAAQ;QAC1B,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ;QAC5B,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC;QAC5B,CAAC,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAChE,CAAC,OAAO,GAAG,CAAC,iBAAiB,CAAC,KAAK,QAAQ,IAAI,GAAG,CAAC,iBAAiB,CAAC,KAAK,SAAS,CAAC;QACpF,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAChC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAgB;IAChD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEhD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,eAAe,QAAQ,+BAA+B,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAY,CAAC;IAEjD,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,eAAe,QAAQ,2BAA2B,CAAC,CAAC;IACtE,CAAC;IAED,MAAM,WAAW,GAAmB;QAClC,EAAE,EAAE,GAAG,CAAC,EAAY;QACpB,IAAI,EAAE,GAAG,CAAC,IAAc;QACxB,MAAM,EAAE,GAAG,CAAC,MAAkC;QAC9C,OAAO,EAAE,GAAG,CAAC,OAAiB;KAC/B,CAAC;IAEF,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC/B,WAAW,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAuB,CAAC;IACrD,CAAC;IACD,IAAI,GAAG,CAAC,iBAAiB,CAAC,KAAK,SAAS,EAAE,CAAC;QACzC,WAAW,CAAC,iBAAiB,CAAC,GAAG,GAAG,CAAC,iBAAiB,CAAW,CAAC;IACpE,CAAC;IAED,OAAO;QACL,WAAW;QACX,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;KACrB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB,EAAE,IAAa;IAChE,MAAM,cAAc,GAA4B;QAC9C,EAAE,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE;QACvB,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;QAC3B,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM;QAC/B,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,KAAK,SAAS,IAAI;YAC7C,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ;SACpC,CAAC;QACF,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC,KAAK,SAAS,IAAI;YACvD,iBAAiB,EAAE,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC;SACvD,CAAC;QACF,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO;KAClC,CAAC;IAEF,MAAM,OAAO,GAAG,QAAQ,aAAa,CAAC,cAAc,CAAC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;IACzE,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function formatBugId(sequenceNumber: number): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id.js","sourceRoot":"","sources":["../../../../src/core/bugs/id.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW,CAAC,cAAsB;IAChD,OAAO,OAAO,cAAc,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
export function buildBugsRootPath(projectRoot) {
|
|
3
|
+
return join(projectRoot, 'bugs');
|
|
4
|
+
}
|
|
5
|
+
export function buildBugFilePath(projectRoot, id, slug) {
|
|
6
|
+
return join(buildBugsRootPath(projectRoot), `${id}-${slug}.md`);
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../../src/core/bugs/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,UAAU,iBAAiB,CAAC,WAAmB;IACnD,OAAO,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,WAAmB,EAAE,EAAU,EAAE,IAAY;IAC5E,OAAO,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,EAAE,GAAG,EAAE,IAAI,IAAI,KAAK,CAAC,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const BUG_STATUS_VALUES: readonly ["open", "in-progress", "resolved", "wont-fix"];
|
|
2
|
+
export type BugStatus = (typeof BUG_STATUS_VALUES)[number];
|
|
3
|
+
export declare const BUG_SEVERITY_VALUES: readonly ["low", "medium", "high", "critical"];
|
|
4
|
+
export type BugSeverity = (typeof BUG_SEVERITY_VALUES)[number];
|
|
5
|
+
export interface BugFrontmatter {
|
|
6
|
+
id: string;
|
|
7
|
+
slug: string;
|
|
8
|
+
status: BugStatus;
|
|
9
|
+
severity?: BugSeverity;
|
|
10
|
+
'related-feature'?: string;
|
|
11
|
+
created: string;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/core/bugs/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,CAAU,CAAC;AAI1F,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAU,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface CreateFixOptions {
|
|
2
|
+
projectRoot: string;
|
|
3
|
+
description: string;
|
|
4
|
+
featureSlug: string;
|
|
5
|
+
now: string;
|
|
6
|
+
}
|
|
7
|
+
export interface CreateFixResult {
|
|
8
|
+
id: string;
|
|
9
|
+
filePath: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function createFix(options: CreateFixOptions): Promise<CreateFixResult>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { mkdir, readdir, stat } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { ScifiError } from '../output/errors.js';
|
|
4
|
+
import { slugify } from '../slugify.js';
|
|
5
|
+
import { buildFeatureDirectoryPath } from '../specs/paths.js';
|
|
6
|
+
import { writeFixFile } from './frontmatter.js';
|
|
7
|
+
import { formatFixId } from './id.js';
|
|
8
|
+
import { buildFixesDirectoryPath, buildFixFilePath } from './paths.js';
|
|
9
|
+
function isMissingPathError(error) {
|
|
10
|
+
return error instanceof Error && 'code' in error && error.code === 'ENOENT';
|
|
11
|
+
}
|
|
12
|
+
export async function createFix(options) {
|
|
13
|
+
const { projectRoot, description, featureSlug, now } = options;
|
|
14
|
+
const featureDir = buildFeatureDirectoryPath(projectRoot, featureSlug);
|
|
15
|
+
const metadataPath = join(featureDir, '.scifi.json');
|
|
16
|
+
await stat(metadataPath).catch((error) => {
|
|
17
|
+
if (isMissingPathError(error)) {
|
|
18
|
+
throw new ScifiError('NOT_FOUND', `Feature "${featureSlug}" does not exist.`, {
|
|
19
|
+
hint: `Create it with \`scifi spec ${featureSlug}\`.`,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
throw error;
|
|
23
|
+
});
|
|
24
|
+
const fixesDir = buildFixesDirectoryPath(projectRoot, featureSlug);
|
|
25
|
+
await mkdir(fixesDir, { recursive: true });
|
|
26
|
+
const existing = await readdir(fixesDir, { withFileTypes: true });
|
|
27
|
+
const mdCount = existing.filter((e) => e.isFile() && e.name.endsWith('.md')).length;
|
|
28
|
+
const id = formatFixId(mdCount + 1);
|
|
29
|
+
const slug = slugify(description);
|
|
30
|
+
const filePath = buildFixFilePath(projectRoot, featureSlug, id, slug);
|
|
31
|
+
await writeFixFile(filePath, {
|
|
32
|
+
frontmatter: {
|
|
33
|
+
id,
|
|
34
|
+
slug,
|
|
35
|
+
status: 'open',
|
|
36
|
+
feature: featureSlug,
|
|
37
|
+
created: now,
|
|
38
|
+
},
|
|
39
|
+
body: `# ${description}\n`,
|
|
40
|
+
});
|
|
41
|
+
return { id, filePath };
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../../../src/core/fixes/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEvE,SAAS,kBAAkB,CAAC,KAAc;IACxC,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC;AAC9E,CAAC;AAcD,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAyB;IACvD,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;IAE/D,MAAM,UAAU,GAAG,yBAAyB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACvE,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;IACrD,MAAM,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QAChD,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,UAAU,CAAC,WAAW,EAAE,YAAY,WAAW,mBAAmB,EAAE;gBAC5E,IAAI,EAAE,+BAA+B,WAAW,KAAK;aACtD,CAAC,CAAC;QACL,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,uBAAuB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACnE,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE3C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAClE,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IAEpF,MAAM,EAAE,GAAG,WAAW,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,WAAW,EAAE,WAAW,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;IAEtE,MAAM,YAAY,CAAC,QAAQ,EAAE;QAC3B,WAAW,EAAE;YACX,EAAE;YACF,IAAI;YACJ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,WAAW;YACpB,OAAO,EAAE,GAAG;SACb;QACD,IAAI,EAAE,KAAK,WAAW,IAAI;KAC3B,CAAC,CAAC;IAEH,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type FixFrontmatter } from './types.js';
|
|
2
|
+
export interface FixFile {
|
|
3
|
+
frontmatter: FixFrontmatter;
|
|
4
|
+
body: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function readFixFile(filePath: string): Promise<FixFile>;
|
|
7
|
+
export declare function writeFixFile(filePath: string, file: FixFile): Promise<void>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
|
|
3
|
+
import { FIX_STATUS_VALUES } from './types.js';
|
|
4
|
+
const FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/;
|
|
5
|
+
function isValidFixStatus(value) {
|
|
6
|
+
return typeof value === 'string' && FIX_STATUS_VALUES.includes(value);
|
|
7
|
+
}
|
|
8
|
+
function isValidRawFixFrontmatter(raw) {
|
|
9
|
+
if (typeof raw !== 'object' || raw === null)
|
|
10
|
+
return false;
|
|
11
|
+
const obj = raw;
|
|
12
|
+
return (typeof obj.id === 'string' &&
|
|
13
|
+
typeof obj.slug === 'string' &&
|
|
14
|
+
isValidFixStatus(obj.status) &&
|
|
15
|
+
typeof obj.feature === 'string' &&
|
|
16
|
+
typeof obj.created === 'string');
|
|
17
|
+
}
|
|
18
|
+
export async function readFixFile(filePath) {
|
|
19
|
+
const content = await readFile(filePath, 'utf8');
|
|
20
|
+
const match = FRONTMATTER_PATTERN.exec(content);
|
|
21
|
+
if (!match) {
|
|
22
|
+
throw new Error(`Fix file at ${filePath} is missing YAML frontmatter.`);
|
|
23
|
+
}
|
|
24
|
+
const raw = parseYaml(match[1] ?? '');
|
|
25
|
+
if (!isValidRawFixFrontmatter(raw)) {
|
|
26
|
+
throw new Error(`Fix file at ${filePath} has invalid frontmatter.`);
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
frontmatter: {
|
|
30
|
+
id: raw.id,
|
|
31
|
+
slug: raw.slug,
|
|
32
|
+
status: raw.status,
|
|
33
|
+
feature: raw.feature,
|
|
34
|
+
created: raw.created,
|
|
35
|
+
},
|
|
36
|
+
body: match[2] ?? '',
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export async function writeFixFile(filePath, file) {
|
|
40
|
+
const rawFrontmatter = {
|
|
41
|
+
id: file.frontmatter.id,
|
|
42
|
+
slug: file.frontmatter.slug,
|
|
43
|
+
status: file.frontmatter.status,
|
|
44
|
+
feature: file.frontmatter.feature,
|
|
45
|
+
created: file.frontmatter.created,
|
|
46
|
+
};
|
|
47
|
+
const content = `---\n${stringifyYaml(rawFrontmatter)}---\n${file.body}`;
|
|
48
|
+
await writeFile(filePath, content, 'utf8');
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=frontmatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../../../src/core/fixes/frontmatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,SAAS,IAAI,aAAa,EAAE,MAAM,MAAM,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAuB,MAAM,YAAY,CAAC;AAOpE,MAAM,mBAAmB,GAAG,4CAA4C,CAAC;AAEzE,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,iBAAuC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC/F,CAAC;AAED,SAAS,wBAAwB,CAAC,GAAY;IAC5C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC1D,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,OAAO,CACL,OAAO,GAAG,CAAC,EAAE,KAAK,QAAQ;QAC1B,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ;QAC5B,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC;QAC5B,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ;QAC/B,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAChC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAgB;IAChD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEhD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,eAAe,QAAQ,+BAA+B,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAY,CAAC;IAEjD,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,eAAe,QAAQ,2BAA2B,CAAC,CAAC;IACtE,CAAC;IAED,OAAO;QACL,WAAW,EAAE;YACX,EAAE,EAAE,GAAG,CAAC,EAAY;YACpB,IAAI,EAAE,GAAG,CAAC,IAAc;YACxB,MAAM,EAAE,GAAG,CAAC,MAAkC;YAC9C,OAAO,EAAE,GAAG,CAAC,OAAiB;YAC9B,OAAO,EAAE,GAAG,CAAC,OAAiB;SAC/B;QACD,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;KACrB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB,EAAE,IAAa;IAChE,MAAM,cAAc,GAA4B;QAC9C,EAAE,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE;QACvB,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;QAC3B,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM;QAC/B,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO;QACjC,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO;KAClC,CAAC;IAEF,MAAM,OAAO,GAAG,QAAQ,aAAa,CAAC,cAAc,CAAC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;IACzE,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function formatFixId(sequenceNumber: number): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id.js","sourceRoot":"","sources":["../../../../src/core/fixes/id.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW,CAAC,cAAsB;IAChD,OAAO,OAAO,cAAc,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { FixFrontmatter } from './types.js';
|
|
2
|
+
export interface FixFileLocation {
|
|
3
|
+
filePath: string;
|
|
4
|
+
frontmatter: FixFrontmatter;
|
|
5
|
+
}
|
|
6
|
+
export declare function listFixes(projectRoot: string, featureSlug: string): Promise<FixFrontmatter[]>;
|
|
7
|
+
export declare function listOpenFixes(projectRoot: string, featureSlug: string): Promise<FixFrontmatter[]>;
|
|
8
|
+
export declare function findFixById(projectRoot: string, featureSlug: string, fixId: string): Promise<FixFileLocation | undefined>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { readdir } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { readFixFile } from './frontmatter.js';
|
|
4
|
+
import { buildFixesDirectoryPath } from './paths.js';
|
|
5
|
+
function isMissingPathError(error) {
|
|
6
|
+
return error instanceof Error && 'code' in error && error.code === 'ENOENT';
|
|
7
|
+
}
|
|
8
|
+
export async function listFixes(projectRoot, featureSlug) {
|
|
9
|
+
const fixesDir = buildFixesDirectoryPath(projectRoot, featureSlug);
|
|
10
|
+
const entries = await readdir(fixesDir, { withFileTypes: true }).catch((error) => {
|
|
11
|
+
if (isMissingPathError(error))
|
|
12
|
+
return [];
|
|
13
|
+
throw error;
|
|
14
|
+
});
|
|
15
|
+
const mdFiles = entries.filter((e) => e.isFile() && e.name.endsWith('.md'));
|
|
16
|
+
const results = await Promise.all(mdFiles.map(async (entry) => {
|
|
17
|
+
const file = await readFixFile(join(fixesDir, entry.name));
|
|
18
|
+
return file.frontmatter;
|
|
19
|
+
}));
|
|
20
|
+
return results;
|
|
21
|
+
}
|
|
22
|
+
export async function listOpenFixes(projectRoot, featureSlug) {
|
|
23
|
+
const fixes = await listFixes(projectRoot, featureSlug);
|
|
24
|
+
return fixes.filter((f) => f.status === 'open' || f.status === 'in-progress');
|
|
25
|
+
}
|
|
26
|
+
export async function findFixById(projectRoot, featureSlug, fixId) {
|
|
27
|
+
const fixesDir = buildFixesDirectoryPath(projectRoot, featureSlug);
|
|
28
|
+
const entries = await readdir(fixesDir, { withFileTypes: true }).catch((error) => {
|
|
29
|
+
if (isMissingPathError(error))
|
|
30
|
+
return [];
|
|
31
|
+
throw error;
|
|
32
|
+
});
|
|
33
|
+
const mdFiles = entries.filter((e) => e.isFile() && e.name.endsWith('.md'));
|
|
34
|
+
for (const entry of mdFiles) {
|
|
35
|
+
const filePath = join(fixesDir, entry.name);
|
|
36
|
+
const file = await readFixFile(filePath);
|
|
37
|
+
if (file.frontmatter.id === fixId) {
|
|
38
|
+
return { filePath, frontmatter: file.frontmatter };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../../../src/core/fixes/list.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { buildFeatureDirectoryPath } from '../specs/paths.js';
|
|
3
|
+
export function buildFixesDirectoryPath(projectRoot, featureSlug) {
|
|
4
|
+
return join(buildFeatureDirectoryPath(projectRoot, featureSlug), 'fixes');
|
|
5
|
+
}
|
|
6
|
+
export function buildFixFilePath(projectRoot, featureSlug, id, slug) {
|
|
7
|
+
return join(buildFixesDirectoryPath(projectRoot, featureSlug), `${id}-${slug}.md`);
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../../src/core/fixes/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,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,gBAAgB,CAC9B,WAAmB,EACnB,WAAmB,EACnB,EAAU,EACV,IAAY;IAEZ,OAAO,IAAI,CAAC,uBAAuB,CAAC,WAAW,EAAE,WAAW,CAAC,EAAE,GAAG,EAAE,IAAI,IAAI,KAAK,CAAC,CAAC;AACrF,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FixStatus } from './types.js';
|
|
2
|
+
export interface UpdateFixStatusResult {
|
|
3
|
+
featureSlug: string;
|
|
4
|
+
id: string;
|
|
5
|
+
slug: string;
|
|
6
|
+
previousStatus: FixStatus;
|
|
7
|
+
newStatus: FixStatus;
|
|
8
|
+
}
|
|
9
|
+
export declare function updateFixStatus(projectRoot: string, featureSlug: string, fixId: string, targetStatus: FixStatus): Promise<UpdateFixStatusResult>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ScifiError } from '../output/errors.js';
|
|
2
|
+
import { readFixFile, writeFixFile } from './frontmatter.js';
|
|
3
|
+
import { findFixById } from './list.js';
|
|
4
|
+
export async function updateFixStatus(projectRoot, featureSlug, fixId, targetStatus) {
|
|
5
|
+
const location = await findFixById(projectRoot, featureSlug, fixId);
|
|
6
|
+
if (location === undefined) {
|
|
7
|
+
throw new ScifiError('NOT_FOUND', `Fix "${fixId}" does not exist in feature "${featureSlug}".`, { hint: "Run `scifi status <slug>` to see this feature's fixes." });
|
|
8
|
+
}
|
|
9
|
+
const previousStatus = location.frontmatter.status;
|
|
10
|
+
if (previousStatus !== 'open' && previousStatus !== 'in-progress') {
|
|
11
|
+
throw new ScifiError('PRECONDITION_FAILED', `Cannot transition fix ${fixId}: it is already ${previousStatus}.`, { hint: 'Only open or in-progress fixes can be resolved or marked wont-fix.' });
|
|
12
|
+
}
|
|
13
|
+
const file = await readFixFile(location.filePath);
|
|
14
|
+
await writeFixFile(location.filePath, {
|
|
15
|
+
...file,
|
|
16
|
+
frontmatter: { ...file.frontmatter, status: targetStatus },
|
|
17
|
+
});
|
|
18
|
+
return {
|
|
19
|
+
featureSlug,
|
|
20
|
+
id: file.frontmatter.id,
|
|
21
|
+
slug: file.frontmatter.slug,
|
|
22
|
+
previousStatus,
|
|
23
|
+
newStatus: targetStatus,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=transition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transition.js","sourceRoot":"","sources":["../../../../src/core/fixes/transition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAWxC,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,WAAmB,EACnB,WAAmB,EACnB,KAAa,EACb,YAAuB;IAEvB,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;IAEpE,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,UAAU,CAClB,WAAW,EACX,QAAQ,KAAK,gCAAgC,WAAW,IAAI,EAC5D,EAAE,IAAI,EAAE,wDAAwD,EAAE,CACnE,CAAC;IACJ,CAAC;IAED,MAAM,cAAc,GAAG,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC;IAEnD,IAAI,cAAc,KAAK,MAAM,IAAI,cAAc,KAAK,aAAa,EAAE,CAAC;QAClE,MAAM,IAAI,UAAU,CAClB,qBAAqB,EACrB,yBAAyB,KAAK,mBAAmB,cAAc,GAAG,EAClE,EAAE,IAAI,EAAE,oEAAoE,EAAE,CAC/E,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAElD,MAAM,YAAY,CAAC,QAAQ,CAAC,QAAQ,EAAE;QACpC,GAAG,IAAI;QACP,WAAW,EAAE,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE;KAC3D,CAAC,CAAC;IAEH,OAAO;QACL,WAAW;QACX,EAAE,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE;QACvB,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;QAC3B,cAAc;QACd,SAAS,EAAE,YAAY;KACxB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const FIX_STATUS_VALUES: readonly ["open", "in-progress", "resolved", "wont-fix"];
|
|
2
|
+
export type FixStatus = (typeof FIX_STATUS_VALUES)[number];
|
|
3
|
+
export interface FixFrontmatter {
|
|
4
|
+
id: string;
|
|
5
|
+
slug: string;
|
|
6
|
+
status: FixStatus;
|
|
7
|
+
feature: string;
|
|
8
|
+
created: string;
|
|
9
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/core/fixes/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,CAAU,CAAC"}
|