@sous-io/sous 0.1.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 +201 -0
- package/README.md +154 -0
- package/bin/run.js +17 -0
- package/bin/xcv +5 -0
- package/package.json +81 -0
- package/shared-prompts/_partials/resume-task.md +51 -0
- package/shared-prompts/_partials/sub-agent-delegation.md +32 -0
- package/shared-prompts/_partials/update-task-file.md +52 -0
- package/shared-prompts/memories/automated-browser-tasks/INDEX.tpl.md +52 -0
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/SKILL.tpl.md +102 -0
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/auth-failure-handling.mjs +81 -0
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/chained-workflow.mjs +126 -0
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/simple-fetch.mjs +92 -0
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/architecture.md +61 -0
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/auth-and-sessions.md +65 -0
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/ctx-api.md +96 -0
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/installation.md +104 -0
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/script-conventions.md +243 -0
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/chrome-state.mjs +148 -0
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/debug.mjs +383 -0
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/debug.spec.mjs +267 -0
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/eslint.config.mjs +56 -0
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/harness.mjs +169 -0
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/keyring.mjs +59 -0
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/logger.mjs +25 -0
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/params.mjs +140 -0
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/run.mjs +140 -0
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/settings.tpl.mjs +1 -0
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/utils.mjs +185 -0
- package/shared-prompts/skills/automated-browser-tasks/create-automated-browser-task/SKILL.tpl.md +52 -0
- package/shared-prompts/skills/automated-browser-tasks/running-automated-browser-tasks/SKILL.tpl.md +59 -0
- package/shared-prompts/skills/automated-browser-tasks/update-automated-browser-task/SKILL.tpl.md +47 -0
- package/shared-prompts/skills/control-flow/approve/SKILL.tpl.md +26 -0
- package/shared-prompts/skills/control-flow/opine/SKILL.tpl.md +58 -0
- package/shared-prompts/skills/control-flow/repeat/SKILL.tpl.md +27 -0
- package/shared-prompts/skills/control-flow/research/SKILL.tpl.md +34 -0
- package/shared-prompts/skills/sous-skills/about-agent-skills/SKILL.tpl.md +177 -0
- package/shared-prompts/skills/sous-skills/about-agent-skills/examples/about-something.md +45 -0
- package/shared-prompts/skills/sous-skills/about-agent-skills/examples/do-something.md +33 -0
- package/shared-prompts/skills/sous-skills/about-agent-skills/references/advanced-patterns.md +87 -0
- package/shared-prompts/skills/sous-skills/about-agent-skills/references/commands.md +46 -0
- package/shared-prompts/skills/sous-skills/about-agent-skills/references/frontmatter.md +25 -0
- package/shared-prompts/skills/sous-skills/about-agent-skills/references/substitutions.md +50 -0
- package/shared-prompts/skills/sous-skills/about-liquid-templates/SKILL.tpl.md +268 -0
- package/shared-prompts/skills/sous-skills/about-liquid-templates/references/liquid-filters.md +82 -0
- package/shared-prompts/skills/sous-skills/about-sous/SKILL.tpl.md +51 -0
- package/shared-prompts/skills/sous-skills/create-skill/SKILL.tpl.md +114 -0
- package/shared-prompts/skills/task-files/about-task-files/SKILL.tpl.md +122 -0
- package/shared-prompts/skills/task-files/continue-task-in-new-branch/SKILL.tpl.md +80 -0
- package/shared-prompts/skills/task-files/go/SKILL.tpl.md +14 -0
- package/shared-prompts/skills/task-files/resume-task/SKILL.tpl.md +13 -0
- package/shared-prompts/skills/task-files/start-task/SKILL.tpl.md +93 -0
- package/shared-prompts/skills/task-files/update/SKILL.tpl.md +14 -0
- package/shared-prompts/skills/task-files/update-task-file/SKILL.tpl.md +13 -0
- package/src/base-command.ts +163 -0
- package/src/commands/build.ts +196 -0
- package/src/commands/clear.ts +71 -0
- package/src/commands/compile.ts +95 -0
- package/src/commands/launch.ts +111 -0
- package/src/commands/prune.ts +48 -0
- package/src/lib/build-service.ts +258 -0
- package/src/lib/config-discovery.ts +199 -0
- package/src/lib/env-local.ts +195 -0
- package/src/lib/include-resolver.ts +146 -0
- package/src/lib/markdown-compiler.ts +580 -0
- package/src/lib/pid-service.ts +88 -0
- package/src/lib/settings.ts +695 -0
- package/src/lib/state.ts +135 -0
- package/src/lib/watch-service.ts +115 -0
- package/src/templating/filters/bullet-list.ts +9 -0
- package/src/templating/filters/index.ts +8 -0
- package/src/templating/init-liquid-engine.ts +82 -0
- package/src/templating/lib/glob-files.ts +74 -0
- package/src/templating/lib/import-export.ts +32 -0
- package/src/templating/lib/tag-args.ts +19 -0
- package/src/templating/tags/exportScalarVarsJs.ts +43 -0
- package/src/templating/tags/getFiles.ts +89 -0
- package/src/templating/tags/index.ts +14 -0
- package/src/templating/tags/listFiles.ts +54 -0
- package/src/templating/tags/showVars.ts +22 -0
- package/src/utils/formatting.ts +338 -0
- package/src/utils/prompts.ts +19 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: about-sous
|
|
3
|
+
description: >
|
|
4
|
+
YOU MUST load this skill when you cannot edit a file in this project, are asked why
|
|
5
|
+
a file keeps reverting, need to know where the source of truth for any managed file
|
|
6
|
+
lives, or need to understand what this project's configuration system is.
|
|
7
|
+
user-invocable: false
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# About Sous
|
|
11
|
+
|
|
12
|
+
Sous (`xcv`) is a CLI tool that compiles markdown templates and manages output files
|
|
13
|
+
for AI coding agents. It reads a central configuration, resolves variables, and
|
|
14
|
+
copies or renders files to their destinations in this project.
|
|
15
|
+
|
|
16
|
+
## Files You Must Never Edit
|
|
17
|
+
|
|
18
|
+
Sous manages certain files in this project by compiling them from a central source.
|
|
19
|
+
**You must never edit these directly.** Your changes will be silently overwritten the
|
|
20
|
+
next time Sous runs:
|
|
21
|
+
|
|
22
|
+
- `.claude/` — Claude Code configuration, skills, and instructions
|
|
23
|
+
- `.codex/` — Codex configuration and skills
|
|
24
|
+
- `AGENTS.md` and `CLAUDE.md` — agent instruction files
|
|
25
|
+
- Any file you did not create yourself in a designated source directory
|
|
26
|
+
|
|
27
|
+
If you need to change something in one of these files, the change must be made at the
|
|
28
|
+
source — in the central configuration this project uses with Sous.
|
|
29
|
+
|
|
30
|
+
## Where Your Skills Live
|
|
31
|
+
|
|
32
|
+
Skills for this project live at `{{ skillsRoot }}`. That is the source directory Sous
|
|
33
|
+
compiles from. Create and edit skills there — never in `.claude/skills/` or
|
|
34
|
+
`.codex/skills/` directly.
|
|
35
|
+
|
|
36
|
+
YOU MUST load `create-skill` when creating a new skill for this project.
|
|
37
|
+
|
|
38
|
+
## Sous's Shared Skill Bundles
|
|
39
|
+
|
|
40
|
+
Sous ships shared skill bundles at `{{ sousRootPath }}/shared-prompts/skills/`, which is
|
|
41
|
+
where the `about-sous`, `about-agent-skills` and `about-liquid-templates` skills you are
|
|
42
|
+
reading came from. Edit them only in the sous repository itself, where they are the
|
|
43
|
+
sources. Never edit a compiled copy of them inside a consuming project — that copy is
|
|
44
|
+
build output and is overwritten on the next Sous run.
|
|
45
|
+
|
|
46
|
+
## Source for this Skill
|
|
47
|
+
|
|
48
|
+
This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
|
|
49
|
+
the output file should not be edited directly.
|
|
50
|
+
|
|
51
|
+
- Source Path: {{ sousTemplatePath }}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: create-skill
|
|
3
|
+
description: >
|
|
4
|
+
YOU MUST use this skill when creating a new skill for this project.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Create a Skill
|
|
8
|
+
|
|
9
|
+
The agent performing this work MUST load `about-agent-skills` for skill structure,
|
|
10
|
+
frontmatter, and architecture principles.
|
|
11
|
+
|
|
12
|
+
Skills for this project live at `{{ skillsRoot }}`. Create new skills there — not in
|
|
13
|
+
`.claude/skills/` or `.codex/skills/` directly (those are managed automatically and
|
|
14
|
+
must not be edited).
|
|
15
|
+
|
|
16
|
+
## Steps
|
|
17
|
+
|
|
18
|
+
### 1. Create the directory
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
{{ skillsRoot }}/<skill-name>/
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The directory name must match the `name` frontmatter field (lowercase, hyphens).
|
|
25
|
+
|
|
26
|
+
**If `{{ skillsRoot }}` is a bundle root**, its immediate subdirectories are *bundles*, not
|
|
27
|
+
skills, and the path gains a segment: `{{ skillsRoot }}/<bundle-name>/<skill-name>/`. Check
|
|
28
|
+
what is already there before creating anything: a directory holding `SKILL.md` /
|
|
29
|
+
`SKILL.tpl.md` files directly means skills go at the top level; a directory holding further
|
|
30
|
+
subdirectories that each contain a skill means you are looking at bundles, so add the skill
|
|
31
|
+
to the bundle it belongs to. When a new skill genuinely needs a new bundle, create the
|
|
32
|
+
bundle directory and add a matching `entryGlob` target in the config of every project that
|
|
33
|
+
should receive it — a bundle with no `entryGlob` is never compiled anywhere.
|
|
34
|
+
|
|
35
|
+
### 2. Write `SKILL.tpl.md`
|
|
36
|
+
|
|
37
|
+
Create `SKILL.tpl.md` in the directory with valid frontmatter and an imperative body.
|
|
38
|
+
See `about-agent-skills` for the full frontmatter reference and topic vs action
|
|
39
|
+
skill guidance.
|
|
40
|
+
|
|
41
|
+
**Distributed skills take extended frontmatter.** A skill compiled out to other projects
|
|
42
|
+
declares its provenance and portability; a project-local skill omits these fields because
|
|
43
|
+
nothing outside the project consumes it:
|
|
44
|
+
|
|
45
|
+
```yaml
|
|
46
|
+
license: MIT
|
|
47
|
+
compatibility:
|
|
48
|
+
- claude
|
|
49
|
+
- codex
|
|
50
|
+
metadata:
|
|
51
|
+
version: 1.0.0
|
|
52
|
+
tags: [<relevant>, <tags>]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 3. Add supporting files (if needed)
|
|
56
|
+
|
|
57
|
+
- `references/` — supplementary documentation loaded on demand
|
|
58
|
+
- `scripts/` — executable scripts the skill uses
|
|
59
|
+
- `examples/` — example outputs
|
|
60
|
+
|
|
61
|
+
Reference all supporting files from `SKILL.md` — the agent will not discover them
|
|
62
|
+
otherwise.
|
|
63
|
+
|
|
64
|
+
### 4. Name the main file `SKILL.tpl.md` and add the source footer
|
|
65
|
+
|
|
66
|
+
Skills in `{{ skillsRoot }}` are compiled and distributed — the main skill file must
|
|
67
|
+
always be named `SKILL.tpl.md`, not `SKILL.md`. No exceptions, and specifically **not even
|
|
68
|
+
when the skill body contains no variables at all**: the mandatory `## Source for this Skill`
|
|
69
|
+
footer itself contains a template variable, so every skill needs a LiquidJS render pass by
|
|
70
|
+
definition. A plain `SKILL.md` is copied verbatim, which would ship the footer's unrendered
|
|
71
|
+
variable straight into the output. The footer:
|
|
72
|
+
|
|
73
|
+
{% raw %}
|
|
74
|
+
```markdown
|
|
75
|
+
## Source for this Skill
|
|
76
|
+
|
|
77
|
+
This skill was compiled from a template and the output file should not be edited directly.
|
|
78
|
+
|
|
79
|
+
- Source Path: {{ sousTemplatePath }}
|
|
80
|
+
```
|
|
81
|
+
{% endraw %}
|
|
82
|
+
|
|
83
|
+
The `{{ sousTemplatePath }}` variable renders to the absolute path of the source template
|
|
84
|
+
at compile time, telling agents where the skill originated.
|
|
85
|
+
|
|
86
|
+
For other files in the skill directory (references, scripts, supporting docs), use `.tpl.`
|
|
87
|
+
naming only when the file genuinely needs LiquidJS processing. YOU MUST load
|
|
88
|
+
`about-liquid-templates` before making that decision.
|
|
89
|
+
|
|
90
|
+
### 5. No build step needed
|
|
91
|
+
|
|
92
|
+
Once the files exist in `{{ skillsRoot }}`, distribution is handled automatically.
|
|
93
|
+
|
|
94
|
+
### 6. Write the body for whoever executes it
|
|
95
|
+
|
|
96
|
+
Per the sub-agent delegation pattern
|
|
97
|
+
(`~sous-shared/_partials/sub-agent-delegation.md`), a skill's steps may run in a delegated
|
|
98
|
+
sub-agent with fresh context. Mark which steps are delegated and which are
|
|
99
|
+
orchestrator-only (anything needing the user or this conversation's contents), and
|
|
100
|
+
phrase skill-loading requirements as "The agent performing this work MUST load `x`".
|
|
101
|
+
See `about-agent-skills` → General Principles.
|
|
102
|
+
|
|
103
|
+
# Related Skills
|
|
104
|
+
|
|
105
|
+
YOU MUST load `about-agent-skills` for skill structure and principles. YOU MUST load
|
|
106
|
+
`about-sous` for context on what is managed automatically in this project. YOU MUST
|
|
107
|
+
load `about-liquid-templates` if any file in your skill needs `.tpl.` processing.
|
|
108
|
+
|
|
109
|
+
## Source for this Skill
|
|
110
|
+
|
|
111
|
+
This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
|
|
112
|
+
the output file should not be edited directly.
|
|
113
|
+
|
|
114
|
+
- Source Path: {{ sousTemplatePath }}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: about-task-files
|
|
3
|
+
description: YOU MUST load this skill when working with task files — including creating, reading, updating, or archiving a task file, or any time you need to know where task files live.
|
|
4
|
+
user-invocable: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
A **task file** is a Markdown document that tracks a unit of work across one or more chat sessions. It is the single source of truth for what has been done, what remains, and what decisions were made.
|
|
8
|
+
|
|
9
|
+
## Who Reads and Writes It
|
|
10
|
+
|
|
11
|
+
Per the sub-agent delegation pattern (`~sous-shared/_partials/sub-agent-delegation.md`), reading and
|
|
12
|
+
writing task files is delegated work: the orchestrator supplies the facts and decisions, and a
|
|
13
|
+
sub-agent loads this skill and does the edit.
|
|
14
|
+
Sub-agents start with fresh context and cannot see the chat conversation, so a delegating prompt
|
|
15
|
+
must state any fact that exists only in the conversation. Anything the sub-agent can gather itself
|
|
16
|
+
(branch name, commits, changed files, error output) should be gathered by the sub-agent.
|
|
17
|
+
|
|
18
|
+
## Location and Naming
|
|
19
|
+
|
|
20
|
+
Task files live at:
|
|
21
|
+
```
|
|
22
|
+
{{ taskFileRoot }}/[branch-name].md
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The filename mirrors the full git branch name — including any `/` separators as path separators:
|
|
26
|
+
- Branch `{{ featureBranchPrefix }}{{ ticketIdExample }}-some-feature` → `{{ taskFileRoot }}/{{ featureBranchPrefix }}{{ ticketIdExample }}-some-feature.md`
|
|
27
|
+
|
|
28
|
+
To find the current task file: run `git status`, take the branch name, construct the path above.
|
|
29
|
+
|
|
30
|
+
**If the file is not found:** run a fresh `git status` to confirm the branch name before concluding it doesn't exist.
|
|
31
|
+
|
|
32
|
+
## Archive Location
|
|
33
|
+
|
|
34
|
+
Completed task files are archived at:
|
|
35
|
+
```
|
|
36
|
+
{{ taskFileRoot }}/archive/[branch-name].md
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The path structure mirrors the task file location — just under `archive/`.
|
|
40
|
+
|
|
41
|
+
## Completion Procedure
|
|
42
|
+
|
|
43
|
+
When the user confirms a task is 100% complete:
|
|
44
|
+
1. Update the task file with the final status
|
|
45
|
+
2. Move it to `{{ taskFileRoot }}/archive/[branch-name].md` (create subdirectories as needed)
|
|
46
|
+
3. Switch to the project's main development branch and follow its branch-switching procedures
|
|
47
|
+
|
|
48
|
+
## File Format
|
|
49
|
+
|
|
50
|
+
```markdown
|
|
51
|
+
# Task: [Feature/Fix Description]
|
|
52
|
+
|
|
53
|
+
**Branch:** `{{ featureBranchPrefix }}{{ ticketIdExample }}-feature-name`
|
|
54
|
+
**Status:** In Progress - Phase 2 Complete
|
|
55
|
+
**Started:** YYYY-MM-DD
|
|
56
|
+
**Updated:** YYYY-MM-DD
|
|
57
|
+
|
|
58
|
+
## Overview
|
|
59
|
+
[Brief description of the task objective]
|
|
60
|
+
|
|
61
|
+
## Current Status
|
|
62
|
+
- Phase 1: Complete
|
|
63
|
+
- Phase 2: Complete
|
|
64
|
+
- Phase 3: In Progress
|
|
65
|
+
|
|
66
|
+
## Recent Progress
|
|
67
|
+
[What was accomplished in the most recent session]
|
|
68
|
+
|
|
69
|
+
## Decisions Made
|
|
70
|
+
[Technical and process decisions, with brief rationale]
|
|
71
|
+
|
|
72
|
+
## Remaining Work
|
|
73
|
+
- [ ] Task with context
|
|
74
|
+
- [ ] Another task
|
|
75
|
+
|
|
76
|
+
## Pending Issues
|
|
77
|
+
[Unresolved problems, blockers, open questions]
|
|
78
|
+
|
|
79
|
+
## Key Learnings
|
|
80
|
+
[Patterns, discoveries, gotchas worth remembering]
|
|
81
|
+
|
|
82
|
+
## Commits Made
|
|
83
|
+
- `abc123f` - description
|
|
84
|
+
|
|
85
|
+
## Files Modified
|
|
86
|
+
- /absolute/path/to/File.ts:45 - what changed and why
|
|
87
|
+
|
|
88
|
+
## Testing URLs
|
|
89
|
+
- http://localhost:5173/path/to/page
|
|
90
|
+
|
|
91
|
+
## Unresolved Errors
|
|
92
|
+
[Test failures, build errors, TypeScript errors — with paths and line numbers]
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Style Guidelines
|
|
96
|
+
|
|
97
|
+
- No emojis or emoticons
|
|
98
|
+
- Concise but not aggressively compressed — important information must not be lost
|
|
99
|
+
- Wrap long lines at 120 characters
|
|
100
|
+
- Absolute paths with line numbers for file references (not ranges)
|
|
101
|
+
- Use `file:/absolute/path/to/File.ts:45` format for clickable links (two slashes, not three)
|
|
102
|
+
|
|
103
|
+
## File Size
|
|
104
|
+
|
|
105
|
+
Task files must not exceed **1,000 lines**. When approaching the limit, condense:
|
|
106
|
+
- Completed phases (keep summary, drop detail)
|
|
107
|
+
- Historical context no longer relevant to upcoming work
|
|
108
|
+
- Information less important to immediate next steps
|
|
109
|
+
|
|
110
|
+
Always preserve in full: current active work, immediate next steps, unresolved issues, recent learnings, recently modified files.
|
|
111
|
+
|
|
112
|
+
## Task Plan Structure
|
|
113
|
+
|
|
114
|
+
When drafting a task plan, segregate work by architectural layer. Work one layer at a time and
|
|
115
|
+
commit at least once per layer.
|
|
116
|
+
|
|
117
|
+
## Source for this Skill
|
|
118
|
+
|
|
119
|
+
This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
|
|
120
|
+
the output file should not be edited directly.
|
|
121
|
+
|
|
122
|
+
- Source Path: {{ sousTemplatePath }}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: continue-task-in-new-branch
|
|
3
|
+
description: YOU MUST load this skill when an MR has been merged and remaining work needs to continue in a new branch — including "continue this work in a new branch", "create a follow-up branch", "split this into another MR", "move remaining work to a new branch".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
The agent performing this work MUST load `about-task-files`.
|
|
7
|
+
|
|
8
|
+
## Delegation
|
|
9
|
+
|
|
10
|
+
Per the sub-agent delegation pattern (`~sous-shared/_partials/sub-agent-delegation.md`), the
|
|
11
|
+
orchestrator does the git branch work itself (steps 1, 2,
|
|
12
|
+
and 6, which change the working tree it is in) and delegates the task file writing (steps 3, 4, 5)
|
|
13
|
+
to one Opus sub-agent. That sub-agent needs the old and new branch names, the remaining-work list,
|
|
14
|
+
and the patterns/gotchas to carry forward; sub-agents cannot see this conversation, so state them in
|
|
15
|
+
the prompt.
|
|
16
|
+
|
|
17
|
+
## Steps
|
|
18
|
+
|
|
19
|
+
### 1. Prepare for Branch Transition
|
|
20
|
+
|
|
21
|
+
Before switching branches, ensure:
|
|
22
|
+
- Current branch is fully pushed to the remote
|
|
23
|
+
- All important context is documented in the current task file (load `update-task-file` if needed)
|
|
24
|
+
- The MR has been merged or is ready to close
|
|
25
|
+
|
|
26
|
+
### 2. Create the New Branch
|
|
27
|
+
|
|
28
|
+
Name the new branch using the original name plus a letter suffix (`-b`, `-c`, etc.):
|
|
29
|
+
```bash
|
|
30
|
+
git checkout <main-development-branch>
|
|
31
|
+
git pull origin <main-development-branch>
|
|
32
|
+
git checkout -b {{ featureBranchPrefix }}{{ ticketIdExample }}-description-b
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 3. Create the New Task File
|
|
36
|
+
|
|
37
|
+
Create `{{ taskFileRoot }}/{{ featureBranchPrefix }}{{ ticketIdExample }}-description-b.md` with:
|
|
38
|
+
- **Task Overview**: brief description and connection to the previous MR
|
|
39
|
+
- **Remaining Work**: clear list of unfinished tasks with enough context to understand each item independently
|
|
40
|
+
- **Key Patterns and Learnings**: essential patterns from the previous branch worth carrying forward
|
|
41
|
+
- **Important Notes**: critical gotchas, blockers, or dependencies
|
|
42
|
+
|
|
43
|
+
Do NOT include: completed tasks (unless essential context), resolved MR comments, detailed change history.
|
|
44
|
+
|
|
45
|
+
### 4. Update the Old Task File
|
|
46
|
+
|
|
47
|
+
Add a "Work Continuation" section to the old task file before archiving:
|
|
48
|
+
|
|
49
|
+
```markdown
|
|
50
|
+
## Work Continuation
|
|
51
|
+
Remaining work has been moved to:
|
|
52
|
+
- **Branch**: {{ featureBranchPrefix }}{{ ticketIdExample }}-description-b
|
|
53
|
+
- **Task File**: {{ taskFileRoot }}/{{ featureBranchPrefix }}{{ ticketIdExample }}-description-b.md
|
|
54
|
+
- **Scope**: [brief description of remaining work]
|
|
55
|
+
|
|
56
|
+
This task file is now archived — work in the associated MR has been completed and merged.
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 5. Archive the Old Task File
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
mv {{ taskFileRoot }}/{{ featureBranchPrefix }}{{ ticketIdExample }}-description-a.md \
|
|
63
|
+
{{ taskFileRoot }}/archive/{{ featureBranchPrefix }}{{ ticketIdExample }}-description-a.md
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Create the archive subdirectory if it doesn't exist.
|
|
67
|
+
|
|
68
|
+
### 6. Clean Up
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Delete the old local branch
|
|
72
|
+
git branch -D {{ featureBranchPrefix }}{{ ticketIdExample }}-description-a
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Source for this Skill
|
|
76
|
+
|
|
77
|
+
This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
|
|
78
|
+
the output file should not be edited directly.
|
|
79
|
+
|
|
80
|
+
- Source Path: {{ sousTemplatePath }}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: go
|
|
3
|
+
description: Resume work on the current branch task — load the task file, analyze progress, identify next steps, and present options.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
@~sous-shared/_partials/resume-task.md
|
|
8
|
+
|
|
9
|
+
## Source for this Skill
|
|
10
|
+
|
|
11
|
+
This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
|
|
12
|
+
the output file should not be edited directly.
|
|
13
|
+
|
|
14
|
+
- Source Path: {{ sousTemplatePath }}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: resume-task
|
|
3
|
+
description: YOU MUST load this skill when the user is resuming work on an existing task — including "resume work", "continue from where we left off", "what's the status?", "what should we do next?", "read the task file", or when starting a new session on a branch that has an existing task file.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
@~sous-shared/_partials/resume-task.md
|
|
7
|
+
|
|
8
|
+
## Source for this Skill
|
|
9
|
+
|
|
10
|
+
This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
|
|
11
|
+
the output file should not be edited directly.
|
|
12
|
+
|
|
13
|
+
- Source Path: {{ sousTemplatePath }}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: start-task
|
|
3
|
+
description: >
|
|
4
|
+
YOU MUST load this skill when the user wants to start work on a new task — including "start a
|
|
5
|
+
new task", "let's work on {{ ticketIdExample }}", "begin a new task", "create a task file", or
|
|
6
|
+
any request to begin fresh work on a ticket.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
The agent performing this work MUST load `about-task-files` and any "about" skills related to the
|
|
10
|
+
project's task management system (e.g. Jira, Linear, etc.).
|
|
11
|
+
|
|
12
|
+
## Delegation
|
|
13
|
+
|
|
14
|
+
Per the sub-agent delegation pattern (`~sous-shared/_partials/sub-agent-delegation.md`):
|
|
15
|
+
|
|
16
|
+
- **Orchestrator-only:** every step that needs the user (picking the ticket, confirming the branch
|
|
17
|
+
name, approving the plan) and the git branch operations, which change the working tree the
|
|
18
|
+
orchestrator is in.
|
|
19
|
+
- **Delegated:** pulling ticket info (step 2) and writing the task file (step 4), each to a
|
|
20
|
+
background sub-agent. Dispatch them in parallel when independent.
|
|
21
|
+
- Sub-agents return links, questions, and confirmations to the orchestrator, which relays them to
|
|
22
|
+
the user.
|
|
23
|
+
|
|
24
|
+
## Steps
|
|
25
|
+
|
|
26
|
+
### 1. Identify the Ticket
|
|
27
|
+
|
|
28
|
+
Look for a ticket identifier (e.g. `{{ ticketIdExample }}`) in the user's message. If none is
|
|
29
|
+
provided:
|
|
30
|
+
- Ask the user to specify one, or offer to help them pick one
|
|
31
|
+
- Once a ticket number is confirmed, proceed
|
|
32
|
+
|
|
33
|
+
### 2. Pull Ticket Info
|
|
34
|
+
|
|
35
|
+
Delegate to a sub-agent: fetch basic ticket info from the project's task management system and
|
|
36
|
+
report it back. If the ticket doesn't exist, go back to step 1. If unassigned, ask the user if they
|
|
37
|
+
want to assign it to themselves. If the status indicates it hasn't been started, ask if they want to
|
|
38
|
+
transition it to an active state. Those questions are orchestrator-only; the sub-agent reports the
|
|
39
|
+
assignee and status and the orchestrator asks.
|
|
40
|
+
|
|
41
|
+
After transitioning, ensure the issue is visible on the team's board. If the project ships an
|
|
42
|
+
"about" skill for its task management system (e.g. `about-jira`, `about-linear`), follow its
|
|
43
|
+
board-move instructions for the board type and target status.
|
|
44
|
+
|
|
45
|
+
### 3. Check for an Existing Branch
|
|
46
|
+
|
|
47
|
+
Look for local branches that include the ticket number:
|
|
48
|
+
```bash
|
|
49
|
+
git branch | grep {{ ticketIdExample }}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
If found, confirm it's the right branch with the user (there may be multiple), then:
|
|
53
|
+
```bash
|
|
54
|
+
git checkout [branch-name]
|
|
55
|
+
git pull origin [branch-name]
|
|
56
|
+
```
|
|
57
|
+
Then go to step 4.
|
|
58
|
+
|
|
59
|
+
### 3a. Create a New Branch
|
|
60
|
+
|
|
61
|
+
If no existing branch is found:
|
|
62
|
+
|
|
63
|
+
1. Switch to the project's main development branch and pull latest
|
|
64
|
+
2. Resolve branch name: `{{ featureBranchPrefix }}{{ ticketPrefix }}[ticket-number]-[short-description]`
|
|
65
|
+
derived from the ticket title. **Confirm with the user before creating.**
|
|
66
|
+
3. Create and switch to the branch:
|
|
67
|
+
```bash
|
|
68
|
+
git checkout -b [branch-name]
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 4. Load or Create the Task File
|
|
72
|
+
|
|
73
|
+
Check for an existing task file at `{{ taskFileRoot }}/[branch-name].md`.
|
|
74
|
+
|
|
75
|
+
- **Found**: read it, note what's already captured, and continue to step 5
|
|
76
|
+
- **Not found**: delegate to a sub-agent, which collects full ticket info (summary, description,
|
|
77
|
+
status, assignee, related issues, comments, story points, sub-tasks, any linked MRs or commits)
|
|
78
|
+
and creates the task file using the format in `about-task-files`. Include relevant testing URLs
|
|
79
|
+
with real record IDs so URLs are actually clickable. Use `file:/absolute/path:line` format for
|
|
80
|
+
source file links.
|
|
81
|
+
|
|
82
|
+
### 5. Plan and Start
|
|
83
|
+
|
|
84
|
+
The orchestrator drafts the task plan, organized by layer (see `about-task-files` for layer
|
|
85
|
+
ordering), and asks the user if they want to begin work. Recording the approved plan in the task
|
|
86
|
+
file is delegated; pass the plan text to the sub-agent verbatim.
|
|
87
|
+
|
|
88
|
+
## Source for this Skill
|
|
89
|
+
|
|
90
|
+
This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a
|
|
91
|
+
template and the output file should not be edited directly.
|
|
92
|
+
|
|
93
|
+
- Source Path: {{ sousTemplatePath }}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: update
|
|
3
|
+
description: Update the task file before ending the session or when context is running low.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
@~sous-shared/_partials/update-task-file.md
|
|
8
|
+
|
|
9
|
+
## Source for this Skill
|
|
10
|
+
|
|
11
|
+
This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
|
|
12
|
+
the output file should not be edited directly.
|
|
13
|
+
|
|
14
|
+
- Source Path: {{ sousTemplatePath }}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: update-task-file
|
|
3
|
+
description: YOU MUST load this skill when context is running low, the user is ending the session, or they say "update the task file", "document our progress", "save our state", "prepare for new session", or invoke the !update command.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
@~sous-shared/_partials/update-task-file.md
|
|
7
|
+
|
|
8
|
+
## Source for this Skill
|
|
9
|
+
|
|
10
|
+
This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
|
|
11
|
+
the output file should not be edited directly.
|
|
12
|
+
|
|
13
|
+
- Source Path: {{ sousTemplatePath }}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { Command, Flags } from "@oclif/core";
|
|
2
|
+
import {
|
|
3
|
+
discoverConfig,
|
|
4
|
+
formatNotFoundMessage,
|
|
5
|
+
resolveConfigFlag,
|
|
6
|
+
type DiscoveredConfig,
|
|
7
|
+
} from "./lib/config-discovery.js";
|
|
8
|
+
import { loadEnvFiles } from "./lib/env-local.js";
|
|
9
|
+
import {
|
|
10
|
+
isConfigError,
|
|
11
|
+
loadSettings,
|
|
12
|
+
type ConfigContext,
|
|
13
|
+
type RawProject,
|
|
14
|
+
type Settings,
|
|
15
|
+
} from "./lib/settings.js";
|
|
16
|
+
import { displayError, displayErrorBlock, header } from "./utils/formatting.js";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Base class for all CLI commands.
|
|
20
|
+
*
|
|
21
|
+
* Startup sequence:
|
|
22
|
+
* 1. Locate the config — `--config <path>` wins, otherwise walk up from cwd
|
|
23
|
+
* looking for a `.sous/` directory holding sous.config.{js,mjs,json}.
|
|
24
|
+
* 2. Load `<.sous>/.env.local`, then `<.sous>/.env`, into process.env (never
|
|
25
|
+
* overwriting real env vars). Precedence: shell > .env.local > .env.
|
|
26
|
+
* 3. Load the config file. Variable resolution happens later, per command.
|
|
27
|
+
*
|
|
28
|
+
* There is no user-level config: nothing is read from `~/.sous`.
|
|
29
|
+
*/
|
|
30
|
+
export abstract class BaseCommand extends Command {
|
|
31
|
+
static baseFlags = {
|
|
32
|
+
project: Flags.string({
|
|
33
|
+
char: "p",
|
|
34
|
+
description: "Project key to operate on",
|
|
35
|
+
}),
|
|
36
|
+
config: Flags.string({
|
|
37
|
+
char: "c",
|
|
38
|
+
description:
|
|
39
|
+
"Path to a sous config file (or a directory containing one). Overrides .sous/ discovery",
|
|
40
|
+
}),
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
protected settings!: Settings;
|
|
44
|
+
|
|
45
|
+
/** Where the active config was found. */
|
|
46
|
+
protected configContext!: ConfigContext;
|
|
47
|
+
|
|
48
|
+
/** The full discovery result, including how the config was located. */
|
|
49
|
+
protected discovered!: DiscoveredConfig;
|
|
50
|
+
|
|
51
|
+
async init(): Promise<void> {
|
|
52
|
+
await super.init();
|
|
53
|
+
header();
|
|
54
|
+
|
|
55
|
+
// Read --config off argv directly. oclif's parse() runs inside each command's
|
|
56
|
+
// run(), which is too late: env vars must be injected before any resolution.
|
|
57
|
+
const configFlag = readConfigFlagFromArgv(this.argv);
|
|
58
|
+
|
|
59
|
+
let discovered: DiscoveredConfig | null;
|
|
60
|
+
|
|
61
|
+
if (configFlag !== undefined) {
|
|
62
|
+
try {
|
|
63
|
+
discovered = resolveConfigFlag(configFlag);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
displayError(error instanceof Error ? error.message : String(error));
|
|
66
|
+
return this.exit(1);
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
discovered = discoverConfig();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!discovered) {
|
|
73
|
+
displayErrorBlock(formatNotFoundMessage());
|
|
74
|
+
return this.exit(1);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
this.discovered = discovered;
|
|
78
|
+
this.configContext = {
|
|
79
|
+
sousDir: discovered.sousDir,
|
|
80
|
+
configPath: discovered.configPath,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// Inject .sous/.env.local and .sous/.env before anything resolves variables.
|
|
84
|
+
loadEnvFiles(discovered.sousDir);
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
this.settings = await loadSettings(discovered.configPath);
|
|
88
|
+
} catch (error) {
|
|
89
|
+
displayErrorBlock(error instanceof Error ? error.message : String(error));
|
|
90
|
+
return this.exit(1);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Renders a configuration error as a plain, readable message instead of an
|
|
96
|
+
* oclif stack trace. The stack for a ConfigError points at Sous internals and
|
|
97
|
+
* tells the user nothing about the config mistake they need to fix.
|
|
98
|
+
*
|
|
99
|
+
* Anything that is not a ConfigError falls through to oclif's normal handling,
|
|
100
|
+
* where a stack trace IS useful (it is a bug in Sous).
|
|
101
|
+
*/
|
|
102
|
+
protected async catch(error: Error & { exitCode?: number }): Promise<unknown> {
|
|
103
|
+
if (isConfigError(error)) {
|
|
104
|
+
displayErrorBlock(error.message);
|
|
105
|
+
return this.exit(1);
|
|
106
|
+
}
|
|
107
|
+
return super.catch(error);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Resolves the active project from the --project flag or settings.defaultProject.
|
|
112
|
+
* Exits with an error if no project key is available or the key is not found.
|
|
113
|
+
*/
|
|
114
|
+
protected resolveProject(flagValue: string | undefined): RawProject & { key: string } {
|
|
115
|
+
const keys = Object.keys(this.settings.projects ?? {});
|
|
116
|
+
const key = flagValue ?? this.settings.defaultProject ?? (keys.length === 1 ? keys[0] : undefined);
|
|
117
|
+
|
|
118
|
+
if (!key) {
|
|
119
|
+
displayError(
|
|
120
|
+
"No project specified.\n" +
|
|
121
|
+
` Config: ${this.configContext.configPath}\n` +
|
|
122
|
+
` Projects defined: ${keys.length > 0 ? keys.join(", ") : "(none)"}\n` +
|
|
123
|
+
" Use --project <key>, or set defaultProject in your config."
|
|
124
|
+
);
|
|
125
|
+
this.exit(1);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const project = this.settings.projects?.[key!];
|
|
129
|
+
|
|
130
|
+
if (!project) {
|
|
131
|
+
displayError(
|
|
132
|
+
`Project '${key}' not found in ${this.configContext.configPath}\n` +
|
|
133
|
+
` Projects defined: ${keys.length > 0 ? keys.join(", ") : "(none)"}`
|
|
134
|
+
);
|
|
135
|
+
this.exit(1);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return { ...project!, key: key! };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Number of projects defined in the active config. */
|
|
142
|
+
protected get projectCount(): number {
|
|
143
|
+
return Object.keys(this.settings.projects ?? {}).length;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Pulls the value of `--config` / `-c` out of a raw argv array.
|
|
149
|
+
* Supports `--config X`, `--config=X`, `-c X`, and `-cX`.
|
|
150
|
+
*
|
|
151
|
+
* @param argv - Raw arguments (oclif's `this.argv`, i.e. argv minus the command).
|
|
152
|
+
* @returns The flag value, or undefined when the flag is absent.
|
|
153
|
+
*/
|
|
154
|
+
export function readConfigFlagFromArgv(argv: string[]): string | undefined {
|
|
155
|
+
for (let i = 0; i < argv.length; i++) {
|
|
156
|
+
const arg = argv[i];
|
|
157
|
+
|
|
158
|
+
if (arg === "--config" || arg === "-c") return argv[i + 1];
|
|
159
|
+
if (arg.startsWith("--config=")) return arg.slice("--config=".length);
|
|
160
|
+
if (arg.startsWith("-c") && arg.length > 2 && !arg.startsWith("-c-")) return arg.slice(2);
|
|
161
|
+
}
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|