@selesai/code 0.5.12 → 0.5.13

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.
@@ -1,39 +1,11 @@
1
1
  #!/usr/bin/env node
2
- // Shared Caveman instruction builder. Caveman is binary on/off (no intensity
3
- // levels), so the skill body is injected verbatim — no mode filtering needed.
4
-
5
- const fs = require('fs');
6
- const path = require('path');
7
-
8
- const SKILL_PATH = path.join(__dirname, '..', '..', 'skills', 'caveman', 'SKILL.md');
9
-
10
- const FALLBACK_INSTRUCTIONS =
11
- 'CAVEMAN MODE ACTIVE.\n\n' +
12
- 'Respond terse like smart caveman. All technical substance stay. Only fluff die.\n\n' +
13
- '## Persistence\n\n' +
14
- 'ACTIVE EVERY RESPONSE once triggered. No revert after many turns. No filler drift. ' +
15
- 'Still active if unsure. Off only when user says "stop caveman" or "normal mode".\n\n' +
16
- '## Rules\n\n' +
17
- 'Drop: articles (a/an/the), filler (just/really/basically/actually/simply), ' +
18
- 'pleasantries (sure/certainly/of course/happy to), hedging. Fragments OK. ' +
19
- 'Short synonyms. Abbreviate common terms (DB/auth/config/req/res/fn/impl). ' +
20
- 'Strip conjunctions. Use arrows for causality (X -> Y). One word when one word enough.\n\n' +
21
- 'Technical terms stay exact. Code blocks unchanged. Errors quoted exact.\n\n' +
22
- '## Auto-Clarity Exception\n\n' +
23
- 'Drop caveman temporarily for: security warnings, irreversible action confirmations, ' +
24
- 'multi-step sequences where fragment order risks misread, user asks to clarify or ' +
25
- 'repeats question. Resume caveman after clear part done.';
26
-
27
- function stripFrontmatter(body) {
28
- return String(body || '').replace(/^---[\s\S]*?---\s*/, '');
29
- }
2
+ // The skill is user-facing documentation. This short runtime prompt is injected
3
+ // on every turn, while extension state owns activation and deactivation.
4
+ const CAVEMAN_INSTRUCTIONS =
5
+ 'CAVEMAN MODE ACTIVE. Terse, technically complete: omit articles, filler, pleasantries, and hedging; fragments, short terms, standard abbreviations, and -> are OK. Preserve technical terms, code blocks, and quoted errors exactly. Use clear normal prose for security warnings, irreversible confirmations, risky multi-step instructions, or requested/repeated clarification; then resume terse mode.';
30
6
 
31
7
  function getCavemanInstructions() {
32
- try {
33
- return 'CAVEMAN MODE ACTIVE.\n\n' + stripFrontmatter(fs.readFileSync(SKILL_PATH, 'utf8'));
34
- } catch (e) {
35
- return FALLBACK_INSTRUCTIONS;
36
- }
8
+ return CAVEMAN_INSTRUCTIONS;
37
9
  }
38
10
 
39
- module.exports = { getCavemanInstructions, stripFrontmatter };
11
+ module.exports = { getCavemanInstructions };
@@ -1,6 +1,4 @@
1
1
  import assert from "node:assert/strict";
2
- import { readFileSync } from "node:fs";
3
- import { fileURLToPath } from "node:url";
4
2
  import test from "node:test";
5
3
 
6
4
  import {
@@ -48,17 +46,13 @@ test("isDeactivationCommand: only the whole message, case-insensitive, trailing
48
46
  assert.equal(isDeactivationCommand("how do I stop caveman re-rendering"), false);
49
47
  });
50
48
 
