Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/product-name-audit.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ git grep -n -i -E 'kapi|ilchul' -- ':!package-lock.json' ':!node_modules'
- CLI worker/runtime helper import paths no longer use `kapi-*` filenames for generic runtime observation, worker event formatting, or GitHub issue context probing.
- Application service implementation import paths no longer use `kapi-*` filenames for the generic workflow service and local service factory.
- The local service factory export uses the semantic `createLocalWorkflowService` name instead of `createLocalKapiService`.
- Presentation helper exports use semantic workflow/tool names for generic helpers (`WorkflowToolDefinition`, `shouldBlockWorkflowToolCall`, `formatWorkflowError`).

## Residual scan after service filename rename

Expand Down
6 changes: 3 additions & 3 deletions src/presentation/command-ui-actions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { isTerminalStatus } from "../domain/state-machine.js";
import type { KapiUiActionContext } from "./tool-core-types.js";
import { formatKapiError, labelLatestSessionEntry, resumeUiState, updateUi } from "./ui.js";
import { formatWorkflowError, labelLatestSessionEntry, resumeUiState, updateUi } from "./ui.js";

interface CommandErrorInput extends KapiUiActionContext {
command: string;
Expand All @@ -9,10 +9,10 @@ interface CommandErrorInput extends KapiUiActionContext {
}

export async function notifyCommandError(input: CommandErrorInput): Promise<void> {
const message = formatKapiError(input.error);
const message = formatWorkflowError(input.error);
input.pi.appendEntry("kapi-workflow", { event: "error", command: input.command, message, ...(input.details ?? {}) });
updateUi(input.ctx, await input.service.getActiveStatus(input.ctx.cwd));
input.ctx.ui.notify(message, "error");
}

export { formatKapiError, isTerminalStatus, labelLatestSessionEntry, resumeUiState, updateUi };
export { formatWorkflowError, isTerminalStatus, labelLatestSessionEntry, resumeUiState, updateUi };
2 changes: 1 addition & 1 deletion src/presentation/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ export function isUnsafeReviewShellCommand(command: string): boolean {
);
}

