71 lines
3.0 KiB
TypeScript
71 lines
3.0 KiB
TypeScript
import { beforeAll, describe, expect, it } from "bun:test";
|
|
import { initTheme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
|
|
import {
|
|
containsWorkflow,
|
|
highlightWorkflow,
|
|
renderWorkflowNotice,
|
|
WORKFLOW_NOTICE,
|
|
} from "@oh-my-pi/pi-coding-agent/modes/workflow";
|
|
|
|
beforeAll(() => {
|
|
// highlightWorkflow reads the global theme's color mode.
|
|
initTheme();
|
|
});
|
|
|
|
describe("workflow keyword detection", () => {
|
|
it("matches the lowercase trigger word delimited by whitespace", () => {
|
|
expect(containsWorkflow("workflowz")).toBe(true);
|
|
expect(containsWorkflow("please workflowz this rollout")).toBe(true);
|
|
expect(containsWorkflow("design the workflowz")).toBe(true);
|
|
expect(containsWorkflow("run these workflowz")).toBe(true);
|
|
});
|
|
|
|
it("ignores old triggers, casing, inflections, punctuation-adjacent, and path-embedded forms", () => {
|
|
expect(containsWorkflow("workflow")).toBe(false);
|
|
expect(containsWorkflow("workflows")).toBe(false);
|
|
expect(containsWorkflow("Workflowz")).toBe(false);
|
|
expect(containsWorkflow("WORKFLOWZ")).toBe(false);
|
|
expect(containsWorkflow("workflowzed the build")).toBe(false);
|
|
expect(containsWorkflow("reworkflowz everything")).toBe(false);
|
|
// A path/extension is not whitespace, so the word never triggers.
|
|
expect(containsWorkflow("packages/coding-agent/test/modes/workflowz.test.ts")).toBe(false);
|
|
expect(containsWorkflow("do it. workflowz.")).toBe(false);
|
|
expect(containsWorkflow("nothing to see here")).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("workflow keyword highlighting", () => {
|
|
it("decorates the keyword with zero-width escapes, preserving visible text", () => {
|
|
const input = "please workflowz this";
|
|
const decorated = highlightWorkflow(input);
|
|
expect(decorated).not.toBe(input);
|
|
expect(decorated).toContain("\x1b");
|
|
expect(Bun.stripANSI(decorated)).toBe(input);
|
|
});
|
|
|
|
it("leaves text without the standalone keyword untouched", () => {
|
|
// Probe hits the substring but the whitespace boundary fails — no decoration.
|
|
expect(highlightWorkflow("workflowzed builds")).toBe("workflowzed builds");
|
|
expect(highlightWorkflow("Workflowz this")).toBe("Workflowz this");
|
|
const filePath = "packages/coding-agent/test/modes/workflowz.test.ts";
|
|
expect(highlightWorkflow(filePath)).toBe(filePath);
|
|
});
|
|
});
|
|
|
|
describe("workflow notice", () => {
|
|
it("is a non-empty system notice carrying the task fan-out contract", () => {
|
|
expect(WORKFLOW_NOTICE.length).toBeGreaterThan(0);
|
|
expect(WORKFLOW_NOTICE).toContain("**workflowz** keyword");
|
|
expect(WORKFLOW_NOTICE).toContain("Use the `task` tool for batched fan-out");
|
|
expect(WORKFLOW_NOTICE).toContain("tasks[]");
|
|
});
|
|
|
|
it("renders flat task-call guidance when task.batch is disabled", () => {
|
|
const notice = renderWorkflowNotice({ taskBatch: false });
|
|
expect(notice).toContain("once per independent subagent");
|
|
expect(notice).toContain("Do not pass `context` or `tasks[]`");
|
|
expect(notice).toContain("one independent task call per leaf");
|
|
expect(notice).not.toContain("Call `task` once per independent fan-out batch");
|
|
});
|
|
});
|