51
- test("getCavemanInstructions reads SKILL.md and strips frontmatter", () => {
49
+ test("getCavemanInstructions returns the compact runtime prompt", () => {
52
50
  const instructions = getCavemanInstructions();
53
- assert.ok(instructions.startsWith("CAVEMAN MODE ACTIVE"));
54
- assert.ok(!instructions.includes("name: caveman")); // frontmatter gone
55
- assert.ok(instructions.includes("Respond terse like smart caveman"));
56
- });
57
-
58
- test("getCavemanInstructions matches src/skills/caveman/SKILL.md body", () => {
59
- const skillPath = fileURLToPath(new URL("../../../skills/caveman/SKILL.md", import.meta.url));
60
- const raw = readFileSync(skillPath, "utf8");
61
- const body = raw.replace(/^---[\s\S]*?---\s*/, "");
62
51
 
63
- assert.ok(getCavemanInstructions().endsWith(body));
52
+ assert.equal(instructions,
53
+ "CAVEMAN MODE ACTIVE. Terse, technically complete: omit articles, filler, pleasantries, and hedging; fragments, short terms, standard abbreviations, and -> are OK. Preserve technical terms, code blocks, and quoted errors exactly. Use clear normal prose for security warnings, irreversible confirmations, risky multi-step instructions, or requested/repeated clarification; then resume terse mode.");
54
+ assert.ok(!instructions.includes("Persistence"));
55
+ assert.ok(!instructions.includes("stop caveman"));
56
+ assert.ok(!instructions.includes("normal mode"));
57
+ assert.ok(instructions.length < 400);
64
58
  });
@@ -184,6 +184,6 @@ export default function ponytailExtension(pi) {
184
184
 
185
185
  pi.on("before_agent_start", async (event) => {
186
186
  if (!currentMode || currentMode === "off") return;
187
- return { systemPrompt: `${event.systemPrompt}\n\n${getPonytailInstructions(currentMode)}` };
187
+ return { systemPrompt: `${event.systemPrompt}\n\n${getPonytailInstructions(currentMode, { compact: true })}` };
188
188
  });
189
189
  }
@@ -7,6 +7,11 @@ const { DEFAULT_MODE, normalizeMode, normalizePersistedMode } = require('./ponyt
7
7
 
8
8
  const INDEPENDENT_MODES = new Set(['review']);
9
9
  const SKILL_PATH = path.join(__dirname, '..', '..', 'skills', 'ponytail', 'SKILL.md');
10
+ const COMPACT_MODE_RULES = {
11
+ lite: 'Build the ask; name a lazier alternative.',
12
+ full: 'Enforce ladder; shortest diff.',
13
+ ultra: 'YAGNI first; delete; challenge the rest.',
14
+ };
10
15
 
11
16
  function filterSkillBodyForMode(body, mode) {
12
17
  const effectiveMode = normalizeMode(mode) || DEFAULT_MODE;
@@ -70,7 +75,15 @@ function getFallbackInstructions(mode) {
70
75
  'Ponytail governs what you build, not how you talk. "stop ponytail" or "normal mode": revert. Level persists until changed or session end.';
71
76
  }
72
77
 
73
- function getPonytailInstructions(mode) {
78
+ function getCompactInstructions(mode) {
79
+ return 'PONYTAIL ' + mode.toUpperCase() + ': persistent every response; off only "stop ponytail"/"normal mode". ' +
80
+ 'Trace first. Ladder: YAGNI -> reuse -> stdlib/native -> installed deps -> minimum diff. ' +
81
+ 'Fix root cause, not caller symptom. No unrequested abstractions/deps/boilerplate; delete first. ' +
82
+ 'Preserve validation, data-loss handling, security, accessibility, explicit asks. ' +
83
+ 'Non-trivial logic: one runnable check. Code first; <=3 lines. ' + COMPACT_MODE_RULES[mode];
84
+ }
85
+
86
+ function getPonytailInstructions(mode, options) {
74
87
  const configuredMode = normalizePersistedMode(mode) || DEFAULT_MODE;
75
88
 
76
89
  if (INDEPENDENT_MODES.has(configuredMode)) {
@@ -78,6 +91,7 @@ function getPonytailInstructions(mode) {
78
91
  }
79
92
 
80
93
  const effectiveMode = normalizeMode(configuredMode) || DEFAULT_MODE;
94
+ if (options?.compact === true) return getCompactInstructions(effectiveMode);
81
95
 
82
96
  try {
83
97
  return 'PONYTAIL MODE ACTIVE — level: ' + effectiveMode + '\n\n' +
@@ -73,8 +73,8 @@ test("/ponytail updates session mode and injects instructions", async () => with
73
73
  });
74
74
 
75
75
  const result = await events.get("before_agent_start")({ systemPrompt: "BASE" }, ctx);
76
- assert.ok(result.systemPrompt.includes("PONYTAIL MODE ACTIVE"));
77
- assert.ok(result.systemPrompt.includes("ultra"));
76
+ assert.match(result.systemPrompt, /^BASE\n\nPONYTAIL ULTRA:/);
77
+ assert.ok(result.systemPrompt.length - "BASE\n\n".length <= 450);
78
78
  }));
79
79
 
80
80
  test("session_start restores latest persisted mode", async () => withTempConfig(async () => {
@@ -90,7 +90,23 @@ test("session_start restores latest persisted mode", async () => withTempConfig(
90
90
  await events.get("session_start")({ reason: "resume" }, ctx);
91
91
  const result = await events.get("before_agent_start")({ systemPrompt: "BASE" }, ctx);
92
92
 
93
- assert.ok(result.systemPrompt.includes("lite"));
93
+ assert.match(result.systemPrompt, /PONYTAIL LITE:/);
94
+ }));
95
+
96
+ test("review mode retains its independent skill prompt", async () => withTempConfig(async () => {
97
+ const { events } = createPiHarness();
98
+ const ctx = createCommandContext({
99
+ sessionManager: {
100
+ getEntries: () => [
101
+ { type: "custom", customType: "ponytail-mode", data: { mode: "review" } },
102
+ ],
103
+ },
104
+ });
105
+
106
+ await events.get("session_start")({ reason: "resume" }, ctx);
107
+ const result = await events.get("before_agent_start")({ systemPrompt: "BASE" }, ctx);
108
+
109
+ assert.equal(result.systemPrompt, "BASE\n\nPONYTAIL MODE ACTIVE — level: review. Behavior defined by /ponytail-review skill.");
94
110
  }));
95
111
 
96
112
  test("skill alias commands delegate to Pi skill commands", async () => {
@@ -133,7 +149,7 @@ test("a request mentioning normal mode stays active", async () => withTempConfig
133
149
  await events.get("input")({ text: "add a normal mode toggle next to dark mode", source: "interactive" }, ctx);
134
150
 
135
151
  const result = await events.get("before_agent_start")({ systemPrompt: "BASE" }, ctx);
136
- assert.match(result.systemPrompt, /PONYTAIL MODE ACTIVE/);
152
+ assert.match(result.systemPrompt, /PONYTAIL ULTRA:/);
137
153
  }));
138
154
 
139
155
  test("status bar renders the mode and flips active on agent_start", async () => withTempConfig(async () => {
@@ -2,8 +2,12 @@ import assert from "node:assert/strict";
2
2
  import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
3
3
  import { tmpdir } from "node:os";
4
4
  import { join } from "node:path";
5
+ import { createRequire } from "node:module";
5
6
  import test from "node:test";
6
7
 
8
+ const require = createRequire(import.meta.url);
9
+ const { getPonytailInstructions } = require("../ponytail-instructions.cjs");
10
+
7
11
  import {
8
12
  filterSkillBodyForMode,
9
13
  parsePonytailCommand,
@@ -74,6 +78,34 @@ test("filterSkillBodyForMode keeps only requested intensity examples and rows",
74
78
  assert.ok(filtered.includes("Other line"));
75
79
  });
76
80
 
81
+ test("compact Ponytail instructions retain core rules and mode distinctions", () => {
82
+ const compact = Object.fromEntries(
83
+ ["lite", "full", "ultra"].map((mode) => [mode, getPonytailInstructions(mode, { compact: true })]),
84
+ );
85
+
86
+ for (const [mode, instructions] of Object.entries(compact)) {
87
+ assert.match(instructions, new RegExp(`^PONYTAIL ${mode.toUpperCase()}:`));
88
+ assert.ok(instructions.length >= 300 && instructions.length <= 450, `${mode}: ${instructions.length} characters`);
89
+ for (const phrase of ["stop ponytail", "Trace first", "root cause", "validation", "data-loss", "security", "accessibility", "runnable check"]) {
90
+ assert.ok(instructions.includes(phrase), `${mode} lacks ${phrase}`);
91
+ }
92
+ }
93
+
94
+ assert.match(compact.lite, /Build the ask; name a lazier alternative/);
95
+ assert.match(compact.full, /Enforce ladder; shortest diff/);
96
+ assert.match(compact.ultra, /YAGNI first; delete; challenge the rest/);
97
+
98
+ const fullSkill = getPonytailInstructions("full");
99
+ assert.match(fullSkill, /## The ladder/);
100
+ assert.ok(fullSkill.length > compact.full.length);
101
+ });
102
+
103
+ test("review instructions remain independent in compact mode", () => {
104
+ const expected = "PONYTAIL MODE ACTIVE — level: review. Behavior defined by /ponytail-review skill.";
105
+ assert.equal(getPonytailInstructions("review"), expected);
106
+ assert.equal(getPonytailInstructions("review", { compact: true }), expected);
107
+ });
108
+
77
109
  test("filterSkillBodyForMode keeps rule bullets that contain a colon", () => {
78
110
  // Regression: rule bullets outside the Intensity section (e.g. the
79
111
  // "No unrequested abstractions:" rule or the `ponytail:` comment convention)
@@ -472,11 +472,6 @@ function registerSharedArtifactWriter(pi: ExtensionAPI): void {
472
472
  name: WORKFLOW_ARTIFACT_TOOL,
473
473
  label: "Write Workflow Artifact",
474
474
  description: "Write the current workflow phase artifact. The workflow enforces the destination path; provide content only.",
475
- promptSnippet: `${WORKFLOW_ARTIFACT_TOOL}(content) - write the active workflow artifact; path is chosen by the workflow, not the agent.`,
476
- promptGuidelines: [
477
- `During any workflow, use ${WORKFLOW_ARTIFACT_TOOL} instead of write/edit for workflow artifacts.`,
478
- "Provide artifact content only; do not provide a path.",
479
- ],
480
475
  parameters: Type.Object({
481
476
  content: Type.String({ description: "Artifact markdown/text content to save." }),
482
477
  }),
@@ -571,11 +566,6 @@ export function createWorkflowExtension(
571
566
  name: start,
572
567
  label: options.toolLabels.start,
573
568
  description: `Start the ${mode} workflow for the given goal. Sets up ${config.phases[0]} as the first phase and returns its prompt. Do not call if a workflow is already active.`,
574
- promptSnippet: `${start}(goal) - start the ${mode} workflow; goal is what the user wants to build.`,
575
- promptGuidelines: [
576
- `Call ${start} only when the user explicitly asks to start a ${mode} workflow and none is active.`,
577
- "Pass the user's full goal as the goal parameter.",
578
- ],
579
569
  parameters: Type.Object({
580
570
  goal: Type.String({
581
571
  description: `What the user wants the ${mode} workflow to build or accomplish.`,
@@ -650,11 +640,6 @@ export function createWorkflowExtension(
650
640
  name: resume,
651
641
  label: options.toolLabels.resume,
652
642
  description: `Resume an explicitly selected ${mode} workflow run. Pass a run id, artifact directory, or workflow.json path.`,
653
- promptSnippet: `${resume}(run) - resume an explicit ${mode} workflow run; run is its id, artifact directory, or workflow.json path.`,
654
- promptGuidelines: [
655
- `Call ${resume} only when the user explicitly selects a ${mode} workflow run.`,
656
- "Workflow runs never resume automatically after reload.",
657
- ],
658
643
  parameters: Type.Object({ run: Type.String({ description: "Run id, artifact directory, or workflow.json path." }) }),
659
644
  async execute(_id, params, _signal, _onUpdate, ctx) {
660
645
  return resumeController(controller, ctx, params.run, end);
@@ -671,10 +656,6 @@ export function createWorkflowExtension(
671
656
  name: end,
672
657
  label: options.toolLabels.end,
673
658
  description: `Close the ${mode} workflow. Must be called when the final phase is complete. Marks the workflow finished and stops the agent loop.`,
674
- promptSnippet: `${end}() - close the finished ${mode} workflow; no further phase transitions allowed.`,
675
- promptGuidelines: [
676
- `Call ${end} exactly once, from the terminal phase, when all close artifacts are complete.`,
677
- ],
678
659
  parameters: Type.Object({}),
679
660
  async execute(_id, _params, _signal, _onUpdate, ctx) {
680
661
  const before = checkpoint(controller);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@selesai/code",
3
- "version": "0.5.12",
3
+ "version": "0.5.13",
4
4
  "description": "Selesai coding agent",
5
5
  "type": "module",
6
6
  "piConfig": {