@compilr-dev/sdk 0.14.0 → 0.16.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/dist/actions/registry.js +12 -3
- package/dist/canvas/index.d.ts +6 -0
- package/dist/canvas/index.js +6 -0
- package/dist/canvas/types.d.ts +113 -0
- package/dist/canvas/types.js +21 -0
- package/dist/canvas/validate.d.ts +13 -0
- package/dist/canvas/validate.js +89 -0
- package/dist/errors/classify.d.ts +30 -0
- package/dist/errors/classify.js +80 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +7 -1
- package/dist/platform/context.d.ts +2 -0
- package/dist/platform/index.d.ts +1 -1
- package/dist/platform/index.js +1 -1
- package/dist/platform/tools/canvas-tools.d.ts +21 -0
- package/dist/platform/tools/canvas-tools.js +183 -0
- package/dist/platform/tools/index.d.ts +1 -0
- package/dist/platform/tools/index.js +5 -0
- package/package.json +9 -1
package/dist/actions/registry.js
CHANGED
|
@@ -14,7 +14,11 @@ export const ACTION_REGISTRY = [
|
|
|
14
14
|
icon: 'Wand2',
|
|
15
15
|
applicableTo: ['project'],
|
|
16
16
|
category: 'design',
|
|
17
|
-
|
|
17
|
+
// BA owns requirements: the 'ba' role (analyst profile) has both
|
|
18
|
+
// backlog_write and documents, so it can complete the full /design action
|
|
19
|
+
// (create work items + write the PRD). The architect profile lacks
|
|
20
|
+
// backlog_write and cannot create the backlog.
|
|
21
|
+
suggestedRole: 'ba',
|
|
18
22
|
needsInput: true,
|
|
19
23
|
inputPrompt: 'What would you like to design?',
|
|
20
24
|
},
|
|
@@ -34,8 +38,13 @@ export const ACTION_REGISTRY = [
|
|
|
34
38
|
description: 'Create a product requirements document',
|
|
35
39
|
icon: 'FileText',
|
|
36
40
|
applicableTo: ['project'],
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
// PRD is artifact-authoring (requirements), grouped with design/architecture
|
|
42
|
+
// rather than backlog-breakdown 'planning' (refine/refine-item).
|
|
43
|
+
category: 'design',
|
|
44
|
+
// Requirements work → Business Analyst, not PM. The 'ba' role (analyst
|
|
45
|
+
// profile) is purpose-built for requirements gathering and has the
|
|
46
|
+
// documents tools needed to author the PRD.
|
|
47
|
+
suggestedRole: 'ba',
|
|
39
48
|
},
|
|
40
49
|
{
|
|
41
50
|
id: 'architecture',
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas — shared contract types.
|
|
3
|
+
*
|
|
4
|
+
* A Canvas is a persisted visual artifact the agent authors as HTML/SVG, with an
|
|
5
|
+
* optional controls manifest that surfaces live parameters ("Tweaks"). These
|
|
6
|
+
* types are the host-agnostic contract: the SDK owns them + the tools; hosts
|
|
7
|
+
* (Desktop) own the renderer.
|
|
8
|
+
*
|
|
9
|
+
* Intentionally dependency-free so this module can be exposed at the renderer-safe
|
|
10
|
+
* subpath `@compilr-dev/sdk/canvas` (the Desktop renderer needs the control types
|
|
11
|
+
* + validation without pulling node-only deps — same pattern as `.../errors`).
|
|
12
|
+
*/
|
|
13
|
+
export type CanvasType = 'infographic' | 'carousel' | 'board';
|
|
14
|
+
/** A control's runtime value. */
|
|
15
|
+
export type ParamValue = string | number | boolean;
|
|
16
|
+
export interface SliderControl {
|
|
17
|
+
type: 'slider';
|
|
18
|
+
param: string;
|
|
19
|
+
label: string;
|
|
20
|
+
default: number;
|
|
21
|
+
min: number;
|
|
22
|
+
max: number;
|
|
23
|
+
step?: number;
|
|
24
|
+
unit?: string;
|
|
25
|
+
group?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface NumberControl {
|
|
28
|
+
type: 'number';
|
|
29
|
+
param: string;
|
|
30
|
+
label: string;
|
|
31
|
+
default: number;
|
|
32
|
+
min?: number;
|
|
33
|
+
max?: number;
|
|
34
|
+
step?: number;
|
|
35
|
+
group?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface ToggleControl {
|
|
38
|
+
type: 'toggle';
|
|
39
|
+
param: string;
|
|
40
|
+
label: string;
|
|
41
|
+
default: boolean;
|
|
42
|
+
group?: string;
|
|
43
|
+
}
|
|
44
|
+
export interface SelectControl {
|
|
45
|
+
type: 'select';
|
|
46
|
+
param: string;
|
|
47
|
+
label: string;
|
|
48
|
+
default: string;
|
|
49
|
+
options: string[];
|
|
50
|
+
group?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface ColorControl {
|
|
53
|
+
type: 'color';
|
|
54
|
+
param: string;
|
|
55
|
+
label: string;
|
|
56
|
+
default: string;
|
|
57
|
+
group?: string;
|
|
58
|
+
}
|
|
59
|
+
export interface TextControl {
|
|
60
|
+
type: 'text';
|
|
61
|
+
param: string;
|
|
62
|
+
label: string;
|
|
63
|
+
default: string;
|
|
64
|
+
placeholder?: string;
|
|
65
|
+
group?: string;
|
|
66
|
+
}
|
|
67
|
+
export type Control = SliderControl | NumberControl | ToggleControl | SelectControl | ColorControl | TextControl;
|
|
68
|
+
export interface ControlManifest {
|
|
69
|
+
controls: Control[];
|
|
70
|
+
}
|
|
71
|
+
/** Full persisted canvas. `content` is the agent's raw HTML/SVG only — the CSP + bridge are injected by the host renderer, never stored. */
|
|
72
|
+
export interface CanvasRecord {
|
|
73
|
+
id: string;
|
|
74
|
+
projectId: string;
|
|
75
|
+
type: CanvasType;
|
|
76
|
+
title: string;
|
|
77
|
+
content: string;
|
|
78
|
+
controls: ControlManifest;
|
|
79
|
+
/** Current tweak state; seeded from control defaults on create. */
|
|
80
|
+
values: Record<string, ParamValue>;
|
|
81
|
+
createdAt: Date;
|
|
82
|
+
updatedAt: Date;
|
|
83
|
+
}
|
|
84
|
+
/** Lightweight list entry (no content). */
|
|
85
|
+
export interface CanvasSummary {
|
|
86
|
+
id: string;
|
|
87
|
+
projectId: string;
|
|
88
|
+
type: CanvasType;
|
|
89
|
+
title: string;
|
|
90
|
+
updatedAt: Date;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Host-implemented persistence for canvases (DB-backed). Optional field on
|
|
94
|
+
* PlatformContext — the canvas tools are absent when a host doesn't provide it.
|
|
95
|
+
*/
|
|
96
|
+
export interface ICanvasService {
|
|
97
|
+
create(input: {
|
|
98
|
+
type: CanvasType;
|
|
99
|
+
title: string;
|
|
100
|
+
content: string;
|
|
101
|
+
controls?: ControlManifest;
|
|
102
|
+
values?: Record<string, ParamValue>;
|
|
103
|
+
/** Defaults to the current project when omitted. */
|
|
104
|
+
projectId?: string;
|
|
105
|
+
}): Promise<CanvasRecord>;
|
|
106
|
+
update(id: string, patch: Partial<Pick<CanvasRecord, 'title' | 'content' | 'controls' | 'values'>>): Promise<CanvasRecord>;
|
|
107
|
+
get(id: string): Promise<CanvasRecord | null>;
|
|
108
|
+
/** Metadata only; scoped to the current project when projectId omitted. */
|
|
109
|
+
list(projectId?: string): Promise<CanvasSummary[]>;
|
|
110
|
+
delete(id: string): Promise<CanvasRecord | null>;
|
|
111
|
+
}
|
|
112
|
+
/** Seed a values map from a manifest's control defaults. */
|
|
113
|
+
export declare function seedValues(manifest: ControlManifest | undefined): Record<string, ParamValue>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas — shared contract types.
|
|
3
|
+
*
|
|
4
|
+
* A Canvas is a persisted visual artifact the agent authors as HTML/SVG, with an
|
|
5
|
+
* optional controls manifest that surfaces live parameters ("Tweaks"). These
|
|
6
|
+
* types are the host-agnostic contract: the SDK owns them + the tools; hosts
|
|
7
|
+
* (Desktop) own the renderer.
|
|
8
|
+
*
|
|
9
|
+
* Intentionally dependency-free so this module can be exposed at the renderer-safe
|
|
10
|
+
* subpath `@compilr-dev/sdk/canvas` (the Desktop renderer needs the control types
|
|
11
|
+
* + validation without pulling node-only deps — same pattern as `.../errors`).
|
|
12
|
+
*/
|
|
13
|
+
/** Seed a values map from a manifest's control defaults. */
|
|
14
|
+
export function seedValues(manifest) {
|
|
15
|
+
const values = {};
|
|
16
|
+
if (!manifest)
|
|
17
|
+
return values;
|
|
18
|
+
for (const c of manifest.controls)
|
|
19
|
+
values[c.param] = c.default;
|
|
20
|
+
return values;
|
|
21
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas controls-manifest validation. Dependency-free (renderer-safe subpath).
|
|
3
|
+
*/
|
|
4
|
+
import type { ControlManifest } from './types.js';
|
|
5
|
+
export interface ManifestValidationResult {
|
|
6
|
+
ok: boolean;
|
|
7
|
+
errors: string[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Validate a controls manifest: array shape, unique + well-formed param names,
|
|
11
|
+
* and per-type default sanity (in range / in options / correct primitive).
|
|
12
|
+
*/
|
|
13
|
+
export declare function validateControlManifest(manifest: ControlManifest): ManifestValidationResult;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas controls-manifest validation. Dependency-free (renderer-safe subpath).
|
|
3
|
+
*/
|
|
4
|
+
/** Param names must be usable as a CSS custom property suffix and a JS key. */
|
|
5
|
+
const PARAM_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
6
|
+
const HEX_RE = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
|
|
7
|
+
/**
|
|
8
|
+
* Validate a controls manifest: array shape, unique + well-formed param names,
|
|
9
|
+
* and per-type default sanity (in range / in options / correct primitive).
|
|
10
|
+
*/
|
|
11
|
+
export function validateControlManifest(manifest) {
|
|
12
|
+
const errors = [];
|
|
13
|
+
// Treat the manifest as untrusted (agent JSON), not the static type.
|
|
14
|
+
const rawControls = manifest.controls;
|
|
15
|
+
if (!Array.isArray(rawControls)) {
|
|
16
|
+
return { ok: false, errors: ['manifest.controls must be an array'] };
|
|
17
|
+
}
|
|
18
|
+
const seen = new Set();
|
|
19
|
+
for (const raw of rawControls) {
|
|
20
|
+
const param = raw.param;
|
|
21
|
+
if (typeof param !== 'string' || !PARAM_RE.test(param)) {
|
|
22
|
+
errors.push(`invalid param name "${String(param)}" (must match ${PARAM_RE.source})`);
|
|
23
|
+
}
|
|
24
|
+
else if (seen.has(param)) {
|
|
25
|
+
errors.push(`duplicate param "${param}"`);
|
|
26
|
+
}
|
|
27
|
+
if (typeof param === 'string')
|
|
28
|
+
seen.add(param);
|
|
29
|
+
validateDefault(raw, errors);
|
|
30
|
+
}
|
|
31
|
+
return { ok: errors.length === 0, errors };
|
|
32
|
+
}
|
|
33
|
+
function validateDefault(control, errors) {
|
|
34
|
+
const c = control;
|
|
35
|
+
const p = c.param;
|
|
36
|
+
switch (c.type) {
|
|
37
|
+
case 'slider': {
|
|
38
|
+
const { min, max, default: d } = c;
|
|
39
|
+
if (typeof min === 'number' && typeof max === 'number' && min > max) {
|
|
40
|
+
errors.push(`${p}: min ${String(min)} > max ${String(max)}`);
|
|
41
|
+
}
|
|
42
|
+
if (typeof d !== 'number') {
|
|
43
|
+
errors.push(`${p}: slider default must be a number`);
|
|
44
|
+
}
|
|
45
|
+
else if (typeof min === 'number' && typeof max === 'number' && (d < min || d > max)) {
|
|
46
|
+
errors.push(`${p}: default ${String(d)} out of range [${String(min)}, ${String(max)}]`);
|
|
47
|
+
}
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
case 'number': {
|
|
51
|
+
const { min, max, default: d } = c;
|
|
52
|
+
if (typeof d !== 'number') {
|
|
53
|
+
errors.push(`${p}: number default must be a number`);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
if (typeof min === 'number' && d < min)
|
|
57
|
+
errors.push(`${p}: default < min`);
|
|
58
|
+
if (typeof max === 'number' && d > max)
|
|
59
|
+
errors.push(`${p}: default > max`);
|
|
60
|
+
}
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
case 'toggle':
|
|
64
|
+
if (typeof c.default !== 'boolean')
|
|
65
|
+
errors.push(`${p}: toggle default must be boolean`);
|
|
66
|
+
break;
|
|
67
|
+
case 'select': {
|
|
68
|
+
const opts = c.options;
|
|
69
|
+
if (!Array.isArray(opts) || opts.length === 0) {
|
|
70
|
+
errors.push(`${p}: select needs a non-empty options array`);
|
|
71
|
+
}
|
|
72
|
+
else if (!opts.includes(c.default)) {
|
|
73
|
+
errors.push(`${p}: default "${String(c.default)}" is not in options`);
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
case 'color':
|
|
78
|
+
if (typeof c.default !== 'string' || !HEX_RE.test(c.default)) {
|
|
79
|
+
errors.push(`${p}: color default must be a hex color (e.g. #FF5722)`);
|
|
80
|
+
}
|
|
81
|
+
break;
|
|
82
|
+
case 'text':
|
|
83
|
+
if (typeof c.default !== 'string')
|
|
84
|
+
errors.push(`${p}: text default must be a string`);
|
|
85
|
+
break;
|
|
86
|
+
default:
|
|
87
|
+
errors.push(`${p}: unknown control type "${c.type}"`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent-error classification.
|
|
3
|
+
*
|
|
4
|
+
* Provider/agent failures surface to hosts in two shapes:
|
|
5
|
+
* - as a thrown `ProviderError` instance (in-process — e.g. the CLI), or
|
|
6
|
+
* - as a stringified message after crossing an IPC/serialization boundary
|
|
7
|
+
* (e.g. the Desktop app's `agent.chat` IPC returns `error: string`).
|
|
8
|
+
*
|
|
9
|
+
* Hosts were string-matching the message independently to detect the common
|
|
10
|
+
* first-run failure (a missing/invalid API key → 401), which is duplicated and
|
|
11
|
+
* fragile. This centralizes the classification so every host shares one
|
|
12
|
+
* implementation; the *remediation copy* stays host-specific (the CLI tells the
|
|
13
|
+
* user to run /config or set an env var; Desktop points to Settings).
|
|
14
|
+
*/
|
|
15
|
+
export type AgentErrorCategory = 'auth' | 'rate_limit' | 'overloaded' | 'server' | 'connection' | 'unknown';
|
|
16
|
+
export interface AgentErrorInfo {
|
|
17
|
+
category: AgentErrorCategory;
|
|
18
|
+
/** HTTP status code if one could be determined. */
|
|
19
|
+
statusCode?: number;
|
|
20
|
+
/** The original message text (for logging / fallback display). */
|
|
21
|
+
raw: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Classify an agent/provider error into a stable category. Accepts a thrown
|
|
25
|
+
* `ProviderError` instance (read by duck-typing its `statusCode`), any `Error`,
|
|
26
|
+
* or a stringified message (post-IPC).
|
|
27
|
+
*/
|
|
28
|
+
export declare function classifyAgentError(err: unknown): AgentErrorInfo;
|
|
29
|
+
/** Convenience: true when the failure is a missing/invalid API key. */
|
|
30
|
+
export declare function isApiKeyError(err: unknown): boolean;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent-error classification.
|
|
3
|
+
*
|
|
4
|
+
* Provider/agent failures surface to hosts in two shapes:
|
|
5
|
+
* - as a thrown `ProviderError` instance (in-process — e.g. the CLI), or
|
|
6
|
+
* - as a stringified message after crossing an IPC/serialization boundary
|
|
7
|
+
* (e.g. the Desktop app's `agent.chat` IPC returns `error: string`).
|
|
8
|
+
*
|
|
9
|
+
* Hosts were string-matching the message independently to detect the common
|
|
10
|
+
* first-run failure (a missing/invalid API key → 401), which is duplicated and
|
|
11
|
+
* fragile. This centralizes the classification so every host shares one
|
|
12
|
+
* implementation; the *remediation copy* stays host-specific (the CLI tells the
|
|
13
|
+
* user to run /config or set an env var; Desktop points to Settings).
|
|
14
|
+
*/
|
|
15
|
+
/** Pull a usable message string out of any thrown value. */
|
|
16
|
+
function messageOf(err) {
|
|
17
|
+
if (typeof err === 'string')
|
|
18
|
+
return err;
|
|
19
|
+
if (err instanceof Error)
|
|
20
|
+
return err.message;
|
|
21
|
+
if (err && typeof err === 'object' && 'message' in err) {
|
|
22
|
+
return String(err.message);
|
|
23
|
+
}
|
|
24
|
+
return String(err);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* First HTTP status code in the text, if any (e.g. "ProviderError: 401 ...").
|
|
28
|
+
* Uses a curated set of codes providers actually return, so a port number or IP
|
|
29
|
+
* octet isn't misread as a status (e.g. `ECONNREFUSED 127.0.0.1:443` must not
|
|
30
|
+
* read as 443 — that would mask a connection error as an HTTP one).
|
|
31
|
+
*/
|
|
32
|
+
function statusFromText(text) {
|
|
33
|
+
const m = text.match(/\b(400|401|403|404|408|409|413|422|429|500|502|503|504|529)\b/);
|
|
34
|
+
return m ? Number(m[1]) : undefined;
|
|
35
|
+
}
|
|
36
|
+
function categorize(statusCode, text) {
|
|
37
|
+
const lower = text.toLowerCase();
|
|
38
|
+
// Auth: key issues. Match on status OR the provider's textual markers, since a
|
|
39
|
+
// stringified error may not preserve the numeric code.
|
|
40
|
+
if (statusCode === 401 ||
|
|
41
|
+
statusCode === 403 ||
|
|
42
|
+
/authentication_error|invalid x-api-key|invalid api key|no api key|x-api-key|permission_error|unauthorized/.test(lower)) {
|
|
43
|
+
return 'auth';
|
|
44
|
+
}
|
|
45
|
+
if (statusCode === 429 || /rate.?limit|too many requests/.test(lower))
|
|
46
|
+
return 'rate_limit';
|
|
47
|
+
if (statusCode === 529 || /overloaded/.test(lower))
|
|
48
|
+
return 'overloaded';
|
|
49
|
+
if ((statusCode !== undefined && statusCode >= 500 && statusCode < 600) ||
|
|
50
|
+
/internal server error/.test(lower)) {
|
|
51
|
+
return 'server';
|
|
52
|
+
}
|
|
53
|
+
if (statusCode === undefined &&
|
|
54
|
+
/econnrefused|econnreset|etimedout|enotfound|network|socket|dns|connection/.test(lower)) {
|
|
55
|
+
return 'connection';
|
|
56
|
+
}
|
|
57
|
+
return 'unknown';
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Classify an agent/provider error into a stable category. Accepts a thrown
|
|
61
|
+
* `ProviderError` instance (read by duck-typing its `statusCode`), any `Error`,
|
|
62
|
+
* or a stringified message (post-IPC).
|
|
63
|
+
*/
|
|
64
|
+
export function classifyAgentError(err) {
|
|
65
|
+
const raw = messageOf(err);
|
|
66
|
+
// A thrown ProviderError carries a numeric `statusCode`; prefer it. Fall back
|
|
67
|
+
// to parsing a status out of the message text (the stringified/IPC case).
|
|
68
|
+
let statusCode;
|
|
69
|
+
if (err && typeof err === 'object' && 'statusCode' in err && typeof err.statusCode === 'number') {
|
|
70
|
+
statusCode = err.statusCode;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
statusCode = statusFromText(raw);
|
|
74
|
+
}
|
|
75
|
+
return { category: categorize(statusCode, raw), statusCode, raw };
|
|
76
|
+
}
|
|
77
|
+
/** Convenience: true when the failure is a missing/invalid API key. */
|
|
78
|
+
export function isApiKeyError(err) {
|
|
79
|
+
return classifyAgentError(err).category === 'auth';
|
|
80
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -64,7 +64,7 @@ export { detectProject, suggestProjectType, detectCommon } from './detection/ind
|
|
|
64
64
|
export type { DetectProjectOptions, DetectionResult, ContentSummary } from './detection/index.js';
|
|
65
65
|
export { createGuideTool, SHARED_GUIDE_ENTRIES, searchGuideEntries, topicToGuideEntry, } from './guide/index.js';
|
|
66
66
|
export type { GuideEntry, ContentTopic, ContentSection, GuideToolConfig } from './guide/index.js';
|
|
67
|
-
export { createPlatformTools, createProjectTools, createWorkItemTools, createDocumentTools, createPlanTools, createBacklogTools, createAnchorTools, createArtifactTools, createEpisodeTools, createImageTools, ProjectAnchorStore, FileArtifactService, } from './platform/index.js';
|
|
67
|
+
export { createPlatformTools, createProjectTools, createWorkItemTools, createDocumentTools, createPlanTools, createBacklogTools, createAnchorTools, createArtifactTools, createEpisodeTools, createCanvasTools, createImageTools, ProjectAnchorStore, FileArtifactService, } from './platform/index.js';
|
|
68
68
|
export type { ProjectAnchorStoreConfig, FileArtifactServiceConfig, ImageToolsConfig, ImageResizer, } from './platform/index.js';
|
|
69
69
|
export { STEP_ORDER, GUIDED_STEP_CRITERIA, getNextStep, isValidTransition, getStepCriteria, formatStepDisplay, getStepNumber, } from './platform/index.js';
|
|
70
70
|
export type { CustomSkill, CompilrSkillExtension, ForkedFromMarker, SkillEligibilityContext, SkillCollision, SkillDiffLine, SkillValidationIssue, ScopeConfig, SkillResolution, } from './skills/index.js';
|
|
@@ -78,6 +78,10 @@ export { PROJECT_TYPES, getProjectTypeConfig, getEnrichedProjectTypeConfig, getP
|
|
|
78
78
|
export type { ActionMeta, SkillMeta } from './project-types/index.js';
|
|
79
79
|
export type { ProjectTypeConfig, ProjectPhase, SuggestedAgent, DocumentTemplate, } from './project-types/index.js';
|
|
80
80
|
export { defineTool, createSuccessResult, createErrorResult, mergeHooks, createLoggingHooks, createClaudeProvider, createOpenAIProvider, createGeminiNativeProvider, createOllamaProvider, createTogetherProvider, createGroqProvider, createFireworksProvider, createPerplexityProvider, createOpenRouterProvider, createMockProvider, MockProvider, Agent, ContextManager, DEFAULT_CONTEXT_CONFIG, createTaskTool, createSuggestTool, defaultAgentTypes, TOOL_SETS, BUILTIN_GUARDRAILS, TOOL_NAMES, getDefaultShellManager, builtinSkills, AnchorManager, MCPManager, AgentError, ProviderError, ToolError, ToolTimeoutError, MaxIterationsError, AbortError, } from '@compilr-dev/agents';
|
|
81
|
+
export { classifyAgentError, isApiKeyError } from './errors/classify.js';
|
|
82
|
+
export type { AgentErrorCategory, AgentErrorInfo } from './errors/classify.js';
|
|
83
|
+
export { validateControlManifest, seedValues } from './canvas/index.js';
|
|
84
|
+
export type { CanvasType, ParamValue, Control, ControlManifest, CanvasRecord, CanvasSummary, ICanvasService, SliderControl, NumberControl, ToggleControl, SelectControl, ColorControl, TextControl, ManifestValidationResult, } from './canvas/index.js';
|
|
81
85
|
export type { Tool, HooksConfig, AgentEvent, Message, LLMProvider, AnchorInput, ToolExecutionResult, AgentRunResult, PermissionHandler, PermissionHandlerResponse, ToolPermission, AgentTypeConfig, GuardrailTriggeredHandler, BeforeLLMHookResult, BeforeToolHook, BeforeToolHookResult, AfterToolHook, AgentState, AgentConfig, SessionInfo, Anchor, AnchorScope, AnchorClearOptions, AnchorPriority, AnchorQueryOptions, FileAccessType, FileAccess, GuardrailResult, GuardrailContext, MCPClient, MCPToolDefinition, } from '@compilr-dev/agents';
|
|
82
86
|
export { DEFAULT_PERMISSION_RULES, WRITE_TOOLS, findMatchingRule, permissionModeLabel, permissionLevelLabel, } from './permissions.js';
|
|
83
87
|
export type { PermissionRule, PermissionMode, PermissionLevel } from './permissions.js';
|
package/dist/index.js
CHANGED
|
@@ -147,7 +147,7 @@ export { createGuideTool, SHARED_GUIDE_ENTRIES, searchGuideEntries, topicToGuide
|
|
|
147
147
|
// =============================================================================
|
|
148
148
|
// Platform Tools (runtime — createPlatformTools factory + individual factories)
|
|
149
149
|
// =============================================================================
|
|
150
|
-
export { createPlatformTools, createProjectTools, createWorkItemTools, createDocumentTools, createPlanTools, createBacklogTools, createAnchorTools, createArtifactTools, createEpisodeTools, createImageTools, ProjectAnchorStore, FileArtifactService, } from './platform/index.js';
|
|
150
|
+
export { createPlatformTools, createProjectTools, createWorkItemTools, createDocumentTools, createPlanTools, createBacklogTools, createAnchorTools, createArtifactTools, createEpisodeTools, createCanvasTools, createImageTools, ProjectAnchorStore, FileArtifactService, } from './platform/index.js';
|
|
151
151
|
// =============================================================================
|
|
152
152
|
// Platform Workflow (pure step-criteria logic)
|
|
153
153
|
// =============================================================================
|
|
@@ -193,6 +193,12 @@ AnchorManager,
|
|
|
193
193
|
MCPManager,
|
|
194
194
|
// Error types
|
|
195
195
|
AgentError, ProviderError, ToolError, ToolTimeoutError, MaxIterationsError, AbortError, } from '@compilr-dev/agents';
|
|
196
|
+
// Error classification — shared by hosts to map provider/agent failures
|
|
197
|
+
// (esp. missing/invalid API key) into stable categories + host-specific copy.
|
|
198
|
+
export { classifyAgentError, isApiKeyError } from './errors/classify.js';
|
|
199
|
+
// Canvas contract — shared visual-canvas types + controls-manifest validation.
|
|
200
|
+
// Also exposed at the renderer-safe subpath `@compilr-dev/sdk/canvas`.
|
|
201
|
+
export { validateControlManifest, seedValues } from './canvas/index.js';
|
|
196
202
|
// =============================================================================
|
|
197
203
|
// Shared Permission Defaults & Utilities
|
|
198
204
|
// =============================================================================
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { IProjectRepository, IWorkItemRepository, IDocumentRepository, IPlanRepository, ICommentRepository } from './repositories.js';
|
|
8
8
|
import type { IAnchorService, IArtifactService, IEpisodeService } from './services.js';
|
|
9
|
+
import type { ICanvasService } from '../canvas/types.js';
|
|
9
10
|
export interface PlatformContext {
|
|
10
11
|
readonly projects: IProjectRepository;
|
|
11
12
|
readonly workItems: IWorkItemRepository;
|
|
@@ -15,6 +16,7 @@ export interface PlatformContext {
|
|
|
15
16
|
readonly anchors?: IAnchorService;
|
|
16
17
|
readonly artifacts?: IArtifactService;
|
|
17
18
|
readonly episodes?: IEpisodeService;
|
|
19
|
+
readonly canvas?: ICanvasService;
|
|
18
20
|
readonly comments?: ICommentRepository;
|
|
19
21
|
}
|
|
20
22
|
export interface PlatformHooks {
|
package/dist/platform/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export type { ProjectType, ProjectStatus, RepoPattern, WorkflowMode, LifecycleSt
|
|
|
5
5
|
export type { IProjectRepository, IWorkItemRepository, IDocumentRepository, IPlanRepository, ICommentRepository, } from './repositories.js';
|
|
6
6
|
export type { IAnchorService, IArtifactService, IEpisodeService, AnchorData, ArtifactType, ArtifactData, ArtifactSummaryData, WorkEpisode, ProjectWorkSummary, } from './services.js';
|
|
7
7
|
export type { PlatformContext, PlatformToolsConfig, PlatformHooks } from './context.js';
|
|
8
|
-
export { createPlatformTools, createProjectTools, createWorkItemTools, createDocumentTools, createPlanTools, createBacklogTools, createAnchorTools, createArtifactTools, createEpisodeTools, createImageTools, } from './tools/index.js';
|
|
8
|
+
export { createPlatformTools, createProjectTools, createWorkItemTools, createDocumentTools, createPlanTools, createBacklogTools, createAnchorTools, createArtifactTools, createEpisodeTools, createCanvasTools, createImageTools, } from './tools/index.js';
|
|
9
9
|
export type { ImageToolsConfig, ImageResizer } from './tools/index.js';
|
|
10
10
|
export { createSQLiteRepositories, SQLiteProjectRepository, SQLiteWorkItemRepository, SQLiteDocumentRepository, SQLitePlanRepository, SQLiteCommentRepository, getDatabase, closeDatabase, closeAllDatabases, databaseExists, SCHEMA_VERSION, SCHEMA_SQL, } from './sqlite/index.js';
|
|
11
11
|
export type { SQLiteRepositories, CreateSQLiteRepositoriesOptions, ProjectDeleteHooks, ProjectRecord, WorkItemRecord, ProjectDocumentRecord, WorkItemCommentRecord, } from './sqlite/index.js';
|
package/dist/platform/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Platform — Repository interfaces, data models, tools, and workflow.
|
|
3
3
|
*/
|
|
4
4
|
// Platform tools (runtime)
|
|
5
|
-
export { createPlatformTools, createProjectTools, createWorkItemTools, createDocumentTools, createPlanTools, createBacklogTools, createAnchorTools, createArtifactTools, createEpisodeTools, createImageTools, } from './tools/index.js';
|
|
5
|
+
export { createPlatformTools, createProjectTools, createWorkItemTools, createDocumentTools, createPlanTools, createBacklogTools, createAnchorTools, createArtifactTools, createEpisodeTools, createCanvasTools, createImageTools, } from './tools/index.js';
|
|
6
6
|
// SQLite implementations (concrete repositories)
|
|
7
7
|
export { createSQLiteRepositories, SQLiteProjectRepository, SQLiteWorkItemRepository, SQLiteDocumentRepository, SQLitePlanRepository, SQLiteCommentRepository, getDatabase, closeDatabase, closeAllDatabases, databaseExists, SCHEMA_VERSION, SCHEMA_SQL, } from './sqlite/index.js';
|
|
8
8
|
// File-based anchor service (shared by CLI and Desktop)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas Tools — agent authoring + management of visual canvases.
|
|
3
|
+
*
|
|
4
|
+
* 4 tools: canvas_write (create/update), canvas_list, canvas_get, canvas_delete.
|
|
5
|
+
*
|
|
6
|
+
* `content` is the agent's raw HTML/SVG; the host renderer injects the CSP +
|
|
7
|
+
* bridge and renders it in a sandboxed iframe. `controls` is the optional Tweaks
|
|
8
|
+
* manifest (validated here). Persistence is delegated to ICanvasService.
|
|
9
|
+
*/
|
|
10
|
+
import type { PlatformToolsConfig } from '../context.js';
|
|
11
|
+
import type { ControlManifest } from '../../canvas/types.js';
|
|
12
|
+
export declare function createCanvasTools(config: PlatformToolsConfig): (import("@compilr-dev/agents").Tool<{
|
|
13
|
+
type: string;
|
|
14
|
+
title: string;
|
|
15
|
+
html: string;
|
|
16
|
+
controls?: ControlManifest;
|
|
17
|
+
canvasId?: string;
|
|
18
|
+
projectId?: string;
|
|
19
|
+
}> | import("@compilr-dev/agents").Tool<{
|
|
20
|
+
canvasId: string;
|
|
21
|
+
}>)[];
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas Tools — agent authoring + management of visual canvases.
|
|
3
|
+
*
|
|
4
|
+
* 4 tools: canvas_write (create/update), canvas_list, canvas_get, canvas_delete.
|
|
5
|
+
*
|
|
6
|
+
* `content` is the agent's raw HTML/SVG; the host renderer injects the CSP +
|
|
7
|
+
* bridge and renders it in a sandboxed iframe. `controls` is the optional Tweaks
|
|
8
|
+
* manifest (validated here). Persistence is delegated to ICanvasService.
|
|
9
|
+
*/
|
|
10
|
+
import { defineTool, createSuccessResult, createErrorResult } from '@compilr-dev/agents';
|
|
11
|
+
import { truncateContent } from './truncate.js';
|
|
12
|
+
import { seedValues } from '../../canvas/types.js';
|
|
13
|
+
import { validateControlManifest } from '../../canvas/validate.js';
|
|
14
|
+
const CANVAS_TYPES = ['infographic', 'carousel', 'board'];
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
16
|
+
export function createCanvasTools(config) {
|
|
17
|
+
const canvas = config.context.canvas;
|
|
18
|
+
if (!canvas)
|
|
19
|
+
throw new Error('canvas service required');
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// canvas_write — create (no canvasId) or update (canvasId given)
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
const canvasWriteTool = defineTool({
|
|
24
|
+
name: 'canvas_write',
|
|
25
|
+
description: 'Create or update a visual canvas (infographic, carousel, or board) rendered from HTML/SVG. ' +
|
|
26
|
+
'Optionally declare a controls manifest ("Tweaks") of live parameters the user can adjust: ' +
|
|
27
|
+
'each control is { type: slider|number|toggle|select|color|text, param, label, default, ...type config }. ' +
|
|
28
|
+
'Bind params in your HTML via CSS custom properties var(--param), [data-bind="param"] text, and ' +
|
|
29
|
+
'[data-show="param"] visibility; for computed updates define window.applyParams(values) in a <script>. ' +
|
|
30
|
+
'Pass canvasId to update an existing canvas; omit it to create a new one.',
|
|
31
|
+
inputSchema: {
|
|
32
|
+
type: 'object',
|
|
33
|
+
properties: {
|
|
34
|
+
type: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
enum: CANVAS_TYPES,
|
|
37
|
+
description: 'Canvas kind: infographic (single composition), carousel (slide sheets), board (infinite 2D).',
|
|
38
|
+
},
|
|
39
|
+
title: { type: 'string', description: 'Canvas title (shown in the library and tab).' },
|
|
40
|
+
html: {
|
|
41
|
+
type: 'string',
|
|
42
|
+
description: 'The canvas content as HTML/SVG. Raw content only — the app injects the sandbox/CSP. ' +
|
|
43
|
+
'May include a <script> defining window.applyParams(values) for live recompute.',
|
|
44
|
+
},
|
|
45
|
+
controls: {
|
|
46
|
+
type: 'object',
|
|
47
|
+
description: 'Optional Tweaks manifest: { "controls": [ { "type": "slider", "param": "headline", "label": "Headline", "default": 40, "min": 24, "max": 72 }, ... ] }.',
|
|
48
|
+
properties: {
|
|
49
|
+
controls: { type: 'array', items: { type: 'object' } },
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
canvasId: {
|
|
53
|
+
type: 'string',
|
|
54
|
+
description: 'Existing canvas id to update. Omit to create a new canvas.',
|
|
55
|
+
},
|
|
56
|
+
projectId: {
|
|
57
|
+
type: 'string',
|
|
58
|
+
description: 'Optional project id. Defaults to the current project.',
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
required: ['type', 'title', 'html'],
|
|
62
|
+
},
|
|
63
|
+
execute: async (input) => {
|
|
64
|
+
try {
|
|
65
|
+
if (input.controls) {
|
|
66
|
+
const check = validateControlManifest(input.controls);
|
|
67
|
+
if (!check.ok) {
|
|
68
|
+
return createErrorResult(`Invalid controls manifest:\n- ${check.errors.join('\n- ')}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (input.canvasId) {
|
|
72
|
+
const updated = await canvas.update(input.canvasId, {
|
|
73
|
+
title: input.title,
|
|
74
|
+
content: input.html,
|
|
75
|
+
// Re-seed values from the new manifest when controls are (re)declared.
|
|
76
|
+
// Phase 1 keeps this simple; a later phase can preserve prior tweaks
|
|
77
|
+
// for surviving params.
|
|
78
|
+
...(input.controls
|
|
79
|
+
? { controls: input.controls, values: seedValues(input.controls) }
|
|
80
|
+
: {}),
|
|
81
|
+
});
|
|
82
|
+
return createSuccessResult(`Updated canvas "${updated.title}" (${updated.type})\nID: ${updated.id}`);
|
|
83
|
+
}
|
|
84
|
+
const controls = input.controls ?? { controls: [] };
|
|
85
|
+
const created = await canvas.create({
|
|
86
|
+
type: input.type,
|
|
87
|
+
title: input.title,
|
|
88
|
+
content: input.html,
|
|
89
|
+
controls,
|
|
90
|
+
values: seedValues(controls),
|
|
91
|
+
projectId: input.projectId,
|
|
92
|
+
});
|
|
93
|
+
return createSuccessResult(`Created canvas "${created.title}" (${created.type})\nID: ${created.id}`);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
return createErrorResult(`Failed to write canvas: ${error instanceof Error ? error.message : String(error)}`);
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
// canvas_list
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
const canvasListTool = defineTool({
|
|
104
|
+
name: 'canvas_list',
|
|
105
|
+
description: 'List the canvases in the current (or given) project.',
|
|
106
|
+
inputSchema: {
|
|
107
|
+
type: 'object',
|
|
108
|
+
properties: {
|
|
109
|
+
projectId: { type: 'string', description: 'Optional project id. Defaults to current.' },
|
|
110
|
+
},
|
|
111
|
+
required: [],
|
|
112
|
+
},
|
|
113
|
+
execute: async (input) => {
|
|
114
|
+
try {
|
|
115
|
+
const items = await canvas.list(input.projectId);
|
|
116
|
+
if (items.length === 0)
|
|
117
|
+
return createSuccessResult('No canvases yet.');
|
|
118
|
+
const lines = items.map((c) => `- [${c.type}] ${c.title} (id: ${c.id})`);
|
|
119
|
+
return createSuccessResult([`${String(items.length)} canvas(es):`, ...lines].join('\n'));
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
return createErrorResult(`Failed to list canvases: ${error instanceof Error ? error.message : String(error)}`);
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
// canvas_get
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
const canvasGetTool = defineTool({
|
|
130
|
+
name: 'canvas_get',
|
|
131
|
+
description: 'Get a canvas by id, including its content, controls manifest, and current values.',
|
|
132
|
+
inputSchema: {
|
|
133
|
+
type: 'object',
|
|
134
|
+
properties: {
|
|
135
|
+
canvasId: { type: 'string', description: 'Canvas id.' },
|
|
136
|
+
},
|
|
137
|
+
required: ['canvasId'],
|
|
138
|
+
},
|
|
139
|
+
execute: async (input) => {
|
|
140
|
+
try {
|
|
141
|
+
const c = await canvas.get(input.canvasId);
|
|
142
|
+
if (!c)
|
|
143
|
+
return createErrorResult(`Canvas "${input.canvasId}" not found.`);
|
|
144
|
+
const tc = truncateContent(c.content);
|
|
145
|
+
const output = `Canvas "${c.title}" (${c.type})\n` +
|
|
146
|
+
`ID: ${c.id}\n` +
|
|
147
|
+
`Controls: ${String(c.controls.controls.length)}\n\n` +
|
|
148
|
+
`--- content ---\n` +
|
|
149
|
+
tc.content;
|
|
150
|
+
return createSuccessResult(output);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
return createErrorResult(`Failed to get canvas: ${error instanceof Error ? error.message : String(error)}`);
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
// canvas_delete
|
|
159
|
+
// ---------------------------------------------------------------------------
|
|
160
|
+
const canvasDeleteTool = defineTool({
|
|
161
|
+
name: 'canvas_delete',
|
|
162
|
+
description: 'Delete a canvas by id.',
|
|
163
|
+
inputSchema: {
|
|
164
|
+
type: 'object',
|
|
165
|
+
properties: {
|
|
166
|
+
canvasId: { type: 'string', description: 'Canvas id.' },
|
|
167
|
+
},
|
|
168
|
+
required: ['canvasId'],
|
|
169
|
+
},
|
|
170
|
+
execute: async (input) => {
|
|
171
|
+
try {
|
|
172
|
+
const deleted = await canvas.delete(input.canvasId);
|
|
173
|
+
if (!deleted)
|
|
174
|
+
return createErrorResult(`Canvas "${input.canvasId}" not found.`);
|
|
175
|
+
return createSuccessResult(`Deleted canvas "${deleted.title}"`);
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
return createErrorResult(`Failed to delete canvas: ${error instanceof Error ? error.message : String(error)}`);
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
return [canvasWriteTool, canvasListTool, canvasGetTool, canvasDeleteTool];
|
|
183
|
+
}
|
|
@@ -31,5 +31,6 @@ export { createBacklogTools } from './backlog-tools.js';
|
|
|
31
31
|
export { createAnchorTools } from './anchor-tools.js';
|
|
32
32
|
export { createArtifactTools } from './artifact-tools.js';
|
|
33
33
|
export { createEpisodeTools } from './episode-tools.js';
|
|
34
|
+
export { createCanvasTools } from './canvas-tools.js';
|
|
34
35
|
export { createImageTools } from './image-tools.js';
|
|
35
36
|
export type { ImageToolsConfig, ImageResizer } from './image-tools.js';
|
|
@@ -16,6 +16,7 @@ import { createBacklogTools } from './backlog-tools.js';
|
|
|
16
16
|
import { createAnchorTools } from './anchor-tools.js';
|
|
17
17
|
import { createArtifactTools } from './artifact-tools.js';
|
|
18
18
|
import { createEpisodeTools } from './episode-tools.js';
|
|
19
|
+
import { createCanvasTools } from './canvas-tools.js';
|
|
19
20
|
import { createImageTools } from './image-tools.js';
|
|
20
21
|
/**
|
|
21
22
|
* Create all platform tools operating against the given context.
|
|
@@ -54,6 +55,9 @@ export function createPlatformTools(config, options) {
|
|
|
54
55
|
if (config.context.episodes) {
|
|
55
56
|
tools.push(...createEpisodeTools(config));
|
|
56
57
|
}
|
|
58
|
+
if (config.context.canvas) {
|
|
59
|
+
tools.push(...createCanvasTools(config));
|
|
60
|
+
}
|
|
57
61
|
return tools;
|
|
58
62
|
}
|
|
59
63
|
// Re-export individual factory functions for selective use
|
|
@@ -65,4 +69,5 @@ export { createBacklogTools } from './backlog-tools.js';
|
|
|
65
69
|
export { createAnchorTools } from './anchor-tools.js';
|
|
66
70
|
export { createArtifactTools } from './artifact-tools.js';
|
|
67
71
|
export { createEpisodeTools } from './episode-tools.js';
|
|
72
|
+
export { createCanvasTools } from './canvas-tools.js';
|
|
68
73
|
export { createImageTools } from './image-tools.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@compilr-dev/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Universal agent runtime for building AI-powered applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -17,6 +17,14 @@
|
|
|
17
17
|
"./flow-runner": {
|
|
18
18
|
"types": "./dist/flow-runner/index.d.ts",
|
|
19
19
|
"import": "./dist/flow-runner/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./errors": {
|
|
22
|
+
"types": "./dist/errors/classify.d.ts",
|
|
23
|
+
"import": "./dist/errors/classify.js"
|
|
24
|
+
},
|
|
25
|
+
"./canvas": {
|
|
26
|
+
"types": "./dist/canvas/index.d.ts",
|
|
27
|
+
"import": "./dist/canvas/index.js"
|
|
20
28
|
}
|
|
21
29
|
},
|
|
22
30
|
"files": [
|