@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,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ctx.utils — generic, site-agnostic helpers for automation scripts.
|
|
3
|
+
*
|
|
4
|
+
* These are the patterns proven during the POC, promoted out of any single
|
|
5
|
+
* script. Site-specific logic (dismissing a particular app's modals, parsing a
|
|
6
|
+
* particular tool's output) stays in the script as step functions.
|
|
7
|
+
*
|
|
8
|
+
* Built per-run and bound to the live `page`/`logger`, so scripts call them as
|
|
9
|
+
* `ctx.utils.foo(...)` without threading `page` through every call.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Build the utils object for a run.
|
|
14
|
+
*
|
|
15
|
+
* @param {import('playwright').Page} page
|
|
16
|
+
* @param {object} logger - The script's logger (a child is created per helper)
|
|
17
|
+
* @returns {object} the ctx.utils surface
|
|
18
|
+
*/
|
|
19
|
+
export function createUtils(page, logger) {
|
|
20
|
+
const log = logger.child('utils');
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
/**
|
|
24
|
+
* RECOMMENDED way to handle modals/banners that appear at an unpredictable
|
|
25
|
+
* time and would block later actions. Registers a Playwright locator handler:
|
|
26
|
+
* whenever `triggerLocator` is present and blocks an action, `dismiss` runs.
|
|
27
|
+
* This is fully timing-independent — no sleeps, no races. Prefer this over
|
|
28
|
+
* `dismissModals` for anything that may appear asynchronously.
|
|
29
|
+
*
|
|
30
|
+
* @param {import('playwright').Locator} triggerLocator - The modal/overlay.
|
|
31
|
+
* @param {(locator) => Promise<void>} dismiss - How to dismiss it.
|
|
32
|
+
* @returns {Promise<void>}
|
|
33
|
+
*/
|
|
34
|
+
async autoDismiss(triggerLocator, dismiss) {
|
|
35
|
+
await page.addLocatorHandler(triggerLocator, dismiss);
|
|
36
|
+
log.info('registered auto-dismiss handler');
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Best-effort one-shot dismissal of modals KNOWN to already be present. Clicks
|
|
41
|
+
* the first of each candidate selector that currently exists; failures are
|
|
42
|
+
* swallowed. Does NOT wait for modals that may appear later — use
|
|
43
|
+
* `autoDismiss` for those. No fixed delays.
|
|
44
|
+
*
|
|
45
|
+
* @param {string[]} selectors
|
|
46
|
+
* @param {object} [opts] - { timeout }
|
|
47
|
+
* @returns {Promise<number>} count of elements clicked
|
|
48
|
+
*/
|
|
49
|
+
async dismissModals(selectors, opts = {}) {
|
|
50
|
+
const { timeout = 2000 } = opts;
|
|
51
|
+
let dismissed = 0;
|
|
52
|
+
for (const sel of selectors) {
|
|
53
|
+
const el = await page.$(sel);
|
|
54
|
+
if (!el) continue;
|
|
55
|
+
try {
|
|
56
|
+
await el.click({ timeout });
|
|
57
|
+
dismissed++;
|
|
58
|
+
} catch {
|
|
59
|
+
// best-effort; modal may have already closed or be non-actionable
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (dismissed) log.info(`dismissed ${dismissed} modal element(s)`);
|
|
63
|
+
return dismissed;
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Click an element located by visible text (regex or string). Defaults to a
|
|
68
|
+
* NON-forced click so Playwright auto-waits for the element to be actionable
|
|
69
|
+
* (visible, stable, not covered) — the resilient default. Pass `force: true`
|
|
70
|
+
* only for the rare element a component library (e.g. Blueprint.js) wrongly
|
|
71
|
+
* reports as disabled, and verify the outcome afterward.
|
|
72
|
+
*
|
|
73
|
+
* @param {RegExp|string} text
|
|
74
|
+
* @param {object} [opts] - { force, timeout }
|
|
75
|
+
*/
|
|
76
|
+
async clickByText(text, opts = {}) {
|
|
77
|
+
const { force = false, timeout = 15000 } = opts;
|
|
78
|
+
const locator = page.getByText(text).first();
|
|
79
|
+
await locator.waitFor({ timeout });
|
|
80
|
+
await locator.click({ force });
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Wait for any element matching `text` (regex or string) to appear, without
|
|
85
|
+
* clicking. Useful for asserting a list/view has rendered.
|
|
86
|
+
*
|
|
87
|
+
* @param {RegExp|string} text
|
|
88
|
+
* @param {object} [opts] - { timeout }
|
|
89
|
+
*/
|
|
90
|
+
async waitForText(text, opts = {}) {
|
|
91
|
+
const { timeout = 15000 } = opts;
|
|
92
|
+
await page.getByText(text).first().waitFor({ timeout });
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Try each selector in order; return the longest text content found among
|
|
97
|
+
* all matches, or null if nothing exceeds `minLength`. Built for "find the
|
|
98
|
+
* log/output blob on the page" cases where the exact container is unknown.
|
|
99
|
+
*
|
|
100
|
+
* @param {string[]} selectors
|
|
101
|
+
* @param {object} [opts] - { minLength }
|
|
102
|
+
* @returns {Promise<string|null>}
|
|
103
|
+
*/
|
|
104
|
+
async extractLongestText(selectors, opts = {}) {
|
|
105
|
+
const { minLength = 50 } = opts;
|
|
106
|
+
for (const sel of selectors) {
|
|
107
|
+
const els = await page.$$(sel);
|
|
108
|
+
if (!els.length) continue;
|
|
109
|
+
const texts = await Promise.all(els.map((el) => el.textContent()));
|
|
110
|
+
const longest = texts
|
|
111
|
+
.filter(Boolean)
|
|
112
|
+
.map((t) => t.trim())
|
|
113
|
+
.sort((a, b) => b.length - a.length)[0];
|
|
114
|
+
if (longest && longest.length >= minLength) return longest;
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Extract the first match of a regex from page text (or supplied text).
|
|
121
|
+
* Returns the trimmed match string, or null.
|
|
122
|
+
*
|
|
123
|
+
* @param {RegExp} pattern
|
|
124
|
+
* @param {object} [opts] - { source: string, group: number }
|
|
125
|
+
* @returns {Promise<string|null>}
|
|
126
|
+
*/
|
|
127
|
+
async extractTextByPattern(pattern, opts = {}) {
|
|
128
|
+
const { source = null, group = 0 } = opts;
|
|
129
|
+
const haystack = source ?? (await page.textContent('body')) ?? '';
|
|
130
|
+
const m = haystack.match(pattern);
|
|
131
|
+
return m ? m[group].trim() : null;
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Capture a screenshot for debugging. No-op-safe: failures are logged, not
|
|
136
|
+
* thrown, so a debug aid never breaks a run.
|
|
137
|
+
*
|
|
138
|
+
* @param {string} path - Absolute file path for the PNG
|
|
139
|
+
* @param {object} [opts] - { fullPage }
|
|
140
|
+
*/
|
|
141
|
+
async screenshot(path, opts = {}) {
|
|
142
|
+
const { fullPage = true } = opts;
|
|
143
|
+
try {
|
|
144
|
+
await page.screenshot({ path, fullPage });
|
|
145
|
+
log.info(`screenshot saved: ${path}`);
|
|
146
|
+
} catch (err) {
|
|
147
|
+
log.warn(`screenshot failed: ${err.message}`);
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Scroll an element matching `selector` into view. Returns true if found.
|
|
153
|
+
*
|
|
154
|
+
* @param {string} selector
|
|
155
|
+
*/
|
|
156
|
+
async scrollIntoView(selector) {
|
|
157
|
+
const el = await page.$(selector);
|
|
158
|
+
if (!el) return false;
|
|
159
|
+
await el.scrollIntoViewIfNeeded().catch(() => {});
|
|
160
|
+
return true;
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Retry an async function until it succeeds or attempts are exhausted.
|
|
165
|
+
* Throws the last error on final failure.
|
|
166
|
+
*
|
|
167
|
+
* @param {Function} fn - async () => result
|
|
168
|
+
* @param {object} [opts] - { attempts, delay, label }
|
|
169
|
+
*/
|
|
170
|
+
async retry(fn, opts = {}) {
|
|
171
|
+
const { attempts = 3, delay = 1000, label = 'operation' } = opts;
|
|
172
|
+
let lastErr;
|
|
173
|
+
for (let i = 1; i <= attempts; i++) {
|
|
174
|
+
try {
|
|
175
|
+
return await fn();
|
|
176
|
+
} catch (err) {
|
|
177
|
+
lastErr = err;
|
|
178
|
+
log.warn(`${label} failed (attempt ${i}/${attempts}): ${err.message}`);
|
|
179
|
+
if (i < attempts) await page.waitForTimeout(delay);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
throw lastErr;
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
}
|
package/shared-prompts/skills/automated-browser-tasks/create-automated-browser-task/SKILL.tpl.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: create-automated-browser-task
|
|
3
|
+
description: >
|
|
4
|
+
YOU MUST load this skill when you need to create a new headless browser
|
|
5
|
+
automation script — i.e. a browser task is required and no existing script
|
|
6
|
+
performs it. Produces a convention-compliant script in the project's
|
|
7
|
+
automation scripts directory.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Create an Automated Browser Task
|
|
11
|
+
|
|
12
|
+
A thin action skill. The architecture, `ctx` API, and full conventions live in
|
|
13
|
+
the parent topic skill; the agent performing this work MUST load
|
|
14
|
+
`about-automated-browser-tasks`.
|
|
15
|
+
|
|
16
|
+
## Delegation
|
|
17
|
+
|
|
18
|
+
Per the sub-agent delegation pattern
|
|
19
|
+
(`~sous-shared/_partials/sub-agent-delegation.md`), writing and iterating on a script is
|
|
20
|
+
delegated work: one Opus sub-agent writes it, runs it, and iterates against the
|
|
21
|
+
real page until it works, then reports the script path and result. Give it the
|
|
22
|
+
target URL, the data to extract, and the params wanted.
|
|
23
|
+
|
|
24
|
+
## Steps
|
|
25
|
+
|
|
26
|
+
1. **Confirm none exists.** Search the project's automation scripts directory for
|
|
27
|
+
a script that already does this. If one is close, prefer
|
|
28
|
+
`update-automated-browser-task` instead.
|
|
29
|
+
2. **Name the file** `verb-noun-qualifier.mjs` (e.g. `get-repo-ci-error.mjs`).
|
|
30
|
+
3. **Declare `meta`** — `name`, a descriptive `description`, and `params`. For each
|
|
31
|
+
param set `required`, `default`, a genuinely descriptive `description`, and a
|
|
32
|
+
`validate` rule (RegExp or function) with an `invalidMessage`. Pull shared
|
|
33
|
+
values (URLs, resource IDs, profile) from `ctx.settings` rather than hardcoding.
|
|
34
|
+
4. **Write `execute(ctx)`** as a thin orchestrator that calls small, named step
|
|
35
|
+
functions. Destructure off `ctx`/`params` at the top. Use `ctx.logger`, never
|
|
36
|
+
`console.log`. Use `ctx.utils` for generic patterns; keep site-specific logic
|
|
37
|
+
in step functions. Give EVERY function a full JSDoc block.
|
|
38
|
+
5. **Return a result object** (`found`, `content`, `outputFile`, a URL, `message`).
|
|
39
|
+
6. **Run it** to verify — see `running-automated-browser-tasks`. Iterate on the
|
|
40
|
+
real page; do not guess selectors.
|
|
41
|
+
|
|
42
|
+
## Reference
|
|
43
|
+
|
|
44
|
+
The exact param spec, `ctx.utils` surface, return shape, and worked examples are
|
|
45
|
+
in the topic skill's references and `examples/`. Read them — do not improvise.
|
|
46
|
+
|
|
47
|
+
## Source for this Skill
|
|
48
|
+
|
|
49
|
+
This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
|
|
50
|
+
the output file should not be edited directly.
|
|
51
|
+
|
|
52
|
+
- Source Path: {{ sousTemplatePath }}
|
package/shared-prompts/skills/automated-browser-tasks/running-automated-browser-tasks/SKILL.tpl.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: running-automated-browser-tasks
|
|
3
|
+
description: >
|
|
4
|
+
YOU MUST load this skill when you need to run an existing headless browser
|
|
5
|
+
automation script for the user — to execute a task, fetch data from a site, or
|
|
6
|
+
verify a script you just wrote or changed.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Run an Automated Browser Task
|
|
10
|
+
|
|
11
|
+
A thin action skill. The agent performing this work MUST load
|
|
12
|
+
`about-automated-browser-tasks` for the architecture and the meaning of `ctx`,
|
|
13
|
+
auth handling, and result shapes.
|
|
14
|
+
|
|
15
|
+
## Delegation
|
|
16
|
+
|
|
17
|
+
Per the sub-agent delegation pattern
|
|
18
|
+
(`~sous-shared/_partials/sub-agent-delegation.md`), a browser run is a slow, multi-step
|
|
19
|
+
execution: delegate it to a background sub-agent, which runs the command,
|
|
20
|
+
interprets the outcome below, and reports the result plus any link or actionable
|
|
21
|
+
message. Run a one-off script inline only when its result blocks the very next
|
|
22
|
+
step.
|
|
23
|
+
|
|
24
|
+
## Invocation
|
|
25
|
+
|
|
26
|
+
Run a script by its absolute path through the runner in this system's `scripts/`
|
|
27
|
+
directory:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
node <scriptsDir>/run.mjs <absolute-path-to-script.mjs> [--param=value ...]
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
- Pass script params as `--paramName=value`.
|
|
34
|
+
- Harness options: `--profileName=<name>` (Chrome profile), `--timeout=<ms>`.
|
|
35
|
+
- The runner loads compiled project `settings.mjs` automatically and prints the
|
|
36
|
+
resolved params (marking which came from defaults/settings) before running.
|
|
37
|
+
|
|
38
|
+
## Reading the outcome
|
|
39
|
+
|
|
40
|
+
- **Success** → `✓` and the result is printed; if the script returned an
|
|
41
|
+
`outputFile` + `content`, the runner writes the file and reports the path.
|
|
42
|
+
- **`error: params`** → a required param was missing or failed validation. Fix the
|
|
43
|
+
invocation; do not edit the script to bypass validation.
|
|
44
|
+
- **`error: auth`** → the session was redirected to a login page. The user must log
|
|
45
|
+
in to the site in their Chrome profile, then the SAME command is re-run; no
|
|
46
|
+
script change needed. A sub-agent cannot ask for this: return the actionable
|
|
47
|
+
message and the link to the orchestrator, which relays them to the user and
|
|
48
|
+
re-dispatches the run afterward.
|
|
49
|
+
- **`error: script`** → an unexpected failure with a stack. Inspect, then use
|
|
50
|
+
`update-automated-browser-task` to fix the root cause and re-run.
|
|
51
|
+
|
|
52
|
+
Never silently swallow a failure or fake a result. Report what happened.
|
|
53
|
+
|
|
54
|
+
## Source for this Skill
|
|
55
|
+
|
|
56
|
+
This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
|
|
57
|
+
the output file should not be edited directly.
|
|
58
|
+
|
|
59
|
+
- Source Path: {{ sousTemplatePath }}
|
package/shared-prompts/skills/automated-browser-tasks/update-automated-browser-task/SKILL.tpl.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: update-automated-browser-task
|
|
3
|
+
description: >
|
|
4
|
+
YOU MUST load this skill when you need to modify, fix, or extend an existing
|
|
5
|
+
headless browser automation script — for example when a script breaks because
|
|
6
|
+
a site's markup changed, or a new param/behavior is needed.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Update an Automated Browser Task
|
|
10
|
+
|
|
11
|
+
A thin action skill. The agent performing this work MUST load
|
|
12
|
+
`about-automated-browser-tasks` for the architecture, `ctx` API, and full
|
|
13
|
+
conventions.
|
|
14
|
+
|
|
15
|
+
## Delegation
|
|
16
|
+
|
|
17
|
+
Per the sub-agent delegation pattern
|
|
18
|
+
(`~sous-shared/_partials/sub-agent-delegation.md`), the fix-and-re-run loop below
|
|
19
|
+
is delegated to one Opus sub-agent, which reports what broke, what it changed, and the verified
|
|
20
|
+
result. Give it the script path and the failing run output.
|
|
21
|
+
|
|
22
|
+
## Steps
|
|
23
|
+
|
|
24
|
+
1. **Read the script** and the run output. Identify the failing step from the
|
|
25
|
+
logger prefixes (`[script:section]`) in the output.
|
|
26
|
+
2. **Reproduce** by running it (see `running-automated-browser-tasks`). For
|
|
27
|
+
selector/markup failures, inspect the live page — use `ctx.utils.screenshot`
|
|
28
|
+
or widen selectors; do not guess.
|
|
29
|
+
3. **Make the smallest correct change.** Fix the root cause, not the symptom. Keep
|
|
30
|
+
the existing decomposition: edit the relevant step function, add a new one if a
|
|
31
|
+
new discrete action is needed.
|
|
32
|
+
4. **Preserve conventions.** Maintain JSDoc blocks, `ctx`/`params` destructuring,
|
|
33
|
+
`ctx.logger` usage, and `meta.params` validation. If you add a param, give it a
|
|
34
|
+
description and a `validate` rule.
|
|
35
|
+
5. **Re-run to verify** the fix end-to-end.
|
|
36
|
+
|
|
37
|
+
## When NOT to update
|
|
38
|
+
|
|
39
|
+
If the change amounts to a different task, create a new script instead
|
|
40
|
+
(`create-automated-browser-task`). Keep each script focused on one job.
|
|
41
|
+
|
|
42
|
+
## Source for this Skill
|
|
43
|
+
|
|
44
|
+
This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
|
|
45
|
+
the output file should not be edited directly.
|
|
46
|
+
|
|
47
|
+
- Source Path: {{ sousTemplatePath }}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: approve
|
|
3
|
+
description: Approve the current plan and instruct Claude to proceed with maximum parallelism.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Your plan looks good, and I approve.
|
|
8
|
+
|
|
9
|
+
While executing the plan, maximize parallelism:
|
|
10
|
+
- Delegate the steps that have any complexity to background sub-agents, per the sub-agent
|
|
11
|
+
delegation pattern (`~sous-shared/_partials/sub-agent-delegation.md`), batching independent
|
|
12
|
+
dispatches into one message.
|
|
13
|
+
- Batch independent investigations (searches, file reads, greps, listings) into concurrent tool
|
|
14
|
+
calls whenever practical.
|
|
15
|
+
- Keep dependent steps sequential (especially edits, formatting/linting, and tests that rely on
|
|
16
|
+
prior changes).
|
|
17
|
+
|
|
18
|
+
Use the best-fit tools for the job. If you can't parallelize a step, say why briefly and proceed
|
|
19
|
+
sequentially.
|
|
20
|
+
|
|
21
|
+
## Source for this Skill
|
|
22
|
+
|
|
23
|
+
This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a
|
|
24
|
+
template and the output file should not be edited directly.
|
|
25
|
+
|
|
26
|
+
- Source Path: {{ sousTemplatePath }}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: opine
|
|
3
|
+
description: >
|
|
4
|
+
Used to send an idea or proposal to the agent and have it repeat it back, then offer an honest
|
|
5
|
+
analysis of viability, practicality, and overall merit. This is a discussion; no action is taken.
|
|
6
|
+
argument-hint: idea or proposal
|
|
7
|
+
disable-model-invocation: true
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
New Idea/Proposal:
|
|
11
|
+
$ARGUMENTS
|
|
12
|
+
|
|
13
|
+
-
|
|
14
|
+
|
|
15
|
+
## CRITICAL: DO NOT ACT ON THIS IDEA
|
|
16
|
+
|
|
17
|
+
This is a discussion, not a request. You must NOT take any action: do not write code, do not edit
|
|
18
|
+
files, do not create branches, do not modify anything. The user is thinking out loud and wants
|
|
19
|
+
your opinion. Your only output is text directed at the user.
|
|
20
|
+
|
|
21
|
+
## Research
|
|
22
|
+
|
|
23
|
+
You may research the codebase and/or the web before responding if you think it would improve the
|
|
24
|
+
accuracy of your analysis. Most ideas won't need this; use your judgement. When you do research,
|
|
25
|
+
prefer sub-agents and run them in parallel where practical.
|
|
26
|
+
|
|
27
|
+
## Step 1: Repeat
|
|
28
|
+
|
|
29
|
+
Repeat the idea or proposal back to me, in your own words and in a well-structured format so
|
|
30
|
+
that I know our understandings are aligned.
|
|
31
|
+
|
|
32
|
+
## Step 2: Analyze
|
|
33
|
+
|
|
34
|
+
After repeating the idea back, offer your analysis in three parts:
|
|
35
|
+
|
|
36
|
+
1. **Viability**: Is this idea technically feasible? Are there any fundamental blockers or
|
|
37
|
+
constraints that would prevent it from working?
|
|
38
|
+
|
|
39
|
+
2. **Practicality**: Even if viable, is it practical? Would it require more steps, complexity,
|
|
40
|
+
or hacky code than I'm probably anticipating? Are there hidden costs (maintenance burden,
|
|
41
|
+
performance implications, edge cases)?
|
|
42
|
+
|
|
43
|
+
3. **Opinion**: Is this a good idea? Give your honest take on whether this is the right approach.
|
|
44
|
+
|
|
45
|
+
## Guidelines
|
|
46
|
+
|
|
47
|
+
- **No action.** This cannot be overstated. Do not act on the idea. Only discuss it.
|
|
48
|
+
- Be open and honest. Push back when you genuinely see problems.
|
|
49
|
+
- "Yes, that seems like a great idea" is an entirely valid response. Do not manufacture
|
|
50
|
+
objections or play devil's advocate just for the sake of it. If the idea is sound, say so.
|
|
51
|
+
If it has real problems, say that too.
|
|
52
|
+
|
|
53
|
+
## Source for this Skill
|
|
54
|
+
|
|
55
|
+
This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a
|
|
56
|
+
template and the output file should not be edited directly.
|
|
57
|
+
|
|
58
|
+
- Source Path: {{ sousTemplatePath }}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: repeat
|
|
3
|
+
description: >
|
|
4
|
+
Used to send an instruction to the agent and have the agent repeat the instruction back to you
|
|
5
|
+
before acting, to ensure that you and the agent are aligned.
|
|
6
|
+
argument-hint: instruction
|
|
7
|
+
disable-model-invocation: true
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
New Instruction:
|
|
11
|
+
$ARGUMENTS
|
|
12
|
+
|
|
13
|
+
-
|
|
14
|
+
|
|
15
|
+
DO NOT ACT, yet. Instead, I want you to repeat the instruction back to me, in your own words and
|
|
16
|
+
in a well-structured format so that I know our understandings are aligned. If I am satisfied with
|
|
17
|
+
your explanation, I will approve you to begin acting.
|
|
18
|
+
|
|
19
|
+
You may do a small amount of research before repeating the instruction back to me, if you think
|
|
20
|
+
it would allow you to be more precise or accurate in your explanation.
|
|
21
|
+
|
|
22
|
+
## Source for this Skill
|
|
23
|
+
|
|
24
|
+
This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a
|
|
25
|
+
template and the output file should not be edited directly.
|
|
26
|
+
|
|
27
|
+
- Source Path: {{ sousTemplatePath }}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: research
|
|
3
|
+
description: Run a research task using background sub-agents
|
|
4
|
+
user-invocable-only: true
|
|
5
|
+
arguments-hint: what to research via background subagents
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Have a background sub-agent do the following:
|
|
9
|
+
$ARGUMENTS
|
|
10
|
+
|
|
11
|
+
## Prefer Parallelism
|
|
12
|
+
|
|
13
|
+
If possible, practical, and reasonable, break the task into multiple parts and assign each part to a sub-agent.
|
|
14
|
+
Running background sub-agents in parallel usually makes things go much faster. Don't break tiny tasks up, though.
|
|
15
|
+
|
|
16
|
+
Batch the independent dispatches into one message so they run at once. Opus by default; Sonnet only
|
|
17
|
+
for rote extraction.
|
|
18
|
+
|
|
19
|
+
## Sub-Agent Prompts
|
|
20
|
+
|
|
21
|
+
Per the sub-agent delegation pattern (`~sous-shared/_partials/sub-agent-delegation.md`), each prompt
|
|
22
|
+
must be self-contained: the question to answer, the
|
|
23
|
+
paths/IDs/facts needed, which skills to load, and the shape of the answer wanted. Sub-agents start
|
|
24
|
+
fresh and cannot see this conversation.
|
|
25
|
+
|
|
26
|
+
Each returns a concise summary, not a file dump. Do not fabricate or predict a pending result; wait
|
|
27
|
+
for the notification. Synthesis and reporting to the user are orchestrator-only.
|
|
28
|
+
|
|
29
|
+
## Source for this Skill
|
|
30
|
+
|
|
31
|
+
This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a
|
|
32
|
+
template and the output file should not be edited directly.
|
|
33
|
+
|
|
34
|
+
- Source Path: {{ sousTemplatePath }}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: about-agent-skills
|
|
3
|
+
description: >
|
|
4
|
+
YOU MUST load this skill when creating, editing, auditing, or reasoning about any
|
|
5
|
+
skill. Covers skill structure, frontmatter fields, invocation, topic vs action
|
|
6
|
+
patterns, naming conventions, and general principles.
|
|
7
|
+
user-invocable: false
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# About Agent Skills
|
|
11
|
+
|
|
12
|
+
A skill is a directory containing a `SKILL.md` file and optional supporting files.
|
|
13
|
+
Skills extend what a coding agent can do — invoke them directly with `/skill-name`,
|
|
14
|
+
or they load automatically when the agent's decision logic matches the `description`.
|
|
15
|
+
|
|
16
|
+
## Where Skills Live
|
|
17
|
+
|
|
18
|
+
Skills for this project live at `{{ skillsRoot }}`. Create and edit skills there —
|
|
19
|
+
never in `.claude/skills/` or `.codex/skills/` directly. See `create-skill` for
|
|
20
|
+
step-by-step instructions.
|
|
21
|
+
|
|
22
|
+
## Directory Structure
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
my-skill/
|
|
26
|
+
├── SKILL.md # Required. Frontmatter + instructions.
|
|
27
|
+
├── references/ # Optional. Deep-dive docs loaded when needed.
|
|
28
|
+
├── examples/ # Optional. Example outputs.
|
|
29
|
+
└── scripts/ # Optional. Executable scripts.
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Supporting files must be referenced from `SKILL.md` — the agent will not know they
|
|
33
|
+
exist otherwise. Keep `SKILL.md` under ~500 lines; move detailed reference material
|
|
34
|
+
to `references/` files.
|
|
35
|
+
|
|
36
|
+
## Core Frontmatter
|
|
37
|
+
|
|
38
|
+
```yaml
|
|
39
|
+
---
|
|
40
|
+
name: my-skill
|
|
41
|
+
description: >
|
|
42
|
+
One or two sentences describing when the agent should invoke this skill.
|
|
43
|
+
Under 500 characters. Write as a trigger condition, not a title.
|
|
44
|
+
disable-model-invocation: true
|
|
45
|
+
user-invocable: false
|
|
46
|
+
---
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**`name`** — becomes the `/slash-command`. Defaults to the directory name if omitted.
|
|
50
|
+
|
|
51
|
+
**`description`** — tells the agent when to invoke this skill. Use strong trigger
|
|
52
|
+
language: open with "YOU MUST load this skill when...". Under 500 chars.
|
|
53
|
+
|
|
54
|
+
**`disable-model-invocation`** — set `true` to prevent the agent from invoking the
|
|
55
|
+
skill automatically. Use this for command skills that represent intentional,
|
|
56
|
+
user-initiated actions (e.g. `/commit`, `/deploy`). If it makes sense for the agent
|
|
57
|
+
to invoke the skill on the user's behalf, omit it.
|
|
58
|
+
|
|
59
|
+
**`user-invocable`** — set `false` to hide the skill from the `/` menu. Use this on
|
|
60
|
+
all topic skills (`about-*`). They are reference material the agent loads
|
|
61
|
+
automatically, not commands for the user to invoke.
|
|
62
|
+
|
|
63
|
+
For all frontmatter fields, see [references/frontmatter.md](references/frontmatter.md).
|
|
64
|
+
|
|
65
|
+
## Topic vs Action Skills
|
|
66
|
+
|
|
67
|
+
**Topic skills** hold reference material and background context for a concept, plus any
|
|
68
|
+
shared scripts the action skills draw from. They are moderately descriptive and reusable
|
|
69
|
+
across many workflows. Always set `user-invocable: false`. Use the `about-*` prefix when
|
|
70
|
+
the skill's primary purpose is background understanding.
|
|
71
|
+
|
|
72
|
+
A topic skill's body holds fundamental knowledge — what is needed in ~75%+ of use cases.
|
|
73
|
+
Deeper reference material (complete tables, edge cases, advanced patterns) goes in
|
|
74
|
+
`references/` files, loaded only when needed. When official documentation exists for the
|
|
75
|
+
topic, fetch it once and store distilled versions in `references/`, including the official
|
|
76
|
+
source URL so the agent can check anything not covered locally. This prevents repeated doc
|
|
77
|
+
fetches during work sessions.
|
|
78
|
+
|
|
79
|
+
**Action skills** perform a specific operation and are as thin as possible — they
|
|
80
|
+
contain only what is exclusive to that action. All shared knowledge belongs in the
|
|
81
|
+
parent topic skill. Action skills carry less cold-start context than topic skills: just
|
|
82
|
+
enough to not be opaque, then delegate depth upward with `YOU MUST load`. Name action
|
|
83
|
+
skills with a verb prefix: `create-`, `deploy-`, `run-`. If the skill operates on a
|
|
84
|
+
specific type, include it after the verb (e.g. `create-skill` operates on a "skill").
|
|
85
|
+
The verb-first pattern immediately distinguishes action skills from topic skills in any
|
|
86
|
+
skill listing.
|
|
87
|
+
|
|
88
|
+
Non-command action skills must NOT have `disable-model-invocation: true` — that flag
|
|
89
|
+
removes the skill from the agent's context entirely, making it undiscoverable. A
|
|
90
|
+
non-command action skill relies on its description to tell the agent when to invoke it
|
|
91
|
+
automatically; omitting the flag is what makes that possible.
|
|
92
|
+
|
|
93
|
+
## Template Files (`.tpl.`)
|
|
94
|
+
|
|
95
|
+
Any file in a skill directory can use `.tpl.` naming to opt into LiquidJS processing
|
|
96
|
+
at compile time. The `.tpl.` segment is stripped from the output filename.
|
|
97
|
+
For when `SKILL.md` must be `SKILL.tpl.md`, see **Template-Compiled Skills** below.
|
|
98
|
+
|
|
99
|
+
YOU MUST load `about-liquid-templates` when deciding whether any file in a skill
|
|
100
|
+
directory needs `.tpl.` naming or when writing LiquidJS syntax.
|
|
101
|
+
|
|
102
|
+
## General Principles
|
|
103
|
+
|
|
104
|
+
**Knowledge lives at the highest common ancestor.** If two skills need the same
|
|
105
|
+
knowledge, it belongs in the most general topic skill covering both — never
|
|
106
|
+
duplicated across skills. Before adding content anywhere, ask whether it belongs
|
|
107
|
+
higher up.
|
|
108
|
+
|
|
109
|
+
**Every skill provides minimal cold-start context.** Assume the agent knows nothing
|
|
110
|
+
about the concept until the skill is loaded, and will not load any other skill unless
|
|
111
|
+
explicitly told to. Include the briefest possible orientation, then point to deeper
|
|
112
|
+
resources.
|
|
113
|
+
|
|
114
|
+
**Never duplicate information that changes over time.** Do not create lists or tables
|
|
115
|
+
that inventory things which will evolve (e.g. available skills, current files in a
|
|
116
|
+
directory). Teach the agent where to look rather than providing a snapshot that will go
|
|
117
|
+
stale. Only document things stable by nature.
|
|
118
|
+
|
|
119
|
+
**Use strong trigger language.** Descriptions must open with `YOU MUST load this
|
|
120
|
+
skill when...`. Cross-references to other skills must use `YOU MUST load` — weak
|
|
121
|
+
language like "consult" or "see" is not sufficient. In a skill body, write the
|
|
122
|
+
requirement so it binds whichever agent executes ("The agent performing this work MUST
|
|
123
|
+
load `x`"), not just the main session: delegated sub-agents start with fresh context and
|
|
124
|
+
must load the skills themselves.
|
|
125
|
+
|
|
126
|
+
**Write steps for whoever executes them.** Do not assume the main session performs
|
|
127
|
+
a skill's steps inline. Say which steps are delegated to a sub-agent and which are
|
|
128
|
+
orchestrator-only (anything needing the user, or the chat conversation's own
|
|
129
|
+
contents). Never rely on "skip this if it is already in context" heuristics: a
|
|
130
|
+
sub-agent's context is always fresh. Steps that produce a link or question for the
|
|
131
|
+
user must return it to the orchestrator, which relays it.
|
|
132
|
+
|
|
133
|
+
**If no action skill exists for a task, ask the user.** Do not improvise an action
|
|
134
|
+
that warrants its own skill.
|
|
135
|
+
|
|
136
|
+
## Template-Compiled Skills
|
|
137
|
+
|
|
138
|
+
Every skill distributed from a shared library — whether this library (`sous`) or any other
|
|
139
|
+
shared skill library — must use `SKILL.tpl.md`, not `SKILL.md`. This is required because
|
|
140
|
+
every distributed skill must end with a `## Source for this Skill` section (see below), and
|
|
141
|
+
that section uses a template variable for the source path, which requires LiquidJS rendering.
|
|
142
|
+
No exceptions.
|
|
143
|
+
|
|
144
|
+
Every such skill's `SKILL.md` must end with a `## Source for this Skill` section:
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
## Source for this Skill
|
|
148
|
+
|
|
149
|
+
This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
|
|
150
|
+
the output file should not be edited directly.
|
|
151
|
+
|
|
152
|
+
- Source Path: <resolved source path>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
This tells agents reading the compiled output where the skill originated and that the
|
|
156
|
+
file must not be edited directly. Because this footer is required, all shared skills must
|
|
157
|
+
use `SKILL.tpl.md` (not `SKILL.md`) so the source path variable can be rendered at
|
|
158
|
+
compile time.
|
|
159
|
+
|
|
160
|
+
## Examples
|
|
161
|
+
|
|
162
|
+
- [examples/about-something.md](examples/about-something.md) — a complete example of a topic (`about-*`) skill
|
|
163
|
+
- [examples/do-something.md](examples/do-something.md) — a complete example of an action skill (command)
|
|
164
|
+
|
|
165
|
+
## Reference Files
|
|
166
|
+
|
|
167
|
+
- [frontmatter.md](references/frontmatter.md) — complete frontmatter field table and invocation matrix
|
|
168
|
+
- [substitutions.md](references/substitutions.md) — `$ARGUMENTS`, `$ARGUMENTS[N]`, `$CLAUDE_SESSION_ID`, `$CLAUDE_SKILL_DIR`
|
|
169
|
+
- [commands.md](references/commands.md) — command-specific conventions: descriptions, headings, arguments, `argument-hint`
|
|
170
|
+
- [advanced-patterns.md](references/advanced-patterns.md) — dynamic context injection, subagent execution (`context: fork`), `allowed-tools`
|
|
171
|
+
|
|
172
|
+
## Source for this Skill
|
|
173
|
+
|
|
174
|
+
This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
|
|
175
|
+
the output file should not be edited directly.
|
|
176
|
+
|
|
177
|
+
- Source Path: {{ sousTemplatePath }}
|