@selesai/code 0.5.13 → 0.5.14
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 +186 -0
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/extensions/package.json +4 -3
- package/dist/extensions/pi-powerline-footer/README.md +1 -1
- package/dist/extensions/pi-powerline-footer/guide.ts +227 -0
- package/dist/extensions/pi-powerline-footer/index.ts +88 -55
- package/dist/extensions/pi-powerline-footer/tests/editor-responsiveness.test.ts +0 -78
- package/dist/extensions/pi-powerline-footer/tests/guide.test.ts +102 -0
- package/dist/extensions/pi-powerline-footer/welcome.ts +65 -30
- package/dist/skills/caveman/SKILL.md +1 -0
- package/dist/skills/handoff/SKILL.md +1 -0
- package/dist/skills/handoff-text/SKILL.md +1 -0
- package/dist/skills/implanger/SKILL.md +1 -0
- package/dist/skills/improve-codebase/SKILL.md +1 -0
- package/dist/skills/planger/SKILL.md +1 -0
- package/dist/skills/ponytail/SKILL.md +1 -0
- package/dist/skills/ponytail-audit/SKILL.md +1 -0
- package/dist/skills/ponytail-debt/SKILL.md +1 -0
- package/dist/skills/ponytail-gain/SKILL.md +1 -0
- package/dist/skills/ponytail-help/SKILL.md +1 -0
- package/dist/skills/ponytail-review/SKILL.md +1 -0
- package/dist/skills/workflow-creation/SKILL.md +1 -0
- package/package.json +23 -2
- package/dist/agents/architect.md +0 -217
- package/dist/agents/builder.md +0 -120
- package/dist/agents/commentator.md +0 -130
- package/dist/agents/explorer.md +0 -51
- package/dist/agents/recapper.md +0 -26
- package/dist/extensions/gitignore-guard.ts +0 -132
- package/dist/extensions/hooks/claude-codex-hooks.json +0 -44
- package/dist/extensions/hooks/copilot-hooks.json +0 -21
- package/dist/extensions/hooks/ponytail-activate.js +0 -91
- package/dist/extensions/hooks/ponytail-config.js +0 -122
- package/dist/extensions/hooks/ponytail-instructions.js +0 -94
- package/dist/extensions/hooks/ponytail-mode-tracker.js +0 -55
- package/dist/extensions/hooks/ponytail-runtime.js +0 -68
- package/dist/extensions/hooks/ponytail-statusline.ps1 +0 -21
- package/dist/extensions/hooks/ponytail-statusline.sh +0 -12
- package/dist/extensions/hooks/ponytail-subagent.js +0 -22
- package/dist/extensions/pi-extension/index.js +0 -189
- package/dist/extensions/pi-extension/package.json +0 -8
- package/dist/extensions/pi-extension/test/extension.test.js +0 -167
- package/dist/extensions/pi-extension/test/helpers.test.js +0 -92
- package/dist/extensions/pi-powerline-footer/welcome-dismiss.ts +0 -34
- package/dist/extensions/pi-subagents/agents/context-builder.md +0 -46
- package/dist/extensions/pi-subagents/agents/delegate.md +0 -12
- package/dist/extensions/pi-subagents/agents/oracle.md +0 -73
- package/dist/extensions/pi-subagents/agents/planner.md +0 -55
- package/dist/extensions/pi-subagents/agents/reviewer.md +0 -79
- package/dist/extensions/pi-subagents/agents/scout.md +0 -50
- package/dist/extensions/pi-subagents/agents/worker.md +0 -55
- package/dist/extensions/pi-subagents/src/runs/shared/spawn-timing.ts +0 -46
- package/dist/extensions/pi-subagents/test/unit/spawn-timing.test.ts +0 -45
- package/dist/extensions/pi-subagents/tsconfig.runner.json +0 -17
- package/dist/extensions/ponytail-pi-extension/index.js +0 -189
- package/dist/extensions/ponytail-pi-extension/package.json +0 -8
- package/dist/extensions/ponytail-pi-extension/test/extension.test.js +0 -167
- package/dist/extensions/ponytail-pi-extension/test/helpers.test.js +0 -92
- package/dist/extensions/prototype.ts +0 -713
- package/dist/extensions/question.ts +0 -350
- package/dist/extensions/quick.ts +0 -630
- package/dist/extensions/tps-tracker.ts +0 -280
- package/dist/extensions/workflow/task-validators.ts +0 -69
- package/dist/skills/selesai-default/SKILL.md +0 -16
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
import { createRequire } from "node:module";
|
|
2
|
-
|
|
3
|
-
const require = createRequire(import.meta.url);
|
|
4
|
-
const {
|
|
5
|
-
DEFAULT_MODE,
|
|
6
|
-
getDefaultMode,
|
|
7
|
-
normalizeMode,
|
|
8
|
-
normalizeConfigMode,
|
|
9
|
-
normalizePersistedMode,
|
|
10
|
-
isDeactivationCommand,
|
|
11
|
-
writeDefaultMode,
|
|
12
|
-
} = require("../hooks/ponytail-config.js");
|
|
13
|
-
const { getPonytailInstructions, filterSkillBodyForMode } = require("../hooks/ponytail-instructions.js");
|
|
14
|
-
|
|
15
|
-
export { filterSkillBodyForMode };
|
|
16
|
-
export const readDefaultMode = getDefaultMode;
|
|
17
|
-
|
|
18
|
-
export function resolveSessionMode(entries, fallbackMode = DEFAULT_MODE) {
|
|
19
|
-
const fallback = normalizePersistedMode(fallbackMode) || DEFAULT_MODE;
|
|
20
|
-
if (!Array.isArray(entries)) return fallback;
|
|
21
|
-
|
|
22
|
-
for (let i = entries.length - 1; i >= 0; i -= 1) {
|
|
23
|
-
const entry = entries[i];
|
|
24
|
-
if (entry?.type !== "custom" || entry?.customType !== "ponytail-mode") continue;
|
|
25
|
-
|
|
26
|
-
const mode = normalizePersistedMode(entry?.data?.mode);
|
|
27
|
-
if (mode) return mode;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return fallback;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function parsePonytailCommand(text, defaultMode = DEFAULT_MODE) {
|
|
34
|
-
const fallback = normalizePersistedMode(defaultMode) || DEFAULT_MODE;
|
|
35
|
-
const normalizedText = String(text || "").trim().toLowerCase();
|
|
36
|
-
|
|
37
|
-
if (!normalizedText) {
|
|
38
|
-
return { type: "set-mode", mode: fallback === "off" ? "full" : fallback };
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const [primary, secondary] = normalizedText.split(/\s+/);
|
|
42
|
-
|
|
43
|
-
if (primary === "status") return { type: "status" };
|
|
44
|
-
|
|
45
|
-
if (primary === "default") {
|
|
46
|
-
const mode = normalizeConfigMode(secondary);
|
|
47
|
-
return mode ? { type: "set-default", mode } : { type: "invalid", reason: "invalid-default-mode" };
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const mode = normalizeMode(primary);
|
|
51
|
-
return mode ? { type: "set-mode", mode } : { type: "invalid", reason: "invalid-mode", mode: primary };
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export { writeDefaultMode };
|
|
55
|
-
|
|
56
|
-
export default function ponytailExtension(pi) {
|
|
57
|
-
let currentMode = DEFAULT_MODE;
|
|
58
|
-
let configuredDefaultMode = getDefaultMode();
|
|
59
|
-
let isActive = false;
|
|
60
|
-
let lastCtx = null;
|
|
61
|
-
|
|
62
|
-
// -- Status bar --
|
|
63
|
-
function syncStatus(ctx) {
|
|
64
|
-
if (ctx) lastCtx = ctx;
|
|
65
|
-
const c = ctx || lastCtx;
|
|
66
|
-
if (!c?.ui?.setStatus || !c.ui.theme?.fg) return;
|
|
67
|
-
const theme = c.ui.theme;
|
|
68
|
-
if (currentMode === "off") {
|
|
69
|
-
c.ui.setStatus("ponytail", "");
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
const levelIcons = { lite: "🌿", full: "⚡", ultra: "🔥" };
|
|
73
|
-
const icon = levelIcons[currentMode] || "";
|
|
74
|
-
const label = currentMode.toUpperCase();
|
|
75
|
-
const indicator = isActive ? theme.fg("accent", "●") : theme.fg("dim", "○");
|
|
76
|
-
c.ui.setStatus("ponytail", indicator + " 🐴 " + theme.fg("muted", "ponytail: ") + theme.fg("text", icon + " " + label));
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const setMode = (mode, ctx) => {
|
|
80
|
-
const normalized = normalizePersistedMode(mode);
|
|
81
|
-
if (!normalized) return;
|
|
82
|
-
|
|
83
|
-
currentMode = normalized;
|
|
84
|
-
pi.appendEntry("ponytail-mode", { mode: normalized });
|
|
85
|
-
syncStatus(ctx);
|
|
86
|
-
ctx?.ui?.notify?.(`Ponytail mode set to ${normalized}.`, "info");
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
const sendAlias = (skillName, args, ctx) => {
|
|
90
|
-
const normalized = String(args || "").trim();
|
|
91
|
-
const message = normalized ? `${skillName} ${normalized}` : skillName;
|
|
92
|
-
|
|
93
|
-
if (ctx?.isIdle?.() === false) {
|
|
94
|
-
pi.sendUserMessage(message, { deliverAs: "followUp" });
|
|
95
|
-
ctx?.ui?.notify?.(`${skillName} queued as follow-up.`, "info");
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
pi.sendUserMessage(message);
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
pi.registerCommand("ponytail", {
|
|
103
|
-
description: "Set or report Ponytail mode",
|
|
104
|
-
handler: async (args, ctx) => {
|
|
105
|
-
const parsed = parsePonytailCommand(args, configuredDefaultMode);
|
|
106
|
-
|
|
107
|
-
if (parsed.type === "status") {
|
|
108
|
-
ctx?.ui?.notify?.(`Ponytail: current ${currentMode} • default ${configuredDefaultMode}`, "info");
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (parsed.type === "set-default") {
|
|
113
|
-
const written = writeDefaultMode(parsed.mode);
|
|
114
|
-
if (written) {
|
|
115
|
-
configuredDefaultMode = getDefaultMode();
|
|
116
|
-
const message = configuredDefaultMode === written
|
|
117
|
-
? `Default Ponytail mode set to ${written}.`
|
|
118
|
-
: `Saved default ${written}, but env override keeps default at ${configuredDefaultMode}.`;
|
|
119
|
-
ctx?.ui?.notify?.(message, "info");
|
|
120
|
-
}
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (parsed.type === "set-mode") {
|
|
125
|
-
setMode(parsed.mode, ctx);
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
ctx?.ui?.notify?.("Unknown or unsupported /ponytail mode.", "warning");
|
|
130
|
-
},
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
pi.registerCommand("ponytail-review", {
|
|
134
|
-
description: "Run /skill:ponytail-review",
|
|
135
|
-
handler: (_args, ctx) => sendAlias("/skill:ponytail-review", "", ctx),
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
pi.registerCommand("ponytail-audit", {
|
|
139
|
-
description: "Run /skill:ponytail-audit",
|
|
140
|
-
handler: (_args, ctx) => sendAlias("/skill:ponytail-audit", "", ctx),
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
pi.registerCommand("ponytail-gain", {
|
|
144
|
-
description: "Run /skill:ponytail-gain",
|
|
145
|
-
handler: (_args, ctx) => sendAlias("/skill:ponytail-gain", "", ctx),
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
pi.registerCommand("ponytail-debt", {
|
|
149
|
-
description: "Run /skill:ponytail-debt",
|
|
150
|
-
handler: (_args, ctx) => sendAlias("/skill:ponytail-debt", "", ctx),
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
pi.registerCommand("ponytail-help", {
|
|
154
|
-
description: "Run /skill:ponytail-help",
|
|
155
|
-
handler: (_args, ctx) => sendAlias("/skill:ponytail-help", "", ctx),
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
pi.on("input", async (event) => {
|
|
159
|
-
if (event?.source === "extension") return;
|
|
160
|
-
|
|
161
|
-
const text = String(event?.text || "");
|
|
162
|
-
if (currentMode !== "off" && isDeactivationCommand(text)) {
|
|
163
|
-
setMode("off");
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
pi.on("session_start", async (_event, ctx) => {
|
|
168
|
-
const entries = ctx?.sessionManager?.getBranch?.() || ctx?.sessionManager?.getEntries?.() || [];
|
|
169
|
-
configuredDefaultMode = getDefaultMode();
|
|
170
|
-
currentMode = resolveSessionMode(entries, configuredDefaultMode);
|
|
171
|
-
syncStatus(ctx);
|
|
172
|
-
ctx?.ui?.notify?.(`Ponytail loaded: ${currentMode}`, "info");
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
pi.on("agent_start", async (_event, ctx) => {
|
|
176
|
-
isActive = true;
|
|
177
|
-
syncStatus(ctx);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
pi.on("agent_end", async (_event, ctx) => {
|
|
181
|
-
isActive = false;
|
|
182
|
-
syncStatus(ctx);
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
pi.on("before_agent_start", async (event) => {
|
|
186
|
-
if (!currentMode || currentMode === "off") return;
|
|
187
|
-
return { systemPrompt: `${event.systemPrompt}\n\n${getPonytailInstructions(currentMode)}` };
|
|
188
|
-
});
|
|
189
|
-
}
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
|
-
import { tmpdir } from "node:os";
|
|
4
|
-
import { join } from "node:path";
|
|
5
|
-
import test from "node:test";
|
|
6
|
-
|
|
7
|
-
import ponytailExtension from "../index.js";
|
|
8
|
-
|
|
9
|
-
function createPiHarness() {
|
|
10
|
-
const events = new Map();
|
|
11
|
-
const commands = new Map();
|
|
12
|
-
const appendedEntries = [];
|
|
13
|
-
const sentUserMessages = [];
|
|
14
|
-
|
|
15
|
-
const pi = {
|
|
16
|
-
on(eventName, handler) {
|
|
17
|
-
events.set(eventName, handler);
|
|
18
|
-
},
|
|
19
|
-
registerCommand(name, options) {
|
|
20
|
-
commands.set(name, options);
|
|
21
|
-
},
|
|
22
|
-
appendEntry(customType, data) {
|
|
23
|
-
appendedEntries.push({ customType, data });
|
|
24
|
-
},
|
|
25
|
-
sendUserMessage(text, options) {
|
|
26
|
-
sentUserMessages.push({ text, options });
|
|
27
|
-
},
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
ponytailExtension(pi);
|
|
31
|
-
return { events, commands, appendedEntries, sentUserMessages };
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function createCommandContext(overrides = {}) {
|
|
35
|
-
return {
|
|
36
|
-
isIdle: () => true,
|
|
37
|
-
sessionManager: { getEntries: () => [] },
|
|
38
|
-
ui: { notify() {} },
|
|
39
|
-
...overrides,
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function withTempConfig(fn) {
|
|
44
|
-
const tempConfigHome = mkdtempSync(join(tmpdir(), "ponytail-test-"));
|
|
45
|
-
const previousXdg = process.env.XDG_CONFIG_HOME;
|
|
46
|
-
process.env.XDG_CONFIG_HOME = tempConfigHome;
|
|
47
|
-
|
|
48
|
-
return Promise.resolve()
|
|
49
|
-
.then(fn)
|
|
50
|
-
.finally(() => {
|
|
51
|
-
if (previousXdg === undefined) delete process.env.XDG_CONFIG_HOME;
|
|
52
|
-
else process.env.XDG_CONFIG_HOME = previousXdg;
|
|
53
|
-
rmSync(tempConfigHome, { recursive: true, force: true });
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
test("extension registers Ponytail commands", () => {
|
|
58
|
-
const { commands } = createPiHarness();
|
|
59
|
-
|
|
60
|
-
assert.deepEqual([...commands.keys()].sort(), ["ponytail", "ponytail-audit", "ponytail-debt", "ponytail-gain", "ponytail-help", "ponytail-review"]);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
test("/ponytail updates session mode and injects instructions", async () => withTempConfig(async () => {
|
|
64
|
-
const { commands, events, appendedEntries } = createPiHarness();
|
|
65
|
-
const ctx = createCommandContext();
|
|
66
|
-
|
|
67
|
-
await events.get("session_start")({ reason: "startup" }, ctx);
|
|
68
|
-
await commands.get("ponytail").handler("ultra", ctx);
|
|
69
|
-
|
|
70
|
-
assert.deepEqual(appendedEntries.at(-1), {
|
|
71
|
-
customType: "ponytail-mode",
|
|
72
|
-
data: { mode: "ultra" },
|
|
73
|
-
});
|
|
74
|
-
|
|
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"));
|
|
78
|
-
}));
|
|
79
|
-
|
|
80
|
-
test("session_start restores latest persisted mode", async () => withTempConfig(async () => {
|
|
81
|
-
const { events } = createPiHarness();
|
|
82
|
-
const ctx = createCommandContext({
|
|
83
|
-
sessionManager: {
|
|
84
|
-
getEntries: () => [
|
|
85
|
-
{ type: "custom", customType: "ponytail-mode", data: { mode: "lite" } },
|
|
86
|
-
],
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
await events.get("session_start")({ reason: "resume" }, ctx);
|
|
91
|
-
const result = await events.get("before_agent_start")({ systemPrompt: "BASE" }, ctx);
|
|
92
|
-
|
|
93
|
-
assert.ok(result.systemPrompt.includes("lite"));
|
|
94
|
-
}));
|
|
95
|
-
|
|
96
|
-
test("skill alias commands delegate to Pi skill commands", async () => {
|
|
97
|
-
const { commands, sentUserMessages } = createPiHarness();
|
|
98
|
-
const ctx = createCommandContext();
|
|
99
|
-
|
|
100
|
-
await commands.get("ponytail-review").handler("", ctx);
|
|
101
|
-
await commands.get("ponytail-audit").handler("", ctx);
|
|
102
|
-
await commands.get("ponytail-debt").handler("", ctx);
|
|
103
|
-
await commands.get("ponytail-gain").handler("", ctx);
|
|
104
|
-
await commands.get("ponytail-help").handler("", ctx);
|
|
105
|
-
|
|
106
|
-
assert.deepEqual(sentUserMessages.map((entry) => entry.text), [
|
|
107
|
-
"/skill:ponytail-review",
|
|
108
|
-
"/skill:ponytail-audit",
|
|
109
|
-
"/skill:ponytail-debt",
|
|
110
|
-
"/skill:ponytail-gain",
|
|
111
|
-
"/skill:ponytail-help",
|
|
112
|
-
]);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
test("normal mode disables persistent instructions", async () => withTempConfig(async () => {
|
|
116
|
-
const { commands, events } = createPiHarness();
|
|
117
|
-
const ctx = createCommandContext();
|
|
118
|
-
|
|
119
|
-
await events.get("session_start")({ reason: "startup" }, ctx);
|
|
120
|
-
await commands.get("ponytail").handler("ultra", ctx);
|
|
121
|
-
await events.get("input")({ text: "normal mode", source: "interactive" }, ctx);
|
|
122
|
-
|
|
123
|
-
const disabled = await events.get("before_agent_start")({ systemPrompt: "BASE" }, ctx);
|
|
124
|
-
assert.equal(disabled, undefined);
|
|
125
|
-
}));
|
|
126
|
-
|
|
127
|
-
test("a request mentioning normal mode stays active", async () => withTempConfig(async () => {
|
|
128
|
-
const { commands, events } = createPiHarness();
|
|
129
|
-
const ctx = createCommandContext();
|
|
130
|
-
|
|
131
|
-
await events.get("session_start")({ reason: "startup" }, ctx);
|
|
132
|
-
await commands.get("ponytail").handler("ultra", ctx);
|
|
133
|
-
await events.get("input")({ text: "add a normal mode toggle next to dark mode", source: "interactive" }, ctx);
|
|
134
|
-
|
|
135
|
-
const result = await events.get("before_agent_start")({ systemPrompt: "BASE" }, ctx);
|
|
136
|
-
assert.match(result.systemPrompt, /PONYTAIL MODE ACTIVE/);
|
|
137
|
-
}));
|
|
138
|
-
|
|
139
|
-
test("status bar renders the mode and flips active on agent_start", async () => withTempConfig(async () => {
|
|
140
|
-
const { events } = createPiHarness();
|
|
141
|
-
const statusWrites = [];
|
|
142
|
-
const ctx = createCommandContext({
|
|
143
|
-
sessionManager: { getEntries: () => [{ type: "custom", customType: "ponytail-mode", data: { mode: "ultra" } }] },
|
|
144
|
-
ui: { notify() {}, setStatus: (key, text) => statusWrites.push({ key, text }), theme: { fg: (_color, text) => text } },
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
await events.get("session_start")({ reason: "resume" }, ctx);
|
|
148
|
-
await events.get("agent_start")({}, ctx);
|
|
149
|
-
|
|
150
|
-
assert.equal(statusWrites.at(-2).key, "ponytail");
|
|
151
|
-
assert.match(statusWrites.at(-2).text, /○.*ULTRA/);
|
|
152
|
-
assert.match(statusWrites.at(-1).text, /●.*ULTRA/);
|
|
153
|
-
}));
|
|
154
|
-
|
|
155
|
-
test("status bar stays silent when ui lacks a theme", async () => withTempConfig(async () => {
|
|
156
|
-
const { events } = createPiHarness();
|
|
157
|
-
const calls = [];
|
|
158
|
-
const ctx = createCommandContext({
|
|
159
|
-
sessionManager: { getEntries: () => [{ type: "custom", customType: "ponytail-mode", data: { mode: "ultra" } }] },
|
|
160
|
-
ui: { notify() {}, setStatus: (_key, text) => calls.push(text) }, // setStatus present, theme absent
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
await events.get("session_start")({ reason: "resume" }, ctx);
|
|
164
|
-
await events.get("agent_start")({}, ctx);
|
|
165
|
-
|
|
166
|
-
assert.deepEqual(calls, []);
|
|
167
|
-
}));
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
3
|
-
import { tmpdir } from "node:os";
|
|
4
|
-
import { join } from "node:path";
|
|
5
|
-
import test from "node:test";
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
filterSkillBodyForMode,
|
|
9
|
-
parsePonytailCommand,
|
|
10
|
-
readDefaultMode,
|
|
11
|
-
resolveSessionMode,
|
|
12
|
-
writeDefaultMode,
|
|
13
|
-
} from "../index.js";
|
|
14
|
-
|
|
15
|
-
test("parsePonytailCommand falls back to full when invoked bare and default is off", () => {
|
|
16
|
-
assert.deepEqual(parsePonytailCommand("", "off"), { type: "set-mode", mode: "full" });
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
test("parsePonytailCommand parses modes, status, and default subcommand", () => {
|
|
20
|
-
assert.deepEqual(parsePonytailCommand("ultra", "full"), { type: "set-mode", mode: "ultra" });
|
|
21
|
-
assert.deepEqual(parsePonytailCommand("status", "full"), { type: "status" });
|
|
22
|
-
assert.deepEqual(parsePonytailCommand("default lite", "full"), { type: "set-default", mode: "lite" });
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test("resolveSessionMode prefers latest persisted session mode", () => {
|
|
26
|
-
const entries = [
|
|
27
|
-
{ type: "custom", customType: "ponytail-mode", data: { mode: "lite" } },
|
|
28
|
-
{ type: "custom", customType: "ponytail-mode", data: { mode: "ultra" } },
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
assert.equal(resolveSessionMode(entries, "full"), "ultra");
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
test("resolveSessionMode returns fallback when entries is not an array", () => {
|
|
35
|
-
assert.equal(resolveSessionMode(null, "ultra"), "ultra");
|
|
36
|
-
assert.equal(resolveSessionMode(undefined, "lite"), "lite");
|
|
37
|
-
assert.equal(resolveSessionMode({}, "full"), "full");
|
|
38
|
-
assert.equal(resolveSessionMode("not an array"), "full"); // DEFAULT_MODE fallback
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
test("readDefaultMode and writeDefaultMode use XDG config path", () => {
|
|
42
|
-
const tempDir = mkdtempSync(join(tmpdir(), "ponytail-config-"));
|
|
43
|
-
const previousXdg = process.env.XDG_CONFIG_HOME;
|
|
44
|
-
const previousDefault = process.env.PONYTAIL_DEFAULT_MODE;
|
|
45
|
-
const configPath = join(tempDir, "ponytail", "config.json");
|
|
46
|
-
process.env.XDG_CONFIG_HOME = tempDir;
|
|
47
|
-
delete process.env.PONYTAIL_DEFAULT_MODE;
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
assert.equal(readDefaultMode(), "full");
|
|
51
|
-
assert.equal(writeDefaultMode("ultra"), "ultra");
|
|
52
|
-
assert.equal(readDefaultMode(), "ultra");
|
|
53
|
-
assert.ok(existsSync(configPath));
|
|
54
|
-
assert.deepEqual(JSON.parse(readFileSync(configPath, "utf8")), { defaultMode: "ultra" });
|
|
55
|
-
} finally {
|
|
56
|
-
if (previousXdg === undefined) delete process.env.XDG_CONFIG_HOME;
|
|
57
|
-
else process.env.XDG_CONFIG_HOME = previousXdg;
|
|
58
|
-
if (previousDefault === undefined) delete process.env.PONYTAIL_DEFAULT_MODE;
|
|
59
|
-
else process.env.PONYTAIL_DEFAULT_MODE = previousDefault;
|
|
60
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
test("filterSkillBodyForMode keeps only requested intensity examples and rows", () => {
|
|
65
|
-
const body = `---\nname: ponytail\n---\n| **lite** | keep lite |\n| **full** | keep full |\n| **ultra** | keep ultra |\n- lite: Lite example\n- full: Full example\n- ultra: Ultra example\nOther line`;
|
|
66
|
-
|
|
67
|
-
const filtered = filterSkillBodyForMode(body, "ultra");
|
|
68
|
-
|
|
69
|
-
assert.ok(!filtered.includes("keep lite"));
|
|
70
|
-
assert.ok(!filtered.includes("keep full"));
|
|
71
|
-
assert.ok(filtered.includes("keep ultra"));
|
|
72
|
-
assert.ok(!filtered.includes("Lite example"));
|
|
73
|
-
assert.ok(filtered.includes("Ultra example"));
|
|
74
|
-
assert.ok(filtered.includes("Other line"));
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test("filterSkillBodyForMode keeps rule bullets that contain a colon", () => {
|
|
78
|
-
// Regression: rule bullets outside the Intensity section (e.g. the
|
|
79
|
-
// "No unrequested abstractions:" rule or the `ponytail:` comment convention)
|
|
80
|
-
// contain a colon and must not be mistaken for mode-example lines.
|
|
81
|
-
const skillPath = new URL("../../skills/ponytail/SKILL.md", import.meta.url);
|
|
82
|
-
const body = readFileSync(skillPath, "utf8");
|
|
83
|
-
|
|
84
|
-
const filtered = filterSkillBodyForMode(body, "full");
|
|
85
|
-
|
|
86
|
-
assert.ok(filtered.includes("No unrequested abstractions"));
|
|
87
|
-
assert.ok(filtered.includes("Mark deliberate simplifications"));
|
|
88
|
-
// The Intensity examples are still filtered down to the active mode.
|
|
89
|
-
assert.ok(filtered.includes('full: "`@lru_cache'));
|
|
90
|
-
assert.ok(!filtered.includes('lite: "Done'));
|
|
91
|
-
assert.ok(!filtered.includes('ultra: "No cache'));
|
|
92
|
-
});
|