chore: rename uwf-* → workflow-*, cli-uwf → cli-workflow

Reclaim the workflow-* package names now that legacy packages are archived.

Package renames:
- @uncaged/uwf-protocol → @uncaged/workflow-protocol
- @uncaged/uwf-moderator → @uncaged/workflow-moderator
- @uncaged/uwf-agent-kit → @uncaged/workflow-agent-kit
- @uncaged/uwf-agent-hermes → @uncaged/workflow-agent-hermes
- @uncaged/cli-uwf → @uncaged/cli-workflow

All internal imports, tsconfig references, and docs updated.
CLI binary name 'uwf' unchanged.

小橘 🍊(NEKO Team)
This commit is contained in:
2026-05-19 07:52:16 +00:00
parent 68246e20b1
commit 7b9cb6a9c8
51 changed files with 67 additions and 67 deletions
@@ -0,0 +1,126 @@
import { describe, expect, test } from "bun:test";
import { createMemoryStore, refs, validate, walk } from "@uncaged/json-cas";
import {
computeDurationMs,
extractLastAssistantContent,
messageToTurnPayload,
parseSessionIdFromStdout,
storeHermesSessionDetail,
} from "../src/session-detail.js";
import type { HermesSessionJson, HermesSessionMessage } from "../src/types.js";
describe("parseSessionIdFromStdout", () => {
test("reads session_id from the last non-empty line", () => {
const stdout = "Done.\n\nsession_id: 20260518_223724_45ab80\n";
expect(parseSessionIdFromStdout(stdout)).toBe("20260518_223724_45ab80");
});
test("reads session_id from the first line (quiet mode)", () => {
const stdout = "session_id: 20260518_165315_3467a1\nHello world\n";
expect(parseSessionIdFromStdout(stdout)).toBe("20260518_165315_3467a1");
});
test("returns null when no session_id line present", () => {
expect(parseSessionIdFromStdout("only assistant text\n")).toBeNull();
});
});
describe("messageToTurnPayload", () => {
test("maps assistant tool_calls to toolCalls", () => {
const msg: HermesSessionMessage = {
role: "assistant",
content: "",
reasoning: null,
tool_calls: [{ function: { name: "read_file", arguments: '{"path":"x"}' } }],
};
const turn = messageToTurnPayload(msg, 0);
expect(turn).toEqual({
index: 0,
role: "assistant",
content: "",
toolCalls: [{ name: "read_file", args: '{"path":"x"}' }],
reasoning: null,
});
});
test("skips user messages", () => {
const msg: HermesSessionMessage = {
role: "user",
content: "hi",
reasoning: null,
tool_calls: null,
};
expect(messageToTurnPayload(msg, 0)).toBeNull();
});
});
describe("extractLastAssistantContent", () => {
test("returns the last non-empty assistant content", () => {
const messages: HermesSessionMessage[] = [
{ role: "assistant", content: "first", reasoning: null, tool_calls: null },
{ role: "tool", content: "tool output", reasoning: null, tool_calls: null },
{ role: "assistant", content: "", reasoning: null, tool_calls: null },
{ role: "assistant", content: "final answer", reasoning: null, tool_calls: null },
];
expect(extractLastAssistantContent(messages)).toBe("final answer");
});
});
describe("computeDurationMs", () => {
test("computes elapsed time from session_start", () => {
const now = Date.parse("2026-05-18T13:32:59.028640Z");
const duration = computeDurationMs("2026-05-18T13:31:59.028640Z", now);
expect(duration).toBe(60_000);
});
});
describe("storeHermesSessionDetail", () => {
test("stores hermes-detail root with cas_ref turns walkable", async () => {
const session: HermesSessionJson = {
session_id: "20260518_133159_6a84e8",
model: "claude-opus-4.6",
session_start: "2026-05-18T13:31:59.028640",
messages: [
{ role: "user", content: "task", reasoning: null, tool_calls: null },
{
role: "assistant",
content: "",
reasoning: "thinking",
tool_calls: [{ function: { name: "terminal", arguments: "{}" } }],
},
{ role: "tool", content: "ok", reasoning: null, tool_calls: null },
{ role: "assistant", content: "done", reasoning: null, tool_calls: null },
],
};
const store = createMemoryStore();
const now = Date.parse("2026-05-18T13:32:59.028640");
const { detailHash, output } = await storeHermesSessionDetail(store, session, now);
expect(output).toBe("done");
const detailNode = store.get(detailHash);
expect(detailNode).not.toBeNull();
if (detailNode === null) {
return;
}
expect(validate(store, detailNode)).toBe(true);
expect(detailNode.payload).toMatchObject({
sessionId: "20260518_133159_6a84e8",
model: "claude-opus-4.6",
duration: 60_000,
turnCount: 3,
});
const turnRefs = refs(store, detailNode);
expect(turnRefs).toHaveLength(3);
const visited: string[] = [];
walk(store, detailHash, (hash) => visited.push(hash));
expect(visited).toContain(detailHash);
for (const turnHash of turnRefs) {
expect(visited).toContain(turnHash);
}
});
});