@workbench-ai/workbench 0.0.68 → 0.0.69

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.
Files changed (47) hide show
  1. package/dist/dev-open/client.css +416 -107
  2. package/dist/dev-open/client.js +272 -231
  3. package/dist/dev-open/fonts/ibm-plex-mono-cyrillic-400-normal.woff +0 -0
  4. package/dist/dev-open/fonts/ibm-plex-mono-cyrillic-400-normal.woff2 +0 -0
  5. package/dist/dev-open/fonts/ibm-plex-mono-cyrillic-500-normal.woff +0 -0
  6. package/dist/dev-open/fonts/ibm-plex-mono-cyrillic-500-normal.woff2 +0 -0
  7. package/dist/dev-open/fonts/ibm-plex-mono-cyrillic-600-normal.woff +0 -0
  8. package/dist/dev-open/fonts/ibm-plex-mono-cyrillic-600-normal.woff2 +0 -0
  9. package/dist/dev-open/fonts/ibm-plex-mono-cyrillic-ext-400-normal.woff +0 -0
  10. package/dist/dev-open/fonts/ibm-plex-mono-cyrillic-ext-400-normal.woff2 +0 -0
  11. package/dist/dev-open/fonts/ibm-plex-mono-cyrillic-ext-500-normal.woff +0 -0
  12. package/dist/dev-open/fonts/ibm-plex-mono-cyrillic-ext-500-normal.woff2 +0 -0
  13. package/dist/dev-open/fonts/ibm-plex-mono-cyrillic-ext-600-normal.woff +0 -0
  14. package/dist/dev-open/fonts/ibm-plex-mono-cyrillic-ext-600-normal.woff2 +0 -0
  15. package/dist/dev-open/fonts/ibm-plex-mono-latin-400-normal.woff +0 -0
  16. package/dist/dev-open/fonts/ibm-plex-mono-latin-400-normal.woff2 +0 -0
  17. package/dist/dev-open/fonts/ibm-plex-mono-latin-500-normal.woff +0 -0
  18. package/dist/dev-open/fonts/ibm-plex-mono-latin-500-normal.woff2 +0 -0
  19. package/dist/dev-open/fonts/ibm-plex-mono-latin-600-normal.woff +0 -0
  20. package/dist/dev-open/fonts/ibm-plex-mono-latin-600-normal.woff2 +0 -0
  21. package/dist/dev-open/fonts/ibm-plex-mono-latin-ext-400-normal.woff +0 -0
  22. package/dist/dev-open/fonts/ibm-plex-mono-latin-ext-400-normal.woff2 +0 -0
  23. package/dist/dev-open/fonts/ibm-plex-mono-latin-ext-500-normal.woff +0 -0
  24. package/dist/dev-open/fonts/ibm-plex-mono-latin-ext-500-normal.woff2 +0 -0
  25. package/dist/dev-open/fonts/ibm-plex-mono-latin-ext-600-normal.woff +0 -0
  26. package/dist/dev-open/fonts/ibm-plex-mono-latin-ext-600-normal.woff2 +0 -0
  27. package/dist/dev-open/fonts/ibm-plex-mono-vietnamese-400-normal.woff +0 -0
  28. package/dist/dev-open/fonts/ibm-plex-mono-vietnamese-400-normal.woff2 +0 -0
  29. package/dist/dev-open/fonts/ibm-plex-mono-vietnamese-500-normal.woff +0 -0
  30. package/dist/dev-open/fonts/ibm-plex-mono-vietnamese-500-normal.woff2 +0 -0
  31. package/dist/dev-open/fonts/ibm-plex-mono-vietnamese-600-normal.woff +0 -0
  32. package/dist/dev-open/fonts/ibm-plex-mono-vietnamese-600-normal.woff2 +0 -0
  33. package/dist/dev-open/fonts/libre-caslon-display-latin-400-normal.woff +0 -0
  34. package/dist/dev-open/fonts/libre-caslon-display-latin-400-normal.woff2 +0 -0
  35. package/dist/dev-open/fonts/libre-caslon-display-latin-ext-400-normal.woff +0 -0
  36. package/dist/dev-open/fonts/libre-caslon-display-latin-ext-400-normal.woff2 +0 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +1101 -244
  39. package/dist/install-targets.d.ts +35 -0
  40. package/dist/install-targets.d.ts.map +1 -0
  41. package/dist/install-targets.js +188 -0
  42. package/dist/open-server.d.ts.map +1 -1
  43. package/dist/open-server.js +72 -4
  44. package/dist/output.d.ts +22 -0
  45. package/dist/output.d.ts.map +1 -0
  46. package/dist/output.js +38 -0
  47. package/package.json +4 -4