export function shouldBlockKapiToolCall(_state: unknown, _event: unknown): { block: true; reason: string } | undefined {
export function shouldBlockWorkflowToolCall(_state: unknown, _event: unknown): { block: true; reason: string } | undefined {
return undefined;
}
4 changes: 2 additions & 2 deletions src/presentation/tool-ui-actions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { isTerminalStatus, type ExtensionAPI, type ExtensionContext, type KapiService, type WorkflowState } from "./ui-support.js";
import { formatKapiError, labelLatestSessionEntry, resumeUiState, updateUi } from "./ui.js";
import { formatWorkflowError, labelLatestSessionEntry, resumeUiState, updateUi } from "./ui.js";

export { formatKapiError };
export { formatWorkflowError };

export function labelToolWorkflow(pi: ExtensionAPI, ctx: ExtensionContext, state: WorkflowState, prefix: string): void {
labelLatestSessionEntry(pi, ctx, `${prefix}:${state.workflowId}/${state.slug}`);
Expand Down
8 changes: 4 additions & 4 deletions src/presentation/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import type { WorkflowState } from "../domain/types.js";
import { getWorkflowDefinition } from "../domain/workflows.js";
import { formatArtifactList, formatArtifactReadResult, formatEvidenceList, formatStatus, formatValidationReport, formatWorkerCapabilities, formatWorkerList, formatWorkerPlan, formatWorkflowCatalog, formatWorkflowContract, formatWorkflowList } from "./tool-formatters.js";
import { evidenceKindSchema, evidenceSchemaFields, optionalTargetParameters, pickEvidenceParams, statusSchema, Type, workflowSchema, type EvidenceParams } from "./tool-inputs.js";
import { formatKapiError, labelToolWorkflow, updateToolUi, updateUiForResumeTool, updateUiForWorkflowPatch } from "./tool-ui-actions.js";
import { formatWorkflowError, labelToolWorkflow, updateToolUi, updateUiForResumeTool, updateUiForWorkflowPatch } from "./tool-ui-actions.js";

type KapiToolDefinition = Parameters<ExtensionAPI["registerTool"]>[0];
type WorkflowToolDefinition = Parameters<ExtensionAPI["registerTool"]>[0];
type StartWorkflowToolParams = Omit<StartWorkflowInput, "workspace">;
type ArtifactWriteParams = Omit<WriteArtifactInput, "workspace">;

Expand Down Expand Up @@ -69,7 +69,7 @@ interface ToolErrorRequest extends KapiUiActionContext {
}

async function kapiToolError(request: ToolErrorRequest): Promise<AgentToolResult<unknown>> {
const message = formatKapiError(request.error);
const message = formatWorkflowError(request.error);
request.pi.appendEntry("kapi-workflow", { event: "tool-error", tool: request.tool, message, ...(request.details ?? {}) });
updateToolUi(request.ctx, await request.service.getActiveStatus(request.ctx.cwd));
return {
Expand All @@ -79,7 +79,7 @@ async function kapiToolError(request: ToolErrorRequest): Promise<AgentToolResult
}

export function registerKapiTools(pi: ExtensionAPI, service: KapiService): void {
const startWorkflowTool: KapiToolDefinition = {
const startWorkflowTool: WorkflowToolDefinition = {
name: "kapi_start_workflow",
label: "Kapi Start Workflow",
description: "Start an explicit Kapi workflow and create its shared state/artifacts.",
Expand Down
2 changes: 1 addition & 1 deletion src/presentation/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function labelLatestSessionEntry(pi: ExtensionAPI, ctx: ExtensionContext,
if (latest) pi.setLabel(latest.id, label);
}

export function formatKapiError(error: unknown): string {
export function formatWorkflowError(error: unknown): string {
const message = error instanceof Error ? error.message : String(error);
return `Kapi action failed: ${message}`;
}
Expand Down
8 changes: 8 additions & 0 deletions test/architecture.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ test("local service factory exports use semantic workflow names", async () => {
assert.match(source, /createLocalWorkflowService/);
});

test("presentation helper exports avoid product-prefixed generic names", async () => {
const presentation = await readTsFiles(path.join(process.cwd(), "src", "presentation"));
assert.doesNotMatch(presentation, /KapiToolDefinition|shouldBlockKapiToolCall|formatKapiError/);
assert.match(presentation, /WorkflowToolDefinition/);
assert.match(presentation, /shouldBlockWorkflowToolCall/);
assert.match(presentation, /formatWorkflowError/);
});

test("domain layer stays independent from Pi, filesystem, tmux, git commands, and process adapters", async () => {
const domain = await readTsFiles(path.join(process.cwd(), "src", "domain"));
assert.doesNotMatch(domain, /@mariozechner/);
Expand Down
10 changes: 5 additions & 5 deletions test/hook-policy.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import assert from "node:assert/strict";
import { test } from "node:test";
import { isUnsafeReviewShellCommand, shouldBlockKapiToolCall } from "../src/presentation/hooks.js";
import { isUnsafeReviewShellCommand, shouldBlockWorkflowToolCall } from "../src/presentation/hooks.js";
import type { WorkflowState } from "../src/domain/types.js";

function state(overrides: Partial<WorkflowState>): WorkflowState {
Expand Down Expand Up @@ -28,10 +28,10 @@ function state(overrides: Partial<WorkflowState>): WorkflowState {

test("durable Ralph hook policy does not inherit removed review/red edit blockers", () => {
const ralph = state({ phase: "build" });
assert.equal(shouldBlockKapiToolCall(ralph, { toolName: "edit" }), undefined);
assert.equal(shouldBlockKapiToolCall(ralph, { toolName: "write", path: "src/example.ts" }), undefined);
assert.equal(shouldBlockKapiToolCall(ralph, { toolName: "bash", command: "rm -rf dist" }), undefined);
assert.equal(shouldBlockKapiToolCall(ralph, { toolName: "bash", command: "git diff -- src/example.ts" }), undefined);
assert.equal(shouldBlockWorkflowToolCall(ralph, { toolName: "edit" }), undefined);
assert.equal(shouldBlockWorkflowToolCall(ralph, { toolName: "write", path: "src/example.ts" }), undefined);
assert.equal(shouldBlockWorkflowToolCall(ralph, { toolName: "bash", command: "rm -rf dist" }), undefined);
assert.equal(shouldBlockWorkflowToolCall(ralph, { toolName: "bash", command: "git diff -- src/example.ts" }), undefined);
});

test("unsafe shell classifier still identifies mutating review-style shell commands", () => {
Expand Down
Loading