@sapiom/harness 0.1.5 → 0.2.0
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/CHANGELOG.md +151 -0
- package/dist/cli/args.d.ts +16 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +80 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/bin.js +30 -66
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/consent.js +1 -1
- package/dist/cli/settings.d.ts.map +1 -1
- package/dist/cli/settings.js +33 -1
- package/dist/cli/settings.js.map +1 -1
- package/dist/core/adapters/adapter.d.ts +2 -2
- package/dist/core/adapters/claude-code.d.ts +60 -2
- package/dist/core/adapters/claude-code.d.ts.map +1 -1
- package/dist/core/adapters/claude-code.js +119 -32
- package/dist/core/adapters/claude-code.js.map +1 -1
- package/dist/core/adapters/codex.d.ts +21 -2
- package/dist/core/adapters/codex.d.ts.map +1 -1
- package/dist/core/adapters/codex.js +53 -2
- package/dist/core/adapters/codex.js.map +1 -1
- package/dist/core/adapters/detect.d.ts +9 -0
- package/dist/core/adapters/detect.d.ts.map +1 -1
- package/dist/core/adapters/detect.js +9 -0
- package/dist/core/adapters/detect.js.map +1 -1
- package/dist/core/api-key-provider.d.ts +79 -0
- package/dist/core/api-key-provider.d.ts.map +1 -0
- package/dist/core/api-key-provider.js +91 -0
- package/dist/core/api-key-provider.js.map +1 -0
- package/dist/core/canvas-body.d.ts +28 -28
- package/dist/core/canvas-body.d.ts.map +1 -1
- package/dist/core/canvas-body.js +117 -55
- package/dist/core/canvas-body.js.map +1 -1
- package/dist/core/canvas-derive.d.ts +43 -0
- package/dist/core/canvas-derive.d.ts.map +1 -0
- package/dist/core/canvas-derive.js +95 -0
- package/dist/core/canvas-derive.js.map +1 -0
- package/dist/core/canvas-enrichment.d.ts +52 -127
- package/dist/core/canvas-enrichment.d.ts.map +1 -1
- package/dist/core/canvas-enrichment.js +17 -178
- package/dist/core/canvas-enrichment.js.map +1 -1
- package/dist/core/canvas-graph.d.ts +40 -1
- package/dist/core/canvas-graph.d.ts.map +1 -1
- package/dist/core/canvas-graph.js +71 -9
- package/dist/core/canvas-graph.js.map +1 -1
- package/dist/core/canvas-interconnections.d.ts +26 -8
- package/dist/core/canvas-interconnections.d.ts.map +1 -1
- package/dist/core/canvas-interconnections.js +132 -24
- package/dist/core/canvas-interconnections.js.map +1 -1
- package/dist/core/canvas-manifest-check.d.ts.map +1 -1
- package/dist/core/canvas-manifest-check.js +15 -2
- package/dist/core/canvas-manifest-check.js.map +1 -1
- package/dist/core/canvas-render.d.ts +8 -15
- package/dist/core/canvas-render.d.ts.map +1 -1
- package/dist/core/canvas-render.js +29 -41
- package/dist/core/canvas-render.js.map +1 -1
- package/dist/core/canvas-run-state.d.ts +50 -5
- package/dist/core/canvas-run-state.d.ts.map +1 -1
- package/dist/core/canvas-run-state.js +176 -11
- package/dist/core/canvas-run-state.js.map +1 -1
- package/dist/core/canvas-svg.d.ts +9 -4
- package/dist/core/canvas-svg.d.ts.map +1 -1
- package/dist/core/canvas-svg.js +84 -13
- package/dist/core/canvas-svg.js.map +1 -1
- package/dist/core/canvas-template.d.ts +9 -10
- package/dist/core/canvas-template.d.ts.map +1 -1
- package/dist/core/canvas-template.js +57 -20
- package/dist/core/canvas-template.js.map +1 -1
- package/dist/core/canvas-watcher.d.ts +22 -1
- package/dist/core/canvas-watcher.d.ts.map +1 -1
- package/dist/core/canvas-watcher.js +111 -30
- package/dist/core/canvas-watcher.js.map +1 -1
- package/dist/core/collector/normalizer.d.ts +8 -0
- package/dist/core/collector/normalizer.d.ts.map +1 -1
- package/dist/core/collector/normalizer.js +8 -0
- package/dist/core/collector/normalizer.js.map +1 -1
- package/dist/core/collector/store.d.ts +75 -1
- package/dist/core/collector/store.d.ts.map +1 -1
- package/dist/core/collector/store.js +334 -2
- package/dist/core/collector/store.js.map +1 -1
- package/dist/core/definition-slug-resolver.d.ts +13 -0
- package/dist/core/definition-slug-resolver.d.ts.map +1 -1
- package/dist/core/definition-slug-resolver.js +29 -0
- package/dist/core/definition-slug-resolver.js.map +1 -1
- package/dist/core/errors.d.ts +10 -4
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +11 -5
- package/dist/core/errors.js.map +1 -1
- package/dist/core/example-seed.d.ts +8 -0
- package/dist/core/example-seed.d.ts.map +1 -1
- package/dist/core/example-seed.js +47 -10
- package/dist/core/example-seed.js.map +1 -1
- package/dist/core/inject/system-prompt.d.ts +8 -0
- package/dist/core/inject/system-prompt.d.ts.map +1 -1
- package/dist/core/inject/system-prompt.js +3 -1
- package/dist/core/inject/system-prompt.js.map +1 -1
- package/dist/core/macros.d.ts.map +1 -1
- package/dist/core/macros.js +5 -6
- package/dist/core/macros.js.map +1 -1
- package/dist/core/paths.d.ts +1 -0
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/paths.js +1 -0
- package/dist/core/paths.js.map +1 -1
- package/dist/core/record-archive.d.ts +187 -0
- package/dist/core/record-archive.d.ts.map +1 -0
- package/dist/core/record-archive.js +465 -0
- package/dist/core/record-archive.js.map +1 -0
- package/dist/core/rehydration.d.ts +72 -0
- package/dist/core/rehydration.d.ts.map +1 -0
- package/dist/core/rehydration.js +72 -0
- package/dist/core/rehydration.js.map +1 -0
- package/dist/core/render-local-run.d.ts +82 -0
- package/dist/core/render-local-run.d.ts.map +1 -0
- package/dist/core/render-local-run.js +105 -0
- package/dist/core/render-local-run.js.map +1 -0
- package/dist/core/render-log-slice.d.ts +30 -0
- package/dist/core/render-log-slice.d.ts.map +1 -0
- package/dist/core/render-log-slice.js +49 -0
- package/dist/core/render-log-slice.js.map +1 -0
- package/dist/core/render-run-state.d.ts.map +1 -1
- package/dist/core/render-run-state.js +30 -49
- package/dist/core/render-run-state.js.map +1 -1
- package/dist/core/resume-brief.d.ts +130 -0
- package/dist/core/resume-brief.d.ts.map +1 -0
- package/dist/core/resume-brief.js +404 -0
- package/dist/core/resume-brief.js.map +1 -0
- package/dist/core/rolling-summary.d.ts +130 -0
- package/dist/core/rolling-summary.d.ts.map +1 -0
- package/dist/core/rolling-summary.js +227 -0
- package/dist/core/rolling-summary.js.map +1 -0
- package/dist/core/run-local-bootstrap.d.ts +93 -0
- package/dist/core/run-local-bootstrap.d.ts.map +1 -0
- package/dist/core/run-local-bootstrap.js +155 -0
- package/dist/core/run-local-bootstrap.js.map +1 -0
- package/dist/core/run-state.d.ts +16 -1
- package/dist/core/run-state.d.ts.map +1 -1
- package/dist/core/run-state.js +75 -25
- package/dist/core/run-state.js.map +1 -1
- package/dist/core/session-manager.d.ts +11 -3
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +56 -7
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-record.d.ts +165 -0
- package/dist/core/session-record.d.ts.map +1 -0
- package/dist/core/session-record.js +470 -0
- package/dist/core/session-record.js.map +1 -0
- package/dist/core/spawn-target.d.ts +12 -0
- package/dist/core/spawn-target.d.ts.map +1 -0
- package/dist/core/spawn-target.js +187 -0
- package/dist/core/spawn-target.js.map +1 -0
- package/dist/core/stub-feedback.d.ts +52 -0
- package/dist/core/stub-feedback.d.ts.map +1 -0
- package/dist/core/stub-feedback.js +33 -0
- package/dist/core/stub-feedback.js.map +1 -0
- package/dist/core/task-manager.d.ts.map +1 -1
- package/dist/core/task-manager.js +9 -1
- package/dist/core/task-manager.js.map +1 -1
- package/dist/core/template-catalog.d.ts +48 -0
- package/dist/core/template-catalog.d.ts.map +1 -0
- package/dist/core/template-catalog.js +338 -0
- package/dist/core/template-catalog.js.map +1 -0
- package/dist/core/workflow-registry.d.ts.map +1 -1
- package/dist/core/workflow-registry.js +2 -2
- package/dist/core/workflow-registry.js.map +1 -1
- package/dist/core/workspace-watcher.d.ts.map +1 -1
- package/dist/core/workspace-watcher.js +4 -3
- package/dist/core/workspace-watcher.js.map +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -1
- package/dist/profiles/default.d.ts.map +1 -1
- package/dist/profiles/default.js +9 -14
- package/dist/profiles/default.js.map +1 -1
- package/dist/server/actions.d.ts +139 -0
- package/dist/server/actions.d.ts.map +1 -0
- package/dist/server/actions.js +430 -0
- package/dist/server/actions.js.map +1 -0
- package/dist/server/auth-routes.d.ts +92 -0
- package/dist/server/auth-routes.d.ts.map +1 -0
- package/dist/server/auth-routes.js +151 -0
- package/dist/server/auth-routes.js.map +1 -0
- package/dist/server/canvas.d.ts.map +1 -1
- package/dist/server/canvas.js +7 -7
- package/dist/server/canvas.js.map +1 -1
- package/dist/server/fs.d.ts.map +1 -1
- package/dist/server/fs.js +17 -1
- package/dist/server/fs.js.map +1 -1
- package/dist/server/index.d.ts +12 -3
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +0 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/ingest.d.ts +11 -0
- package/dist/server/ingest.d.ts.map +1 -1
- package/dist/server/ingest.js +1 -0
- package/dist/server/ingest.js.map +1 -1
- package/dist/server/macros.d.ts +4 -6
- package/dist/server/macros.d.ts.map +1 -1
- package/dist/server/macros.js.map +1 -1
- package/dist/server/rest.d.ts +18 -6
- package/dist/server/rest.d.ts.map +1 -1
- package/dist/server/rest.js +185 -50
- package/dist/server/rest.js.map +1 -1
- package/dist/server/runs.d.ts +16 -15
- package/dist/server/runs.d.ts.map +1 -1
- package/dist/server/runs.js +15 -80
- package/dist/server/runs.js.map +1 -1
- package/dist/server/static.d.ts +15 -1
- package/dist/server/static.d.ts.map +1 -1
- package/dist/server/static.js +54 -4
- package/dist/server/static.js.map +1 -1
- package/dist/server/templates.d.ts +24 -0
- package/dist/server/templates.d.ts.map +1 -0
- package/dist/server/templates.js +54 -0
- package/dist/server/templates.js.map +1 -0
- package/dist/shared/types.d.ts +558 -66
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/shared/types.js +19 -11
- package/dist/shared/types.js.map +1 -1
- package/dist/web/assets/index-DC65cskq.js +446 -0
- package/dist/web/assets/index-xtD-3FFa.css +32 -0
- package/dist/web/canvas/sess-boot/index.html +305 -0
- package/dist/web/index.html +4 -9
- package/package.json +8 -4
- package/dist/core/canvas-enrich.d.ts +0 -115
- package/dist/core/canvas-enrich.d.ts.map +0 -1
- package/dist/core/canvas-enrich.js +0 -186
- package/dist/core/canvas-enrich.js.map +0 -1
- package/dist/core/run-spend.d.ts +0 -55
- package/dist/core/run-spend.d.ts.map +0 -1
- package/dist/core/run-spend.js +0 -109
- package/dist/core/run-spend.js.map +0 -1
- package/dist/core/run-transactions.d.ts +0 -60
- package/dist/core/run-transactions.d.ts.map +0 -1
- package/dist/core/run-transactions.js +0 -129
- package/dist/core/run-transactions.js.map +0 -1
- package/dist/profiles/canvas-guidelines.d.ts +0 -20
- package/dist/profiles/canvas-guidelines.d.ts.map +0 -1
- package/dist/profiles/canvas-guidelines.js +0 -48
- package/dist/profiles/canvas-guidelines.js.map +0 -1
- package/dist/server/skills.d.ts +0 -51
- package/dist/server/skills.d.ts.map +0 -1
- package/dist/server/skills.js +0 -312
- package/dist/server/skills.js.map +0 -1
- package/dist/web/assets/index-DM84J83Y.js +0 -234
- package/dist/web/assets/index-DemtWW4L.css +0 -32
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* run-transactions — fetches the per-call cost drill-down for an execution
|
|
3
|
-
* from the core surface and maps it to a {@link RunCall}[] the canvas shows
|
|
4
|
-
* when a user clicks a step and asks "why is this costly".
|
|
5
|
-
*
|
|
6
|
-
* WHY this exists alongside run-spend: `/spend` gives per-STEP aggregates
|
|
7
|
-
* (totalUsd + entryCount). This endpoint itemises the individual billable
|
|
8
|
-
* capability calls that make up that total (e.g. "renderPdfs $7.95 = 1 sandbox
|
|
9
|
-
* call"), which is what makes the debug macros actionable.
|
|
10
|
-
*
|
|
11
|
-
* WHY provider-agnostic: the raw upstream service name (the provider) is mapped
|
|
12
|
-
* to a generic capability label here, server-side, so the browser never
|
|
13
|
-
* receives — and this open-source file never hard-codes — a provider or model
|
|
14
|
-
* name. See the capability-label heuristic below (keyed on generic op/resource
|
|
15
|
-
* tokens, never a brand).
|
|
16
|
-
*
|
|
17
|
-
* WHY the key stays server-side: identical rationale to run-state / run-spend —
|
|
18
|
-
* the Sapiom API key is a harness credential that must never reach the browser.
|
|
19
|
-
*/
|
|
20
|
-
import { resolveCoreBaseUrl } from "./run-spend.js";
|
|
21
|
-
/**
|
|
22
|
-
* Map a raw upstream operation/resource to a provider-agnostic capability
|
|
23
|
-
* label. Keyed ONLY on generic tokens (message / sandbox / search) and the
|
|
24
|
-
* operation verb — deliberately never on a provider/brand name, so this file
|
|
25
|
-
* stays clean of internal service names and the label is stable if the
|
|
26
|
-
* underlying provider is swapped. Unknown shapes fall back to the operation
|
|
27
|
-
* verb, which is itself generic ("create", "execute", …).
|
|
28
|
-
*/
|
|
29
|
-
export function capabilityLabel(op, resource) {
|
|
30
|
-
const r = (resource ?? "").toLowerCase();
|
|
31
|
-
if (op === "generate" || r.includes("message") || r.includes("completion")) {
|
|
32
|
-
return "LLM";
|
|
33
|
-
}
|
|
34
|
-
if (r.includes("sandbox"))
|
|
35
|
-
return "sandbox";
|
|
36
|
-
if (r.includes("search"))
|
|
37
|
-
return "web search";
|
|
38
|
-
return op || "capability";
|
|
39
|
-
}
|
|
40
|
-
/** Sum the active, non-estimate captured USD across a transaction's cost rows. */
|
|
41
|
-
function activeCapturedUsd(costs) {
|
|
42
|
-
let total = 0;
|
|
43
|
-
for (const c of costs) {
|
|
44
|
-
const cost = c;
|
|
45
|
-
if (cost.isActive === true && cost.isEstimate === false) {
|
|
46
|
-
const n = Number(cost.fiatAmount);
|
|
47
|
-
if (Number.isFinite(n))
|
|
48
|
-
total += n;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return total;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Create a fetcher that resolves an execution's per-call cost breakdown from
|
|
55
|
-
* the core transactions endpoint. Like the spend fetcher, it is intentionally
|
|
56
|
-
* non-throwing: every error path returns a typed {@link RunCallsResult} with
|
|
57
|
-
* `ok: false` so the router forwards the status without a try/catch.
|
|
58
|
-
*
|
|
59
|
-
* Only BILLABLE calls are returned (active captured USD > 0) — the free
|
|
60
|
-
* `workflows` orchestration rows are dropped as noise. Each call is attributed
|
|
61
|
-
* to `metadata.workflowStepName ?? actionName` so the canvas can match it to a
|
|
62
|
-
* step node.
|
|
63
|
-
*/
|
|
64
|
-
export function createRunTransactionsFetcher(opts) {
|
|
65
|
-
const { apiKey, baseUrl = resolveCoreBaseUrl(), fetchImpl = fetch } = opts;
|
|
66
|
-
return {
|
|
67
|
-
async fetch(executionId) {
|
|
68
|
-
if (!apiKey) {
|
|
69
|
-
return {
|
|
70
|
-
ok: false,
|
|
71
|
-
status: 503,
|
|
72
|
-
error: "harness is not signed in to Sapiom",
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
// filter[trace_external_id] == the workflow execution id; page[limit] is
|
|
76
|
-
// the endpoint's pagination knob (NOT `limit`/`page[size]`, which 400).
|
|
77
|
-
const url = `${baseUrl}/v1/transactions` +
|
|
78
|
-
`?filter[trace_external_id]=${encodeURIComponent(executionId)}` +
|
|
79
|
-
`&page[limit]=100`;
|
|
80
|
-
let res;
|
|
81
|
-
try {
|
|
82
|
-
res = await fetchImpl(url, { headers: { "x-api-key": apiKey } });
|
|
83
|
-
}
|
|
84
|
-
catch {
|
|
85
|
-
return { ok: false, status: 502, error: "gateway unreachable" };
|
|
86
|
-
}
|
|
87
|
-
if (res.status === 404) {
|
|
88
|
-
return { ok: false, status: 404, error: "transactions not found" };
|
|
89
|
-
}
|
|
90
|
-
if (!res.ok) {
|
|
91
|
-
return {
|
|
92
|
-
ok: false,
|
|
93
|
-
status: 502,
|
|
94
|
-
error: `gateway responded ${res.status}`,
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
try {
|
|
98
|
-
const body = (await res.json());
|
|
99
|
-
const rows = Array.isArray(body.data) ? body.data : [];
|
|
100
|
-
const calls = [];
|
|
101
|
-
for (const row of rows) {
|
|
102
|
-
const t = row;
|
|
103
|
-
const costs = Array.isArray(t.costs) ? t.costs : [];
|
|
104
|
-
const usd = activeCapturedUsd(costs);
|
|
105
|
-
if (usd <= 0)
|
|
106
|
-
continue; // billable calls only — drop free orchestration
|
|
107
|
-
const op = typeof t.actionName === "string" ? t.actionName : "";
|
|
108
|
-
const resource = typeof t.resourceName === "string" ? t.resourceName : "";
|
|
109
|
-
const metadata = t.metadata ?? {};
|
|
110
|
-
const stepName = (typeof metadata.workflowStepName === "string" &&
|
|
111
|
-
metadata.workflowStepName) ||
|
|
112
|
-
op ||
|
|
113
|
-
"unknown";
|
|
114
|
-
calls.push({
|
|
115
|
-
stepName,
|
|
116
|
-
capability: capabilityLabel(op, resource),
|
|
117
|
-
op,
|
|
118
|
-
usd: usd.toFixed(6),
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
return { ok: true, calls };
|
|
122
|
-
}
|
|
123
|
-
catch {
|
|
124
|
-
return { ok: false, status: 502, error: "could not decode transactions" };
|
|
125
|
-
}
|
|
126
|
-
},
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
//# sourceMappingURL=run-transactions.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"run-transactions.js","sourceRoot":"","sources":["../../src/core/run-transactions.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Canvas style contract: injected everywhere an agent is asked to write to
|
|
3
|
-
* `.sapiom/canvas/index.html` (the Visualize macro's inject text, and the
|
|
4
|
-
* system prompt's canvas paragraph for freeform "show me X" asks), so every
|
|
5
|
-
* generated canvas looks Sapiom-native regardless of which prompt triggered
|
|
6
|
-
* it. Kept prompt-sized on purpose — this rides in prompts, not docs.
|
|
7
|
-
*
|
|
8
|
-
* Colors are the harness's own dark-theme tokens (web/src/styles.css,
|
|
9
|
-
* `[data-theme="dark"]`) — dark is the canonical canvas look. Structural
|
|
10
|
-
* conventions (rounded nodes with a uniform glow, straight-then-curved
|
|
11
|
-
* arrowed edges, stats header, legend footer) mirror what
|
|
12
|
-
* scripts/seed-example.mjs's reference canvas already renders; this doesn't
|
|
13
|
-
* change that seed, just documents its pattern for agents generating new
|
|
14
|
-
* ones. Edge/glow/legend wording tightened after a live Visualize proof
|
|
15
|
-
* (see PR history) surfaced ambiguities two different agent runs resolved
|
|
16
|
-
* inconsistently — see git blame for the before/after if the wording here
|
|
17
|
-
* ever seems oddly specific.
|
|
18
|
-
*/
|
|
19
|
-
export declare const CANVAS_STYLE_GUIDELINES: string;
|
|
20
|
-
//# sourceMappingURL=canvas-guidelines.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"canvas-guidelines.d.ts","sourceRoot":"","sources":["../../src/profiles/canvas-guidelines.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,uBAAuB,QA4B5B,CAAC"}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Canvas style contract: injected everywhere an agent is asked to write to
|
|
3
|
-
* `.sapiom/canvas/index.html` (the Visualize macro's inject text, and the
|
|
4
|
-
* system prompt's canvas paragraph for freeform "show me X" asks), so every
|
|
5
|
-
* generated canvas looks Sapiom-native regardless of which prompt triggered
|
|
6
|
-
* it. Kept prompt-sized on purpose — this rides in prompts, not docs.
|
|
7
|
-
*
|
|
8
|
-
* Colors are the harness's own dark-theme tokens (web/src/styles.css,
|
|
9
|
-
* `[data-theme="dark"]`) — dark is the canonical canvas look. Structural
|
|
10
|
-
* conventions (rounded nodes with a uniform glow, straight-then-curved
|
|
11
|
-
* arrowed edges, stats header, legend footer) mirror what
|
|
12
|
-
* scripts/seed-example.mjs's reference canvas already renders; this doesn't
|
|
13
|
-
* change that seed, just documents its pattern for agents generating new
|
|
14
|
-
* ones. Edge/glow/legend wording tightened after a live Visualize proof
|
|
15
|
-
* (see PR history) surfaced ambiguities two different agent runs resolved
|
|
16
|
-
* inconsistently — see git blame for the before/after if the wording here
|
|
17
|
-
* ever seems oddly specific.
|
|
18
|
-
*/
|
|
19
|
-
export const CANVAS_STYLE_GUIDELINES = `
|
|
20
|
-
Canvas style contract (.sapiom/canvas/index.html):
|
|
21
|
-
- One self-contained HTML file: inline all CSS/JS, no external stylesheets/
|
|
22
|
-
scripts or CDN fonts (the CSP blocks them) — no build step, no dependencies.
|
|
23
|
-
- Dark theme, Sapiom palette: background #0f0f0f, panel #1a1a1a, border
|
|
24
|
-
#2e2e2e, text #fafafa, dim text #a1a1aa, accent/success #6be195, escalation
|
|
25
|
-
#f59e0b, failure #f87171.
|
|
26
|
-
- Monospace throughout: ui-monospace, "SF Mono", Menlo, Consolas, monospace.
|
|
27
|
-
- Header: title + short status badge, one-line subtitle, and a stats row
|
|
28
|
-
(e.g. step count, terminal-outcome count, branch count) as label/value pairs.
|
|
29
|
-
- Render the workflow as an inline SVG graph, top-to-bottom: rounded-rect
|
|
30
|
-
nodes (12-16px radius). Every node gets the same subtle glow on its
|
|
31
|
-
border — never reserve the glow for entry/terminal nodes only; role and
|
|
32
|
-
outcome are conveyed by border/stroke color, not by which nodes glow.
|
|
33
|
-
- Edges: straight lines with arrowhead markers for a single-successor step,
|
|
34
|
-
curved paths with arrowhead markers only where a step branches into
|
|
35
|
-
multiple successors — don't curve every edge, that reads as noise on a
|
|
36
|
-
simple linear chain.
|
|
37
|
-
- Color-code terminal outcomes by meaning: accent/green = success, amber =
|
|
38
|
-
escalation/needs-attention, red = failure. Reserve those colors for actual
|
|
39
|
-
terminal branches, not regular steps.
|
|
40
|
-
- Footer legend: one visually distinct marker per node kind used (shape
|
|
41
|
-
and/or fill vs. outline — never reuse the identical marker for two
|
|
42
|
-
different kinds just because they happen to share a color) + label, plus
|
|
43
|
-
a short note that this is a static preview to regenerate after the
|
|
44
|
-
workflow changes.
|
|
45
|
-
- Prefer clarity over decoration: no motion, gradients, or ornamentation that
|
|
46
|
-
doesn't help someone understand the graph's structure in a few seconds.
|
|
47
|
-
`.trim();
|
|
48
|
-
//# sourceMappingURL=canvas-guidelines.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"canvas-guidelines.js","sourceRoot":"","sources":["../../src/profiles/canvas-guidelines.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BtC,CAAC,IAAI,EAAE,CAAC"}
|
package/dist/server/skills.d.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Skills listing server — backs GET /api/skills and GET /api/skills/:id.
|
|
3
|
-
*
|
|
4
|
-
* Two skill sources are merged:
|
|
5
|
-
* 1. Installed @sapiom packages: scans node_modules/@sapiom/{pkg}/skills/SKILL.md
|
|
6
|
-
* (gracefully empty when no package ships skills yet).
|
|
7
|
-
* 2. User's own ~/.claude/skills/{id}/SKILL.md (same convention Claude Code
|
|
8
|
-
* uses for project-specific skills).
|
|
9
|
-
*
|
|
10
|
-
* Path-traversal safety: skill ids are slug-shaped identifiers (letters,
|
|
11
|
-
* digits, hyphens, underscores) — any id that fails the SAFE_SLUG regex is
|
|
12
|
-
* rejected with a 404 before any filesystem access.
|
|
13
|
-
*
|
|
14
|
-
* The list endpoint (GET /api/skills) does a full directory walk across both
|
|
15
|
-
* roots. The detail endpoint (GET /api/skills/:id) resolves in O(1) by
|
|
16
|
-
* constructing candidate paths directly from the slug (= directory name),
|
|
17
|
-
* without re-walking the tree.
|
|
18
|
-
*
|
|
19
|
-
* Markdown is served as-is — the SPA renders it client-side (no HTML
|
|
20
|
-
* injection here). The frontmatter block is stripped before delivery so the
|
|
21
|
-
* rendered view shows only the body.
|
|
22
|
-
*/
|
|
23
|
-
import { Router } from "express";
|
|
24
|
-
export interface SkillMeta {
|
|
25
|
-
/** Stable identifier: directory name of the skill folder. */
|
|
26
|
-
id: string;
|
|
27
|
-
/** Human name from the `name:` frontmatter field. Falls back to the id. */
|
|
28
|
-
name: string;
|
|
29
|
-
/** One-line description from the `description:` frontmatter field. */
|
|
30
|
-
description: string;
|
|
31
|
-
/** Logical source group — shown in the panel's section header. */
|
|
32
|
-
source: "package" | "user";
|
|
33
|
-
}
|
|
34
|
-
export interface SkillDetail extends SkillMeta {
|
|
35
|
-
/** The full SKILL.md body with the frontmatter block stripped. */
|
|
36
|
-
body: string;
|
|
37
|
-
}
|
|
38
|
-
export interface SkillsRouterOptions {
|
|
39
|
-
/** Override the node_modules root for testing. */
|
|
40
|
-
nodeModulesRoot?: string;
|
|
41
|
-
/** Override the user skills root (default: ~/.claude/skills). */
|
|
42
|
-
userSkillsRoot?: string;
|
|
43
|
-
/**
|
|
44
|
-
* Include the user's personal ~/.claude/skills in the LIST response.
|
|
45
|
-
* Off by default — the panel shows only Sapiom package skills so a
|
|
46
|
-
* developer's own skills don't clutter the product's skill list.
|
|
47
|
-
*/
|
|
48
|
-
showUserSkills?: boolean;
|
|
49
|
-
}
|
|
50
|
-
export declare function createSkillsRouter(options?: SkillsRouterOptions): Router;
|
|
51
|
-
//# sourceMappingURL=skills.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/server/skills.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAOH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGjC,MAAM,WAAW,SAAS;IACxB,6DAA6D;IAC7D,EAAE,EAAE,MAAM,CAAC;IACX,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAC;CACd;AAoKD,MAAM,WAAW,mBAAmB;IAClC,kDAAkD;IAClD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iEAAiE;IACjE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAkI5E"}
|
package/dist/server/skills.js
DELETED
|
@@ -1,312 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Skills listing server — backs GET /api/skills and GET /api/skills/:id.
|
|
3
|
-
*
|
|
4
|
-
* Two skill sources are merged:
|
|
5
|
-
* 1. Installed @sapiom packages: scans node_modules/@sapiom/{pkg}/skills/SKILL.md
|
|
6
|
-
* (gracefully empty when no package ships skills yet).
|
|
7
|
-
* 2. User's own ~/.claude/skills/{id}/SKILL.md (same convention Claude Code
|
|
8
|
-
* uses for project-specific skills).
|
|
9
|
-
*
|
|
10
|
-
* Path-traversal safety: skill ids are slug-shaped identifiers (letters,
|
|
11
|
-
* digits, hyphens, underscores) — any id that fails the SAFE_SLUG regex is
|
|
12
|
-
* rejected with a 404 before any filesystem access.
|
|
13
|
-
*
|
|
14
|
-
* The list endpoint (GET /api/skills) does a full directory walk across both
|
|
15
|
-
* roots. The detail endpoint (GET /api/skills/:id) resolves in O(1) by
|
|
16
|
-
* constructing candidate paths directly from the slug (= directory name),
|
|
17
|
-
* without re-walking the tree.
|
|
18
|
-
*
|
|
19
|
-
* Markdown is served as-is — the SPA renders it client-side (no HTML
|
|
20
|
-
* injection here). The frontmatter block is stripped before delivery so the
|
|
21
|
-
* rendered view shows only the body.
|
|
22
|
-
*/
|
|
23
|
-
import * as fs from "node:fs/promises";
|
|
24
|
-
import { existsSync } from "node:fs";
|
|
25
|
-
import * as path from "node:path";
|
|
26
|
-
import * as os from "node:os";
|
|
27
|
-
import { createRequire } from "node:module";
|
|
28
|
-
import { Router } from "express";
|
|
29
|
-
import rateLimit from "express-rate-limit";
|
|
30
|
-
/** Stable slug: only letters, digits, and hyphens/underscores. */
|
|
31
|
-
const SAFE_SLUG = /^[a-zA-Z0-9_-]+$/;
|
|
32
|
-
/**
|
|
33
|
-
* Build `<root>/<slug>/SKILL.md` and return it ONLY if the resolved path stays
|
|
34
|
-
* inside `root`. Two independent barriers against path traversal: (1) callers
|
|
35
|
-
* validate the slug with SAFE_SLUG, and (2) this containment check on the
|
|
36
|
-
* fully-resolved path — a defense-in-depth barrier that also makes the
|
|
37
|
-
* no-traversal guarantee legible to static analysis (the resolved child must
|
|
38
|
-
* sit under the resolved root + separator). Returns null if containment fails.
|
|
39
|
-
*/
|
|
40
|
-
function resolveSkillFileWithin(root, slug) {
|
|
41
|
-
const resolvedRoot = path.resolve(root);
|
|
42
|
-
const candidate = path.resolve(resolvedRoot, slug, "SKILL.md");
|
|
43
|
-
if (candidate !== path.join(resolvedRoot, slug, "SKILL.md") ||
|
|
44
|
-
!candidate.startsWith(resolvedRoot + path.sep)) {
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
return candidate;
|
|
48
|
-
}
|
|
49
|
-
/** Parse the `---\n...\n---` YAML frontmatter block (simple key: value only). */
|
|
50
|
-
function parseFrontmatter(raw) {
|
|
51
|
-
const meta = {};
|
|
52
|
-
if (!raw.startsWith("---"))
|
|
53
|
-
return { meta, body: raw };
|
|
54
|
-
const end = raw.indexOf("\n---", 3);
|
|
55
|
-
if (end === -1)
|
|
56
|
-
return { meta, body: raw };
|
|
57
|
-
const block = raw.slice(3, end).trim();
|
|
58
|
-
for (const line of block.split("\n")) {
|
|
59
|
-
const colon = line.indexOf(":");
|
|
60
|
-
if (colon === -1)
|
|
61
|
-
continue;
|
|
62
|
-
const key = line.slice(0, colon).trim();
|
|
63
|
-
// Strip inline quotes and leading whitespace; handle multi-line by
|
|
64
|
-
// collapsing continuation lines (indented) into the value.
|
|
65
|
-
const value = line.slice(colon + 1).trim().replace(/^["']|["']$/g, "");
|
|
66
|
-
if (key)
|
|
67
|
-
meta[key] = value;
|
|
68
|
-
}
|
|
69
|
-
return { meta, body: raw.slice(end + 4).trimStart() };
|
|
70
|
-
}
|
|
71
|
-
/** Read and parse a SKILL.md file, returning null on any fs/parse error. */
|
|
72
|
-
async function readSkillFile(filePath, id, source) {
|
|
73
|
-
try {
|
|
74
|
-
const raw = await fs.readFile(filePath, "utf-8");
|
|
75
|
-
const { meta, body } = parseFrontmatter(raw);
|
|
76
|
-
return {
|
|
77
|
-
id,
|
|
78
|
-
name: meta.name ?? id,
|
|
79
|
-
description: meta.description ?? "",
|
|
80
|
-
source,
|
|
81
|
-
body,
|
|
82
|
-
filePath,
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Scan node_modules/@sapiom/{pkg}/skills/{id}/SKILL.md, starting from the
|
|
91
|
-
* given root (defaults to the directory this module lives in, walking up to
|
|
92
|
-
* find the node_modules directory). Returns the discovered skills.
|
|
93
|
-
*/
|
|
94
|
-
async function scanPackageSkills(nodeModulesRoot) {
|
|
95
|
-
const nmRoot = nodeModulesRoot ?? findNodeModules();
|
|
96
|
-
const sapiomDir = path.join(nmRoot, "@sapiom");
|
|
97
|
-
const results = [];
|
|
98
|
-
let pkgDirs;
|
|
99
|
-
try {
|
|
100
|
-
pkgDirs = await fs.readdir(sapiomDir);
|
|
101
|
-
}
|
|
102
|
-
catch {
|
|
103
|
-
return results; // no @sapiom packages installed — gracefully empty
|
|
104
|
-
}
|
|
105
|
-
for (const pkg of pkgDirs) {
|
|
106
|
-
const skillsDir = path.join(sapiomDir, pkg, "skills");
|
|
107
|
-
let skillDirs;
|
|
108
|
-
try {
|
|
109
|
-
skillDirs = await fs.readdir(skillsDir);
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
continue; // package has no skills directory
|
|
113
|
-
}
|
|
114
|
-
for (const skillDir of skillDirs) {
|
|
115
|
-
const skillFile = path.join(skillsDir, skillDir, "SKILL.md");
|
|
116
|
-
const parsed = await readSkillFile(skillFile, skillDir, "package");
|
|
117
|
-
if (parsed)
|
|
118
|
-
results.push(parsed);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
return results;
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Resolve the node_modules directory that actually holds the installed
|
|
125
|
-
* @sapiom packages, robust to install layout.
|
|
126
|
-
*
|
|
127
|
-
* The naive "walk up from dist/server/skills.js to my own package-root's
|
|
128
|
-
* node_modules" breaks under npm/npx HOISTING: `npx @sapiom/harness` installs
|
|
129
|
-
* agent-core as a SIBLING in a shared node_modules (…/@sapiom/agent-core),
|
|
130
|
-
* NOT nested under …/@sapiom/harness/node_modules — so the naive path reads an
|
|
131
|
-
* empty (or absent) @sapiom dir and finds zero package skills.
|
|
132
|
-
*
|
|
133
|
-
* Use Node's own module search list (`require.resolve.paths`) for the scope
|
|
134
|
-
* package — the node_modules dirs walking up from this file — and return the
|
|
135
|
-
* first that actually contains `@sapiom/agent-core`. This is symlink-aware (it
|
|
136
|
-
* stats the entry, not its realpath), so it works for BOTH npm/npx hoisting AND
|
|
137
|
-
* pnpm workspace symlinks (where agent-core is linked under
|
|
138
|
-
* packages/harness/node_modules, and resolving to its realpath would wrongly
|
|
139
|
-
* point outside any node_modules). Falls back to the old relative guess, then cwd.
|
|
140
|
-
*/
|
|
141
|
-
function findNodeModules() {
|
|
142
|
-
try {
|
|
143
|
-
const require = createRequire(import.meta.url);
|
|
144
|
-
for (const p of require.resolve.paths("@sapiom/agent-core") ?? []) {
|
|
145
|
-
if (existsSync(path.join(p, "@sapiom", "agent-core")))
|
|
146
|
-
return p;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
catch {
|
|
150
|
-
// agent-core unresolvable — fall through to the relative guess.
|
|
151
|
-
}
|
|
152
|
-
try {
|
|
153
|
-
// Legacy fallback: dist/server/skills.js → dist/server → dist → package-root.
|
|
154
|
-
const here = new URL(import.meta.url).pathname;
|
|
155
|
-
return path.join(path.dirname(path.dirname(path.dirname(here))), "node_modules");
|
|
156
|
-
}
|
|
157
|
-
catch {
|
|
158
|
-
return path.join(process.cwd(), "node_modules");
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
/** Scan ~/.claude/skills/{id}/SKILL.md. Returns discovered skills. */
|
|
162
|
-
async function scanUserSkills() {
|
|
163
|
-
const skillsDir = path.join(os.homedir(), ".claude", "skills");
|
|
164
|
-
const results = [];
|
|
165
|
-
let skillDirs;
|
|
166
|
-
try {
|
|
167
|
-
skillDirs = await fs.readdir(skillsDir);
|
|
168
|
-
}
|
|
169
|
-
catch {
|
|
170
|
-
return results; // directory doesn't exist — gracefully empty
|
|
171
|
-
}
|
|
172
|
-
for (const skillDir of skillDirs) {
|
|
173
|
-
const skillFile = path.join(skillsDir, skillDir, "SKILL.md");
|
|
174
|
-
const parsed = await readSkillFile(skillFile, skillDir, "user");
|
|
175
|
-
if (parsed)
|
|
176
|
-
results.push(parsed);
|
|
177
|
-
}
|
|
178
|
-
return results;
|
|
179
|
-
}
|
|
180
|
-
export function createSkillsRouter(options = {}) {
|
|
181
|
-
const router = Router();
|
|
182
|
-
// These routes touch the filesystem (skill discovery + detail reads). The
|
|
183
|
-
// harness server is localhost-only and boot-token-gated (a single local
|
|
184
|
-
// user), so this ceiling is far above any real interactive flow and never
|
|
185
|
-
// fires in practice — it's a backstop that bounds a runaway/buggy client
|
|
186
|
-
// from hammering the FS, and the explicit rate-limit control on an
|
|
187
|
-
// FS-backed route surface.
|
|
188
|
-
router.use(rateLimit({
|
|
189
|
-
windowMs: 60000,
|
|
190
|
-
limit: 240,
|
|
191
|
-
standardHeaders: true,
|
|
192
|
-
legacyHeaders: false,
|
|
193
|
-
}));
|
|
194
|
-
/**
|
|
195
|
-
* GET /api/skills — list all discoverable skills with id, name, description,
|
|
196
|
-
* and source. Safe: no paths are exposed; ids are directory names.
|
|
197
|
-
*/
|
|
198
|
-
router.get("/api/skills", async (_req, res) => {
|
|
199
|
-
try {
|
|
200
|
-
// Personal user skills (~/.claude/skills) are OPT-IN, off by default: the
|
|
201
|
-
// panel surfaces what Sapiom ships (e.g. sapiom-agent-authoring), not the
|
|
202
|
-
// developer's own skills. Flip showUserSkills for a bring-your-own view.
|
|
203
|
-
const [pkgSkills, userSkills] = await Promise.all([
|
|
204
|
-
scanPackageSkills(options.nodeModulesRoot),
|
|
205
|
-
options.showUserSkills
|
|
206
|
-
? options.userSkillsRoot
|
|
207
|
-
? scanUserSkillsFromRoot(options.userSkillsRoot)
|
|
208
|
-
: scanUserSkills()
|
|
209
|
-
: Promise.resolve([]),
|
|
210
|
-
]);
|
|
211
|
-
// Dedupe by id: user skills (when enabled) win over package skills.
|
|
212
|
-
const byId = new Map();
|
|
213
|
-
for (const skill of [...pkgSkills, ...userSkills]) {
|
|
214
|
-
byId.set(skill.id, { id: skill.id, name: skill.name, description: skill.description, source: skill.source });
|
|
215
|
-
}
|
|
216
|
-
res.json(Array.from(byId.values()));
|
|
217
|
-
}
|
|
218
|
-
catch (err) {
|
|
219
|
-
res.status(500).json({ error: err.message });
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
/**
|
|
223
|
-
* GET /api/skills/:id — full detail (meta + markdown body) for a single
|
|
224
|
-
* skill. Path-traversal safe: the id must be a safe slug (letters, digits,
|
|
225
|
-
* hyphens, underscores only) — the slug IS the directory name, so we can
|
|
226
|
-
* resolve it in O(1) by stat/reading `<root>/<slug>/SKILL.md` across the
|
|
227
|
-
* two roots (user first, per collision rule) without a full directory walk.
|
|
228
|
-
*
|
|
229
|
-
* The slug regex + containment guard (SAFE_SLUG + the two fixed roots)
|
|
230
|
-
* ensure no traversal is possible — a slug can never contain a path separator.
|
|
231
|
-
*/
|
|
232
|
-
router.get("/api/skills/:id", async (req, res) => {
|
|
233
|
-
const { id } = req.params;
|
|
234
|
-
// Reject anything that isn't a safe slug up front — prevents any path-
|
|
235
|
-
// traversal attempt before filesystem access.
|
|
236
|
-
if (!id || !SAFE_SLUG.test(id)) {
|
|
237
|
-
res.status(404).json({ error: `Unknown skill '${id}'` });
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
try {
|
|
241
|
-
// O(1) resolution: the id is the directory name, so build the candidate
|
|
242
|
-
// paths directly through the containment barrier. User root first (user
|
|
243
|
-
// skills win on id collision).
|
|
244
|
-
const userRoot = options.userSkillsRoot ??
|
|
245
|
-
path.join(os.homedir(), ".claude", "skills");
|
|
246
|
-
const userSkillFile = resolveSkillFileWithin(userRoot, id);
|
|
247
|
-
// Try user skill first; fall through to package skills on null result.
|
|
248
|
-
let found = userSkillFile
|
|
249
|
-
? await readSkillFile(userSkillFile, id, "user")
|
|
250
|
-
: null;
|
|
251
|
-
if (!found) {
|
|
252
|
-
// Package skills: resolve the node_modules root and try each @sapiom
|
|
253
|
-
// package's skills directory for a matching id. Still O(packages) but
|
|
254
|
-
// avoids the full readdir of every skills subdirectory.
|
|
255
|
-
const nmRoot = options.nodeModulesRoot ?? findNodeModules();
|
|
256
|
-
const sapiomDir = path.join(nmRoot, "@sapiom");
|
|
257
|
-
let pkgDirs;
|
|
258
|
-
try {
|
|
259
|
-
pkgDirs = await import("node:fs/promises").then((fsp) => fsp.readdir(sapiomDir));
|
|
260
|
-
}
|
|
261
|
-
catch {
|
|
262
|
-
pkgDirs = [];
|
|
263
|
-
}
|
|
264
|
-
for (const pkg of pkgDirs) {
|
|
265
|
-
const candidate = resolveSkillFileWithin(path.join(sapiomDir, pkg, "skills"), id);
|
|
266
|
-
const parsed = candidate
|
|
267
|
-
? await readSkillFile(candidate, id, "package")
|
|
268
|
-
: null;
|
|
269
|
-
if (parsed) {
|
|
270
|
-
found = parsed;
|
|
271
|
-
break;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
if (!found) {
|
|
276
|
-
res.status(404).json({ error: `Unknown skill '${id}'` });
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
const detail = {
|
|
280
|
-
id: found.id,
|
|
281
|
-
name: found.name,
|
|
282
|
-
description: found.description,
|
|
283
|
-
source: found.source,
|
|
284
|
-
body: found.body,
|
|
285
|
-
};
|
|
286
|
-
res.json(detail);
|
|
287
|
-
}
|
|
288
|
-
catch (err) {
|
|
289
|
-
res.status(500).json({ error: err.message });
|
|
290
|
-
}
|
|
291
|
-
});
|
|
292
|
-
return router;
|
|
293
|
-
}
|
|
294
|
-
/** Scan skills from a custom root (for testing). Same logic as scanUserSkills. */
|
|
295
|
-
async function scanUserSkillsFromRoot(root) {
|
|
296
|
-
const results = [];
|
|
297
|
-
let skillDirs;
|
|
298
|
-
try {
|
|
299
|
-
skillDirs = await fs.readdir(root);
|
|
300
|
-
}
|
|
301
|
-
catch {
|
|
302
|
-
return results;
|
|
303
|
-
}
|
|
304
|
-
for (const skillDir of skillDirs) {
|
|
305
|
-
const skillFile = path.join(root, skillDir, "SKILL.md");
|
|
306
|
-
const parsed = await readSkillFile(skillFile, skillDir, "user");
|
|
307
|
-
if (parsed)
|
|
308
|
-
results.push(parsed);
|
|
309
|
-
}
|
|
310
|
-
return results;
|
|
311
|
-
}
|
|
312
|
-
//# sourceMappingURL=skills.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/server/skills.ts"],"names":[],"mappings":"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"}
|