@g3nomaly/skills 0.3.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +95 -0
- package/dist/cli/adapter.d.ts +30 -0
- package/dist/cli/adapter.d.ts.map +1 -0
- package/dist/cli/adapter.js +86 -0
- package/dist/cli/adapter.js.map +1 -0
- package/dist/cli/commands/add.d.ts +17 -0
- package/dist/cli/commands/add.d.ts.map +1 -0
- package/dist/cli/commands/add.js +108 -0
- package/dist/cli/commands/add.js.map +1 -0
- package/dist/cli/commands/hook.d.ts +6 -0
- package/dist/cli/commands/hook.d.ts.map +1 -0
- package/dist/cli/commands/hook.js +18 -0
- package/dist/cli/commands/hook.js.map +1 -0
- package/dist/cli/commands/init.d.ts +22 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +119 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/ls.d.ts +4 -0
- package/dist/cli/commands/ls.d.ts.map +1 -0
- package/dist/cli/commands/ls.js +8 -0
- package/dist/cli/commands/ls.js.map +1 -0
- package/dist/cli/commands/remove.d.ts +12 -0
- package/dist/cli/commands/remove.d.ts.map +1 -0
- package/dist/cli/commands/remove.js +60 -0
- package/dist/cli/commands/remove.js.map +1 -0
- package/dist/cli/commands/update.d.ts +13 -0
- package/dist/cli/commands/update.d.ts.map +1 -0
- package/dist/cli/commands/update.js +49 -0
- package/dist/cli/commands/update.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +72 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/decisions/index.d.ts +6 -0
- package/dist/decisions/index.d.ts.map +1 -0
- package/dist/decisions/index.js +5 -0
- package/dist/decisions/index.js.map +1 -0
- package/dist/decisions/paths.d.ts +4 -0
- package/dist/decisions/paths.d.ts.map +1 -0
- package/dist/decisions/paths.js +12 -0
- package/dist/decisions/paths.js.map +1 -0
- package/dist/decisions/read.d.ts +18 -0
- package/dist/decisions/read.d.ts.map +1 -0
- package/dist/decisions/read.js +45 -0
- package/dist/decisions/read.js.map +1 -0
- package/dist/decisions/write.d.ts +20 -0
- package/dist/decisions/write.d.ts.map +1 -0
- package/dist/decisions/write.js +48 -0
- package/dist/decisions/write.js.map +1 -0
- package/dist/filetree/ensure.d.ts +7 -0
- package/dist/filetree/ensure.d.ts.map +1 -0
- package/dist/filetree/ensure.js +36 -0
- package/dist/filetree/ensure.js.map +1 -0
- package/dist/filetree/entries.d.ts +9 -0
- package/dist/filetree/entries.d.ts.map +1 -0
- package/dist/filetree/entries.js +49 -0
- package/dist/filetree/entries.js.map +1 -0
- package/dist/filetree/frontmatter.d.ts +16 -0
- package/dist/filetree/frontmatter.d.ts.map +1 -0
- package/dist/filetree/frontmatter.js +43 -0
- package/dist/filetree/frontmatter.js.map +1 -0
- package/dist/filetree/generate.d.ts +16 -0
- package/dist/filetree/generate.d.ts.map +1 -0
- package/dist/filetree/generate.js +62 -0
- package/dist/filetree/generate.js.map +1 -0
- package/dist/filetree/index.d.ts +17 -0
- package/dist/filetree/index.d.ts.map +1 -0
- package/dist/filetree/index.js +13 -0
- package/dist/filetree/index.js.map +1 -0
- package/dist/filetree/levels.d.ts +25 -0
- package/dist/filetree/levels.d.ts.map +1 -0
- package/dist/filetree/levels.js +45 -0
- package/dist/filetree/levels.js.map +1 -0
- package/dist/filetree/locate.d.ts +44 -0
- package/dist/filetree/locate.d.ts.map +1 -0
- package/dist/filetree/locate.js +76 -0
- package/dist/filetree/locate.js.map +1 -0
- package/dist/filetree/paths.d.ts +15 -0
- package/dist/filetree/paths.d.ts.map +1 -0
- package/dist/filetree/paths.js +38 -0
- package/dist/filetree/paths.js.map +1 -0
- package/dist/filetree/read.d.ts +23 -0
- package/dist/filetree/read.d.ts.map +1 -0
- package/dist/filetree/read.js +36 -0
- package/dist/filetree/read.js.map +1 -0
- package/dist/filetree/remove.d.ts +9 -0
- package/dist/filetree/remove.d.ts.map +1 -0
- package/dist/filetree/remove.js +17 -0
- package/dist/filetree/remove.js.map +1 -0
- package/dist/filetree/root.d.ts +9 -0
- package/dist/filetree/root.d.ts.map +1 -0
- package/dist/filetree/root.js +15 -0
- package/dist/filetree/root.js.map +1 -0
- package/dist/filetree/status.d.ts +21 -0
- package/dist/filetree/status.d.ts.map +1 -0
- package/dist/filetree/status.js +55 -0
- package/dist/filetree/status.js.map +1 -0
- package/dist/hooks/cli.d.ts +29 -0
- package/dist/hooks/cli.d.ts.map +1 -0
- package/dist/hooks/cli.js +65 -0
- package/dist/hooks/cli.js.map +1 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +3 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins/grilling/.claude-plugin/plugin.json +7 -0
- package/dist/plugins/grilling/skills/domain-modeling/ADR-FORMAT.md +47 -0
- package/dist/plugins/grilling/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
- package/dist/plugins/grilling/skills/domain-modeling/SKILL.md +74 -0
- package/dist/plugins/grilling/skills/domain-modeling/agents/openai.yaml +3 -0
- package/dist/plugins/grilling/skills/grill-me/SKILL.md +7 -0
- package/dist/plugins/grilling/skills/grill-me/agents/openai.yaml +5 -0
- package/dist/plugins/grilling/skills/grill-with-docs/SKILL.md +7 -0
- package/dist/plugins/grilling/skills/grill-with-docs/agents/openai.yaml +5 -0
- package/dist/plugins/grilling/skills/grilling/SKILL.md +12 -0
- package/dist/plugins/grilling/skills/grilling/agents/openai.yaml +3 -0
- package/dist/plugins/speech/.claude-plugin/plugin.json +7 -0
- package/dist/plugins/speech/skills/emphasise/SKILL.md +49 -0
- package/dist/plugins/speech/skills/emphasise/agents/openai.yaml +5 -0
- package/dist/plugins/speech/skills/unslop/SKILL.md +80 -0
- package/dist/plugins/task-manager/.claude-plugin/plugin.json +11 -0
- package/dist/plugins/task-manager/hooks/hooks.json +19 -0
- package/dist/plugins/task-manager/skills/decisions/SKILL.md +39 -0
- package/dist/plugins/task-manager/skills/decisions/agents/openai.yaml +5 -0
- package/dist/plugins/task-manager/skills/decisions/references/usage.md +26 -0
- package/dist/plugins/task-manager/skills/task-manager/SKILL.md +99 -0
- package/dist/plugins/task-manager/skills/vocabulary/SKILL.md +42 -0
- package/dist/plugins/task-manager/skills/vocabulary/agents/openai.yaml +5 -0
- package/dist/plugins/task-manager/skills/vocabulary/references/usage.md +26 -0
- package/dist/plugins/using-hooks/.claude-plugin/plugin.json +7 -0
- package/dist/plugins/using-hooks/skills/hook-post-tool-use/SKILL.md +79 -0
- package/dist/plugins/using-hooks/skills/hook-post-tool-use/agents/openai.yaml +5 -0
- package/dist/plugins/using-hooks/skills/hook-pre-tool-use/SKILL.md +84 -0
- package/dist/plugins/using-hooks/skills/hook-pre-tool-use/agents/openai.yaml +5 -0
- package/dist/plugins/using-hooks/skills/hook-stop/SKILL.md +69 -0
- package/dist/plugins/using-hooks/skills/hook-stop/agents/openai.yaml +5 -0
- package/dist/plugins/using-hooks/skills/hook-user-prompt-submit/SKILL.md +64 -0
- package/dist/plugins/using-hooks/skills/hook-user-prompt-submit/agents/openai.yaml +5 -0
- package/dist/plugins/workflow/.claude-plugin/plugin.json +16 -0
- package/dist/plugins/workflow/agents/reviewer.md +9 -0
- package/dist/plugins/workflow/skills/execute/SKILL.md +21 -0
- package/dist/plugins/workflow/skills/execute/agents/openai.yaml +5 -0
- package/dist/plugins/workflow/skills/orchestrator/SKILL.md +27 -0
- package/dist/plugins/workflow/skills/orchestrator/agents/openai.yaml +5 -0
- package/dist/plugins/workflow/skills/plan/SKILL.md +18 -0
- package/dist/plugins/workflow/skills/plan/agents/openai.yaml +5 -0
- package/dist/plugins/workflow/skills/plan/references/task-frontmatter.md +33 -0
- package/dist/plugins/workflow/skills/review/SKILL.md +25 -0
- package/dist/plugins/workflow/skills/review/agents/openai.yaml +5 -0
- package/dist/plugins/workflow/skills/run/SKILL.md +33 -0
- package/dist/plugins/workflow/skills/run/agents/openai.yaml +5 -0
- package/dist/plugins/workflow/skills/run/references/sub-agents.md +46 -0
- package/dist/plugins/workflow/skills/sync/SKILL.md +18 -0
- package/dist/plugins/workflow/skills/sync/agents/openai.yaml +5 -0
- package/dist/plugins/workflow/skills/worktree/SKILL.md +38 -0
- package/dist/plugins/workflow/skills/worktree/agents/openai.yaml +5 -0
- package/dist/plugins/workflow/skills/worktree/references/git-commands.md +27 -0
- package/dist/plugins/writing/.claude-plugin/plugin.json +7 -0
- package/dist/plugins/writing/skills/writing-great-hooks/SKILL.md +192 -0
- package/dist/plugins/writing/skills/writing-great-hooks/agents/openai.yaml +5 -0
- package/dist/plugins/writing/skills/writing-great-skills/GLOSSARY.md +201 -0
- package/dist/plugins/writing/skills/writing-great-skills/SKILL.md +92 -0
- package/dist/plugins/writing/skills/writing-great-skills/agents/openai.yaml +5 -0
- package/dist/plugins/writing/skills/writing-great-tasks/SKILL.md +136 -0
- package/dist/plugins/writing/skills/writing-great-tasks/agents/openai.yaml +5 -0
- package/dist/plugins/writing/skills/writing-great-tasks/templates/template_task.md +108 -0
- package/dist/registry/index.d.ts +5 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +6 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/registry/loadPackageRegistry.d.ts +14 -0
- package/dist/registry/loadPackageRegistry.d.ts.map +1 -0
- package/dist/registry/loadPackageRegistry.js +59 -0
- package/dist/registry/loadPackageRegistry.js.map +1 -0
- package/dist/registry/readSkillDir.d.ts +12 -0
- package/dist/registry/readSkillDir.d.ts.map +1 -0
- package/dist/registry/readSkillDir.js +59 -0
- package/dist/registry/readSkillDir.js.map +1 -0
- package/dist/registry/types.d.ts +53 -0
- package/dist/registry/types.d.ts.map +1 -0
- package/dist/registry/types.js +35 -0
- package/dist/registry/types.js.map +1 -0
- package/dist/registry/userManifest.d.ts +7 -0
- package/dist/registry/userManifest.d.ts.map +1 -0
- package/dist/registry/userManifest.js +21 -0
- package/dist/registry/userManifest.js.map +1 -0
- package/dist/remote/fetch.d.ts +16 -0
- package/dist/remote/fetch.d.ts.map +1 -0
- package/dist/remote/fetch.js +41 -0
- package/dist/remote/fetch.js.map +1 -0
- package/dist/remote/index.d.ts +7 -0
- package/dist/remote/index.d.ts.map +1 -0
- package/dist/remote/index.js +5 -0
- package/dist/remote/index.js.map +1 -0
- package/dist/remote/manifest.d.ts +23 -0
- package/dist/remote/manifest.d.ts.map +1 -0
- package/dist/remote/manifest.js +116 -0
- package/dist/remote/manifest.js.map +1 -0
- package/dist/remote/registry.d.ts +18 -0
- package/dist/remote/registry.d.ts.map +1 -0
- package/dist/remote/registry.js +58 -0
- package/dist/remote/registry.js.map +1 -0
- package/dist/schemas/config.d.ts +3 -0
- package/dist/schemas/config.d.ts.map +1 -0
- package/dist/schemas/config.js +3 -0
- package/dist/schemas/config.js.map +1 -0
- package/dist/schemas/decision.d.ts +43 -0
- package/dist/schemas/decision.d.ts.map +1 -0
- package/dist/schemas/decision.js +24 -0
- package/dist/schemas/decision.js.map +1 -0
- package/dist/schemas/index.d.ts +17 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +10 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/phase.d.ts +46 -0
- package/dist/schemas/phase.d.ts.map +1 -0
- package/dist/schemas/phase.js +16 -0
- package/dist/schemas/phase.js.map +1 -0
- package/dist/schemas/plan.d.ts +44 -0
- package/dist/schemas/plan.d.ts.map +1 -0
- package/dist/schemas/plan.js +15 -0
- package/dist/schemas/plan.js.map +1 -0
- package/dist/schemas/primitives.d.ts +38 -0
- package/dist/schemas/primitives.d.ts.map +1 -0
- package/dist/schemas/primitives.js +33 -0
- package/dist/schemas/primitives.js.map +1 -0
- package/dist/schemas/task.d.ts +70 -0
- package/dist/schemas/task.d.ts.map +1 -0
- package/dist/schemas/task.js +19 -0
- package/dist/schemas/task.js.map +1 -0
- package/dist/schemas/term.d.ts +17 -0
- package/dist/schemas/term.d.ts.map +1 -0
- package/dist/schemas/term.js +22 -0
- package/dist/schemas/term.js.map +1 -0
- package/dist/schemas/validation.d.ts +24 -0
- package/dist/schemas/validation.d.ts.map +1 -0
- package/dist/schemas/validation.js +39 -0
- package/dist/schemas/validation.js.map +1 -0
- package/dist/task-manager/hooks/add-decision.d.ts +2 -0
- package/dist/task-manager/hooks/add-decision.d.ts.map +1 -0
- package/dist/task-manager/hooks/add-decision.js +19 -0
- package/dist/task-manager/hooks/add-decision.js.map +1 -0
- package/dist/task-manager/hooks/cleanup.d.ts +2 -0
- package/dist/task-manager/hooks/cleanup.d.ts.map +1 -0
- package/dist/task-manager/hooks/cleanup.js +27 -0
- package/dist/task-manager/hooks/cleanup.js.map +1 -0
- package/dist/task-manager/hooks/get-decision.d.ts +2 -0
- package/dist/task-manager/hooks/get-decision.d.ts.map +1 -0
- package/dist/task-manager/hooks/get-decision.js +11 -0
- package/dist/task-manager/hooks/get-decision.js.map +1 -0
- package/dist/task-manager/hooks/get-entry.d.ts +2 -0
- package/dist/task-manager/hooks/get-entry.d.ts.map +1 -0
- package/dist/task-manager/hooks/get-entry.js +20 -0
- package/dist/task-manager/hooks/get-entry.js.map +1 -0
- package/dist/task-manager/hooks/get-term.d.ts +2 -0
- package/dist/task-manager/hooks/get-term.d.ts.map +1 -0
- package/dist/task-manager/hooks/get-term.js +13 -0
- package/dist/task-manager/hooks/get-term.js.map +1 -0
- package/dist/task-manager/hooks/guard-tree.d.ts +2 -0
- package/dist/task-manager/hooks/guard-tree.d.ts.map +1 -0
- package/dist/task-manager/hooks/guard-tree.js +63 -0
- package/dist/task-manager/hooks/guard-tree.js.map +1 -0
- package/dist/task-manager/hooks/index.d.ts +4 -0
- package/dist/task-manager/hooks/index.d.ts.map +1 -0
- package/dist/task-manager/hooks/index.js +32 -0
- package/dist/task-manager/hooks/index.js.map +1 -0
- package/dist/task-manager/hooks/list-decisions.d.ts +2 -0
- package/dist/task-manager/hooks/list-decisions.d.ts.map +1 -0
- package/dist/task-manager/hooks/list-decisions.js +20 -0
- package/dist/task-manager/hooks/list-decisions.js.map +1 -0
- package/dist/task-manager/hooks/list-entries.d.ts +2 -0
- package/dist/task-manager/hooks/list-entries.d.ts.map +1 -0
- package/dist/task-manager/hooks/list-entries.js +19 -0
- package/dist/task-manager/hooks/list-entries.js.map +1 -0
- package/dist/task-manager/hooks/list-terms.d.ts +2 -0
- package/dist/task-manager/hooks/list-terms.d.ts.map +1 -0
- package/dist/task-manager/hooks/list-terms.js +8 -0
- package/dist/task-manager/hooks/list-terms.js.map +1 -0
- package/dist/task-manager/hooks/next-entry.d.ts +2 -0
- package/dist/task-manager/hooks/next-entry.d.ts.map +1 -0
- package/dist/task-manager/hooks/next-entry.js +23 -0
- package/dist/task-manager/hooks/next-entry.js.map +1 -0
- package/dist/task-manager/hooks/remove-term.d.ts +2 -0
- package/dist/task-manager/hooks/remove-term.d.ts.map +1 -0
- package/dist/task-manager/hooks/remove-term.js +15 -0
- package/dist/task-manager/hooks/remove-term.js.map +1 -0
- package/dist/task-manager/hooks/set-state.d.ts +2 -0
- package/dist/task-manager/hooks/set-state.d.ts.map +1 -0
- package/dist/task-manager/hooks/set-state.js +15 -0
- package/dist/task-manager/hooks/set-state.js.map +1 -0
- package/dist/task-manager/hooks/set-term.d.ts +2 -0
- package/dist/task-manager/hooks/set-term.d.ts.map +1 -0
- package/dist/task-manager/hooks/set-term.js +27 -0
- package/dist/task-manager/hooks/set-term.js.map +1 -0
- package/dist/task-manager/hooks/sync-tree.d.ts +2 -0
- package/dist/task-manager/hooks/sync-tree.d.ts.map +1 -0
- package/dist/task-manager/hooks/sync-tree.js +28 -0
- package/dist/task-manager/hooks/sync-tree.js.map +1 -0
- package/dist/task-manager/index.d.ts +2 -0
- package/dist/task-manager/index.d.ts.map +1 -0
- package/dist/task-manager/index.js +3 -0
- package/dist/task-manager/index.js.map +1 -0
- package/dist/vocabulary/file.d.ts +15 -0
- package/dist/vocabulary/file.d.ts.map +1 -0
- package/dist/vocabulary/file.js +80 -0
- package/dist/vocabulary/file.js.map +1 -0
- package/dist/vocabulary/index.d.ts +4 -0
- package/dist/vocabulary/index.d.ts.map +1 -0
- package/dist/vocabulary/index.js +4 -0
- package/dist/vocabulary/index.js.map +1 -0
- package/dist/vocabulary/match.d.ts +22 -0
- package/dist/vocabulary/match.d.ts.map +1 -0
- package/dist/vocabulary/match.js +31 -0
- package/dist/vocabulary/match.js.map +1 -0
- package/dist/workflow/gates.d.ts +24 -0
- package/dist/workflow/gates.d.ts.map +1 -0
- package/dist/workflow/gates.js +34 -0
- package/dist/workflow/gates.js.map +1 -0
- package/dist/workflow/hooks/advance-step.d.ts +2 -0
- package/dist/workflow/hooks/advance-step.d.ts.map +1 -0
- package/dist/workflow/hooks/advance-step.js +51 -0
- package/dist/workflow/hooks/advance-step.js.map +1 -0
- package/dist/workflow/hooks/current-step.d.ts +2 -0
- package/dist/workflow/hooks/current-step.d.ts.map +1 -0
- package/dist/workflow/hooks/current-step.js +24 -0
- package/dist/workflow/hooks/current-step.js.map +1 -0
- package/dist/workflow/hooks/index.d.ts +4 -0
- package/dist/workflow/hooks/index.d.ts.map +1 -0
- package/dist/workflow/hooks/index.js +10 -0
- package/dist/workflow/hooks/index.js.map +1 -0
- package/dist/workflow/hooks/ready-phases.d.ts +2 -0
- package/dist/workflow/hooks/ready-phases.d.ts.map +1 -0
- package/dist/workflow/hooks/ready-phases.js +15 -0
- package/dist/workflow/hooks/ready-phases.js.map +1 -0
- package/dist/workflow/index.d.ts +8 -0
- package/dist/workflow/index.d.ts.map +1 -0
- package/dist/workflow/index.js +6 -0
- package/dist/workflow/index.js.map +1 -0
- package/dist/workflow/phase.d.ts +16 -0
- package/dist/workflow/phase.d.ts.map +1 -0
- package/dist/workflow/phase.js +22 -0
- package/dist/workflow/phase.js.map +1 -0
- package/dist/workflow/steps.d.ts +15 -0
- package/dist/workflow/steps.d.ts.map +1 -0
- package/dist/workflow/steps.js +32 -0
- package/dist/workflow/steps.js.map +1 -0
- package/package.json +62 -3
- package/README.md +0 -3
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// packages/skills/src/cli/commands/remove.ts
|
|
2
|
+
import { removeEntries, ConflictDecision, StepKind } from "@g3nomaly/core/cli";
|
|
3
|
+
import { saveUserManifest } from "../../registry/userManifest";
|
|
4
|
+
import { openSkillProject, resolveSkillKeys, skillRegistry, skillTargets } from "../adapter";
|
|
5
|
+
export const noValueDialogue = {
|
|
6
|
+
steps: {
|
|
7
|
+
selectSkills: {
|
|
8
|
+
kind: StepKind.MultiSelect,
|
|
9
|
+
message: "Select skills to remove:",
|
|
10
|
+
choices: (input) => input.keyChoices ?? [],
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
export const cascadeDialogue = {
|
|
15
|
+
steps: {
|
|
16
|
+
cascade: {
|
|
17
|
+
kind: StepKind.Confirm,
|
|
18
|
+
message: "Also remove {dependents}?",
|
|
19
|
+
initial: true,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
export const collisionDialogue = {
|
|
24
|
+
steps: {
|
|
25
|
+
conflict: {
|
|
26
|
+
kind: StepKind.Select,
|
|
27
|
+
message: "{key} ({target}) has local changes. What would you like to do?",
|
|
28
|
+
choices: [
|
|
29
|
+
{ value: ConflictDecision.Keep, label: "Keep the skill — remove nothing" },
|
|
30
|
+
{ value: ConflictDecision.Overwrite, label: "Remove it anyway, including my changes" },
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
export const incompleteDialogue = {
|
|
36
|
+
steps: {
|
|
37
|
+
incomplete: {
|
|
38
|
+
kind: StepKind.Confirm,
|
|
39
|
+
message: "{key} ({target}) is missing {missing} on disk. Remove the rest and untrack it?",
|
|
40
|
+
initial: true,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
/** Removes installed skills and drops them from each target's `skills.json`. */
|
|
45
|
+
export async function removeCommand(keys, options = {}, deps = {}) {
|
|
46
|
+
const { projectRoot, config } = await openSkillProject(deps);
|
|
47
|
+
const registry = await skillRegistry();
|
|
48
|
+
const targets = await skillTargets(config, projectRoot, options.targets);
|
|
49
|
+
// Unknown keys stay in the list so the command reports them as "not installed".
|
|
50
|
+
const { resolved, unknown } = resolveSkillKeys(keys, registry);
|
|
51
|
+
await removeEntries(registry, targets, [...resolved, ...unknown], options, {
|
|
52
|
+
onNoValue: noValueDialogue,
|
|
53
|
+
onCascade: cascadeDialogue,
|
|
54
|
+
onCollision: collisionDialogue,
|
|
55
|
+
onIncomplete: incompleteDialogue,
|
|
56
|
+
});
|
|
57
|
+
for (const target of targets)
|
|
58
|
+
saveUserManifest(target.store);
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=remove.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove.js","sourceRoot":"","sources":["../../../src/cli/commands/remove.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAO7F,MAAM,CAAC,MAAM,eAAe,GAA2B;IACrD,KAAK,EAAE;QACL,YAAY,EAAE;YACZ,IAAI,EAAK,QAAQ,CAAC,WAAW;YAC7B,OAAO,EAAE,0BAA0B;YACnC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,IAAI,EAAE;SAC3C;KACF;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAA2B;IACrD,KAAK,EAAE;QACL,OAAO,EAAE;YACP,IAAI,EAAK,QAAQ,CAAC,OAAO;YACzB,OAAO,EAAE,2BAA2B;YACpC,OAAO,EAAE,IAAI;SACd;KACF;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAA2B;IACvD,KAAK,EAAE;QACL,QAAQ,EAAE;YACR,IAAI,EAAK,QAAQ,CAAC,MAAM;YACxB,OAAO,EAAE,gEAAgE;YACzE,OAAO,EAAE;gBACP,EAAE,KAAK,EAAE,gBAAgB,CAAC,IAAI,EAAO,KAAK,EAAE,iCAAiC,EAAE;gBAC/E,EAAE,KAAK,EAAE,gBAAgB,CAAC,SAAS,EAAE,KAAK,EAAE,wCAAwC,EAAE;aACvF;SACF;KACF;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAA2B;IACxD,KAAK,EAAE;QACL,UAAU,EAAE;YACV,IAAI,EAAK,QAAQ,CAAC,OAAO;YACzB,OAAO,EAAE,gFAAgF;YACzF,OAAO,EAAE,IAAI;SACd;KACF;CACF,CAAC;AAEF,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAc,EAAE,OAAO,GAAkB,EAAE,EAAE,IAAI,GAAgB,EAAE;IACrG,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAG,MAAM,aAAa,EAAE,CAAC;IACvC,MAAM,OAAO,GAAI,MAAM,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAE1E,gFAAgF;IAChF,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,gBAAgB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAE/D,MAAM,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC,GAAG,QAAQ,EAAE,GAAG,OAAO,CAAC,EAAE,OAAO,EAAE;QACzE,SAAS,EAAK,eAAe;QAC7B,SAAS,EAAK,eAAe;QAC7B,WAAW,EAAG,iBAAiB;QAC/B,YAAY,EAAE,kBAAkB;KACjC,CAAC,CAAC;IAEH,KAAK,MAAM,MAAM,IAAI,OAAO;QAAE,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC/D,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Dialogue, InstallInput, InstallOptions } from "@g3nomaly/core/cli";
|
|
2
|
+
import type { ProjectDeps } from "../adapter";
|
|
3
|
+
export interface UpdateOptions extends InstallOptions {
|
|
4
|
+
targets?: string[];
|
|
5
|
+
}
|
|
6
|
+
export declare const entryNotFoundDialogue: Dialogue<InstallInput>;
|
|
7
|
+
export declare const collisionDialogue: Dialogue<InstallInput>;
|
|
8
|
+
/**
|
|
9
|
+
* Re-installs skills already present in a target's `skills.json`. Files the
|
|
10
|
+
* user changed since install are reported and kept unless overwritten.
|
|
11
|
+
*/
|
|
12
|
+
export declare function updateCommand(keys: string[], options?: UpdateOptions, deps?: ProjectDeps): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=update.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/update.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGjF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,WAAW,aAAc,SAAQ,cAAc;IACnD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,eAAO,MAAM,qBAAqB,EAAE,QAAQ,CAAC,YAAY,CAQxD,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CAAC,YAAY,CAWpD,CAAC;AAEF;;;GAGG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,aAAkB,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBtH"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// packages/skills/src/cli/commands/update.ts
|
|
2
|
+
import { updateEntries, runDialogueValue, ConflictDecision, StepKind, c, lineError } from "@g3nomaly/core/cli";
|
|
3
|
+
import { saveUserManifest } from "../../registry/userManifest";
|
|
4
|
+
import { openSkillProject, resolveSkillKeys, skillRegistry, skillSource, skillTargets } from "../adapter";
|
|
5
|
+
export const entryNotFoundDialogue = {
|
|
6
|
+
steps: {
|
|
7
|
+
entryNotFound: {
|
|
8
|
+
kind: StepKind.Confirm,
|
|
9
|
+
message: "Unknown skill(s): {unknown}. Continue with the remaining selection?",
|
|
10
|
+
initial: false,
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
export const collisionDialogue = {
|
|
15
|
+
steps: {
|
|
16
|
+
conflict: {
|
|
17
|
+
kind: StepKind.Select,
|
|
18
|
+
message: "{key} ({target}) has local changes. What would you like to do?",
|
|
19
|
+
choices: [
|
|
20
|
+
{ value: ConflictDecision.Keep, label: "Keep my changes — skip modified files" },
|
|
21
|
+
{ value: ConflictDecision.Overwrite, label: "Overwrite with the package version" },
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Re-installs skills already present in a target's `skills.json`. Files the
|
|
28
|
+
* user changed since install are reported and kept unless overwritten.
|
|
29
|
+
*/
|
|
30
|
+
export async function updateCommand(keys, options = {}, deps = {}) {
|
|
31
|
+
const { projectRoot, config } = await openSkillProject(deps);
|
|
32
|
+
const registry = await skillRegistry();
|
|
33
|
+
const targets = await skillTargets(config, projectRoot, options.targets);
|
|
34
|
+
const { resolved, unknown } = resolveSkillKeys(keys, registry);
|
|
35
|
+
if (unknown.length > 0) {
|
|
36
|
+
console.error(lineError(`Unknown skill(s): ${unknown.map((k) => c.key(k)).join(", ")}. Run ${c.cmd("g3n-skills ls")} to see what is available.`));
|
|
37
|
+
const proceed = resolved.length > 0
|
|
38
|
+
&& (await runDialogueValue(entryNotFoundDialogue, { unknown: unknown.map((k) => c.key(k)).join(", ") }, options.answers)) === true;
|
|
39
|
+
if (!proceed)
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
await updateEntries(registry, targets, skillSource, resolved, options, {
|
|
43
|
+
onCollision: collisionDialogue,
|
|
44
|
+
});
|
|
45
|
+
if (!options.dryRun)
|
|
46
|
+
for (const target of targets)
|
|
47
|
+
saveUserManifest(target.store);
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../../src/cli/commands/update.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/G,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAO1G,MAAM,CAAC,MAAM,qBAAqB,GAA2B;IAC3D,KAAK,EAAE;QACL,aAAa,EAAE;YACb,IAAI,EAAK,QAAQ,CAAC,OAAO;YACzB,OAAO,EAAE,qEAAqE;YAC9E,OAAO,EAAE,KAAK;SACf;KACF;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAA2B;IACvD,KAAK,EAAE;QACL,QAAQ,EAAE;YACR,IAAI,EAAK,QAAQ,CAAC,MAAM;YACxB,OAAO,EAAE,gEAAgE;YACzE,OAAO,EAAE;gBACP,EAAE,KAAK,EAAE,gBAAgB,CAAC,IAAI,EAAO,KAAK,EAAE,uCAAuC,EAAE;gBACrF,EAAE,KAAK,EAAE,gBAAgB,CAAC,SAAS,EAAE,KAAK,EAAE,oCAAoC,EAAE;aACnF;SACF;KACF;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAc,EAAE,OAAO,GAAkB,EAAE,EAAE,IAAI,GAAgB,EAAE;IACrG,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAG,MAAM,aAAa,EAAE,CAAC;IACvC,MAAM,OAAO,GAAI,MAAM,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAE1E,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,gBAAgB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC/D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,qBAAqB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,4BAA4B,CAAC,CAAC,CAAC;QAClJ,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC;eAC9B,CAAC,MAAM,gBAAgB,CAAC,qBAAqB,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,CAAC;QACrI,IAAI,CAAC,OAAO;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE;QACrE,WAAW,EAAE,iBAAiB;KAC/B,CAAC,CAAC;IAEH,IAAI,CAAC,OAAO,CAAC,MAAM;QAAE,KAAK,MAAM,MAAM,IAAI,OAAO;YAAE,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACpF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// packages/skills/src/cli/index.ts
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { readPackageMeta, warnIfOutdated } from "@g3nomaly/core/utils";
|
|
5
|
+
import { SkillTargetSchema } from "@g3nomaly/core/config";
|
|
6
|
+
import { initCommand } from "./commands/init";
|
|
7
|
+
import { addCommand } from "./commands/add";
|
|
8
|
+
import { removeCommand } from "./commands/remove";
|
|
9
|
+
import { updateCommand } from "./commands/update";
|
|
10
|
+
import { lsCommand } from "./commands/ls";
|
|
11
|
+
import { hookCommand } from "./commands/hook";
|
|
12
|
+
function parseTargets(value) {
|
|
13
|
+
return value === undefined ? undefined : [SkillTargetSchema.parse(value)];
|
|
14
|
+
}
|
|
15
|
+
// `hook` bypasses Commander so the hook's own `--flags` reach it untouched.
|
|
16
|
+
if (process.argv[2] === "hook") {
|
|
17
|
+
hookCommand(process.argv[3], process.argv.slice(4));
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
const program = new Command()
|
|
21
|
+
.name("g3n-skills")
|
|
22
|
+
.description("Install g3n skills into a project's agent directories");
|
|
23
|
+
program
|
|
24
|
+
.command("init")
|
|
25
|
+
.description("Configure which harnesses skills are installed for")
|
|
26
|
+
.option("-f, --force", "Reconfigure without prompting")
|
|
27
|
+
.option("--targets <list>", "Comma-separated targets (claude,codex); skips the prompt")
|
|
28
|
+
.action(async (opts) => {
|
|
29
|
+
const targets = opts.targets?.split(",").map((t) => SkillTargetSchema.parse(t.trim()));
|
|
30
|
+
await initCommand({ force: opts.force, targets });
|
|
31
|
+
});
|
|
32
|
+
program
|
|
33
|
+
.command("add [skills...]")
|
|
34
|
+
.description("Install skills or whole groups (e.g. speech, grilling)")
|
|
35
|
+
.option("-f, --force", "Overwrite locally modified files")
|
|
36
|
+
.option("-t, --target <target>", "Only this target (claude|codex)")
|
|
37
|
+
.option("--remote <url>", "Install from a git repository with a plugin or marketplace manifest instead of the package")
|
|
38
|
+
.action(async (skills, opts) => {
|
|
39
|
+
await addCommand(skills, { force: opts.force, targets: parseTargets(opts.target), remote: opts.remote });
|
|
40
|
+
});
|
|
41
|
+
program
|
|
42
|
+
.command("remove [skills...]")
|
|
43
|
+
.description("Remove installed skills")
|
|
44
|
+
.option("-f, --force", "Remove even if files have been modified")
|
|
45
|
+
.option("-t, --target <target>", "Only this target (claude|codex)")
|
|
46
|
+
.action(async (skills, opts) => {
|
|
47
|
+
await removeCommand(skills, { force: opts.force, targets: parseTargets(opts.target) });
|
|
48
|
+
});
|
|
49
|
+
program
|
|
50
|
+
.command("update [skills...]")
|
|
51
|
+
.description("Re-install installed skills from the package")
|
|
52
|
+
.option("-f, --force", "Overwrite locally modified files without prompting")
|
|
53
|
+
.option("--dry-run", "Report what would change without writing")
|
|
54
|
+
.option("-t, --target <target>", "Only this target (claude|codex)")
|
|
55
|
+
.action(async (skills, opts) => {
|
|
56
|
+
await updateCommand(skills, { force: opts.force, dryRun: opts.dryRun, targets: parseTargets(opts.target) });
|
|
57
|
+
});
|
|
58
|
+
program
|
|
59
|
+
.command("ls")
|
|
60
|
+
.description("List skills available in the package")
|
|
61
|
+
.option("--json", "Output as JSON")
|
|
62
|
+
.action(async (opts) => {
|
|
63
|
+
await lsCommand({ json: opts.json });
|
|
64
|
+
});
|
|
65
|
+
program
|
|
66
|
+
.command("hook <name> [flags...]")
|
|
67
|
+
.description("Run a task-manager hook: sync-tree, guard-tree, next-entry, get-entry, list-entries, set-state, cleanup");
|
|
68
|
+
const self = readPackageMeta(import.meta.url);
|
|
69
|
+
await warnIfOutdated(self.name, self.version, import.meta.url);
|
|
70
|
+
program.parseAsync();
|
|
71
|
+
}
|
|
72
|
+
//# 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,6 @@
|
|
|
1
|
+
export { decisionsDirFor, decisionPathFor } from "./paths";
|
|
2
|
+
export { listDecisionIds, readDecision } from "./read";
|
|
3
|
+
export type { DecisionDocument } from "./read";
|
|
4
|
+
export { nextDecisionId, addDecision } from "./write";
|
|
5
|
+
export type { NewDecision } from "./write";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/decisions/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE3D,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACvD,YAAY,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAE/C,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtD,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/decisions/index.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE3D,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAGvD,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/decisions/paths.ts"],"names":[],"mappings":"AAKA,8CAA8C;AAC9C,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAEnE"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// packages/skills/src/decisions/paths.ts
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { DECISIONS_DIR } from "../schemas/decision";
|
|
4
|
+
import { MARKDOWN } from "../filetree/levels";
|
|
5
|
+
/** Folder holding a plan's decision files. */
|
|
6
|
+
export function decisionsDirFor(planDir) {
|
|
7
|
+
return join(planDir, DECISIONS_DIR);
|
|
8
|
+
}
|
|
9
|
+
export function decisionPathFor(planDir, id) {
|
|
10
|
+
return join(decisionsDirFor(planDir), `${id}${MARKDOWN}`);
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/decisions/paths.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,8CAA8C;AAC9C,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,OAAO,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,EAAU;IACzD,OAAO,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type Decision } from "../schemas/decision";
|
|
2
|
+
/** One decision as it sits on disk: where it was read from, its fields, its prose. */
|
|
3
|
+
export interface DecisionDocument {
|
|
4
|
+
file: string;
|
|
5
|
+
meta: Decision;
|
|
6
|
+
body: string;
|
|
7
|
+
}
|
|
8
|
+
/** Ids of a plan's decisions, in numbered order. A plan with no `decisions/` folder has none. */
|
|
9
|
+
export declare function listDecisionIds(planDir: string): Promise<string[]>;
|
|
10
|
+
/**
|
|
11
|
+
* Reads one decision of a plan and checks it against its schema.
|
|
12
|
+
*
|
|
13
|
+
* @param id file name without extension, e.g. `0001-use-jwt`
|
|
14
|
+
* @throws FileValidationError when a field fails its schema, or when the `id`
|
|
15
|
+
* inside the file disagrees with the file it was read from
|
|
16
|
+
*/
|
|
17
|
+
export declare function readDecision(planDir: string, id: string): Promise<DecisionDocument>;
|
|
18
|
+
//# sourceMappingURL=read.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/decisions/read.ts"],"names":[],"mappings":"AAGA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAKpE,sFAAsF;AACtF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,iGAAiG;AACjG,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAcxE;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAgBzF"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// packages/skills/src/decisions/read.ts
|
|
2
|
+
import { readdir } from "node:fs/promises";
|
|
3
|
+
import { FileValidationError, parseFile } from "../schemas/validation";
|
|
4
|
+
import { DecisionSchema } from "../schemas/decision";
|
|
5
|
+
import { MARKDOWN } from "../filetree/levels";
|
|
6
|
+
import { readDocument } from "../filetree/frontmatter";
|
|
7
|
+
import { decisionPathFor, decisionsDirFor } from "./paths";
|
|
8
|
+
/** Ids of a plan's decisions, in numbered order. A plan with no `decisions/` folder has none. */
|
|
9
|
+
export async function listDecisionIds(planDir) {
|
|
10
|
+
let files;
|
|
11
|
+
try {
|
|
12
|
+
files = await readdir(decisionsDirFor(planDir), { withFileTypes: true });
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT")
|
|
16
|
+
return [];
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
return files
|
|
20
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith(MARKDOWN))
|
|
21
|
+
.map((entry) => entry.name.slice(0, -MARKDOWN.length))
|
|
22
|
+
.sort((a, b) => a.localeCompare(b));
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Reads one decision of a plan and checks it against its schema.
|
|
26
|
+
*
|
|
27
|
+
* @param id file name without extension, e.g. `0001-use-jwt`
|
|
28
|
+
* @throws FileValidationError when a field fails its schema, or when the `id`
|
|
29
|
+
* inside the file disagrees with the file it was read from
|
|
30
|
+
*/
|
|
31
|
+
export async function readDecision(planDir, id) {
|
|
32
|
+
const file = decisionPathFor(planDir, id);
|
|
33
|
+
if (!(await Bun.file(file).exists())) {
|
|
34
|
+
throw new Error(`no decision "${id}" in ${decisionsDirFor(planDir)}`);
|
|
35
|
+
}
|
|
36
|
+
const { frontmatter, body } = await readDocument(file);
|
|
37
|
+
const meta = parseFile(DecisionSchema, file, frontmatter);
|
|
38
|
+
if (meta.id !== id) {
|
|
39
|
+
throw new FileValidationError(file, [
|
|
40
|
+
{ field: "id", message: `is "${meta.id}" but it was read as "${id}"` },
|
|
41
|
+
]);
|
|
42
|
+
}
|
|
43
|
+
return { file, meta, body };
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=read.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/decisions/read.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,cAAc,EAAiB,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAS3D,iGAAiG;AACjG,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAe;IACnD,IAAI,KAAK,CAAC;IAEV,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAC;QACzG,MAAM,KAAK,CAAC;IACd,CAAC;IAED,OAAO,KAAK;SACT,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;SAClE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;SACrD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAe,EAAE,EAAU;IAC5D,MAAM,IAAI,GAAG,eAAe,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC1C,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,gBAAgB,EAAE,QAAQ,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;IACvD,MAAM,IAAI,GAAG,SAAS,CAAC,cAAc,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;IAE1D,IAAI,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;QACnB,MAAM,IAAI,mBAAmB,CAAC,IAAI,EAAE;YAClC,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,IAAI,CAAC,EAAE,yBAAyB,EAAE,GAAG,EAAE;SACvE,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type DecisionStatus } from "../schemas/decision";
|
|
2
|
+
import { type DecisionDocument } from "./read";
|
|
3
|
+
/** What `addDecision` needs from its caller; the id and date are worked out here. */
|
|
4
|
+
export interface NewDecision {
|
|
5
|
+
title: string;
|
|
6
|
+
status: DecisionStatus;
|
|
7
|
+
/** Id of the earlier decision this one replaces; that file is moved to `superseded` */
|
|
8
|
+
supersedes?: string;
|
|
9
|
+
body: string;
|
|
10
|
+
}
|
|
11
|
+
/** Next free id in a plan: one above the highest number in use, then the title as a slug. */
|
|
12
|
+
export declare function nextDecisionId(planDir: string, title: string): Promise<string>;
|
|
13
|
+
/**
|
|
14
|
+
* Writes a new decision file into a plan, numbered after the ones already
|
|
15
|
+
* there and dated today. Called by the `add-decision` hook.
|
|
16
|
+
*
|
|
17
|
+
* @throws Error when `supersedes` names no decision of this plan
|
|
18
|
+
*/
|
|
19
|
+
export declare function addDecision(planDir: string, decision: NewDecision): Promise<DecisionDocument>;
|
|
20
|
+
//# sourceMappingURL=write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/decisions/write.ts"],"names":[],"mappings":"AAGA,OAAO,EAAwC,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGhG,OAAO,EAAiC,KAAK,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAE9E,qFAAqF;AACrF,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,cAAc,CAAC;IACvB,uFAAuF;IACvF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AASD,6FAA6F;AAC7F,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAOpF;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAwBnG"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// packages/skills/src/decisions/write.ts
|
|
2
|
+
import { mkdir } from "node:fs/promises";
|
|
3
|
+
import { parseFile } from "../schemas/validation";
|
|
4
|
+
import { DecisionSchema, DecisionStatusSchema } from "../schemas/decision";
|
|
5
|
+
import { setStatusLine } from "../filetree/status";
|
|
6
|
+
import { decisionPathFor, decisionsDirFor } from "./paths";
|
|
7
|
+
import { listDecisionIds, readDecision } from "./read";
|
|
8
|
+
function slugFor(title) {
|
|
9
|
+
const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
10
|
+
if (slug === "")
|
|
11
|
+
throw new Error(`title "${title}" has no letters or digits to build an id from`);
|
|
12
|
+
return slug;
|
|
13
|
+
}
|
|
14
|
+
/** Next free id in a plan: one above the highest number in use, then the title as a slug. */
|
|
15
|
+
export async function nextDecisionId(planDir, title) {
|
|
16
|
+
const numbers = (await listDecisionIds(planDir)).map((id) => Number.parseInt(id.slice(0, 4), 10));
|
|
17
|
+
const next = Math.max(0, ...numbers.filter((n) => Number.isInteger(n))) + 1;
|
|
18
|
+
if (next > 9999)
|
|
19
|
+
throw new Error(`${decisionsDirFor(planDir)} has used every decision number`);
|
|
20
|
+
return `${String(next).padStart(4, "0")}-${slugFor(title)}`;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Writes a new decision file into a plan, numbered after the ones already
|
|
24
|
+
* there and dated today. Called by the `add-decision` hook.
|
|
25
|
+
*
|
|
26
|
+
* @throws Error when `supersedes` names no decision of this plan
|
|
27
|
+
*/
|
|
28
|
+
export async function addDecision(planDir, decision) {
|
|
29
|
+
const replaced = decision.supersedes === undefined
|
|
30
|
+
? undefined
|
|
31
|
+
: await readDecision(planDir, decision.supersedes);
|
|
32
|
+
const id = await nextDecisionId(planDir, decision.title);
|
|
33
|
+
const file = decisionPathFor(planDir, id);
|
|
34
|
+
const meta = parseFile(DecisionSchema, file, {
|
|
35
|
+
id,
|
|
36
|
+
title: decision.title,
|
|
37
|
+
status: decision.status,
|
|
38
|
+
date: new Date().toISOString().slice(0, 10),
|
|
39
|
+
...(decision.supersedes === undefined ? {} : { supersedes: decision.supersedes }),
|
|
40
|
+
});
|
|
41
|
+
await mkdir(decisionsDirFor(planDir), { recursive: true });
|
|
42
|
+
await Bun.write(file, `---\n${Bun.YAML.stringify(meta, null, 2).trimEnd()}\n---\n\n${decision.body.trim()}\n`);
|
|
43
|
+
if (replaced !== undefined && replaced.meta.status !== "superseded") {
|
|
44
|
+
await setStatusLine(replaced.file, "superseded", DecisionStatusSchema);
|
|
45
|
+
}
|
|
46
|
+
return readDecision(planDir, id);
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/decisions/write.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates every folder and index file the tree under `root` is missing, and
|
|
3
|
+
* leaves everything that already exists untouched. A hook can call this on
|
|
4
|
+
* every run.
|
|
5
|
+
*/
|
|
6
|
+
export declare function ensureTree(root: string): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=ensure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ensure.d.ts","sourceRoot":"","sources":["../../src/filetree/ensure.ts"],"names":[],"mappings":"AAQA;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5D"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// packages/skills/src/filetree/ensure.ts
|
|
2
|
+
import { mkdir } from "node:fs/promises";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { CHILD_LEVEL } from "./levels";
|
|
5
|
+
import { childDirFor, indexPathFor, tasksDirFor } from "./paths";
|
|
6
|
+
import { listEntryNames } from "./entries";
|
|
7
|
+
import { generateIndex } from "./generate";
|
|
8
|
+
/**
|
|
9
|
+
* Creates every folder and index file the tree under `root` is missing, and
|
|
10
|
+
* leaves everything that already exists untouched. A hook can call this on
|
|
11
|
+
* every run.
|
|
12
|
+
*/
|
|
13
|
+
export async function ensureTree(root) {
|
|
14
|
+
await ensureFrom(resolve(root), "root");
|
|
15
|
+
}
|
|
16
|
+
/** `dir` is absolute; `childDirFor` keeps it that way down the walk. */
|
|
17
|
+
async function ensureFrom(dir, level) {
|
|
18
|
+
await mkdir(dir, { recursive: true });
|
|
19
|
+
if (level === "phase")
|
|
20
|
+
await mkdir(tasksDirFor(dir), { recursive: true });
|
|
21
|
+
await ensureIndexFile(dir, level);
|
|
22
|
+
const child = CHILD_LEVEL[level];
|
|
23
|
+
if (child === null)
|
|
24
|
+
return;
|
|
25
|
+
for (const name of await listEntryNames(dir, level)) {
|
|
26
|
+
await ensureFrom(childDirFor(dir, name), child);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** Builds a missing index from the folder it belongs to; keeps an existing one. */
|
|
30
|
+
async function ensureIndexFile(dir, level) {
|
|
31
|
+
const exists = await Bun.file(indexPathFor(dir, level)).exists();
|
|
32
|
+
if (exists)
|
|
33
|
+
return;
|
|
34
|
+
await generateIndex(dir, level);
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=ensure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ensure.js","sourceRoot":"","sources":["../../src/filetree/ensure.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAkB,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAY;IAC3C,MAAM,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;AAC1C,CAAC;AAED,wEAAwE;AACxE,KAAK,UAAU,UAAU,CAAC,GAAW,EAAE,KAAgB;IACrD,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,IAAI,KAAK,KAAK,OAAO;QAAE,MAAM,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1E,MAAM,eAAe,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAElC,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IACjC,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO;IAE3B,KAAK,MAAM,IAAI,IAAI,MAAM,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC;QACpD,MAAM,UAAU,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;IAClD,CAAC;AACH,CAAC;AAED,mFAAmF;AACnF,KAAK,UAAU,eAAe,CAAC,GAAW,EAAE,KAAgB;IAC1D,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACjE,IAAI,MAAM;QAAE,OAAO;IAEnB,MAAM,aAAa,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type TreeLevel } from "./levels";
|
|
2
|
+
/**
|
|
3
|
+
* Names of the entries of a folder at `level`, alphabetical — the order the
|
|
4
|
+
* queue runs in. A folder only counts as an entry once it holds its own
|
|
5
|
+
* `<name>.md`, so a directory left behind by hand is skipped rather than
|
|
6
|
+
* reported as a broken plan.
|
|
7
|
+
*/
|
|
8
|
+
export declare function listEntryNames(dir: string, level: TreeLevel): Promise<string[]>;
|
|
9
|
+
//# sourceMappingURL=entries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entries.d.ts","sourceRoot":"","sources":["../../src/filetree/entries.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwB,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAGhE;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAMrF"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// packages/skills/src/filetree/entries.ts
|
|
2
|
+
import { readdir } from "node:fs/promises";
|
|
3
|
+
import { ENTRY_KIND, MARKDOWN } from "./levels";
|
|
4
|
+
import { entryPathFor, tasksDirFor } from "./paths";
|
|
5
|
+
/**
|
|
6
|
+
* Names of the entries of a folder at `level`, alphabetical — the order the
|
|
7
|
+
* queue runs in. A folder only counts as an entry once it holds its own
|
|
8
|
+
* `<name>.md`, so a directory left behind by hand is skipped rather than
|
|
9
|
+
* reported as a broken plan.
|
|
10
|
+
*/
|
|
11
|
+
export async function listEntryNames(dir, level) {
|
|
12
|
+
const names = ENTRY_KIND[level] === "folder"
|
|
13
|
+
? await listFolderEntries(dir, level)
|
|
14
|
+
: await listTaskEntries(dir);
|
|
15
|
+
return names.sort((a, b) => a.localeCompare(b));
|
|
16
|
+
}
|
|
17
|
+
async function listFolderEntries(dir, level) {
|
|
18
|
+
const names = [];
|
|
19
|
+
for (const entry of await readdir(dir, { withFileTypes: true })) {
|
|
20
|
+
if (!entry.isDirectory())
|
|
21
|
+
continue;
|
|
22
|
+
const described = await Bun.file(entryPathFor(dir, level, entry.name)).exists();
|
|
23
|
+
if (described)
|
|
24
|
+
names.push(entry.name);
|
|
25
|
+
}
|
|
26
|
+
return names;
|
|
27
|
+
}
|
|
28
|
+
/** A phase with no `tasks/` folder yet has no tasks, which is not an error. */
|
|
29
|
+
async function listTaskEntries(phaseDir) {
|
|
30
|
+
let files;
|
|
31
|
+
try {
|
|
32
|
+
files = await readdir(tasksDirFor(phaseDir), { withFileTypes: true });
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (isMissing(error))
|
|
36
|
+
return [];
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
return files
|
|
40
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith(MARKDOWN))
|
|
41
|
+
.map((entry) => entry.name.slice(0, -MARKDOWN.length));
|
|
42
|
+
}
|
|
43
|
+
function isMissing(error) {
|
|
44
|
+
return (typeof error === "object" &&
|
|
45
|
+
error !== null &&
|
|
46
|
+
"code" in error &&
|
|
47
|
+
error.code === "ENOENT");
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=entries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entries.js","sourceRoot":"","sources":["../../src/filetree/entries.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAkB,MAAM,UAAU,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAW,EAAE,KAAgB;IAChE,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,QAAQ;QAC1C,CAAC,CAAC,MAAM,iBAAiB,CAAC,GAAG,EAAE,KAAK,CAAC;QACrC,CAAC,CAAC,MAAM,eAAe,CAAC,GAAG,CAAC,CAAC;IAE/B,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,GAAW,EAAE,KAAgB;IAC5D,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,KAAK,IAAI,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAChE,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;YAAE,SAAS;QAEnC,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAChF,IAAI,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,+EAA+E;AAC/E,KAAK,UAAU,eAAe,CAAC,QAAgB;IAC7C,IAAI,KAAK,CAAC;IAEV,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACxE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,SAAS,CAAC,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAChC,MAAM,KAAK,CAAC;IACd,CAAC;IAED,OAAO,KAAK;SACT,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;SAClE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,SAAS,SAAS,CAAC,KAAc;IAC/B,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,MAAM,IAAI,KAAK;QACf,KAAK,CAAC,IAAI,KAAK,QAAQ,CACxB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** A `.md` file split at its closing fence. */
|
|
2
|
+
export interface Document {
|
|
3
|
+
frontmatter: unknown;
|
|
4
|
+
/** Everything after the closing fence, leading blank lines trimmed. */
|
|
5
|
+
body: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Reads a `.md` file as its frontmatter mapping plus the prose under it.
|
|
9
|
+
*
|
|
10
|
+
* @throws FileValidationError when the file has no frontmatter block or the
|
|
11
|
+
* block is not a YAML mapping
|
|
12
|
+
*/
|
|
13
|
+
export declare function readDocument(file: string): Promise<Document>;
|
|
14
|
+
/** Reads only the frontmatter mapping of a `.md` file. */
|
|
15
|
+
export declare function readFrontmatter(file: string): Promise<unknown>;
|
|
16
|
+
//# sourceMappingURL=frontmatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/filetree/frontmatter.ts"],"names":[],"mappings":"AAKA,+CAA+C;AAC/C,MAAM,WAAW,QAAQ;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAmBlE;AAED,0DAA0D;AAC1D,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAEpE"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// packages/skills/src/filetree/frontmatter.ts
|
|
2
|
+
import { FileValidationError } from "../schemas/validation";
|
|
3
|
+
const FENCE = "---";
|
|
4
|
+
/**
|
|
5
|
+
* Reads a `.md` file as its frontmatter mapping plus the prose under it.
|
|
6
|
+
*
|
|
7
|
+
* @throws FileValidationError when the file has no frontmatter block or the
|
|
8
|
+
* block is not a YAML mapping
|
|
9
|
+
*/
|
|
10
|
+
export async function readDocument(file) {
|
|
11
|
+
const text = await Bun.file(file).text();
|
|
12
|
+
const split = splitAtFences(text);
|
|
13
|
+
if (split === null) {
|
|
14
|
+
throw new FileValidationError(file, [
|
|
15
|
+
{ field: "(frontmatter)", message: `no ${FENCE} block at the top of the file` },
|
|
16
|
+
]);
|
|
17
|
+
}
|
|
18
|
+
const frontmatter = Bun.YAML.parse(split.block);
|
|
19
|
+
if (typeof frontmatter !== "object" || frontmatter === null || Array.isArray(frontmatter)) {
|
|
20
|
+
throw new FileValidationError(file, [
|
|
21
|
+
{ field: "(frontmatter)", message: "block is not a YAML mapping" },
|
|
22
|
+
]);
|
|
23
|
+
}
|
|
24
|
+
return { frontmatter, body: split.body };
|
|
25
|
+
}
|
|
26
|
+
/** Reads only the frontmatter mapping of a `.md` file. */
|
|
27
|
+
export async function readFrontmatter(file) {
|
|
28
|
+
return (await readDocument(file)).frontmatter;
|
|
29
|
+
}
|
|
30
|
+
/** Text inside the fences and text after them, or `null` when there are none. */
|
|
31
|
+
function splitAtFences(text) {
|
|
32
|
+
const lines = text.split("\n");
|
|
33
|
+
if (lines[0]?.trimEnd() !== FENCE)
|
|
34
|
+
return null;
|
|
35
|
+
const closing = lines.findIndex((line, index) => index > 0 && line.trimEnd() === FENCE);
|
|
36
|
+
if (closing === -1)
|
|
37
|
+
return null;
|
|
38
|
+
return {
|
|
39
|
+
block: lines.slice(1, closing).join("\n"),
|
|
40
|
+
body: lines.slice(closing + 1).join("\n").replace(/^\n+/, ""),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=frontmatter.js.map
|