bigpowers 2.87.7 → 2.88.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/.agents/skills/commit-message/SKILL.md +4 -2
- package/.agents/skills/kickoff-branch/SKILL.md +12 -7
- package/.agents/skills/release-branch/SKILL.md +12 -6
- package/.agents/skills/survey-context/SKILL.md +11 -6
- package/.cline/skills/commit-message/SKILL.md +4 -2
- package/.cline/skills/kickoff-branch/SKILL.md +12 -7
- package/.cline/skills/release-branch/SKILL.md +12 -6
- package/.cline/skills/survey-context/SKILL.md +11 -6
- package/.codebuddy/skills/commit-message/SKILL.md +4 -2
- package/.codebuddy/skills/kickoff-branch/SKILL.md +12 -7
- package/.codebuddy/skills/release-branch/SKILL.md +12 -6
- package/.codebuddy/skills/survey-context/SKILL.md +11 -6
- package/.codex/skills/commit-message/SKILL.md +4 -2
- package/.codex/skills/kickoff-branch/SKILL.md +12 -7
- package/.codex/skills/release-branch/SKILL.md +12 -6
- package/.codex/skills/survey-context/SKILL.md +11 -6
- package/.copilot/skills/commit-message/SKILL.md +4 -2
- package/.copilot/skills/kickoff-branch/SKILL.md +12 -7
- package/.copilot/skills/release-branch/SKILL.md +12 -6
- package/.copilot/skills/survey-context/SKILL.md +11 -6
- package/.cursor/rules/commit-message.mdc +4 -2
- package/.cursor/rules/kickoff-branch.mdc +12 -7
- package/.cursor/rules/release-branch.mdc +12 -6
- package/.cursor/rules/survey-context.mdc +11 -6
- package/.gemini/extensions/bigpowers/commands/prompts/commit-message.md +4 -2
- package/.gemini/extensions/bigpowers/commands/prompts/kickoff-branch.md +12 -7
- package/.gemini/extensions/bigpowers/commands/prompts/release-branch.md +12 -6
- package/.gemini/extensions/bigpowers/commands/prompts/survey-context.md +11 -6
- package/.gemini/extensions/bigpowers/gemini-extension.json +1 -1
- package/.gemini/extensions/bigpowers/skills/commit-message/SKILL.md +4 -2
- package/.gemini/extensions/bigpowers/skills/kickoff-branch/SKILL.md +12 -7
- package/.gemini/extensions/bigpowers/skills/release-branch/SKILL.md +12 -6
- package/.gemini/extensions/bigpowers/skills/survey-context/SKILL.md +11 -6
- package/.hermes/skills/commit-message/SKILL.md +4 -2
- package/.hermes/skills/kickoff-branch/SKILL.md +12 -7
- package/.hermes/skills/release-branch/SKILL.md +12 -6
- package/.hermes/skills/survey-context/SKILL.md +11 -6
- package/.kilocode/rules/commit-message.md +4 -2
- package/.kilocode/rules/kickoff-branch.md +12 -7
- package/.kilocode/rules/release-branch.md +12 -6
- package/.kilocode/rules/survey-context.md +11 -6
- package/.mimocode/skills/commit-message/SKILL.md +4 -2
- package/.mimocode/skills/kickoff-branch/SKILL.md +12 -7
- package/.mimocode/skills/release-branch/SKILL.md +12 -6
- package/.mimocode/skills/survey-context/SKILL.md +11 -6
- package/.opencode/skills/commit-message/SKILL.md +4 -2
- package/.opencode/skills/kickoff-branch/SKILL.md +12 -7
- package/.opencode/skills/release-branch/SKILL.md +12 -6
- package/.opencode/skills/survey-context/SKILL.md +11 -6
- package/.pi/package.json +1 -1
- package/.pi/prompts/commit-message.md +4 -2
- package/.pi/prompts/kickoff-branch.md +12 -7
- package/.pi/prompts/release-branch.md +12 -6
- package/.pi/prompts/survey-context.md +11 -6
- package/.pi/skills/commit-message/SKILL.md +4 -2
- package/.pi/skills/kickoff-branch/SKILL.md +12 -7
- package/.pi/skills/release-branch/SKILL.md +12 -6
- package/.pi/skills/survey-context/SKILL.md +11 -6
- package/.qwen/skills/commit-message/SKILL.md +4 -2
- package/.qwen/skills/kickoff-branch/SKILL.md +12 -7
- package/.qwen/skills/release-branch/SKILL.md +12 -6
- package/.qwen/skills/survey-context/SKILL.md +11 -6
- package/.trae/skills/commit-message/SKILL.md +4 -2
- package/.trae/skills/kickoff-branch/SKILL.md +12 -7
- package/.trae/skills/release-branch/SKILL.md +12 -6
- package/.trae/skills/survey-context/SKILL.md +11 -6
- package/.windsurf/rules/commit-message.md +4 -2
- package/.windsurf/rules/kickoff-branch.md +12 -7
- package/.windsurf/rules/release-branch.md +12 -6
- package/.windsurf/rules/survey-context.md +11 -6
- package/.zcode/skills/commit-message/SKILL.md +4 -2
- package/.zcode/skills/kickoff-branch/SKILL.md +12 -7
- package/.zcode/skills/release-branch/SKILL.md +12 -6
- package/.zcode/skills/survey-context/SKILL.md +11 -6
- package/CHANGELOG.md +14 -0
- package/CONTRIBUTORS.md +48 -0
- package/README.md +27 -0
- package/SKILL-INDEX.md +1 -1
- package/bin/bigpowers.js +8 -0
- package/bin/init.js +39 -0
- package/extensions/omp-hooks.ts +406 -0
- package/hooks/pre/bash.sh +47 -0
- package/package.json +6 -1
- package/scripts/lib/__pycache__/link_utils.cpython-312.pyc +0 -0
- package/scripts/lib/__pycache__/srp_engine_links.cpython-312.pyc +0 -0
- package/scripts/lib/golden-suite-gates.sh +2 -0
- package/scripts/lib/install-helpers.js +53 -1
- package/scripts/lib/project-runtime.sh +110 -0
- package/scripts/omp-smoke.ts +82 -0
- package/scripts/test-install-helpers.js +88 -0
- package/scripts/test-project-runtime.sh +91 -0
- package/scripts/validate-omp-extension.sh +103 -0
- package/skills/commit-message/SKILL.md +4 -2
- package/skills/kickoff-branch/SKILL.md +12 -7
- package/skills/release-branch/SKILL.md +12 -6
- package/skills/survey-context/SKILL.md +11 -6
- package/skills-lock.json +5 -5
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// story: e82s03
|
|
2
|
+
// Runtime smoke for extensions/omp-hooks.ts.
|
|
3
|
+
// Imports the extension, registers a fake ExtensionAPI, calls registered hooks,
|
|
4
|
+
// and asserts the slash-command handler awaits injection.
|
|
5
|
+
|
|
6
|
+
import bigpowers from "../extensions/omp-hooks.ts";
|
|
7
|
+
|
|
8
|
+
type AnyObj = Record<string, unknown>;
|
|
9
|
+
type Listener = (...args: unknown[]) => unknown;
|
|
10
|
+
|
|
11
|
+
function makeZod(): AnyObj {
|
|
12
|
+
const chainable: AnyObj = {};
|
|
13
|
+
chainable.optional = () => chainable;
|
|
14
|
+
chainable.describe = () => chainable;
|
|
15
|
+
return chainable;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const commands = new Map<string, { description: string; handler: Listener }>();
|
|
19
|
+
const tools: AnyObj[] = [];
|
|
20
|
+
const events = new Map<string, Listener>();
|
|
21
|
+
const sendCalls: AnyObj[] = [];
|
|
22
|
+
|
|
23
|
+
const pi: AnyObj = {
|
|
24
|
+
setLabel: () => {},
|
|
25
|
+
zod: {
|
|
26
|
+
object: (_shape: AnyObj) => makeZod(),
|
|
27
|
+
string: () => makeZod(),
|
|
28
|
+
enum: () => makeZod(),
|
|
29
|
+
},
|
|
30
|
+
registerCommand: (name: string, spec: { description: string; handler: Listener }) => {
|
|
31
|
+
commands.set(name, spec);
|
|
32
|
+
},
|
|
33
|
+
registerTool: (tool: AnyObj) => {
|
|
34
|
+
tools.push(tool);
|
|
35
|
+
},
|
|
36
|
+
on: (event: string, handler: Listener) => {
|
|
37
|
+
events.set(event, handler);
|
|
38
|
+
},
|
|
39
|
+
sendUserMessage: async (content: string, opts?: { deliverAs?: string }) => {
|
|
40
|
+
sendCalls.push({ kind: "sendUserMessage", content, opts });
|
|
41
|
+
return undefined;
|
|
42
|
+
},
|
|
43
|
+
sendMessage: async (msg: AnyObj, opts?: { triggerTurn?: boolean; deliverAs?: string }) => {
|
|
44
|
+
sendCalls.push({ kind: "sendMessage", msg, opts });
|
|
45
|
+
return undefined;
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
await bigpowers(pi as unknown as never);
|
|
50
|
+
|
|
51
|
+
console.log(JSON.stringify({
|
|
52
|
+
commands: commands.size,
|
|
53
|
+
tool: tools[0]?.name,
|
|
54
|
+
events: [...events.keys()],
|
|
55
|
+
firstCommand: [...commands.keys()].slice(0, 5),
|
|
56
|
+
sendUserMessageAwaitable: typeof pi.sendUserMessage === "function",
|
|
57
|
+
}));
|
|
58
|
+
|
|
59
|
+
// Exercise the /survey-context handler end-to-end.
|
|
60
|
+
const handler = commands.get("survey-context")?.handler;
|
|
61
|
+
if (!handler) throw new Error("survey-context command not registered");
|
|
62
|
+
await handler("", {});
|
|
63
|
+
|
|
64
|
+
// Verify a nonexistent command is not present.
|
|
65
|
+
const fallback = commands.get("nonexistent-skill-for-test")?.handler;
|
|
66
|
+
if (fallback) throw new Error("unexpected command registered");
|
|
67
|
+
|
|
68
|
+
// Test bigpowers_skill run path.
|
|
69
|
+
const skillTool = tools[0];
|
|
70
|
+
if (!skillTool?.execute) throw new Error("bigpowers_skill tool missing execute");
|
|
71
|
+
const runResult = await skillTool.execute(
|
|
72
|
+
"call-1",
|
|
73
|
+
{ action: "run", skill: "verify-work", args: "ping" },
|
|
74
|
+
new AbortController().signal,
|
|
75
|
+
() => {},
|
|
76
|
+
{},
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
console.log(JSON.stringify({
|
|
80
|
+
sendCalls,
|
|
81
|
+
runDetails: runResult.details,
|
|
82
|
+
}));
|
|
@@ -269,6 +269,94 @@ try {
|
|
|
269
269
|
}
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
+
// story: BUG-2026-08-31-pi-scripts-provisioning (#116)
|
|
273
|
+
// A package consumer project needs bigpowers' scripts/ + specs/ scaffolding
|
|
274
|
+
// so SKILL.md bodies ("bash scripts/run-skill-verify.sh") and verify gates
|
|
275
|
+
// ("test -f scripts/... && test -d specs/bugs") resolve outside a checkout.
|
|
276
|
+
{
|
|
277
|
+
const { initProject, initProjectRemove } = require('../scripts/lib/install-helpers.js');
|
|
278
|
+
const savedInitCwd = process.cwd();
|
|
279
|
+
const consumerDir = mkdtempSync(path.join(os.tmpdir(), 'bp-init-project-'));
|
|
280
|
+
try {
|
|
281
|
+
process.chdir(consumerDir);
|
|
282
|
+
|
|
283
|
+
// (a) init provisions scripts/ + specs/ scaffolding
|
|
284
|
+
initProject(ROOT);
|
|
285
|
+
assert.ok(
|
|
286
|
+
fs.lstatSync(path.join(consumerDir, 'scripts')).isSymbolicLink(),
|
|
287
|
+
'init must symlink scripts/ into the consumer project'
|
|
288
|
+
);
|
|
289
|
+
assert.strictEqual(
|
|
290
|
+
fs.readlinkSync(path.join(consumerDir, 'scripts')),
|
|
291
|
+
path.join(ROOT, 'scripts'),
|
|
292
|
+
'scripts symlink must point at the package scripts tree'
|
|
293
|
+
);
|
|
294
|
+
assert.ok(
|
|
295
|
+
fs.existsSync(path.join(consumerDir, 'scripts', 'run-skill-verify.sh')),
|
|
296
|
+
'scripts/run-skill-verify.sh must resolve through the link (skill verify gate)'
|
|
297
|
+
);
|
|
298
|
+
assert.ok(
|
|
299
|
+
fs.existsSync(path.join(consumerDir, 'specs', 'bugs')),
|
|
300
|
+
'init must scaffold specs/bugs (fix-bug verify gate probes it)'
|
|
301
|
+
);
|
|
302
|
+
assert.ok(
|
|
303
|
+
fs.existsSync(path.join(consumerDir, 'specs', 'verifications')),
|
|
304
|
+
'init must scaffold specs/verifications'
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
// (b) init --remove cleans managed artifacts only
|
|
308
|
+
initProjectRemove(ROOT);
|
|
309
|
+
assert.ok(
|
|
310
|
+
!fs.existsSync(path.join(consumerDir, 'scripts')),
|
|
311
|
+
'init --remove must remove the managed scripts symlink'
|
|
312
|
+
);
|
|
313
|
+
assert.ok(
|
|
314
|
+
!fs.existsSync(path.join(consumerDir, 'specs')),
|
|
315
|
+
'init --remove must remove the untouched scaffolded specs tree'
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
// (c) refuses a pre-existing non-managed scripts/ (never clobbers)
|
|
319
|
+
fs.mkdirSync(path.join(consumerDir, 'scripts'));
|
|
320
|
+
fs.writeFileSync(path.join(consumerDir, 'scripts', 'mine.sh'), 'echo mine\n');
|
|
321
|
+
assert.throws(
|
|
322
|
+
() => initProject(ROOT),
|
|
323
|
+
/Refusing to replace/,
|
|
324
|
+
'init must refuse a user-owned scripts/ dir'
|
|
325
|
+
);
|
|
326
|
+
assert.ok(
|
|
327
|
+
fs.existsSync(path.join(consumerDir, 'scripts', 'mine.sh')),
|
|
328
|
+
'user-owned scripts/ content must survive the refusal'
|
|
329
|
+
);
|
|
330
|
+
} finally {
|
|
331
|
+
process.chdir(savedInitCwd);
|
|
332
|
+
rmSync(consumerDir, { recursive: true, force: true });
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// (d) CLI dispatch drift guard: `bigpowers init` must stay wired
|
|
336
|
+
const bigpowersSrc = fs.readFileSync(path.join(ROOT, 'bin', 'bigpowers.js'), 'utf8');
|
|
337
|
+
assert.ok(
|
|
338
|
+
/'init'/.test(bigpowersSrc),
|
|
339
|
+
"bin/bigpowers.js must dispatch the 'init' command"
|
|
340
|
+
);
|
|
341
|
+
assert.ok(
|
|
342
|
+
fs.existsSync(path.join(ROOT, 'bin', 'init.js')),
|
|
343
|
+
'bin/init.js must exist'
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// story: BUG-2026-08-31-pi-scripts-provisioning (follow-up from PR #114 review)
|
|
348
|
+
// The managed-symlink check must not treat a string-prefix sibling of the
|
|
349
|
+
// package root (e.g. <ROOT>-evil) as managed — needs a path-separator boundary.
|
|
350
|
+
{
|
|
351
|
+
const dst = path.join(tmpHome, 'prefix-boundary-hook.sh');
|
|
352
|
+
fs.symlinkSync(path.join(`${ROOT}-evil`, 'x.sh'), dst); // dangling foreign link
|
|
353
|
+
assert.throws(
|
|
354
|
+
() => linkHook(rtkSrc, dst),
|
|
355
|
+
/Refusing to replace/,
|
|
356
|
+
'managed-symlink check must require a path-separator boundary (prefix sibling is NOT managed)'
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
|
|
272
360
|
console.log('test-install-helpers: ALL PASS');
|
|
273
361
|
} finally {
|
|
274
362
|
rmSync(tmpHome, { recursive: true, force: true });
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# story: e82s01
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
6
|
+
# shellcheck disable=SC1091
|
|
7
|
+
source "$ROOT/scripts/lib/project-runtime.sh"
|
|
8
|
+
|
|
9
|
+
PASS=0
|
|
10
|
+
FAIL=0
|
|
11
|
+
TMPDIR_ROOT="$(mktemp -d)"
|
|
12
|
+
trap 'rm -rf "$TMPDIR_ROOT"' EXIT
|
|
13
|
+
|
|
14
|
+
pass() {
|
|
15
|
+
echo " PASS $1"
|
|
16
|
+
PASS=$((PASS + 1))
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
fail() {
|
|
20
|
+
echo " FAIL $1" >&2
|
|
21
|
+
FAIL=$((FAIL + 1))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
assert_eq() {
|
|
25
|
+
local name="$1" expected="$2" actual="$3"
|
|
26
|
+
if [[ "$actual" == "$expected" ]]; then
|
|
27
|
+
pass "$name"
|
|
28
|
+
else
|
|
29
|
+
fail "$name — expected '$expected', got '$actual'"
|
|
30
|
+
fi
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
assert_fails_with() {
|
|
34
|
+
local name="$1" expected="$2"
|
|
35
|
+
shift 2
|
|
36
|
+
local output
|
|
37
|
+
if output="$("$@" 2>&1)"; then
|
|
38
|
+
fail "$name — command unexpectedly succeeded"
|
|
39
|
+
elif [[ "$output" == *"$expected"* ]]; then
|
|
40
|
+
pass "$name"
|
|
41
|
+
else
|
|
42
|
+
fail "$name — expected error containing '$expected', got '$output'"
|
|
43
|
+
fi
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
make_project() {
|
|
47
|
+
local name="$1"
|
|
48
|
+
local project="$TMPDIR_ROOT/$name"
|
|
49
|
+
mkdir -p "$project/.bigpowers"
|
|
50
|
+
printf '%s\n' "$project"
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
DEFAULT_PROJECT="$(make_project default)"
|
|
54
|
+
assert_eq "default specs directory" "specs" "$(bp_specs_dir "$DEFAULT_PROJECT")"
|
|
55
|
+
assert_eq "default specs path" "$DEFAULT_PROJECT/specs/state.yaml" \
|
|
56
|
+
"$(bp_specs_path "$DEFAULT_PROJECT" state.yaml)"
|
|
57
|
+
assert_eq "repository without VCS" "none" "$(bp_vcs_kind "$DEFAULT_PROJECT")"
|
|
58
|
+
|
|
59
|
+
CONFIG_PROJECT="$(make_project configured)"
|
|
60
|
+
cat > "$CONFIG_PROJECT/.bigpowers/config.yaml" <<'YAML'
|
|
61
|
+
specs_dir: .specs
|
|
62
|
+
vcs: git
|
|
63
|
+
YAML
|
|
64
|
+
assert_eq "configured specs directory" ".specs" "$(bp_specs_dir "$CONFIG_PROJECT")"
|
|
65
|
+
assert_eq "configured specs path" "$CONFIG_PROJECT/.specs/release-plan.yaml" \
|
|
66
|
+
"$(bp_specs_path "$CONFIG_PROJECT" release-plan.yaml)"
|
|
67
|
+
assert_eq "configured VCS" "git" "$(bp_vcs_kind "$CONFIG_PROJECT")"
|
|
68
|
+
|
|
69
|
+
assert_eq "environment specs override" "private-specs" \
|
|
70
|
+
"$(BIGPOWERS_SPECS_DIR=private-specs bp_specs_dir "$CONFIG_PROJECT")"
|
|
71
|
+
assert_eq "environment VCS override" "jj" \
|
|
72
|
+
"$(BIGPOWERS_VCS=jj bp_vcs_kind "$CONFIG_PROJECT")"
|
|
73
|
+
|
|
74
|
+
COLOCATED_PROJECT="$(make_project colocated)"
|
|
75
|
+
mkdir -p "$COLOCATED_PROJECT/.git" "$COLOCATED_PROJECT/.jj"
|
|
76
|
+
assert_eq "auto prefers Jujutsu in colocated repository" "jj" \
|
|
77
|
+
"$(bp_vcs_kind "$COLOCATED_PROJECT")"
|
|
78
|
+
|
|
79
|
+
INVALID_PROJECT="$(make_project invalid)"
|
|
80
|
+
printf '%s\n' 'vcs: svn' > "$INVALID_PROJECT/.bigpowers/config.yaml"
|
|
81
|
+
assert_fails_with "invalid VCS is actionable" \
|
|
82
|
+
"Expected one of: auto, git, jj" bp_vcs_kind "$INVALID_PROJECT"
|
|
83
|
+
|
|
84
|
+
EMPTY_PROJECT="$(make_project empty)"
|
|
85
|
+
printf '%s\n' 'specs_dir: ""' > "$EMPTY_PROJECT/.bigpowers/config.yaml"
|
|
86
|
+
assert_fails_with "empty specs directory is rejected" \
|
|
87
|
+
"specs_dir must not be empty" bp_specs_dir "$EMPTY_PROJECT"
|
|
88
|
+
|
|
89
|
+
echo "---"
|
|
90
|
+
echo "test-project-runtime: $PASS passed, $FAIL failed"
|
|
91
|
+
[[ "$FAIL" -eq 0 ]]
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# story: e82s03
|
|
3
|
+
# OMP extension integrity guard — validates the extension entry is wired
|
|
4
|
+
# correctly and all source skills are discoverable via skills/<name>/SKILL.md.
|
|
5
|
+
# Run before merging any branch that touches extensions/.
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
9
|
+
cd "$REPO_ROOT"
|
|
10
|
+
|
|
11
|
+
ERRORS=0
|
|
12
|
+
|
|
13
|
+
fail() {
|
|
14
|
+
echo "FAIL: $*"
|
|
15
|
+
ERRORS=$((ERRORS + 1))
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
pass() {
|
|
19
|
+
echo "ok : $*"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# ── 1. Package has exactly one omp.extensions entry ────────────────────────
|
|
23
|
+
echo "--- [OMP] manifest: single extension entry ---"
|
|
24
|
+
EXT_COUNT=$(node -e "const p = require('./package.json'); const exts = p.omp?.extensions; if (!exts) { console.log(0); } else { console.log(exts.length); }")
|
|
25
|
+
if [[ "$EXT_COUNT" -eq 1 ]]; then
|
|
26
|
+
pass "omp.extensions has exactly 1 entry"
|
|
27
|
+
else
|
|
28
|
+
fail "omp.extensions has $EXT_COUNT entries (expected 1)"
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# ── 2. Extension file exists ───────────────────────────────────────────────
|
|
32
|
+
echo "--- [OMP] extension file exists ---"
|
|
33
|
+
EXT_PATH=$(node -e "const p = require('./package.json'); console.log(p.omp?.extensions?.[0] || '')")
|
|
34
|
+
if [[ -z "$EXT_PATH" ]]; then
|
|
35
|
+
fail "No omp.extensions entry found"
|
|
36
|
+
else
|
|
37
|
+
if [[ -f "$EXT_PATH" ]]; then
|
|
38
|
+
pass "extension file '$EXT_PATH' exists"
|
|
39
|
+
else
|
|
40
|
+
fail "extension file '$EXT_PATH' does not exist"
|
|
41
|
+
fi
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# ── 3. Extension source contains required symbols ──────────────────────────
|
|
45
|
+
echo "--- [OMP] required runtime symbols in extension ---"
|
|
46
|
+
if [[ -n "$EXT_PATH" && -f "$EXT_PATH" ]]; then
|
|
47
|
+
for sym in "registerCommand" "registerTool" "tool_call"; do
|
|
48
|
+
if grep -q "$sym" "$EXT_PATH" 2>/dev/null; then
|
|
49
|
+
pass "symbol '$sym' found in extension source"
|
|
50
|
+
else
|
|
51
|
+
fail "symbol '$sym' NOT found in extension source"
|
|
52
|
+
fi
|
|
53
|
+
done
|
|
54
|
+
else
|
|
55
|
+
fail "Cannot scan extension symbols — file not resolved"
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
# ── 4. Skill discovery root is skills/ ────────────────────────────────────
|
|
59
|
+
echo "--- [OMP] source skill discoverability (skills/<name>/SKILL.md) ---"
|
|
60
|
+
SKILLS_ROOT="$REPO_ROOT/skills"
|
|
61
|
+
if [[ ! -d "$SKILLS_ROOT" ]]; then
|
|
62
|
+
fail "skills/ directory not found at $SKILLS_ROOT"
|
|
63
|
+
else
|
|
64
|
+
TOTAL=0
|
|
65
|
+
MISSING=0
|
|
66
|
+
while IFS= read -r skill_md; do
|
|
67
|
+
rel="${skill_md#"$SKILLS_ROOT"/}"
|
|
68
|
+
# Each should be exactly <name>/SKILL.md (one level of nesting).
|
|
69
|
+
if [[ "$rel" != */SKILL.md || "${rel%%/*}" == "" ]]; then
|
|
70
|
+
fail "unexpected SKILL.md path: $rel"
|
|
71
|
+
MISSING=$((MISSING + 1))
|
|
72
|
+
continue
|
|
73
|
+
fi
|
|
74
|
+
TOTAL=$((TOTAL + 1))
|
|
75
|
+
done < <(find "$SKILLS_ROOT" -maxdepth 2 -name SKILL.md 2>/dev/null | sort)
|
|
76
|
+
|
|
77
|
+
if [[ "$TOTAL" -eq 0 ]]; then
|
|
78
|
+
fail "no skills found under skills/"
|
|
79
|
+
elif [[ "$MISSING" -eq 0 ]]; then
|
|
80
|
+
pass "$TOTAL source skills all at skills/<name>/SKILL.md"
|
|
81
|
+
else
|
|
82
|
+
fail "$MISSING/$TOTAL skills at unexpected paths"
|
|
83
|
+
fi
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# ── 5. Extension scans skills/ not the repo root ──────────────────────────
|
|
87
|
+
echo "--- [OMP] extension targets skills/ root ---"
|
|
88
|
+
if [[ -n "$EXT_PATH" && -f "$EXT_PATH" ]]; then
|
|
89
|
+
if grep -q 'join(pluginRoot(), "skills")' "$EXT_PATH" 2>/dev/null; then
|
|
90
|
+
pass "extension calls discoverSkills with skills/ subdirectory"
|
|
91
|
+
else
|
|
92
|
+
fail "extension does not target skills/ — check discoverSkills call in $EXT_PATH"
|
|
93
|
+
fi
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# ── Summary ────────────────────────────────────────────────────────────────
|
|
97
|
+
echo "---"
|
|
98
|
+
if [[ "$ERRORS" -eq 0 ]]; then
|
|
99
|
+
echo "OMP extension validation passed"
|
|
100
|
+
else
|
|
101
|
+
echo "OMP extension validation FAILED ($ERRORS error(s))"
|
|
102
|
+
exit 1
|
|
103
|
+
fi
|
|
@@ -5,6 +5,8 @@ effort: standard
|
|
|
5
5
|
description: Reviews working-tree changes, then drafts a Conventional Commits title/body and states the semantic-release version bump a single such commit would imply. Also notes which defensive-code categories were touched. Use when the user wants to commit recent work, prepare a Conventional Commits message, or asks for semantic-release / semver-consistent messaging before git commit.
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
+
# story: e82s02
|
|
9
|
+
|
|
8
10
|
# Commit Message
|
|
9
11
|
> **HARD GATE** — **HARD GATE** — Commits must follow Conventional Commits spec (type(scope): description). Do NOT use vague messages like 'fix' or 'updates.' The message must explain the 'why,' not the 'what.'
|
|
10
12
|
|
|
@@ -16,7 +18,7 @@ description: Reviews working-tree changes, then drafts a Conventional Commits ti
|
|
|
16
18
|
|
|
17
19
|
## What "last chat" means
|
|
18
20
|
|
|
19
|
-
- **Primary source of truth:** `git status`, `git diff
|
|
21
|
+
- **Primary source of truth:** Read `state.yaml` `vcs.kind`. Git uses `git status`, `git diff`, and `git diff --cached`; Jujutsu uses `jj status`, `jj diff`, and `jj log -r @`. Run in the repo root.
|
|
20
22
|
- **Context:** use the current conversation to summarize *intent* and to spot **breaking** API/behavior changes that diff alone may not show.
|
|
21
23
|
- If the user tracks a session baseline (e.g. branch, tag, or `git stash create` at start), you may `git diff <baseline>..HEAD` plus uncommitted diffs; otherwise use only the index and working tree.
|
|
22
24
|
|
|
@@ -31,7 +33,7 @@ description: Reviews working-tree changes, then drafts a Conventional Commits ti
|
|
|
31
33
|
7. **Deliver** — Output:
|
|
32
34
|
- Proposed **full commit message** (title + optional body + footers).
|
|
33
35
|
- **Release bump** this commit would drive: `patch` | `minor` | `major` | `none`.
|
|
34
|
-
- Optional `git
|
|
36
|
+
- Optional native command: Git `git commit -m`; Jujutsu `jj commit -m`. Never omit `-m` or run destructive commands unless asked.
|
|
35
37
|
|
|
36
38
|
## Checklist before finalizing
|
|
37
39
|
|
|
@@ -2,20 +2,21 @@
|
|
|
2
2
|
name: kickoff-branch
|
|
3
3
|
model: haiku
|
|
4
4
|
effort: standard
|
|
5
|
-
description: Create
|
|
5
|
+
description: Create an isolated Git worktree/branch or Jujutsu workspace, then verify a clean test baseline before code. Use when starting a feature or task.
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# story: e51s03
|
|
9
9
|
# story: e20s03
|
|
10
|
+
# story: e82s02
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
# Kickoff Branch
|
|
13
14
|
|
|
14
|
-
> **HARD GATE** — Direct work on `main` or
|
|
15
|
+
> **HARD GATE** — Direct Git work on `main`/`master` or reuse of an unrelated Jujutsu change is prohibited. Create a feature branch/worktree or Jujutsu workspace/change.
|
|
15
16
|
>
|
|
16
17
|
> **HARD GATE** — Do NOT proceed with development until **Preflight** passes on the default branch. Red Preflight blocks branch creation and all forward work — invoke `quick-fix` or `fix-bug` per CONVENTIONS § Discovered Defects.
|
|
17
18
|
|
|
18
|
-
Create an isolated
|
|
19
|
+
Create an isolated Git worktree or Jujutsu workspace before code. **Preflight must be green** first — solo-default owns the whole tree.
|
|
19
20
|
|
|
20
21
|
## Process
|
|
21
22
|
|
|
@@ -23,9 +24,13 @@ Create an isolated working environment before touching any code. **Preflight mus
|
|
|
23
24
|
|
|
24
25
|
Ask if not already known: "What's the name of this feature or task?" Use it as the branch name slug (kebab-case, max 40 chars).
|
|
25
26
|
|
|
26
|
-
### 2.
|
|
27
|
+
### 2. Select the VCS procedure
|
|
27
28
|
|
|
28
|
-
>
|
|
29
|
+
Read `state.yaml` `vcs.kind`. For `jj`, do not run the Git blocks below: verify with `jj status` and `jj log -r '::@' -n 5`, create isolation with `jj workspace add ../<task-slug> -r @`, then run `jj -R ../<task-slug> describe -m "feat: <task>"`. Record the new stable change ID. For `git`, continue below.
|
|
30
|
+
|
|
31
|
+
### 2a. Anchor Git on the default branch (main or master)
|
|
32
|
+
|
|
33
|
+
> **HARD GATE** — Git kickoff MUST start from an updated, clean default branch in the **primary** repository root (not a linked worktree).
|
|
29
34
|
|
|
30
35
|
```bash
|
|
31
36
|
# Detect default branch
|
|
@@ -64,7 +69,7 @@ fi
|
|
|
64
69
|
- **Non-spec dirty files** (src/, scripts/, SKILL.md, …) still enforce the full clean-tree gate.
|
|
65
70
|
- If not on `$DEFAULT` after checkout, stop and fix before continuing.
|
|
66
71
|
|
|
67
|
-
### 3.
|
|
72
|
+
### 3. Git pre-flight & conflict resolution
|
|
68
73
|
|
|
69
74
|
Before creating the worktree, verify the target environment is clean:
|
|
70
75
|
|
|
@@ -84,7 +89,7 @@ git worktree list | grep "<task-slug>"
|
|
|
84
89
|
- **Branch exists:** If the branch exists but no worktree is attached, ask to use the existing branch (`git worktree add ../<task-slug> <task-slug>`) or delete it.
|
|
85
90
|
- **Ghost worktree:** If `git worktree list` shows the path but the directory is missing, run `git worktree prune` to clear the stale metadata. `bash scripts/cleanup-worktrees.sh` does this plus reports any worktree whose branch is already merged or deleted — advisory only, it prints the `git worktree remove`/`git branch -d` commands rather than running them, so review before acting.
|
|
86
91
|
|
|
87
|
-
### 4. Create worktree + branch
|
|
92
|
+
### 4. Create Git worktree + branch
|
|
88
93
|
|
|
89
94
|
```bash
|
|
90
95
|
# From the main repo root (not another worktree)
|
|
@@ -10,6 +10,7 @@ description: Make the merge/PR/keep/discard decision for a feature branch, verif
|
|
|
10
10
|
<!-- story: e45s15 -->
|
|
11
11
|
<!-- story: e45s32 -->
|
|
12
12
|
<!-- story: e45s39 -->
|
|
13
|
+
<!-- story: e82s02 -->
|
|
13
14
|
<!-- story: e20s02 -->
|
|
14
15
|
|
|
15
16
|
|
|
@@ -32,7 +33,7 @@ Read `specs/state.yaml` key `workflow_mode` (`team-pr` | `solo-git`). Fall back
|
|
|
32
33
|
| **solo-local** | `workflow_mode: solo-git` | Auto: `scripts/land-branch.sh` if present, else fallback (Step 5) |
|
|
33
34
|
| **team-pr** | `workflow_mode: team-pr` (default) | `gh pr create` → `gh pr merge --squash` |
|
|
34
35
|
|
|
35
|
-
If unsure, prefer **solo-local**.
|
|
36
|
+
If unsure, prefer **solo-local**. Also read `state.yaml` `vcs.kind`: Git follows the procedures below; Jujutsu uses workspaces/bookmarks and must not call Git-only landing scripts.
|
|
36
37
|
|
|
37
38
|
## Process
|
|
38
39
|
|
|
@@ -75,16 +76,21 @@ Run `gate-trace` before merge. FAIL blocks merge; CONCERNS requires explicit ove
|
|
|
75
76
|
|
|
76
77
|
Options: **Release (solo-local)** / **Open PR** / **Keep branch** / **Discard**
|
|
77
78
|
|
|
78
|
-
### 5.
|
|
79
|
+
### 5. Integrate
|
|
79
80
|
|
|
80
|
-
Run `commit-message`
|
|
81
|
+
Run `commit-message` first. Git solo-local uses `land-branch.sh`. Jujutsu team mode explicitly advances and pushes a bookmark; `-m` is mandatory for commit/describe operations:
|
|
81
82
|
|
|
82
83
|
```bash
|
|
83
|
-
#
|
|
84
|
+
# Git solo-local
|
|
84
85
|
bash scripts/land-branch.sh <task-slug> "feat(scope): description"
|
|
85
|
-
#
|
|
86
|
+
# Jujutsu team PR
|
|
87
|
+
jj describe -m "feat(scope): description"
|
|
88
|
+
jj bookmark set <task-slug> -r @
|
|
89
|
+
jj git push -b <task-slug>
|
|
86
90
|
```
|
|
87
91
|
|
|
92
|
+
Jujutsu solo-local landing is unsupported: run `bp_require_vcs_operation "$PWD" land-branch` and stop with its remediation instead of invoking the Git backend.
|
|
93
|
+
|
|
88
94
|
### 6. Create PR (team-pr only)
|
|
89
95
|
|
|
90
96
|
Create the pull request with a **literal provenance marker** in the body so agent-generated PRs are identifiable and do not rot silently:
|
|
@@ -133,7 +139,7 @@ bash scripts/wait-for-ci.sh --timeout 600 --interval 30
|
|
|
133
139
|
|
|
134
140
|
### 8. Clean up & return
|
|
135
141
|
|
|
136
|
-
|
|
142
|
+
Git: prune worktree, delete branch, return to main. Jujutsu: `jj workspace forget <workspace>` only after integration; do not delete its bookmark implicitly. Cycle-time: see [REFERENCE.md](REFERENCE.md#cycle-time).
|
|
137
143
|
|
|
138
144
|
Report: "Branch released."
|
|
139
145
|
|
|
@@ -5,6 +5,8 @@ effort: standard
|
|
|
5
5
|
description: Per-task context bootstrap — reads existing specs/ and tech-architecture docs to map the current lifecycle phase and suggest the next skill. Use at the start of any task, when returning after a break, or when unsure what to do next. For deriving a tech-stack doc from scratch, use map-codebase first.
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
+
# story: e82s02
|
|
9
|
+
|
|
8
10
|
# Survey Context
|
|
9
11
|
|
|
10
12
|
Read the project's current state and give a phase map + next-skill recommendation. This is the "where am I?" skill — run it at the start of every task.
|
|
@@ -52,15 +54,18 @@ Legacy markdown (`specs/archive/STATE.md`, `RELEASE-PLAN.md`) is **not** SoT if
|
|
|
52
54
|
|
|
53
55
|
If `CLAUDE.md` exists at the project root, read it for project context (stack, commands, architecture, conventions).
|
|
54
56
|
|
|
55
|
-
### 4. Check
|
|
57
|
+
### 4. Check VCS state
|
|
58
|
+
|
|
59
|
+
Read `state.yaml` `vcs.kind` (or resolve `auto`). Use native identity:
|
|
56
60
|
|
|
57
61
|
```bash
|
|
58
|
-
|
|
59
|
-
git log --oneline -5
|
|
60
|
-
|
|
62
|
+
# Git
|
|
63
|
+
git status --short; git log --oneline -5; git branch --show-current
|
|
64
|
+
# Jujutsu
|
|
65
|
+
jj status; jj log -r 'mine() & ::@' -n 5
|
|
61
66
|
```
|
|
62
67
|
|
|
63
|
-
|
|
68
|
+
For Jujutsu, compare stable change IDs and bookmarks with the `vcs` block; never interpret colocated Git's detached HEAD as branch state.
|
|
64
69
|
|
|
65
70
|
### 5. Map the lifecycle phase
|
|
66
71
|
|
|
@@ -125,7 +130,7 @@ Loop through all `specs/epics/*/epic.yaml` files and print a summary of story co
|
|
|
125
130
|
|
|
126
131
|
### check-gates (absorbed)
|
|
127
132
|
|
|
128
|
-
Print
|
|
133
|
+
Print `active_flow`, validate YAML, then show `git status` or `jj status` according to `vcs.kind`. Use before handoffs or context transitions.
|
|
129
134
|
|
|
130
135
|
## Handoff
|
|
131
136
|
|
package/skills-lock.json
CHANGED
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"commit-message": {
|
|
35
35
|
"description": "Reviews working-tree changes, then drafts a Conventional Commits title/body and states the semantic-release version bump a single such commit would imply. Also notes which defensive-code categories were touched. Use when the user wants to commit recent work, prepare a Conventional Commits message, or asks for semantic-release / semver-consistent messaging before git commit.",
|
|
36
|
-
"sha256": "
|
|
36
|
+
"sha256": "3c1413ae4e3c1476",
|
|
37
37
|
"path": "skills/commit-messageSKILL.md"
|
|
38
38
|
},
|
|
39
39
|
"compose-workflow": {
|
|
@@ -187,8 +187,8 @@
|
|
|
187
187
|
"path": "skills/investigate-bugSKILL.md"
|
|
188
188
|
},
|
|
189
189
|
"kickoff-branch": {
|
|
190
|
-
"description": "Create
|
|
191
|
-
"sha256": "
|
|
190
|
+
"description": "Create an isolated Git worktree/branch or Jujutsu workspace, then verify a clean test baseline before code. Use when starting a feature or task.",
|
|
191
|
+
"sha256": "ae1628400f08dc20",
|
|
192
192
|
"path": "skills/kickoff-branchSKILL.md"
|
|
193
193
|
},
|
|
194
194
|
"maintain-wiki": {
|
|
@@ -253,7 +253,7 @@
|
|
|
253
253
|
},
|
|
254
254
|
"release-branch": {
|
|
255
255
|
"description": "Make the merge/PR/keep/discard decision for a feature branch, verify coverage gates, create the PR with gh, and clean up the worktree. Use when a feature is done and ready to ship, or when user says \"release\", \"merge\", or \"open a PR\".",
|
|
256
|
-
"sha256": "
|
|
256
|
+
"sha256": "aaaf314d6b4f97f6",
|
|
257
257
|
"path": "skills/release-branchSKILL.md"
|
|
258
258
|
},
|
|
259
259
|
"request-review": {
|
|
@@ -353,7 +353,7 @@
|
|
|
353
353
|
},
|
|
354
354
|
"survey-context": {
|
|
355
355
|
"description": "Per-task context bootstrap — reads existing specs/ and tech-architecture docs to map the current lifecycle phase and suggest the next skill. Use at the start of any task, when returning after a break, or when unsure what to do next. For deriving a tech-stack doc from scratch, use map-codebase first.",
|
|
356
|
-
"sha256": "
|
|
356
|
+
"sha256": "30e1fea4e6e9ab63",
|
|
357
357
|
"path": "skills/survey-contextSKILL.md"
|
|
358
358
|
},
|
|
359
359
|
"terse-mode": {
|