@sous-io/sous 0.1.0 → 0.2.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/README.md +121 -35
- package/bin/run.js +10 -1
- package/docs/markdown/README.md +27 -0
- package/docs/markdown/_sidebar.md +18 -0
- package/docs/markdown/commands.md +308 -0
- package/docs/markdown/config-discovery.md +74 -0
- package/docs/markdown/config-inspection.md +69 -0
- package/docs/markdown/config-layers.md +92 -0
- package/docs/markdown/config-variables.md +79 -0
- package/docs/markdown/configuration.md +71 -0
- package/docs/markdown/design-principles.md +59 -0
- package/docs/markdown/repositories-authoring.md +408 -0
- package/docs/markdown/repositories-consuming.md +580 -0
- package/docs/markdown/repositories-file-formats.md +1084 -0
- package/docs/markdown/repositories-variables.md +387 -0
- package/docs/markdown/repositories.md +303 -0
- package/docs/markdown/skill-categories.md +58 -0
- package/package.json +73 -9
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/SKILL.tpl.md +20 -20
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/examples/about-something.md +2 -2
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/examples/do-something.md +1 -1
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/advanced-patterns.md +6 -6
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/commands.md +5 -5
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/frontmatter.md +3 -3
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-liquid-templates/SKILL.tpl.md +40 -25
- package/recipes/core/sous-skills/skills/about-sous/SKILL.tpl.md +70 -0
- package/recipes/core/sous-skills/skills/about-sous-configuration/SKILL.tpl.md +75 -0
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/create-skill/SKILL.tpl.md +8 -9
- package/recipes/core/sous-skills/sous.recipe.yaml +45 -0
- package/sous.config.schema.json +337 -0
- package/src/base-command.ts +220 -67
- package/src/commands/build.ts +150 -73
- package/src/commands/clear.ts +23 -15
- package/src/commands/compile.ts +74 -16
- package/src/commands/config/get.ts +110 -0
- package/src/commands/config/show.ts +32 -0
- package/src/commands/config/validate.ts +53 -0
- package/src/commands/help.ts +46 -0
- package/src/commands/launch.ts +36 -14
- package/src/commands/lock/rebuild.ts +241 -0
- package/src/commands/lock/show.ts +115 -0
- package/src/commands/namespace/list.ts +117 -0
- package/src/commands/namespace/show.ts +110 -0
- package/src/commands/prune.ts +3 -11
- package/src/commands/recipe/list.ts +95 -0
- package/src/commands/recipe/show.ts +301 -0
- package/src/commands/repo/add.ts +145 -0
- package/src/commands/repo/gc.ts +172 -0
- package/src/commands/repo/init.ts +136 -0
- package/src/commands/repo/link.ts +500 -0
- package/src/commands/repo/list.ts +179 -0
- package/src/commands/repo/release.ts +619 -0
- package/src/commands/repo/remove.ts +193 -0
- package/src/commands/repo/search.ts +189 -0
- package/src/commands/repo/submit.ts +133 -0
- package/src/commands/repo/unlink.ts +147 -0
- package/src/commands/subscription/add.ts +285 -0
- package/src/commands/subscription/list.ts +129 -0
- package/src/commands/subscription/remove.ts +181 -0
- package/src/commands/vars/ask.ts +374 -0
- package/src/commands/vars/index.ts +79 -0
- package/src/commands/vars/list.ts +67 -0
- package/src/commands/vars/show.ts +77 -0
- package/src/config-command.ts +30 -0
- package/src/lib/build-service.ts +206 -54
- package/src/lib/config-discovery.ts +220 -27
- package/src/lib/config-inspect.ts +145 -0
- package/src/lib/config-kernel.mjs +377 -0
- package/src/lib/config-schema.ts +361 -0
- package/src/lib/env-file.ts +328 -0
- package/src/lib/env-local.ts +18 -1
- package/src/lib/errors.ts +32 -0
- package/src/lib/include-resolver.ts +108 -15
- package/src/lib/interactive.ts +165 -0
- package/src/lib/markdown-compiler.ts +118 -37
- package/src/lib/package-info.ts +25 -0
- package/src/lib/pid-service.ts +32 -21
- package/src/lib/refs/find.ts +589 -0
- package/src/lib/refs/index.ts +12 -0
- package/src/lib/refs/pick.ts +147 -0
- package/src/lib/refs/scopes.ts +61 -0
- package/src/lib/repos/catalog-display.ts +116 -0
- package/src/lib/repos/catalog-inputs.ts +160 -0
- package/src/lib/repos/catalog.ts +722 -0
- package/src/lib/repos/core-recipe.ts +105 -0
- package/src/lib/repos/defaults.ts +175 -0
- package/src/lib/repos/formats/common.ts +389 -0
- package/src/lib/repos/formats/index-file.ts +215 -0
- package/src/lib/repos/formats/links-map.ts +96 -0
- package/src/lib/repos/formats/lockfile.ts +167 -0
- package/src/lib/repos/formats/patterns.ts +57 -0
- package/src/lib/repos/formats/recipe-manifest.ts +395 -0
- package/src/lib/repos/formats/repo-manifest.ts +88 -0
- package/src/lib/repos/formats/store-entry.ts +84 -0
- package/src/lib/repos/freshness.ts +208 -0
- package/src/lib/repos/git-clone.ts +312 -0
- package/src/lib/repos/identity.ts +89 -0
- package/src/lib/repos/index.ts +58 -0
- package/src/lib/repos/links.ts +353 -0
- package/src/lib/repos/load-manifest.ts +236 -0
- package/src/lib/repos/lock-service.ts +453 -0
- package/src/lib/repos/locked-namespace-resolver.ts +90 -0
- package/src/lib/repos/locked-recipes.ts +254 -0
- package/src/lib/repos/managed-layer.ts +422 -0
- package/src/lib/repos/namespace-resolver.ts +370 -0
- package/src/lib/repos/providers/base.ts +206 -0
- package/src/lib/repos/providers/git.ts +233 -0
- package/src/lib/repos/providers/github.ts +294 -0
- package/src/lib/repos/providers/gitlab.ts +263 -0
- package/src/lib/repos/providers/http.ts +102 -0
- package/src/lib/repos/providers/index-cache.ts +382 -0
- package/src/lib/repos/providers/index.ts +106 -0
- package/src/lib/repos/providers/local.ts +391 -0
- package/src/lib/repos/providers/provider.ts +401 -0
- package/src/lib/repos/recipe-config-layers.ts +287 -0
- package/src/lib/repos/recipe-targets.ts +223 -0
- package/src/lib/repos/ref-search.ts +46 -0
- package/src/lib/repos/ref.ts +513 -0
- package/src/lib/repos/reference-report.ts +122 -0
- package/src/lib/repos/release/bump.ts +161 -0
- package/src/lib/repos/release/git-state.ts +305 -0
- package/src/lib/repos/release/index-builder.ts +635 -0
- package/src/lib/repos/release/index.ts +16 -0
- package/src/lib/repos/release/plan.ts +512 -0
- package/src/lib/repos/release/submit-service.ts +496 -0
- package/src/lib/repos/release/tags.ts +243 -0
- package/src/lib/repos/release/validate.ts +463 -0
- package/src/lib/repos/resolver.ts +789 -0
- package/src/lib/repos/scaffold/index.ts +238 -0
- package/src/lib/repos/scaffold/templates.ts +413 -0
- package/src/lib/repos/seed.ts +414 -0
- package/src/lib/repos/store/contract.ts +64 -0
- package/src/lib/repos/store/hash.ts +114 -0
- package/src/lib/repos/store/recipe-store.ts +599 -0
- package/src/lib/repos/store/settings.ts +58 -0
- package/src/lib/repos/subscription-service.ts +2678 -0
- package/src/lib/repos/trust.ts +447 -0
- package/src/lib/settings.ts +546 -189
- package/src/lib/sous-home.ts +104 -0
- package/src/lib/state.ts +52 -20
- package/src/lib/vars/ask.ts +1152 -0
- package/src/lib/vars/definition-source.ts +252 -0
- package/src/lib/vars/display.ts +233 -0
- package/src/lib/vars/index.ts +18 -0
- package/src/lib/vars/ladder.ts +282 -0
- package/src/lib/vars/mappings.ts +265 -0
- package/src/lib/vars/names.ts +94 -0
- package/src/lib/vars/preanswers.ts +395 -0
- package/src/lib/vars/question-plan.ts +218 -0
- package/src/lib/vars/report.ts +228 -0
- package/src/lib/vars/safe-regex.ts +235 -0
- package/src/lib/vars/validate.ts +312 -0
- package/src/lib/watch-loop.ts +148 -0
- package/src/templating/init-liquid-engine.ts +58 -16
- package/src/utils/choice-prompt.ts +143 -0
- package/src/utils/command-errors.ts +186 -0
- package/src/utils/command-help.ts +45 -0
- package/src/utils/confirm-prompt.ts +110 -0
- package/src/utils/flags.ts +153 -0
- package/src/utils/formatting.ts +540 -55
- package/src/utils/prompts.ts +35 -1
- package/src/utils/sous-directory.ts +245 -0
- package/src/utils/table.ts +603 -0
- package/src/utils/value-prompt.ts +119 -0
- package/bin/xcv +0 -5
- package/shared-prompts/_partials/resume-task.md +0 -51
- package/shared-prompts/_partials/sub-agent-delegation.md +0 -32
- package/shared-prompts/_partials/update-task-file.md +0 -52
- package/shared-prompts/memories/automated-browser-tasks/INDEX.tpl.md +0 -52
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/SKILL.tpl.md +0 -102
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/auth-failure-handling.mjs +0 -81
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/chained-workflow.mjs +0 -126
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/simple-fetch.mjs +0 -92
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/architecture.md +0 -61
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/auth-and-sessions.md +0 -65
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/ctx-api.md +0 -96
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/installation.md +0 -104
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/script-conventions.md +0 -243
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/chrome-state.mjs +0 -148
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/debug.mjs +0 -383
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/debug.spec.mjs +0 -267
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/eslint.config.mjs +0 -56
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/harness.mjs +0 -169
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/keyring.mjs +0 -59
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/logger.mjs +0 -25
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/params.mjs +0 -140
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/run.mjs +0 -140
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/settings.tpl.mjs +0 -1
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/utils.mjs +0 -185
- package/shared-prompts/skills/automated-browser-tasks/create-automated-browser-task/SKILL.tpl.md +0 -52
- package/shared-prompts/skills/automated-browser-tasks/running-automated-browser-tasks/SKILL.tpl.md +0 -59
- package/shared-prompts/skills/automated-browser-tasks/update-automated-browser-task/SKILL.tpl.md +0 -47
- package/shared-prompts/skills/control-flow/approve/SKILL.tpl.md +0 -26
- package/shared-prompts/skills/control-flow/opine/SKILL.tpl.md +0 -58
- package/shared-prompts/skills/control-flow/repeat/SKILL.tpl.md +0 -27
- package/shared-prompts/skills/control-flow/research/SKILL.tpl.md +0 -34
- package/shared-prompts/skills/sous-skills/about-sous/SKILL.tpl.md +0 -51
- package/shared-prompts/skills/task-files/about-task-files/SKILL.tpl.md +0 -122
- package/shared-prompts/skills/task-files/continue-task-in-new-branch/SKILL.tpl.md +0 -80
- package/shared-prompts/skills/task-files/go/SKILL.tpl.md +0 -14
- package/shared-prompts/skills/task-files/resume-task/SKILL.tpl.md +0 -13
- package/shared-prompts/skills/task-files/start-task/SKILL.tpl.md +0 -93
- package/shared-prompts/skills/task-files/update/SKILL.tpl.md +0 -14
- package/shared-prompts/skills/task-files/update-task-file/SKILL.tpl.md +0 -13
- /package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/substitutions.md +0 -0
- /package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-liquid-templates/references/liquid-filters.md +0 -0
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Param resolution and validation.
|
|
3
|
-
*
|
|
4
|
-
* Scripts declare their params in `meta.params`. The framework resolves and
|
|
5
|
-
* validates them BEFORE `execute()` runs, so a script never validates its own
|
|
6
|
-
* input.
|
|
7
|
-
*
|
|
8
|
-
* Resolution order (lowest to highest priority):
|
|
9
|
-
* ctx.settings < meta.params[x].default < explicit (CLI) params
|
|
10
|
-
*
|
|
11
|
-
* A param spec supports:
|
|
12
|
-
* required {boolean} - error if no value resolves
|
|
13
|
-
* default {*} - fallback value
|
|
14
|
-
* description {string} - shown in CLI listings and error messages
|
|
15
|
-
* validate {RegExp|Function}
|
|
16
|
-
* RegExp - the resolved value (coerced to string) must match
|
|
17
|
-
* Function - (value, resolvedParams) => true | false | string
|
|
18
|
-
* true = valid
|
|
19
|
-
* string = invalid; the string is used as the error message
|
|
20
|
-
* false = invalid; `invalidMessage` (or a default) is used
|
|
21
|
-
* invalidMessage {string} - error message for a failing RegExp, or for a
|
|
22
|
-
* validate function that returns `false`
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
export class ParamError extends Error {
|
|
26
|
-
constructor(message) {
|
|
27
|
-
super(message);
|
|
28
|
-
this.name = 'ParamError';
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Resolve and validate params for a script.
|
|
34
|
-
*
|
|
35
|
-
* @param {object} meta - The script's `meta` export (may have `.params`).
|
|
36
|
-
* @param {object} explicit - Params explicitly provided (e.g. from CLI).
|
|
37
|
-
* @param {object} settings - Compiled project settings (ctx.settings).
|
|
38
|
-
* @returns {object} The fully-resolved params object.
|
|
39
|
-
* @throws {ParamError} If a required param is missing or a value fails validation.
|
|
40
|
-
*/
|
|
41
|
-
export function resolveParams(meta, explicit = {}, settings = {}) {
|
|
42
|
-
const spec = meta?.params || {};
|
|
43
|
-
const scriptName = meta?.name || 'script';
|
|
44
|
-
const resolved = {};
|
|
45
|
-
const missing = [];
|
|
46
|
-
|
|
47
|
-
for (const [key, def] of Object.entries(spec)) {
|
|
48
|
-
let value;
|
|
49
|
-
if (key in explicit) value = explicit[key];
|
|
50
|
-
else if (def.default !== undefined) value = def.default;
|
|
51
|
-
else if (key in settings) value = settings[key];
|
|
52
|
-
|
|
53
|
-
if (value === undefined) {
|
|
54
|
-
if (def.required) missing.push(key);
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
resolved[key] = value;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Pass through any explicit params not declared in meta (escape hatch).
|
|
61
|
-
for (const [key, value] of Object.entries(explicit)) {
|
|
62
|
-
if (!(key in resolved)) resolved[key] = value;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (missing.length) {
|
|
66
|
-
throw new ParamError(
|
|
67
|
-
`Missing required param(s) for "${scriptName}":\n${missing
|
|
68
|
-
.map((k) => describeParam(k, spec[k]))
|
|
69
|
-
.join('\n')}`
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const invalid = validateParams(spec, resolved);
|
|
74
|
-
if (invalid.length) {
|
|
75
|
-
throw new ParamError(
|
|
76
|
-
`Invalid param(s) for "${scriptName}":\n${invalid
|
|
77
|
-
.map(({ key, message }) => ` - ${key}: ${message}`)
|
|
78
|
-
.join('\n')}`
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return resolved;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Run each declared param's `validate` rule against its resolved value.
|
|
87
|
-
*
|
|
88
|
-
* @param {object} spec - The `meta.params` spec object.
|
|
89
|
-
* @param {object} resolved - The resolved param values.
|
|
90
|
-
* @returns {Array<{key: string, message: string}>} One entry per failure.
|
|
91
|
-
*/
|
|
92
|
-
function validateParams(spec, resolved) {
|
|
93
|
-
const failures = [];
|
|
94
|
-
|
|
95
|
-
for (const [key, def] of Object.entries(spec)) {
|
|
96
|
-
if (!(key in resolved) || !def?.validate) continue;
|
|
97
|
-
const message = runValidator(def, resolved[key], resolved);
|
|
98
|
-
if (message) failures.push({ key, message });
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return failures;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Apply a single param's validator to a value.
|
|
106
|
-
*
|
|
107
|
-
* @param {object} def - The param spec (has `validate` and optional `invalidMessage`).
|
|
108
|
-
* @param {*} value - The resolved value to check.
|
|
109
|
-
* @param {object} resolved - All resolved params (passed to function validators).
|
|
110
|
-
* @returns {string|null} An error message if invalid, otherwise null.
|
|
111
|
-
*/
|
|
112
|
-
function runValidator(def, value, resolved) {
|
|
113
|
-
const { validate, invalidMessage } = def;
|
|
114
|
-
|
|
115
|
-
if (validate instanceof RegExp) {
|
|
116
|
-
return validate.test(String(value))
|
|
117
|
-
? null
|
|
118
|
-
: invalidMessage || `value "${value}" does not match ${validate}`;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (typeof validate === 'function') {
|
|
122
|
-
const result = validate(value, resolved);
|
|
123
|
-
if (result === true) return null;
|
|
124
|
-
if (typeof result === 'string') return result;
|
|
125
|
-
return invalidMessage || `value "${value}" is invalid`;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return null;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Format a param for inclusion in a "missing required" error message.
|
|
133
|
-
*
|
|
134
|
-
* @param {string} key - The param name.
|
|
135
|
-
* @param {object} [def] - The param spec (may carry a description).
|
|
136
|
-
* @returns {string} A single indented line.
|
|
137
|
-
*/
|
|
138
|
-
function describeParam(key, def) {
|
|
139
|
-
return def?.description ? ` - ${key}: ${def.description}` : ` - ${key}`;
|
|
140
|
-
}
|
package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/run.mjs
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Runner — executes an automation script by absolute path with given params.
|
|
5
|
-
*
|
|
6
|
-
* Usage:
|
|
7
|
-
* node run.mjs <absolute-path-to-script.mjs> [--param=value ...]
|
|
8
|
-
*
|
|
9
|
-
* Harness options are passed the same way and intercepted before params:
|
|
10
|
-
* --profileName=<name> Chrome profile to pull cookies from
|
|
11
|
-
* --timeout=<ms> Overall script timeout
|
|
12
|
-
* --headless=false (debug) run headed — rarely useful for this system
|
|
13
|
-
*
|
|
14
|
-
* Everything else (--foo=bar) becomes a script param. The harness resolves
|
|
15
|
-
* defaults + settings and validates required params before execute() runs.
|
|
16
|
-
*
|
|
17
|
-
* Project settings compiled by sous (settings.mjs, a sibling of this file) are
|
|
18
|
-
* loaded automatically and passed to the harness as ctx.settings.
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
import { resolve, dirname, join } from 'path';
|
|
22
|
-
import { existsSync, writeFileSync } from 'fs';
|
|
23
|
-
import { fileURLToPath, pathToFileURL } from 'url';
|
|
24
|
-
|
|
25
|
-
const HARNESS_OPTIONS = ['headless', 'profileName', 'timeout'];
|
|
26
|
-
|
|
27
|
-
const args = process.argv.slice(2);
|
|
28
|
-
if (args.length === 0 || args[0] === '--help') {
|
|
29
|
-
console.log('Usage: node run.mjs <absolute-path-to-script.mjs> [--param=value ...]');
|
|
30
|
-
process.exit(args.length === 0 ? 1 : 0);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const scriptPath = resolve(args[0]);
|
|
34
|
-
if (!existsSync(scriptPath)) {
|
|
35
|
-
console.error(`Script not found: ${scriptPath}`);
|
|
36
|
-
process.exit(1);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const { params, options } = parseArgs(args.slice(1));
|
|
40
|
-
const settings = await loadSettings();
|
|
41
|
-
const script = await import(pathToFileURL(scriptPath).href);
|
|
42
|
-
const meta = script.meta || {};
|
|
43
|
-
|
|
44
|
-
printRunHeader(meta, params, options, settings);
|
|
45
|
-
|
|
46
|
-
// Imported lazily so --help and arg validation don't require playwright et al.
|
|
47
|
-
const { runScript } = await import('./harness.mjs');
|
|
48
|
-
const result = await runScript(script, params, { ...options, settings });
|
|
49
|
-
|
|
50
|
-
reportResult(result);
|
|
51
|
-
process.exit(result.success ? 0 : 1);
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Split `--key=value` args into harness options and script params.
|
|
55
|
-
*
|
|
56
|
-
* @param {string[]} rest - CLI args after the script path.
|
|
57
|
-
* @returns {{params: object, options: object}}
|
|
58
|
-
*/
|
|
59
|
-
function parseArgs(rest) {
|
|
60
|
-
const params = {};
|
|
61
|
-
const options = {};
|
|
62
|
-
for (const arg of rest) {
|
|
63
|
-
const match = arg.match(/^--([\w-]+)=(.*)$/s);
|
|
64
|
-
if (!match) continue;
|
|
65
|
-
const [, key, value] = match;
|
|
66
|
-
if (!HARNESS_OPTIONS.includes(key)) {
|
|
67
|
-
params[key] = value;
|
|
68
|
-
} else if (key === 'headless') {
|
|
69
|
-
options.headless = value !== 'false';
|
|
70
|
-
} else if (key === 'timeout') {
|
|
71
|
-
options.timeout = parseInt(value, 10);
|
|
72
|
-
} else {
|
|
73
|
-
options[key] = value;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return { params, options };
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Load compiled project settings (settings.mjs) sitting beside this runner.
|
|
81
|
-
*
|
|
82
|
-
* @returns {Promise<object>} The settings object, or {} if none is present.
|
|
83
|
-
*/
|
|
84
|
-
async function loadSettings() {
|
|
85
|
-
const here = dirname(fileURLToPath(import.meta.url));
|
|
86
|
-
const settingsPath = join(here, 'settings.mjs');
|
|
87
|
-
if (!existsSync(settingsPath)) return {};
|
|
88
|
-
const mod = await import(pathToFileURL(settingsPath).href);
|
|
89
|
-
return mod.default || {};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Print the resolved params (with defaults/settings marked) before running.
|
|
94
|
-
*
|
|
95
|
-
* @param {object} meta - The script's meta export.
|
|
96
|
-
* @param {object} params - Explicit CLI params.
|
|
97
|
-
* @param {object} options - Harness options.
|
|
98
|
-
* @param {object} settings - Compiled project settings.
|
|
99
|
-
* @returns {void}
|
|
100
|
-
*/
|
|
101
|
-
function printRunHeader(meta, params, options, settings) {
|
|
102
|
-
console.log(`\n▶ Running: ${meta.name || '(unnamed script)'}`);
|
|
103
|
-
console.log(' Params:');
|
|
104
|
-
const spec = meta.params || {};
|
|
105
|
-
const keys = new Set([...Object.keys(spec), ...Object.keys(params)]);
|
|
106
|
-
for (const key of keys) {
|
|
107
|
-
let value, origin;
|
|
108
|
-
if (key in params) { value = params[key]; origin = ''; }
|
|
109
|
-
else if (spec[key]?.default !== undefined) { value = spec[key].default; origin = ' (default)'; }
|
|
110
|
-
else if (key in settings) { value = settings[key]; origin = ' (settings)'; }
|
|
111
|
-
else continue;
|
|
112
|
-
console.log(` ${key}: ${value}${origin}`);
|
|
113
|
-
}
|
|
114
|
-
if (Object.keys(options).length) console.log(` Options: ${JSON.stringify(options)}`);
|
|
115
|
-
console.log('');
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Print the run outcome and, on success, write any requested output file.
|
|
120
|
-
*
|
|
121
|
-
* @param {object} result - The harness result envelope.
|
|
122
|
-
* @returns {void}
|
|
123
|
-
*/
|
|
124
|
-
function reportResult(result) {
|
|
125
|
-
console.log('\n' + '─'.repeat(60));
|
|
126
|
-
if (result.success) {
|
|
127
|
-
console.log('✓ Script completed successfully\n');
|
|
128
|
-
if (result.data?.outputFile && result.data?.content) {
|
|
129
|
-
writeFileSync(result.data.outputFile, result.data.content);
|
|
130
|
-
console.log(`Output written to: ${result.data.outputFile}`);
|
|
131
|
-
} else {
|
|
132
|
-
console.log(JSON.stringify(result.data, null, 2));
|
|
133
|
-
}
|
|
134
|
-
} else {
|
|
135
|
-
console.log(`✗ Script failed (${result.error})\n`);
|
|
136
|
-
console.log(result.message);
|
|
137
|
-
if (result.stack && result.error === 'script') console.log(`\nStack:\n${result.stack}`);
|
|
138
|
-
if (result.debugDir) console.log(`\nDebug snapshot (screenshot, HTML, text): ${result.debugDir}`);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{% exportScalarVarsJs %}
|
|
@@ -1,185 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
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 }}
|
|
@@ -1,26 +0,0 @@
|
|
|
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 }}
|