@compilr-dev/sdk 0.16.0 → 0.17.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/canvas/types.d.ts +18 -26
- package/dist/canvas/types.js +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/platform/context.d.ts +2 -3
- package/dist/platform/index.d.ts +1 -1
- package/dist/platform/repositories.d.ts +8 -0
- package/dist/platform/sqlite/canvas-repository.d.ts +18 -0
- package/dist/platform/sqlite/canvas-repository.js +93 -0
- package/dist/platform/sqlite/db.js +18 -0
- package/dist/platform/sqlite/index.d.ts +3 -1
- package/dist/platform/sqlite/index.js +3 -0
- package/dist/platform/sqlite/schema.d.ts +13 -2
- package/dist/platform/sqlite/schema.js +16 -1
- package/dist/platform/tools/canvas-tools.d.ts +5 -4
- package/dist/platform/tools/canvas-tools.js +43 -32
- package/dist/platform/tools/index.js +1 -1
- package/package.json +1 -1
package/dist/canvas/types.d.ts
CHANGED
|
@@ -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
|
|
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
|
-
/**
|
|
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:
|
|
74
|
-
projectId:
|
|
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:
|
|
87
|
-
projectId:
|
|
89
|
+
id: number;
|
|
90
|
+
projectId: number;
|
|
88
91
|
type: CanvasType;
|
|
89
92
|
title: string;
|
|
90
93
|
updatedAt: Date;
|
|
91
94
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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>;
|
package/dist/canvas/types.js
CHANGED
|
@@ -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
|
|
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,
|
|
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
|
|
18
|
+
readonly canvases?: ICanvasRepository;
|
|
20
19
|
readonly comments?: ICommentRepository;
|
|
21
20
|
}
|
|
22
21
|
export interface PlatformHooks {
|
package/dist/platform/index.d.ts
CHANGED
|
@@ -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 =
|
|
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
|
+
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
|
|
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
|
-
|
|
18
|
-
|
|
18
|
+
canvas_id?: number;
|
|
19
|
+
project_id?: number;
|
|
19
20
|
}> | import("@compilr-dev/agents").Tool<{
|
|
20
|
-
|
|
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
|
|
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
|
|
18
|
-
|
|
19
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
53
|
-
type: '
|
|
54
|
+
canvas_id: {
|
|
55
|
+
type: 'number',
|
|
54
56
|
description: 'Existing canvas id to update. Omit to create a new canvas.',
|
|
55
57
|
},
|
|
56
|
-
|
|
57
|
-
type: '
|
|
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.
|
|
72
|
-
const updated = await
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
146
|
+
canvas_id: { type: 'number', description: 'Canvas id.' },
|
|
136
147
|
},
|
|
137
|
-
required: ['
|
|
148
|
+
required: ['canvas_id'],
|
|
138
149
|
},
|
|
139
150
|
execute: async (input) => {
|
|
140
151
|
try {
|
|
141
|
-
const c = await
|
|
152
|
+
const c = await canvases.getById(input.canvas_id);
|
|
142
153
|
if (!c)
|
|
143
|
-
return createErrorResult(`Canvas
|
|
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
|
-
|
|
177
|
+
canvas_id: { type: 'number', description: 'Canvas id.' },
|
|
167
178
|
},
|
|
168
|
-
required: ['
|
|
179
|
+
required: ['canvas_id'],
|
|
169
180
|
},
|
|
170
181
|
execute: async (input) => {
|
|
171
182
|
try {
|
|
172
|
-
const
|
|
173
|
-
if (!
|
|
174
|
-
return createErrorResult(`Canvas
|
|
175
|
-
return createSuccessResult(`Deleted canvas
|
|
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.
|
|
58
|
+
if (config.context.canvases) {
|
|
59
59
|
tools.push(...createCanvasTools(config));
|
|
60
60
|
}
|
|
61
61
|
return tools;
|