@compilr-dev/sdk 0.16.0 → 0.17.1

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.
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * A Canvas is a persisted visual artifact the agent authors as HTML/SVG, with an
5
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.
6
+ * types are the host-agnostic contract: the SDK owns them + the repository + the
7
+ * tools; hosts (Desktop) own the renderer.
8
8
  *
9
9
  * Intentionally dependency-free so this module can be exposed at the renderer-safe
10
10
  * subpath `@compilr-dev/sdk/canvas` (the Desktop renderer needs the control types
@@ -68,10 +68,13 @@ export type Control = SliderControl | NumberControl | ToggleControl | SelectCont
68
68
  export interface ControlManifest {
69
69
  controls: Control[];
70
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. */
71
+ /**
72
+ * Full persisted canvas. `content` is the agent's raw HTML/SVG only — the CSP +
73
+ * bridge are injected by the host renderer, never stored.
74
+ */
72
75
  export interface CanvasRecord {
73
- id: string;
74
- projectId: string;
76
+ id: number;
77
+ projectId: number;
75
78
  type: CanvasType;
76
79
  title: string;
77
80
  content: string;
@@ -83,31 +86,20 @@ export interface CanvasRecord {
83
86
  }
84
87
  /** Lightweight list entry (no content). */
85
88
  export interface CanvasSummary {
86
- id: string;
87
- projectId: string;
89
+ id: number;
90
+ projectId: number;
88
91
  type: CanvasType;
89
92
  title: string;
90
93
  updatedAt: Date;
91
94
  }
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>;
95
+ export interface CreateCanvasInput {
96
+ projectId: number;
97
+ type: CanvasType;
98
+ title: string;
99
+ content: string;
100
+ controls?: ControlManifest;
101
+ values?: Record<string, ParamValue>;
111
102
  }
103
+ export type UpdateCanvasInput = Partial<Pick<CanvasRecord, 'title' | 'content' | 'controls' | 'values'>>;
112
104
  /** Seed a values map from a manifest's control defaults. */
113
105
  export declare function seedValues(manifest: ControlManifest | undefined): Record<string, ParamValue>;
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * A Canvas is a persisted visual artifact the agent authors as HTML/SVG, with an
5
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.
6
+ * types are the host-agnostic contract: the SDK owns them + the repository + the
7
+ * tools; hosts (Desktop) own the renderer.
8
8
  *
9
9
  * Intentionally dependency-free so this module can be exposed at the renderer-safe
10
10
  * subpath `@compilr-dev/sdk/canvas` (the Desktop renderer needs the control types
package/dist/index.d.ts CHANGED
@@ -53,7 +53,7 @@ export { CapabilityManager, CapabilityContext, createCapabilityHook, autoDetectC
53
53
  export type { CapabilityPack, CapabilityTier, LoadedCapability, CapabilityCatalogEntry, CapabilityLoadResult, CapabilityManagerConfig, CapabilityContextConfig, CapabilityHookConfig, ConditionalModule, AutoDetectResult, } from './capabilities/index.js';
54
54
  export { SystemPromptBuilder, buildSystemPrompt, detectGitRepository, getModuleStats, ALL_MODULES, IDENTITY_MODULE, STYLE_MODULE, TASK_EXECUTION_MODULE, TODO_MANAGEMENT_MODULE, TOOL_USAGE_DIRECT_MODULE, TOOL_USAGE_HINTS_MODULE, PLATFORM_TOOL_HINTS_MODULE, FACTORY_TOOL_HINTS_MODULE, TOOL_USAGE_META_MODULE, DELEGATION_MODULE, GIT_SAFETY_MODULE, SUGGEST_MODULE, IMPORTANT_RULES_MODULE, VISUAL_OUTPUT_MODULE, ENVIRONMENT_MODULE, shouldIncludeModule, getEstimatedTokensForConditions, getTotalEstimatedTokens, } from './system-prompt/index.js';
55
55
  export type { SystemPromptContext, BuildResult, SystemPromptModule, ModuleConditions, } from './system-prompt/index.js';
56
- export type { ProjectType, ProjectStatus, RepoPattern, WorkflowMode, LifecycleState, WorkItemType, WorkItemStatus, WorkItemPriority, GuidedStep, DocumentType, PlanStatus, Project, WorkItem, ProjectDocument, Plan, PlanSummary, PlanWithWorkItem, HistoryEntry, CreateProjectInput, UpdateProjectInput, ProjectListOptions, CreateWorkItemInput, UpdateWorkItemInput, QueryWorkItemsInput, CreateDocumentInput, UpdateDocumentInput, CreatePlanInput, UpdatePlanInput, ListPlansOptions, WorkItemQueryResult, ProjectListResult, BulkCreateItem, WorkItemComment, CreateCommentInput, UpdateCommentInput, IProjectRepository, IWorkItemRepository, IDocumentRepository, IPlanRepository, ICommentRepository, IAnchorService, IArtifactService, IEpisodeService, AnchorData, ArtifactType, ArtifactData, ArtifactSummaryData, WorkEpisode, ProjectWorkSummary, PlatformContext, PlatformToolsConfig, PlatformHooks, StepCriteria, } from './platform/index.js';
56
+ export type { ProjectType, ProjectStatus, RepoPattern, WorkflowMode, LifecycleState, WorkItemType, WorkItemStatus, WorkItemPriority, GuidedStep, DocumentType, PlanStatus, Project, WorkItem, ProjectDocument, Plan, PlanSummary, PlanWithWorkItem, HistoryEntry, CreateProjectInput, UpdateProjectInput, ProjectListOptions, CreateWorkItemInput, UpdateWorkItemInput, QueryWorkItemsInput, CreateDocumentInput, UpdateDocumentInput, CreatePlanInput, UpdatePlanInput, ListPlansOptions, WorkItemQueryResult, ProjectListResult, BulkCreateItem, WorkItemComment, CreateCommentInput, UpdateCommentInput, IProjectRepository, IWorkItemRepository, IDocumentRepository, IPlanRepository, ICommentRepository, ICanvasRepository, IAnchorService, IArtifactService, IEpisodeService, AnchorData, ArtifactType, ArtifactData, ArtifactSummaryData, WorkEpisode, ProjectWorkSummary, PlatformContext, PlatformToolsConfig, PlatformHooks, StepCriteria, } from './platform/index.js';
57
57
  export { createSQLiteRepositories, SQLiteProjectRepository, SQLiteWorkItemRepository, SQLiteDocumentRepository, SQLitePlanRepository, SQLiteCommentRepository, getDatabase, closeDatabase, closeAllDatabases, databaseExists, SCHEMA_VERSION, SCHEMA_SQL, } from './platform/index.js';
58
58
  export type { SQLiteRepositories, CreateSQLiteRepositoriesOptions, ProjectDeleteHooks, ProjectRecord, WorkItemRecord, ProjectDocumentRecord, WorkItemCommentRecord, } from './platform/index.js';
59
59
  export { createAskUserTool, createAskUserSimpleTool, createProposeAlternativesTool, createInteractiveFlowTool, validateFlow, INTERACTIVE_FLOW_INPUT_SCHEMA, } from './tools/index.js';
@@ -81,7 +81,7 @@ export { defineTool, createSuccessResult, createErrorResult, mergeHooks, createL
81
81
  export { classifyAgentError, isApiKeyError } from './errors/classify.js';
82
82
  export type { AgentErrorCategory, AgentErrorInfo } from './errors/classify.js';
83
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';
84
+ export type { CanvasType, ParamValue, Control, ControlManifest, CanvasRecord, CanvasSummary, CreateCanvasInput, UpdateCanvasInput, SliderControl, NumberControl, ToggleControl, SelectControl, ColorControl, TextControl, ManifestValidationResult, } from './canvas/index.js';
85
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';
86
86
  export { DEFAULT_PERMISSION_RULES, WRITE_TOOLS, findMatchingRule, permissionModeLabel, permissionLevelLabel, } from './permissions.js';
87
87
  export type { PermissionRule, PermissionMode, PermissionLevel } from './permissions.js';
@@ -4,9 +4,8 @@
4
4
  * Provides a single entry point for data access, abstracting over the
5
5
  * underlying storage backend (SQLite in CLI, PostgreSQL in web/API).
6
6
  */
7
- import type { IProjectRepository, IWorkItemRepository, IDocumentRepository, IPlanRepository, ICommentRepository } from './repositories.js';
7
+ import type { IProjectRepository, IWorkItemRepository, IDocumentRepository, IPlanRepository, ICommentRepository, ICanvasRepository } from './repositories.js';
8
8
  import type { IAnchorService, IArtifactService, IEpisodeService } from './services.js';
9
- import type { ICanvasService } from '../canvas/types.js';
10
9
  export interface PlatformContext {
11
10
  readonly projects: IProjectRepository;
12
11
  readonly workItems: IWorkItemRepository;
@@ -16,7 +15,7 @@ export interface PlatformContext {
16
15
  readonly anchors?: IAnchorService;
17
16
  readonly artifacts?: IArtifactService;
18
17
  readonly episodes?: IEpisodeService;
19
- readonly canvas?: ICanvasService;
18
+ readonly canvases?: ICanvasRepository;
20
19
  readonly comments?: ICommentRepository;
21
20
  }
22
21
  export interface PlatformHooks {
@@ -2,7 +2,7 @@
2
2
  * Platform — Repository interfaces, data models, tools, and workflow.
3
3
  */
4
4
  export type { ProjectType, ProjectStatus, RepoPattern, WorkflowMode, LifecycleState, WorkItemType, WorkItemStatus, WorkItemPriority, GuidedStep, DocumentType, PlanStatus, Project, WorkItem, ProjectDocument, Plan, PlanSummary, PlanWithWorkItem, HistoryEntry, CreateProjectInput, UpdateProjectInput, ProjectListOptions, CreateWorkItemInput, UpdateWorkItemInput, QueryWorkItemsInput, CreateDocumentInput, UpdateDocumentInput, CreatePlanInput, UpdatePlanInput, ListPlansOptions, WorkItemQueryResult, ProjectListResult, BulkCreateItem, WorkItemComment, CreateCommentInput, UpdateCommentInput, } from './types.js';
5
- export type { IProjectRepository, IWorkItemRepository, IDocumentRepository, IPlanRepository, ICommentRepository, } from './repositories.js';
5
+ export type { IProjectRepository, IWorkItemRepository, IDocumentRepository, IPlanRepository, ICommentRepository, ICanvasRepository, } 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
8
  export { createPlatformTools, createProjectTools, createWorkItemTools, createDocumentTools, createPlanTools, createBacklogTools, createAnchorTools, createArtifactTools, createEpisodeTools, createCanvasTools, createImageTools, } from './tools/index.js';
@@ -6,6 +6,7 @@
6
6
  * backends (PostgreSQL, HTTP APIs).
7
7
  */
8
8
  import type { Project, WorkItem, WorkItemComment, ProjectDocument, Plan, PlanSummary, PlanWithWorkItem, HistoryEntry, CreateProjectInput, UpdateProjectInput, ProjectListOptions, CreateWorkItemInput, UpdateWorkItemInput, QueryWorkItemsInput, CreateCommentInput, UpdateCommentInput, CreateDocumentInput, UpdateDocumentInput, CreatePlanInput, UpdatePlanInput, ListPlansOptions, WorkItemQueryResult, ProjectListResult, BulkCreateItem, ProjectStatus, WorkItemType, WorkItemStatus, DocumentType, PlanStatus } from './types.js';
9
+ import type { CanvasRecord, CanvasSummary, CreateCanvasInput, UpdateCanvasInput } from '../canvas/types.js';
9
10
  export interface IProjectRepository {
10
11
  create(input: CreateProjectInput): Promise<Project>;
11
12
  getById(id: number): Promise<Project | null>;
@@ -46,6 +47,13 @@ export interface IDocumentRepository {
46
47
  deleteByType(projectId: number, docType: DocumentType): Promise<boolean>;
47
48
  getTypeCounts(projectId: number): Promise<Record<string, number>>;
48
49
  }
50
+ export interface ICanvasRepository {
51
+ create(input: CreateCanvasInput): Promise<CanvasRecord>;
52
+ getById(id: number): Promise<CanvasRecord | null>;
53
+ listByProject(projectId: number): Promise<CanvasSummary[]>;
54
+ update(id: number, input: UpdateCanvasInput): Promise<CanvasRecord | null>;
55
+ delete(id: number): Promise<boolean>;
56
+ }
49
57
  export interface IPlanRepository {
50
58
  create(input: CreatePlanInput): Promise<Plan>;
51
59
  getById(id: number): Promise<Plan | null>;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * SQLite Canvas Repository — concrete implementation of ICanvasRepository.
3
+ *
4
+ * `controls` and `values` are stored as JSON text columns. Note `values` is a
5
+ * SQL reserved word, so it is always quoted as "values" in statements.
6
+ */
7
+ import type Database from 'better-sqlite3';
8
+ import type { ICanvasRepository } from '../repositories.js';
9
+ import type { CanvasRecord, CanvasSummary, CreateCanvasInput, UpdateCanvasInput } from '../../canvas/types.js';
10
+ export declare class SQLiteCanvasRepository implements ICanvasRepository {
11
+ private readonly db;
12
+ constructor(db: Database.Database);
13
+ create(input: CreateCanvasInput): Promise<CanvasRecord>;
14
+ getById(id: number): Promise<CanvasRecord | null>;
15
+ listByProject(projectId: number): Promise<CanvasSummary[]>;
16
+ update(id: number, input: UpdateCanvasInput): Promise<CanvasRecord | null>;
17
+ delete(id: number): Promise<boolean>;
18
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * SQLite Canvas Repository — concrete implementation of ICanvasRepository.
3
+ *
4
+ * `controls` and `values` are stored as JSON text columns. Note `values` is a
5
+ * SQL reserved word, so it is always quoted as "values" in statements.
6
+ */
7
+ function parseControls(json) {
8
+ try {
9
+ const parsed = JSON.parse(json);
10
+ return Array.isArray(parsed.controls) ? { controls: parsed.controls } : { controls: [] };
11
+ }
12
+ catch {
13
+ return { controls: [] };
14
+ }
15
+ }
16
+ function parseValues(json) {
17
+ try {
18
+ return JSON.parse(json);
19
+ }
20
+ catch {
21
+ return {};
22
+ }
23
+ }
24
+ function toCanvas(r) {
25
+ return {
26
+ id: r.id,
27
+ projectId: r.project_id,
28
+ type: r.type,
29
+ title: r.title,
30
+ content: r.content,
31
+ controls: parseControls(r.controls),
32
+ values: parseValues(r.values),
33
+ createdAt: new Date(r.created_at),
34
+ updatedAt: new Date(r.updated_at),
35
+ };
36
+ }
37
+ function toSummary(r) {
38
+ return {
39
+ id: r.id,
40
+ projectId: r.project_id,
41
+ type: r.type,
42
+ title: r.title,
43
+ updatedAt: new Date(r.updated_at),
44
+ };
45
+ }
46
+ export class SQLiteCanvasRepository {
47
+ db;
48
+ constructor(db) {
49
+ this.db = db;
50
+ }
51
+ create(input) {
52
+ const now = new Date().toISOString();
53
+ const controls = JSON.stringify(input.controls ?? { controls: [] });
54
+ const values = JSON.stringify(input.values ?? {});
55
+ const result = this.db
56
+ .prepare(`INSERT INTO canvases (project_id, type, title, content, controls, "values", created_at, updated_at)
57
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
58
+ .run(input.projectId, input.type, input.title, input.content, controls, values, now, now);
59
+ const record = this.db
60
+ .prepare('SELECT * FROM canvases WHERE id = ?')
61
+ .get(Number(result.lastInsertRowid));
62
+ return Promise.resolve(toCanvas(record));
63
+ }
64
+ getById(id) {
65
+ const record = this.db.prepare('SELECT * FROM canvases WHERE id = ?').get(id);
66
+ return Promise.resolve(record ? toCanvas(record) : null);
67
+ }
68
+ listByProject(projectId) {
69
+ const rows = this.db
70
+ .prepare('SELECT * FROM canvases WHERE project_id = ? ORDER BY updated_at DESC')
71
+ .all(projectId);
72
+ return Promise.resolve(rows.map(toSummary));
73
+ }
74
+ update(id, input) {
75
+ const existing = this.db.prepare('SELECT * FROM canvases WHERE id = ?').get(id);
76
+ if (!existing)
77
+ return Promise.resolve(null);
78
+ const now = new Date().toISOString();
79
+ const title = input.title ?? existing.title;
80
+ const content = input.content ?? existing.content;
81
+ const controls = input.controls ? JSON.stringify(input.controls) : existing.controls;
82
+ const values = input.values ? JSON.stringify(input.values) : existing.values;
83
+ this.db
84
+ .prepare(`UPDATE canvases SET title = ?, content = ?, controls = ?, "values" = ?, updated_at = ? WHERE id = ?`)
85
+ .run(title, content, controls, values, now, id);
86
+ const record = this.db.prepare('SELECT * FROM canvases WHERE id = ?').get(id);
87
+ return Promise.resolve(toCanvas(record));
88
+ }
89
+ delete(id) {
90
+ const result = this.db.prepare('DELETE FROM canvases WHERE id = ?').run(id);
91
+ return Promise.resolve(result.changes > 0);
92
+ }
93
+ }
@@ -157,4 +157,22 @@ function runMigrations(db, fromVersion, toVersion) {
157
157
  `);
158
158
  db.prepare('INSERT INTO schema_version (version) VALUES (?)').run(7);
159
159
  }
160
+ if (fromVersion < 8 && toVersion >= 8) {
161
+ db.exec(`
162
+ CREATE TABLE IF NOT EXISTS canvases (
163
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
164
+ project_id INTEGER NOT NULL,
165
+ type TEXT NOT NULL,
166
+ title TEXT NOT NULL,
167
+ content TEXT NOT NULL,
168
+ controls TEXT NOT NULL DEFAULT '{"controls":[]}',
169
+ "values" TEXT NOT NULL DEFAULT '{}',
170
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
171
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
172
+ FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
173
+ );
174
+ CREATE INDEX IF NOT EXISTS idx_canvases_project ON canvases(project_id);
175
+ `);
176
+ db.prepare('INSERT INTO schema_version (version) VALUES (?)').run(8);
177
+ }
160
178
  }
@@ -17,13 +17,14 @@
17
17
  */
18
18
  import type Database from 'better-sqlite3';
19
19
  import { type ProjectDeleteHooks } from './project-repository.js';
20
- import type { IProjectRepository, IWorkItemRepository, IDocumentRepository, IPlanRepository, ICommentRepository } from '../repositories.js';
20
+ import type { IProjectRepository, IWorkItemRepository, IDocumentRepository, IPlanRepository, ICommentRepository, ICanvasRepository } from '../repositories.js';
21
21
  export interface SQLiteRepositories {
22
22
  projects: IProjectRepository;
23
23
  workItems: IWorkItemRepository;
24
24
  documents: IDocumentRepository;
25
25
  plans: IPlanRepository;
26
26
  comments: ICommentRepository;
27
+ canvases: ICanvasRepository;
27
28
  }
28
29
  export interface CreateSQLiteRepositoriesOptions {
29
30
  projectDeleteHooks?: ProjectDeleteHooks;
@@ -37,6 +38,7 @@ export { SQLiteWorkItemRepository } from './work-item-repository.js';
37
38
  export { SQLiteDocumentRepository } from './document-repository.js';
38
39
  export { SQLitePlanRepository } from './plan-repository.js';
39
40
  export { SQLiteCommentRepository } from './comment-repository.js';
41
+ export { SQLiteCanvasRepository } from './canvas-repository.js';
40
42
  export { getDatabase, closeDatabase, closeAllDatabases, databaseExists } from './db.js';
41
43
  export { SCHEMA_VERSION, SCHEMA_SQL } from './schema.js';
42
44
  export type { ProjectRecord, WorkItemRecord, ProjectDocumentRecord, WorkItemCommentRecord, } from './schema.js';
@@ -20,6 +20,7 @@ import { SQLiteWorkItemRepository } from './work-item-repository.js';
20
20
  import { SQLiteDocumentRepository } from './document-repository.js';
21
21
  import { SQLitePlanRepository } from './plan-repository.js';
22
22
  import { SQLiteCommentRepository } from './comment-repository.js';
23
+ import { SQLiteCanvasRepository } from './canvas-repository.js';
23
24
  /**
24
25
  * Create all 4 platform repositories backed by a single SQLite database.
25
26
  */
@@ -30,6 +31,7 @@ export function createSQLiteRepositories(db, options) {
30
31
  documents: new SQLiteDocumentRepository(db),
31
32
  plans: new SQLitePlanRepository(db),
32
33
  comments: new SQLiteCommentRepository(db),
34
+ canvases: new SQLiteCanvasRepository(db),
33
35
  };
34
36
  }
35
37
  // Re-export classes for advanced usage
@@ -38,6 +40,7 @@ export { SQLiteWorkItemRepository } from './work-item-repository.js';
38
40
  export { SQLiteDocumentRepository } from './document-repository.js';
39
41
  export { SQLitePlanRepository } from './plan-repository.js';
40
42
  export { SQLiteCommentRepository } from './comment-repository.js';
43
+ export { SQLiteCanvasRepository } from './canvas-repository.js';
41
44
  // Re-export database utilities
42
45
  export { getDatabase, closeDatabase, closeAllDatabases, databaseExists } from './db.js';
43
46
  // Re-export schema (for consumers that need direct access)
@@ -4,8 +4,8 @@
4
4
  * Shared between CLI and Desktop — both access ~/.compilr-dev/projects.db
5
5
  * Schema version must be kept in sync across all consumers.
6
6
  */
7
- export declare const SCHEMA_VERSION = 7;
8
- export declare const SCHEMA_SQL = "\n-- Schema version tracking\nCREATE TABLE IF NOT EXISTS schema_version (\n version INTEGER PRIMARY KEY,\n applied_at DATETIME DEFAULT CURRENT_TIMESTAMP\n);\n\n-- Projects table\nCREATE TABLE IF NOT EXISTS projects (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT UNIQUE NOT NULL,\n display_name TEXT NOT NULL,\n description TEXT,\n type TEXT DEFAULT 'general',\n status TEXT DEFAULT 'active',\n path TEXT NOT NULL,\n docs_path TEXT,\n repo_pattern TEXT DEFAULT 'single',\n language TEXT,\n framework TEXT,\n package_manager TEXT,\n runtime_version TEXT,\n commands TEXT,\n git_remote TEXT,\n git_branch TEXT DEFAULT 'main',\n workflow_mode TEXT DEFAULT 'flexible',\n lifecycle_state TEXT DEFAULT 'setup',\n current_item_id TEXT,\n last_context TEXT,\n metadata TEXT,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n last_activity_at DATETIME\n);\n\n-- Work items (backlog items, tasks, bugs)\nCREATE TABLE IF NOT EXISTS work_items (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n project_id INTEGER NOT NULL,\n item_number INTEGER NOT NULL,\n item_id TEXT NOT NULL,\n type TEXT NOT NULL,\n status TEXT DEFAULT 'backlog',\n priority TEXT DEFAULT 'medium',\n guided_step TEXT,\n owner TEXT,\n title TEXT NOT NULL,\n description TEXT,\n estimated_effort TEXT,\n actual_minutes INTEGER,\n completed_at DATETIME,\n completed_by TEXT,\n commit_hash TEXT,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,\n UNIQUE (project_id, item_id)\n);\n\n-- Project documents (PRD, architecture, plans, etc.)\nCREATE TABLE IF NOT EXISTS project_documents (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n project_id INTEGER NOT NULL,\n doc_type TEXT NOT NULL,\n title TEXT NOT NULL,\n content TEXT NOT NULL,\n status TEXT,\n work_item_id INTEGER,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,\n FOREIGN KEY (work_item_id) REFERENCES work_items(id) ON DELETE SET NULL\n);\n\n-- Work item history (audit trail)\nCREATE TABLE IF NOT EXISTS work_item_history (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n work_item_id INTEGER NOT NULL,\n project_id INTEGER NOT NULL,\n action TEXT NOT NULL,\n old_value TEXT,\n new_value TEXT,\n notes TEXT,\n changed_by TEXT,\n changed_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (work_item_id) REFERENCES work_items(id) ON DELETE CASCADE,\n FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE\n);\n\n-- Indexes\nCREATE INDEX IF NOT EXISTS idx_projects_path ON projects(path);\nCREATE INDEX IF NOT EXISTS idx_projects_docs_path ON projects(docs_path);\nCREATE INDEX IF NOT EXISTS idx_projects_status ON projects(status);\nCREATE INDEX IF NOT EXISTS idx_work_items_project ON work_items(project_id);\nCREATE INDEX IF NOT EXISTS idx_work_items_status ON work_items(status);\nCREATE INDEX IF NOT EXISTS idx_work_items_priority ON work_items(priority);\nCREATE INDEX IF NOT EXISTS idx_work_items_owner ON work_items(owner);\nCREATE INDEX IF NOT EXISTS idx_project_documents_project ON project_documents(project_id);\nCREATE INDEX IF NOT EXISTS idx_project_documents_type ON project_documents(doc_type);\nCREATE INDEX IF NOT EXISTS idx_project_documents_status ON project_documents(status);\nCREATE INDEX IF NOT EXISTS idx_project_documents_work_item ON project_documents(work_item_id);\nCREATE INDEX IF NOT EXISTS idx_work_item_history_item ON work_item_history(work_item_id);\n\n-- Terminal sessions (multi-terminal awareness)\nCREATE TABLE IF NOT EXISTS terminal_sessions (\n id TEXT PRIMARY KEY,\n project_id INTEGER,\n pid INTEGER NOT NULL,\n tty_path TEXT,\n label TEXT,\n started_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n last_heartbeat DATETIME DEFAULT CURRENT_TIMESTAMP,\n active_agent TEXT DEFAULT 'default',\n agents_json TEXT DEFAULT '[]',\n status TEXT DEFAULT 'active',\n FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE SET NULL\n);\nCREATE INDEX IF NOT EXISTS idx_terminal_sessions_project ON terminal_sessions(project_id);\nCREATE INDEX IF NOT EXISTS idx_terminal_sessions_status ON terminal_sessions(status);\n\n-- File locks (multi-terminal file lock awareness)\nCREATE TABLE IF NOT EXISTS file_locks (\n path TEXT NOT NULL,\n project_id INTEGER NOT NULL,\n session_id TEXT NOT NULL,\n agent_id TEXT NOT NULL,\n locked_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (path, project_id),\n FOREIGN KEY (session_id) REFERENCES terminal_sessions(id) ON DELETE CASCADE,\n FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE\n);\nCREATE INDEX IF NOT EXISTS idx_file_locks_session ON file_locks(session_id);\n\n-- Session notifications (cross-session notifications)\nCREATE TABLE IF NOT EXISTS session_notifications (\n id TEXT PRIMARY KEY,\n project_id INTEGER NOT NULL,\n from_session_id TEXT NOT NULL,\n to_session_id TEXT,\n type TEXT NOT NULL,\n title TEXT NOT NULL,\n message TEXT,\n payload_json TEXT,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n read_at DATETIME,\n FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,\n FOREIGN KEY (from_session_id) REFERENCES terminal_sessions(id) ON DELETE CASCADE\n);\nCREATE INDEX IF NOT EXISTS idx_session_notifications_project ON session_notifications(project_id);\nCREATE INDEX IF NOT EXISTS idx_session_notifications_to_session ON session_notifications(to_session_id);\nCREATE INDEX IF NOT EXISTS idx_session_notifications_unread ON session_notifications(read_at);\n\n-- Work item comments\nCREATE TABLE IF NOT EXISTS work_item_comments (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n work_item_id INTEGER NOT NULL,\n project_id INTEGER NOT NULL,\n author TEXT NOT NULL,\n content TEXT NOT NULL,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (work_item_id) REFERENCES work_items(id) ON DELETE CASCADE,\n FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE\n);\nCREATE INDEX IF NOT EXISTS idx_work_item_comments_work_item ON work_item_comments(work_item_id);\nCREATE INDEX IF NOT EXISTS idx_work_item_comments_project ON work_item_comments(project_id);\n";
7
+ export declare const SCHEMA_VERSION = 8;
8
+ export declare const SCHEMA_SQL = "\n-- Schema version tracking\nCREATE TABLE IF NOT EXISTS schema_version (\n version INTEGER PRIMARY KEY,\n applied_at DATETIME DEFAULT CURRENT_TIMESTAMP\n);\n\n-- Projects table\nCREATE TABLE IF NOT EXISTS projects (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT UNIQUE NOT NULL,\n display_name TEXT NOT NULL,\n description TEXT,\n type TEXT DEFAULT 'general',\n status TEXT DEFAULT 'active',\n path TEXT NOT NULL,\n docs_path TEXT,\n repo_pattern TEXT DEFAULT 'single',\n language TEXT,\n framework TEXT,\n package_manager TEXT,\n runtime_version TEXT,\n commands TEXT,\n git_remote TEXT,\n git_branch TEXT DEFAULT 'main',\n workflow_mode TEXT DEFAULT 'flexible',\n lifecycle_state TEXT DEFAULT 'setup',\n current_item_id TEXT,\n last_context TEXT,\n metadata TEXT,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n last_activity_at DATETIME\n);\n\n-- Work items (backlog items, tasks, bugs)\nCREATE TABLE IF NOT EXISTS work_items (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n project_id INTEGER NOT NULL,\n item_number INTEGER NOT NULL,\n item_id TEXT NOT NULL,\n type TEXT NOT NULL,\n status TEXT DEFAULT 'backlog',\n priority TEXT DEFAULT 'medium',\n guided_step TEXT,\n owner TEXT,\n title TEXT NOT NULL,\n description TEXT,\n estimated_effort TEXT,\n actual_minutes INTEGER,\n completed_at DATETIME,\n completed_by TEXT,\n commit_hash TEXT,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,\n UNIQUE (project_id, item_id)\n);\n\n-- Project documents (PRD, architecture, plans, etc.)\nCREATE TABLE IF NOT EXISTS project_documents (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n project_id INTEGER NOT NULL,\n doc_type TEXT NOT NULL,\n title TEXT NOT NULL,\n content TEXT NOT NULL,\n status TEXT,\n work_item_id INTEGER,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,\n FOREIGN KEY (work_item_id) REFERENCES work_items(id) ON DELETE SET NULL\n);\n\n-- Work item history (audit trail)\nCREATE TABLE IF NOT EXISTS work_item_history (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n work_item_id INTEGER NOT NULL,\n project_id INTEGER NOT NULL,\n action TEXT NOT NULL,\n old_value TEXT,\n new_value TEXT,\n notes TEXT,\n changed_by TEXT,\n changed_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (work_item_id) REFERENCES work_items(id) ON DELETE CASCADE,\n FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE\n);\n\n-- Indexes\nCREATE INDEX IF NOT EXISTS idx_projects_path ON projects(path);\nCREATE INDEX IF NOT EXISTS idx_projects_docs_path ON projects(docs_path);\nCREATE INDEX IF NOT EXISTS idx_projects_status ON projects(status);\nCREATE INDEX IF NOT EXISTS idx_work_items_project ON work_items(project_id);\nCREATE INDEX IF NOT EXISTS idx_work_items_status ON work_items(status);\nCREATE INDEX IF NOT EXISTS idx_work_items_priority ON work_items(priority);\nCREATE INDEX IF NOT EXISTS idx_work_items_owner ON work_items(owner);\nCREATE INDEX IF NOT EXISTS idx_project_documents_project ON project_documents(project_id);\nCREATE INDEX IF NOT EXISTS idx_project_documents_type ON project_documents(doc_type);\nCREATE INDEX IF NOT EXISTS idx_project_documents_status ON project_documents(status);\nCREATE INDEX IF NOT EXISTS idx_project_documents_work_item ON project_documents(work_item_id);\nCREATE INDEX IF NOT EXISTS idx_work_item_history_item ON work_item_history(work_item_id);\n\n-- Terminal sessions (multi-terminal awareness)\nCREATE TABLE IF NOT EXISTS terminal_sessions (\n id TEXT PRIMARY KEY,\n project_id INTEGER,\n pid INTEGER NOT NULL,\n tty_path TEXT,\n label TEXT,\n started_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n last_heartbeat DATETIME DEFAULT CURRENT_TIMESTAMP,\n active_agent TEXT DEFAULT 'default',\n agents_json TEXT DEFAULT '[]',\n status TEXT DEFAULT 'active',\n FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE SET NULL\n);\nCREATE INDEX IF NOT EXISTS idx_terminal_sessions_project ON terminal_sessions(project_id);\nCREATE INDEX IF NOT EXISTS idx_terminal_sessions_status ON terminal_sessions(status);\n\n-- File locks (multi-terminal file lock awareness)\nCREATE TABLE IF NOT EXISTS file_locks (\n path TEXT NOT NULL,\n project_id INTEGER NOT NULL,\n session_id TEXT NOT NULL,\n agent_id TEXT NOT NULL,\n locked_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (path, project_id),\n FOREIGN KEY (session_id) REFERENCES terminal_sessions(id) ON DELETE CASCADE,\n FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE\n);\nCREATE INDEX IF NOT EXISTS idx_file_locks_session ON file_locks(session_id);\n\n-- Session notifications (cross-session notifications)\nCREATE TABLE IF NOT EXISTS session_notifications (\n id TEXT PRIMARY KEY,\n project_id INTEGER NOT NULL,\n from_session_id TEXT NOT NULL,\n to_session_id TEXT,\n type TEXT NOT NULL,\n title TEXT NOT NULL,\n message TEXT,\n payload_json TEXT,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n read_at DATETIME,\n FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,\n FOREIGN KEY (from_session_id) REFERENCES terminal_sessions(id) ON DELETE CASCADE\n);\nCREATE INDEX IF NOT EXISTS idx_session_notifications_project ON session_notifications(project_id);\nCREATE INDEX IF NOT EXISTS idx_session_notifications_to_session ON session_notifications(to_session_id);\nCREATE INDEX IF NOT EXISTS idx_session_notifications_unread ON session_notifications(read_at);\n\n-- Work item comments\nCREATE TABLE IF NOT EXISTS work_item_comments (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n work_item_id INTEGER NOT NULL,\n project_id INTEGER NOT NULL,\n author TEXT NOT NULL,\n content TEXT NOT NULL,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (work_item_id) REFERENCES work_items(id) ON DELETE CASCADE,\n FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE\n);\nCREATE INDEX IF NOT EXISTS idx_work_item_comments_work_item ON work_item_comments(work_item_id);\nCREATE INDEX IF NOT EXISTS idx_work_item_comments_project ON work_item_comments(project_id);\n\n-- Canvases (visual reasoning surfaces: infographic / carousel / board)\nCREATE TABLE IF NOT EXISTS canvases (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n project_id INTEGER NOT NULL,\n type TEXT NOT NULL,\n title TEXT NOT NULL,\n content TEXT NOT NULL,\n controls TEXT NOT NULL DEFAULT '{\"controls\":[]}',\n \"values\" TEXT NOT NULL DEFAULT '{}',\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE\n);\nCREATE INDEX IF NOT EXISTS idx_canvases_project ON canvases(project_id);\n";
9
9
  export interface ProjectRecord {
10
10
  id: number;
11
11
  name: string;
@@ -63,6 +63,17 @@ export interface ProjectDocumentRecord {
63
63
  created_at: string;
64
64
  updated_at: string;
65
65
  }
66
+ export interface CanvasDbRecord {
67
+ id: number;
68
+ project_id: number;
69
+ type: string;
70
+ title: string;
71
+ content: string;
72
+ controls: string;
73
+ values: string;
74
+ created_at: string;
75
+ updated_at: string;
76
+ }
66
77
  export interface WorkItemCommentRecord {
67
78
  id: number;
68
79
  work_item_id: number;
@@ -4,7 +4,7 @@
4
4
  * Shared between CLI and Desktop — both access ~/.compilr-dev/projects.db
5
5
  * Schema version must be kept in sync across all consumers.
6
6
  */
7
- export const SCHEMA_VERSION = 7;
7
+ export const SCHEMA_VERSION = 8;
8
8
  export const SCHEMA_SQL = `
9
9
  -- Schema version tracking
10
10
  CREATE TABLE IF NOT EXISTS schema_version (
@@ -171,4 +171,19 @@ CREATE TABLE IF NOT EXISTS work_item_comments (
171
171
  );
172
172
  CREATE INDEX IF NOT EXISTS idx_work_item_comments_work_item ON work_item_comments(work_item_id);
173
173
  CREATE INDEX IF NOT EXISTS idx_work_item_comments_project ON work_item_comments(project_id);
174
+
175
+ -- Canvases (visual reasoning surfaces: infographic / carousel / board)
176
+ CREATE TABLE IF NOT EXISTS canvases (
177
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
178
+ project_id INTEGER NOT NULL,
179
+ type TEXT NOT NULL,
180
+ title TEXT NOT NULL,
181
+ content TEXT NOT NULL,
182
+ controls TEXT NOT NULL DEFAULT '{"controls":[]}',
183
+ "values" TEXT NOT NULL DEFAULT '{}',
184
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
185
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
186
+ FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
187
+ );
188
+ CREATE INDEX IF NOT EXISTS idx_canvases_project ON canvases(project_id);
174
189
  `;
@@ -5,7 +5,8 @@
5
5
  *
6
6
  * `content` is the agent's raw HTML/SVG; the host renderer injects the CSP +
7
7
  * bridge and renders it in a sandboxed iframe. `controls` is the optional Tweaks
8
- * manifest (validated here). Persistence is delegated to ICanvasService.
8
+ * manifest (validated here). Persistence is delegated to ctx.canvases
9
+ * (ICanvasRepository); the current project is resolved like the document tools.
9
10
  */
10
11
  import type { PlatformToolsConfig } from '../context.js';
11
12
  import type { ControlManifest } from '../../canvas/types.js';
@@ -14,8 +15,8 @@ export declare function createCanvasTools(config: PlatformToolsConfig): (import(
14
15
  title: string;
15
16
  html: string;
16
17
  controls?: ControlManifest;
17
- canvasId?: string;
18
- projectId?: string;
18
+ canvas_id?: number;
19
+ project_id?: number;
19
20
  }> | import("@compilr-dev/agents").Tool<{
20
- canvasId: string;
21
+ canvas_id: number;
21
22
  }>)[];
@@ -5,7 +5,8 @@
5
5
  *
6
6
  * `content` is the agent's raw HTML/SVG; the host renderer injects the CSP +
7
7
  * bridge and renders it in a sandboxed iframe. `controls` is the optional Tweaks
8
- * manifest (validated here). Persistence is delegated to ICanvasService.
8
+ * manifest (validated here). Persistence is delegated to ctx.canvases
9
+ * (ICanvasRepository); the current project is resolved like the document tools.
9
10
  */
10
11
  import { defineTool, createSuccessResult, createErrorResult } from '@compilr-dev/agents';
11
12
  import { truncateContent } from './truncate.js';
@@ -14,11 +15,12 @@ import { validateControlManifest } from '../../canvas/validate.js';
14
15
  const CANVAS_TYPES = ['infographic', 'carousel', 'board'];
15
16
  // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
16
17
  export function createCanvasTools(config) {
17
- const canvas = config.context.canvas;
18
- if (!canvas)
19
- throw new Error('canvas service required');
18
+ const ctx = config.context;
19
+ const canvases = ctx.canvases;
20
+ if (!canvases)
21
+ throw new Error('canvases repository required');
20
22
  // ---------------------------------------------------------------------------
21
- // canvas_write — create (no canvasId) or update (canvasId given)
23
+ // canvas_write — create (no canvas_id) or update (canvas_id given)
22
24
  // ---------------------------------------------------------------------------
23
25
  const canvasWriteTool = defineTool({
24
26
  name: 'canvas_write',
@@ -27,7 +29,7 @@ export function createCanvasTools(config) {
27
29
  'each control is { type: slider|number|toggle|select|color|text, param, label, default, ...type config }. ' +
28
30
  'Bind params in your HTML via CSS custom properties var(--param), [data-bind="param"] text, and ' +
29
31
  '[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.',
32
+ 'Pass canvas_id to update an existing canvas; omit it to create a new one.',
31
33
  inputSchema: {
32
34
  type: 'object',
33
35
  properties: {
@@ -49,12 +51,12 @@ export function createCanvasTools(config) {
49
51
  controls: { type: 'array', items: { type: 'object' } },
50
52
  },
51
53
  },
52
- canvasId: {
53
- type: 'string',
54
+ canvas_id: {
55
+ type: 'number',
54
56
  description: 'Existing canvas id to update. Omit to create a new canvas.',
55
57
  },
56
- projectId: {
57
- type: 'string',
58
+ project_id: {
59
+ type: 'number',
58
60
  description: 'Optional project id. Defaults to the current project.',
59
61
  },
60
62
  },
@@ -68,29 +70,34 @@ export function createCanvasTools(config) {
68
70
  return createErrorResult(`Invalid controls manifest:\n- ${check.errors.join('\n- ')}`);
69
71
  }
70
72
  }
71
- if (input.canvasId) {
72
- const updated = await canvas.update(input.canvasId, {
73
+ if (input.canvas_id !== undefined) {
74
+ const updated = await canvases.update(input.canvas_id, {
73
75
  title: input.title,
74
76
  content: input.html,
75
77
  // 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
+ // Phase 1 keeps this simple; a later phase can preserve prior tweaks.
78
79
  ...(input.controls
79
80
  ? { controls: input.controls, values: seedValues(input.controls) }
80
81
  : {}),
81
82
  });
82
- return createSuccessResult(`Updated canvas "${updated.title}" (${updated.type})\nID: ${updated.id}`);
83
+ if (!updated)
84
+ return createErrorResult(`Canvas ${String(input.canvas_id)} not found.`);
85
+ return createSuccessResult(`Updated canvas "${updated.title}" (${updated.type})\nID: ${String(updated.id)}`);
86
+ }
87
+ const projectId = input.project_id ?? ctx.currentProjectId;
88
+ if (!projectId) {
89
+ return createErrorResult('No active project. Provide project_id or select a project.');
83
90
  }
84
91
  const controls = input.controls ?? { controls: [] };
85
- const created = await canvas.create({
92
+ const created = await canvases.create({
93
+ projectId,
86
94
  type: input.type,
87
95
  title: input.title,
88
96
  content: input.html,
89
97
  controls,
90
98
  values: seedValues(controls),
91
- projectId: input.projectId,
92
99
  });
93
- return createSuccessResult(`Created canvas "${created.title}" (${created.type})\nID: ${created.id}`);
100
+ return createSuccessResult(`Created canvas "${created.title}" (${created.type})\nID: ${String(created.id)}`);
94
101
  }
95
102
  catch (error) {
96
103
  return createErrorResult(`Failed to write canvas: ${error instanceof Error ? error.message : String(error)}`);
@@ -106,16 +113,20 @@ export function createCanvasTools(config) {
106
113
  inputSchema: {
107
114
  type: 'object',
108
115
  properties: {
109
- projectId: { type: 'string', description: 'Optional project id. Defaults to current.' },
116
+ project_id: { type: 'number', description: 'Optional project id. Defaults to current.' },
110
117
  },
111
118
  required: [],
112
119
  },
113
120
  execute: async (input) => {
114
121
  try {
115
- const items = await canvas.list(input.projectId);
122
+ const projectId = input.project_id ?? ctx.currentProjectId;
123
+ if (!projectId) {
124
+ return createErrorResult('No active project. Provide project_id or select a project.');
125
+ }
126
+ const items = await canvases.listByProject(projectId);
116
127
  if (items.length === 0)
117
128
  return createSuccessResult('No canvases yet.');
118
- const lines = items.map((c) => `- [${c.type}] ${c.title} (id: ${c.id})`);
129
+ const lines = items.map((c) => `- [${c.type}] ${c.title} (id: ${String(c.id)})`);
119
130
  return createSuccessResult([`${String(items.length)} canvas(es):`, ...lines].join('\n'));
120
131
  }
121
132
  catch (error) {
@@ -132,18 +143,18 @@ export function createCanvasTools(config) {
132
143
  inputSchema: {
133
144
  type: 'object',
134
145
  properties: {
135
- canvasId: { type: 'string', description: 'Canvas id.' },
146
+ canvas_id: { type: 'number', description: 'Canvas id.' },
136
147
  },
137
- required: ['canvasId'],
148
+ required: ['canvas_id'],
138
149
  },
139
150
  execute: async (input) => {
140
151
  try {
141
- const c = await canvas.get(input.canvasId);
152
+ const c = await canvases.getById(input.canvas_id);
142
153
  if (!c)
143
- return createErrorResult(`Canvas "${input.canvasId}" not found.`);
154
+ return createErrorResult(`Canvas ${String(input.canvas_id)} not found.`);
144
155
  const tc = truncateContent(c.content);
145
156
  const output = `Canvas "${c.title}" (${c.type})\n` +
146
- `ID: ${c.id}\n` +
157
+ `ID: ${String(c.id)}\n` +
147
158
  `Controls: ${String(c.controls.controls.length)}\n\n` +
148
159
  `--- content ---\n` +
149
160
  tc.content;
@@ -163,16 +174,16 @@ export function createCanvasTools(config) {
163
174
  inputSchema: {
164
175
  type: 'object',
165
176
  properties: {
166
- canvasId: { type: 'string', description: 'Canvas id.' },
177
+ canvas_id: { type: 'number', description: 'Canvas id.' },
167
178
  },
168
- required: ['canvasId'],
179
+ required: ['canvas_id'],
169
180
  },
170
181
  execute: async (input) => {
171
182
  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}"`);
183
+ const ok = await canvases.delete(input.canvas_id);
184
+ if (!ok)
185
+ return createErrorResult(`Canvas ${String(input.canvas_id)} not found.`);
186
+ return createSuccessResult(`Deleted canvas ${String(input.canvas_id)}`);
176
187
  }
177
188
  catch (error) {
178
189
  return createErrorResult(`Failed to delete canvas: ${error instanceof Error ? error.message : String(error)}`);
@@ -55,7 +55,7 @@ export function createPlatformTools(config, options) {
55
55
  if (config.context.episodes) {
56
56
  tools.push(...createEpisodeTools(config));
57
57
  }
58
- if (config.context.canvas) {
58
+ if (config.context.canvases) {
59
59
  tools.push(...createCanvasTools(config));
60
60
  }
61
61
  return tools;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@compilr-dev/sdk",
3
- "version": "0.16.0",
3
+ "version": "0.17.1",
4
4
  "description": "Universal agent runtime for building AI-powered applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",