@@ -0,0 +1,35 @@
1
+ import { type Json, type SurfaceSnapshotFile } from "@workbench-ai/workbench-core";
2
+ export type WorkbenchInstallAgentTarget = "codex" | "claude";
3
+ export type WorkbenchInstallTargetName = WorkbenchInstallAgentTarget | "local";
4
+ export interface WorkbenchInstallSnapshot {
5
+ name: string;
6
+ files: SurfaceSnapshotFile[];
7
+ }
8
+ export interface WorkbenchInstallTarget {
9
+ agent: WorkbenchInstallTargetName;
10
+ mode: "copy";
11
+ destination: string;
12
+ }
13
+ export interface WorkbenchInstallTargetResult extends WorkbenchInstallTarget {
14
+ previous: "none" | "overwritten" | "unchanged";
15
+ }
16
+ export interface WorkbenchInstallResult {
17
+ result: "installed" | "unchanged";
18
+ targets: WorkbenchInstallTargetResult[];
19
+ filesCopied: number;
20
+ }
21
+ export declare function supportedInstallTargets(): WorkbenchInstallTarget[];
22
+ export declare function resolveInstallTargets(options: {
23
+ agents: readonly string[];
24
+ local: boolean;
25
+ skillName: string;
26
+ }): WorkbenchInstallTarget[];
27
+ export declare function installSnapshotToTargets(options: {
28
+ snapshot: WorkbenchInstallSnapshot;
29
+ targets: readonly WorkbenchInstallTarget[];
30
+ overwrite: boolean;
31
+ dryRun: boolean;
32
+ }): Promise<WorkbenchInstallResult>;
33
+ export declare function normalizeInstallSnapshotPath(filePath: string): string;
34
+ export declare function installTargetsToJson(targets: readonly WorkbenchInstallTarget[]): Json[];
35
+ //# sourceMappingURL=install-targets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-targets.d.ts","sourceRoot":"","sources":["../src/install-targets.ts"],"names":[],"mappings":"AAIA,OAAO,EAAuB,KAAK,IAAI,EAAE,KAAK,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAExG,MAAM,MAAM,2BAA2B,GAAG,OAAO,GAAG,QAAQ,CAAC;AAC7D,MAAM,MAAM,0BAA0B,GAAG,2BAA2B,GAAG,OAAO,CAAC;AAE/E,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,mBAAmB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,0BAA0B,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,4BAA6B,SAAQ,sBAAsB;IAC1E,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,WAAW,CAAC;CAChD;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,WAAW,GAAG,WAAW,CAAC;IAClC,OAAO,EAAE,4BAA4B,EAAE,CAAC;IACxC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,uBAAuB,IAAI,sBAAsB,EAAE,CAMlE;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE;IAC7C,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,sBAAsB,EAAE,CA8B3B;AAED,wBAAsB,wBAAwB,CAAC,OAAO,EAAE;IACtD,QAAQ,EAAE,wBAAwB,CAAC;IACnC,OAAO,EAAE,SAAS,sBAAsB,EAAE,CAAC;IAC3C,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;CACjB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAyDlC;AAiBD,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAgBrE;AAyDD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,SAAS,sBAAsB,EAAE,GAAG,IAAI,EAAE,CAMvF"}
@@ -0,0 +1,188 @@
1
+ import { promises as fs } from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { WorkbenchCodedError } from "@workbench-ai/workbench-core";
5
+ export function supportedInstallTargets() {
6
+ return [
7
+ { agent: "codex", mode: "copy", destination: path.join(workbenchAgentHome("codex"), "skills", "<skill>") },
8
+ { agent: "claude", mode: "copy", destination: path.join(workbenchAgentHome("claude"), "skills", "<skill>") },
9
+ { agent: "local", mode: "copy", destination: path.join(process.cwd(), ".agents", "skills", "<skill>") },
10
+ ];
11
+ }
12
+ export function resolveInstallTargets(options) {
13
+ const targets = [];
14
+ for (const rawAgent of options.agents) {
15
+ const agent = rawAgent.trim().toLowerCase();
16
+ if (agent !== "codex" && agent !== "claude") {
17
+ throw new WorkbenchCodedError("usage", `Unsupported install agent: ${rawAgent}`, {
18
+ remediation: "Use --agent codex, --agent claude, or --local.",
19
+ exitCode: 2,
20
+ });
21
+ }
22
+ targets.push({
23
+ agent,
24
+ mode: "copy",
25
+ destination: path.join(workbenchAgentHome(agent), "skills", options.skillName),
26
+ });
27
+ }
28
+ if (options.local) {
29
+ targets.push({
30
+ agent: "local",
31
+ mode: "copy",
32
+ destination: path.join(process.cwd(), ".agents", "skills", options.skillName),
33
+ });
34
+ }
35
+ if (targets.length === 0) {
36
+ throw new WorkbenchCodedError("install_target_required", "workbench install requires an explicit target.", {
37
+ remediation: "Run workbench install --source SOURCE --agent codex, workbench install --source SOURCE --agent claude, or workbench install --source SOURCE --local.",
38
+ exitCode: 2,
39
+ });
40
+ }
41
+ return dedupeTargets(targets);
42
+ }
43
+ export async function installSnapshotToTargets(options) {
44
+ const normalizedFiles = options.snapshot.files.map((file) => ({
45
+ ...file,
46
+ path: normalizeInstallSnapshotPath(file.path),
47
+ }));
48
+ const next = new Map(normalizedFiles.map((file) => [file.path, installFileContent(file)]));
49
+ // Pre-validate every target before mutating any destination so a conflict
50
+ // on a later target cannot leave an earlier target partially installed.
51
+ const plan = [];
52
+ for (const target of options.targets) {
53
+ const existing = await readExistingTree(target.destination).catch((error) => {
54
+ const code = error.code;
55
+ if (code === "ENOENT") {
56
+ return null;
57
+ }
58
+ if (code === "ENOTDIR") {
59
+ const conflictPath = error.path ?? target.destination;
60
+ throw new WorkbenchCodedError("install_failed", `Install target path is blocked by an existing file: ${conflictPath}`, {
61
+ remediation: `Remove the conflicting file ${conflictPath} and rerun the install.`,
62
+ subject: { destination: target.destination, conflictPath },
63
+ exitCode: 1,
64
+ });
65
+ }
66
+ throw error;
67
+ });
68
+ const identical = existing ? fileMapsEqual(existing, next) : false;
69
+ if (identical) {
70
+ plan.push({ target, previous: "unchanged" });
71
+ continue;
72
+ }
73
+ if (existing && !options.overwrite) {
74
+ throw new WorkbenchCodedError("install_failed", `Install target already exists: ${target.destination}`, {
75
+ remediation: "Pass --yes to overwrite the existing target.",
76
+ subject: { destination: target.destination },
77
+ exitCode: 1,
78
+ });
79
+ }
80
+ plan.push({ target, previous: existing ? "overwritten" : "none" });
81
+ }
82
+ let filesCopied = 0;
83
+ const results = [];
84
+ for (const entry of plan) {
85
+ results.push({ ...entry.target, previous: entry.previous });
86
+ if (entry.previous === "unchanged") {
87
+ continue;
88
+ }
89
+ filesCopied += normalizedFiles.length;
90
+ if (!options.dryRun) {
91
+ await fs.rm(entry.target.destination, { recursive: true, force: true });
92
+ await writeSnapshotFiles(entry.target.destination, normalizedFiles);
93
+ }
94
+ }
95
+ return {
96
+ result: plan.some((entry) => entry.previous !== "unchanged") ? "installed" : "unchanged",
97
+ targets: results,
98
+ filesCopied,
99
+ };
100
+ }
101
+ function workbenchAgentHome(agent) {
102
+ if (agent === "codex") {
103
+ return process.env.CODEX_HOME?.trim() || path.join(os.homedir(), ".codex");
104
+ }
105
+ return process.env.CLAUDE_HOME?.trim() || path.join(os.homedir(), ".claude");
106
+ }
107
+ function dedupeTargets(targets) {
108
+ const byDestination = new Map();
109
+ for (const target of targets) {
110
+ byDestination.set(target.destination, target);
111
+ }
112
+ return [...byDestination.values()];
113
+ }
114
+ export function normalizeInstallSnapshotPath(filePath) {
115
+ const normalized = filePath.replace(/\\/gu, "/");
116
+ if (!normalized || normalized.includes("\0") || normalized.startsWith("/")) {
117
+ throw new WorkbenchCodedError("install_failed", `Invalid source file path: ${filePath}`, {
118
+ subject: { path: filePath },
119
+ exitCode: 1,
120
+ });
121
+ }
122
+ const parts = normalized.split("/");
123
+ if (parts.some((part) => part === "" || part === "." || part === "..")) {
124
+ throw new WorkbenchCodedError("install_failed", `Invalid source file path: ${filePath}`, {
125
+ subject: { path: filePath },
126
+ exitCode: 1,
127
+ });
128
+ }
129
+ return normalized;
130
+ }
131
+ function installFileContent(file) {
132
+ if (file.encoding === "base64") {
133
+ return Buffer.from(file.content, "base64");
134
+ }
135
+ return file.content;
136
+ }
137
+ async function writeSnapshotFiles(root, files) {
138
+ for (const file of files) {
139
+ const filePath = path.join(root, file.path);
140
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
141
+ await fs.writeFile(filePath, installFileContent(file));
142
+ if (file.executable) {
143
+ await fs.chmod(filePath, 0o755);
144
+ }
145
+ }
146
+ }
147
+ async function readExistingTree(root) {
148
+ const result = new Map();
149
+ await readExistingTreeInto(root, "", result);
150
+ return result;
151
+ }
152
+ async function readExistingTreeInto(root, relativeDir, result) {
153
+ const dir = path.join(root, relativeDir);
154
+ const entries = await fs.readdir(dir, { withFileTypes: true });
155
+ for (const entry of entries) {
156
+ const relativePath = relativeDir ? path.join(relativeDir, entry.name) : entry.name;
157
+ const fullPath = path.join(root, relativePath);
158
+ if (entry.isDirectory()) {
159
+ await readExistingTreeInto(root, relativePath, result);
160
+ }
161
+ else if (entry.isFile()) {
162
+ result.set(relativePath.replace(/\\/gu, "/"), await fs.readFile(fullPath));
163
+ }
164
+ }
165
+ }
166
+ function fileMapsEqual(left, right) {
167
+ if (left.size !== right.size) {
168
+ return false;
169
+ }
170
+ for (const [key, rightValue] of right) {
171
+ const leftValue = left.get(key);
172
+ if (!leftValue) {
173
+ return false;
174
+ }
175
+ const rightBuffer = Buffer.isBuffer(rightValue) ? rightValue : Buffer.from(rightValue);
176
+ if (!leftValue.equals(rightBuffer)) {
177
+ return false;
178
+ }
179
+ }
180
+ return true;
181
+ }
182
+ export function installTargetsToJson(targets) {
183
+ return targets.map((target) => ({
184
+ agent: target.agent,
185
+ mode: target.mode,
186
+ destination: target.destination,
187
+ }));
188
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"open-server.d.ts","sourceRoot":"","sources":["../src/open-server.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,+BAA+B;IAC9C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,0BAA0B;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,wBAAsB,wBAAwB,CAC5C,OAAO,GAAE,+BAAoC,GAC5C,OAAO,CAAC,0BAA0B,CAAC,CA+BrC"}
1
+ {"version":3,"file":"open-server.d.ts","sourceRoot":"","sources":["../src/open-server.ts"],"names":[],"mappings":"AAoBA,MAAM,WAAW,+BAA+B;IAC9C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,0BAA0B;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,wBAAsB,wBAAwB,CAC5C,OAAO,GAAE,+BAAoC,GAC5C,OAAO,CAAC,0BAA0B,CAAC,CA+BrC"}
@@ -2,11 +2,11 @@ import { createServer } from "node:http";
2
2
  import { promises as fs } from "node:fs";
3
3
  import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
- import { createWorkbenchInspectionSnapshot, workbenchInspectionFileContent, workbenchInspectionFileManifest, WorkbenchUserError, } from "@workbench-ai/workbench-core";
5
+ import { createWorkbenchReadOnlyInspectionSnapshot, workbenchJobEvidenceForSnapshot, workbenchInspectionFileContent, workbenchInspectionFileManifest, WorkbenchUserError, } from "@workbench-ai/workbench-core";
6
6
  export async function startWorkbenchOpenServer(options = {}) {
7
7
  const host = options.host ?? "127.0.0.1";
8
8
  const port = options.port ?? 0;
9
- const assetRoot = path.join(path.dirname(fileURLToPath(import.meta.url)), "dev-open");
9
+ const assetRoot = await resolveDevOpenAssetRoot();
10
10
  const server = createServer((request, response) => {
11
11
  void handleRequest({ request, response, assetRoot, dir: options.dir, authToken: options.authToken });
12
12
  });
@@ -36,17 +36,53 @@ export async function startWorkbenchOpenServer(options = {}) {
36
36
  }),
37
37
  };
