mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-31 22:14:25 +01:00
* feat(gen-skill-docs): add --plan-mode=off to omit the plan-mode preamble (#3168)
Generated skills ship a ~1.8 KB "## Plan Mode Safe Operations" +
"## Skill Invocation During Plan Mode" block on every skill, for hosts
and users who never enter plan mode. This adds a --plan-mode=off flag to
gen-skill-docs that drops that block at gen time. Default builds
(planMode undefined or true) keep the block byte-identically.
The "PLAN MODE EXCEPTION — ALWAYS RUN" markers inside skill bodies
still apply when the flag is off.
(cherry picked from commit 51edee9915)
* style(types): fix stray indentation on TemplateContext.installRoot
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* feat(config): plan_mode_preamble key wires --plan-mode=off into setup and every installed render
gstack-config plan_mode_preamble (on|off, default on) makes ./setup pass
--plan-mode=off to every gen:skill-docs render, gbrain-refresh and the
gstack-relink router render. The default Claude install, which otherwise
serves the committed SKILL.md files, gets a plain render with the key off;
the activation record notes plan_mode=off so switching back on removes the
render, including on the gbrain=unknown keep branch. With the key on or
unset every path and record is byte-for-byte unchanged.
Fixes #3168. Finishes #3213 by @xingzihai.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(setup,relink): plan_mode_preamble=off survives builds and failed renders; alias follows the router
Review findings on the plan_mode_preamble wiring:
- a build renders env hosts without --plan-mode=off, so with the key off
setup no longer skips their re-render after a build;
- with the key off the gbrain-absent branch leaves the render to the plain
re-render, so a failed render keeps the previous one;
- gstack-relink refreshes the _gstack-command alias after re-rendering the
router (also fixes the same staleness for disabled_skills).
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: xingzihai <xingzihai@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
88 lines
3.5 KiB
TypeScript
88 lines
3.5 KiB
TypeScript
/**
|
|
* Unit tests for the --plan-mode=off flag (#3168).
|
|
*
|
|
* `--plan-mode=off` drops the "## Plan Mode Safe Operations" +
|
|
* "## Skill Invocation During Plan Mode" preamble block from generated
|
|
* skills, for hosts and users who never enter plan mode. Default builds
|
|
* (planMode undefined or true) keep the block byte-identically.
|
|
*
|
|
* Pure-function tests against the resolvers — fast, free, no subprocess.
|
|
*/
|
|
|
|
import { describe, test, expect } from 'bun:test';
|
|
import type { TemplateContext } from '../scripts/resolvers/types';
|
|
import { generatePlanModeInfo, generateCompletionStatus } from '../scripts/resolvers/preamble/generate-completion-status';
|
|
import { generatePreamble } from '../scripts/resolvers/preamble';
|
|
|
|
function makeCtx(planMode?: boolean, tier: number = 4): TemplateContext {
|
|
return {
|
|
skillName: 'test-skill',
|
|
tmplPath: '/tmp/test/SKILL.md.tmpl',
|
|
host: 'claude',
|
|
paths: {
|
|
skillRoot: '~/.claude/skills/gstack',
|
|
localSkillRoot: '.claude/skills',
|
|
binDir: '~/.claude/skills/gstack/bin',
|
|
browseDir: '~/.claude/skills/gstack/browse/dist',
|
|
designDir: '~/.claude/skills/gstack/design/dist',
|
|
makePdfDir: '~/.claude/skills/gstack/make-pdf/dist',
|
|
},
|
|
preambleTier: tier,
|
|
planMode,
|
|
};
|
|
}
|
|
|
|
describe('plan-mode off — generatePlanModeInfo', () => {
|
|
test('planMode undefined: emits both plan-mode sections (default behavior)', () => {
|
|
const out = generatePlanModeInfo(makeCtx(undefined));
|
|
expect(out).toContain('## Plan Mode Safe Operations');
|
|
expect(out).toContain('## Skill Invocation During Plan Mode');
|
|
});
|
|
|
|
test('planMode true: emits both plan-mode sections', () => {
|
|
const out = generatePlanModeInfo(makeCtx(true));
|
|
expect(out).toContain('## Plan Mode Safe Operations');
|
|
expect(out).toContain('## Skill Invocation During Plan Mode');
|
|
});
|
|
|
|
test('planMode false: returns empty string', () => {
|
|
expect(generatePlanModeInfo(makeCtx(false))).toBe('');
|
|
});
|
|
|
|
test('planMode false: no plan-mode heading survives', () => {
|
|
const out = generatePlanModeInfo(makeCtx(false));
|
|
expect(out).not.toContain('Plan Mode Safe Operations');
|
|
expect(out).not.toContain('Skill Invocation During Plan Mode');
|
|
});
|
|
});
|
|
|
|
describe('plan-mode off — generatePreamble integration', () => {
|
|
test('default tier-2 preamble includes the plan-mode block', () => {
|
|
const out = generatePreamble(makeCtx(undefined, 2));
|
|
expect(out).toContain('## Plan Mode Safe Operations');
|
|
expect(out).toContain('## Skill Invocation During Plan Mode');
|
|
});
|
|
|
|
test('planMode false tier-2 preamble drops the plan-mode block', () => {
|
|
const out = generatePreamble(makeCtx(false, 2));
|
|
expect(out).not.toContain('## Plan Mode Safe Operations');
|
|
expect(out).not.toContain('## Skill Invocation During Plan Mode');
|
|
});
|
|
|
|
test('planMode false preamble is measurably smaller than default', () => {
|
|
const defaultLen = generatePreamble(makeCtx(undefined, 2)).length;
|
|
const offLen = generatePreamble(makeCtx(false, 2)).length;
|
|
// The plan-mode block is ~1.8 KB; assert at least 1 KB saved.
|
|
expect(defaultLen - offLen).toBeGreaterThan(1024);
|
|
});
|
|
|
|
test('planMode undefined preamble is byte-identical to planMode true', () => {
|
|
expect(generatePreamble(makeCtx(undefined, 2))).toBe(generatePreamble(makeCtx(true, 2)));
|
|
});
|
|
|
|
test('planMode false: PLAN MODE EXCEPTION markers inside skill bodies still apply (completion status keeps its telemetry exception)', () => {
|
|
const out = generateCompletionStatus(makeCtx(false));
|
|
expect(out).toContain('PLAN MODE EXCEPTION — ALWAYS RUN');
|
|
});
|
|
});
|