38
38
  }
39
+ async function resolveDevOpenAssetRoot() {
40
+ const moduleDir = path.dirname(fileURLToPath(import.meta.url));
41
+ const candidates = [
42
+ path.join(moduleDir, "dev-open"),
43
+ path.join(moduleDir, "..", "dist", "dev-open"),
44
+ ];
45
+ for (const candidate of candidates) {
46
+ try {
47
+ await fs.access(path.join(candidate, "client.js"));
48
+ return candidate;
49
+ }
50
+ catch {
51
+ // Try the next source/build layout.
52
+ }
53
+ }
54
+ return candidates[0];
55
+ }
39
56
  async function handleRequest({ request, response, assetRoot, dir, authToken, }) {
40
57
  try {
41
58
  const url = new URL(request.url ?? "/", "http://workbench.local");
42
59
  if (url.pathname === "/api/snapshot") {
43
- const snapshot = await createWorkbenchInspectionSnapshot({ dir, authToken });
60
+ const snapshot = await createWorkbenchReadOnlyInspectionSnapshot({ dir, authToken });
44
61
  sendText(response, 200, `${JSON.stringify(inspectionSnapshotManifest(snapshot), null, 2)}\n`, "application/json; charset=utf-8");
45
62
  return;
46
63
  }
64
+ const jobEvidenceRoute = parseJobEvidenceApiPath(url.pathname);
65
+ if (jobEvidenceRoute) {
66
+ const runId = url.searchParams.get("run")?.trim();
67
+ if (!runId) {
68
+ sendText(response, 400, `${JSON.stringify({ message: "run is required" })}\n`, "application/json; charset=utf-8");
69
+ return;
70
+ }
71
+ const snapshot = await createWorkbenchReadOnlyInspectionSnapshot({ dir, authToken });
72
+ const detail = workbenchJobEvidenceForSnapshot(snapshot, {
73
+ runId,
74
+ jobId: jobEvidenceRoute.jobId,
75
+ });
76
+ if (!detail) {
77
+ sendText(response, 404, `${JSON.stringify({ message: "Job evidence not found" })}\n`, "application/json; charset=utf-8");
78
+ return;
79
+ }
80
+ sendText(response, 200, `${JSON.stringify(detail, null, 2)}\n`, "application/json; charset=utf-8");
81
+ return;
82
+ }
47
83
  const fileRoute = parseInspectionFileApiPath(url.pathname);
48
84
  if (fileRoute) {
49
- const snapshot = await createWorkbenchInspectionSnapshot({ dir, authToken });
85
+ const snapshot = await createWorkbenchReadOnlyInspectionSnapshot({ dir, authToken });
50
86
  const content = inspectionFileContentForSnapshot(snapshot, fileRoute);
51
87
  if (!content) {
52
88
  sendText(response, 404, `${JSON.stringify({ message: "File not found" })}\n`, "application/json; charset=utf-8");
@@ -80,6 +116,27 @@ function inspectionSnapshotManifest(snapshot) {
80
116
  ...version,
81
117
  files: inspectionFileManifests(version.files),
82
118
  })),
119
+ skillBundles: snapshot.skillBundles.map((bundle) => ({
120
+ ...bundle,
121
+ files: inspectionFileManifests(bundle.files),
122
+ })),
123
+ evals: snapshot.evals.map((evalSnapshot) => ({
124
+ ...evalSnapshot,
125
+ files: inspectionFileManifests(evalSnapshot.files),
126
+ })),
127
+ ...(snapshot.comparison ? {
128
+ comparison: {
129
+ ...snapshot.comparison,
130
+ versions: snapshot.comparison.versions.map((version) => ({
131
+ ...version,
132
+ files: inspectionFileManifests(version.files),
133
+ })),
134
+ skills: snapshot.comparison.skills.map((bundle) => ({
135
+ ...bundle,
136
+ files: inspectionFileManifests(bundle.files),
137
+ })),
138
+ },
139
+ } : {}),
83
140
  traces: snapshot.traces.map((trace) => ({
84
141
  ...trace,
85
142
  files: inspectionFileManifests(trace.files),
@@ -93,6 +150,14 @@ function inspectionSnapshotManifest(snapshot) {
93
150
  function inspectionFileManifests(files) {
94
151
  return files.map(workbenchInspectionFileManifest);
95
152
  }
153
+ function parseJobEvidenceApiPath(pathname) {
154
+ const segments = pathname.split("/").filter(Boolean).map((segment) => decodeURIComponent(segment));
155
+ const [api, jobs, jobId, evidence] = segments;
156
+ if (api !== "api" || jobs !== "jobs" || evidence !== "evidence" || !jobId || segments.length !== 4) {
157
+ return null;
158
+ }
159
+ return { jobId };
160
+ }
96
161
  function parseInspectionFileApiPath(pathname) {
97
162
  const segments = pathname.split("/").filter(Boolean).map((segment) => decodeURIComponent(segment));
98
163
  const [api, ownerKind, ownerId, files, ...filePath] = segments;
@@ -170,6 +235,9 @@ function contentType(filePath) {
170
235
  if (filePath.endsWith(".woff2")) {
171
236
  return "font/woff2";
172
237
  }
238
+ if (filePath.endsWith(".woff")) {
239
+ return "font/woff";
240
+ }
173
241
  return "application/octet-stream";
174
242
  }
175
243
  function displayHost(host) {
@@ -0,0 +1,22 @@
1
+ import { type Json } from "@workbench-ai/workbench-core";
2
+ import type { CliIo } from "./index.js";
3
+ export interface ParsedCliFlags {
4
+ flags: Record<string, string | boolean | string[]>;
5
+ }
6
+ export interface WorkbenchCliSuccessEnvelope {
7
+ schema: string;
8
+ ok: true;
9
+ [key: string]: Json | undefined;
10
+ }
11
+ export interface WorkbenchCliErrorEnvelope {
12
+ schema: "workbench.cli.error.v1";
13
+ ok: false;
14
+ code: string;
15
+ message: string;
16
+ retryable: boolean;
17
+ remediation?: string;
18
+ subject?: Record<string, Json>;
19
+ }
20
+ export declare function emitResult(schema: string, body: Record<string, Json | undefined>, parsed: ParsedCliFlags, io: CliIo, text: () => string): number;
21
+ export declare function emitError(error: unknown, parsed: ParsedCliFlags, io: CliIo): number;
22
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,IAAI,EAAE,MAAM,8BAA8B,CAAC;AAEhF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,CAAC,CAAC;CACpD;AAED,MAAM,WAAW,2BAA2B;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,IAAI,CAAC;IACT,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACjC;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,wBAAwB,CAAC;IACjC,EAAE,EAAE,KAAK,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;CAChC;AAED,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,GAAG,SAAS,CAAC,EACtC,MAAM,EAAE,cAAc,EACtB,EAAE,EAAE,KAAK,EACT,IAAI,EAAE,MAAM,MAAM,GACjB,MAAM,CAaR;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,EAAE,KAAK,GAAG,MAAM,CAoBnF"}
package/dist/output.js ADDED
@@ -0,0 +1,38 @@
1
+ import { codedErrorFromUnknown } from "@workbench-ai/workbench-core";
2
+ export function emitResult(schema, body, parsed, io, text) {
3
+ if (parsed.flags.json === true) {
4
+ const envelope = { schema, ok: true };
5
+ for (const [key, value] of Object.entries(body)) {
6
+ if (value !== undefined) {
7
+ envelope[key] = value;
8
+ }
9
+ }
10
+ io.stdout.write(`${JSON.stringify(envelope, null, 2)}\n`);
11
+ }
12
+ else {
13
+ io.stdout.write(`${text()}\n`);
14
+ }
15
+ return 0;
16
+ }
17
+ export function emitError(error, parsed, io) {
18
+ const coded = codedErrorFromUnknown(error);
19
+ const envelope = {
20
+ schema: "workbench.cli.error.v1",
21
+ ok: false,
22
+ code: coded.code,
23
+ message: coded.message,
24
+ retryable: coded.retryable,
25
+ ...(coded.remediation ? { remediation: coded.remediation } : {}),
26
+ ...(coded.subject ? { subject: coded.subject } : {}),
27
+ };
28
+ if (parsed.flags.json === true) {
29
+ io.stdout.write(`${JSON.stringify(envelope, null, 2)}\n`);
30
+ }
31
+ else {
32
+ io.stderr.write(`error[${envelope.code}]: ${envelope.message}\n`);
33
+ if (envelope.remediation) {
34
+ io.stderr.write(`next: ${envelope.remediation}\n`);
35
+ }
36
+ }
37
+ return coded.exitCode;
38
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workbench-ai/workbench",
3
- "version": "0.0.68",
3
+ "version": "0.0.69",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/workbench-ai/workbench.git",
@@ -21,9 +21,9 @@
21
21
  ],
22
22
  "dependencies": {
23
23
  "yaml": "^2.8.2",
24
- "@workbench-ai/workbench-core": "0.0.68",
25
- "@workbench-ai/workbench-built-in-adapters": "0.0.68",
26
- "@workbench-ai/workbench-protocol": "0.0.68"
24
+ "@workbench-ai/workbench-built-in-adapters": "0.0.69",
25
+ "@workbench-ai/workbench-protocol": "0.0.69",
26
+ "@workbench-ai/workbench-core": "0.0.69"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@tailwindcss/postcss": "^4.2.2",