@kobinflow/canvas-agent 0.6.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.
Files changed (50) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +159 -0
  3. package/agent-instructions.md +13 -0
  4. package/dist/agent/claude.d.ts +3 -0
  5. package/dist/agent/claude.js +54 -0
  6. package/dist/agent/codex-client.d.ts +139 -0
  7. package/dist/agent/codex-client.js +937 -0
  8. package/dist/agent/codex-event-history.d.ts +21 -0
  9. package/dist/agent/codex-event-history.js +163 -0
  10. package/dist/agent/codex-history.d.ts +46 -0
  11. package/dist/agent/codex-history.js +822 -0
  12. package/dist/agent/codex-protocol.d.ts +335 -0
  13. package/dist/agent/codex-protocol.js +1 -0
  14. package/dist/agent/codex.d.ts +178 -0
  15. package/dist/agent/codex.js +509 -0
  16. package/dist/agent/message-metadata.d.ts +51 -0
  17. package/dist/agent/message-metadata.js +378 -0
  18. package/dist/agent/types.d.ts +45 -0
  19. package/dist/agent/types.js +1 -0
  20. package/dist/canvas/operations.d.ts +13 -0
  21. package/dist/canvas/operations.js +167 -0
  22. package/dist/canvas/schemas.d.ts +989 -0
  23. package/dist/canvas/schemas.js +155 -0
  24. package/dist/canvas/session.d.ts +163 -0
  25. package/dist/canvas/session.js +523 -0
  26. package/dist/canvas/tools.d.ts +214 -0
  27. package/dist/canvas/tools.js +27 -0
  28. package/dist/canvas/types.d.ts +34 -0
  29. package/dist/canvas/types.js +1 -0
  30. package/dist/config.d.ts +30 -0
  31. package/dist/config.js +86 -0
  32. package/dist/index.d.ts +2 -0
  33. package/dist/index.js +7 -0
  34. package/dist/server/http.d.ts +2 -0
  35. package/dist/server/http.js +576 -0
  36. package/dist/server/mcp.d.ts +2 -0
  37. package/dist/server/mcp.js +27 -0
  38. package/dist/skills/store.d.ts +54 -0
  39. package/dist/skills/store.js +426 -0
  40. package/dist/utils/agent-runtime.d.ts +8 -0
  41. package/dist/utils/agent-runtime.js +33 -0
  42. package/dist/utils/date.d.ts +2 -0
  43. package/dist/utils/date.js +7 -0
  44. package/dist/utils/logger.d.ts +17 -0
  45. package/dist/utils/logger.js +81 -0
  46. package/dist/utils/value.d.ts +5 -0
  47. package/dist/utils/value.js +8 -0
  48. package/dist/version-check.d.ts +2 -0
  49. package/dist/version-check.js +65 -0
  50. package/package.json +55 -0
@@ -0,0 +1,214 @@
1
+ import { type ToolName } from "./schemas.js";
2
+ import type { CanvasNode, CanvasSnapshot } from "./types.js";
3
+ /** 判断传入名称是否为已注册的画布工具。 */
4
+ export declare function isToolName(name: unknown): name is ToolName;
5
+ /** 按工具名称校验并解析调用参数。 */
6
+ export declare function parseToolInput(name: ToolName, input: unknown): {
7
+ path: string;
8
+ } | {
9
+ keyword?: string | undefined;
10
+ page?: number | undefined;
11
+ pageSize?: number | undefined;
12
+ } | {
13
+ ops: (import("zod").objectOutputType<{
14
+ type: import("zod").ZodLiteral<"add_node">;
15
+ nodeType: import("zod").ZodOptional<import("zod").ZodEnum<["image", "text", "config", "video", "audio"]>>;
16
+ id: import("zod").ZodOptional<import("zod").ZodString>;
17
+ title: import("zod").ZodOptional<import("zod").ZodString>;
18
+ x: import("zod").ZodOptional<import("zod").ZodNumber>;
19
+ y: import("zod").ZodOptional<import("zod").ZodNumber>;
20
+ width: import("zod").ZodOptional<import("zod").ZodNumber>;
21
+ height: import("zod").ZodOptional<import("zod").ZodNumber>;
22
+ position: import("zod").ZodOptional<import("zod").ZodObject<{
23
+ x: import("zod").ZodNumber;
24
+ y: import("zod").ZodNumber;
25
+ }, "strip", import("zod").ZodTypeAny, {
26
+ x: number;
27
+ y: number;
28
+ }, {
29
+ x: number;
30
+ y: number;
31
+ }>>;
32
+ metadata: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodUnknown>>;
33
+ }, import("zod").ZodTypeAny, "passthrough"> | import("zod").objectOutputType<{
34
+ type: import("zod").ZodLiteral<"update_node">;
35
+ id: import("zod").ZodString;
36
+ patch: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodUnknown>>;
37
+ metadata: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodUnknown>>;
38
+ }, import("zod").ZodTypeAny, "passthrough"> | import("zod").objectOutputType<{
39
+ type: import("zod").ZodLiteral<"delete_node">;
40
+ id: import("zod").ZodOptional<import("zod").ZodString>;
41
+ ids: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
42
+ }, import("zod").ZodTypeAny, "passthrough"> | import("zod").objectOutputType<{
43
+ type: import("zod").ZodLiteral<"delete_connections">;
44
+ id: import("zod").ZodOptional<import("zod").ZodString>;
45
+ ids: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
46
+ all: import("zod").ZodOptional<import("zod").ZodBoolean>;
47
+ }, import("zod").ZodTypeAny, "passthrough"> | import("zod").objectOutputType<{
48
+ type: import("zod").ZodLiteral<"connect_nodes">;
49
+ id: import("zod").ZodOptional<import("zod").ZodString>;
50
+ fromNodeId: import("zod").ZodString;
51
+ toNodeId: import("zod").ZodString;
52
+ }, import("zod").ZodTypeAny, "passthrough"> | import("zod").objectOutputType<{
53
+ type: import("zod").ZodLiteral<"set_viewport">;
54
+ viewport: import("zod").ZodObject<{
55
+ x: import("zod").ZodNumber;
56
+ y: import("zod").ZodNumber;
57
+ k: import("zod").ZodNumber;
58
+ }, "strip", import("zod").ZodTypeAny, {
59
+ x: number;
60
+ y: number;
61
+ k: number;
62
+ }, {
63
+ x: number;
64
+ y: number;
65
+ k: number;
66
+ }>;
67
+ }, import("zod").ZodTypeAny, "passthrough"> | import("zod").objectOutputType<{
68
+ type: import("zod").ZodLiteral<"select_nodes">;
69
+ ids: import("zod").ZodArray<import("zod").ZodString, "many">;
70
+ }, import("zod").ZodTypeAny, "passthrough"> | import("zod").objectOutputType<{
71
+ type: import("zod").ZodLiteral<"run_generation">;
72
+ nodeId: import("zod").ZodString;
73
+ mode: import("zod").ZodOptional<import("zod").ZodEnum<["text", "image", "video", "audio"]>>;
74
+ prompt: import("zod").ZodOptional<import("zod").ZodString>;
75
+ }, import("zod").ZodTypeAny, "passthrough">)[];
76
+ } | {
77
+ nodeType: "image" | "video" | "audio" | "text" | "config";
78
+ title?: string | undefined;
79
+ metadata?: Record<string, unknown> | undefined;
80
+ width?: number | undefined;
81
+ height?: number | undefined;
82
+ x?: number | undefined;
83
+ y?: number | undefined;
84
+ } | {
85
+ attachmentIds: string[];
86
+ x?: number | undefined;
87
+ y?: number | undefined;
88
+ gap?: number | undefined;
89
+ direction?: "row" | "column" | undefined;
90
+ } | {
91
+ text?: string | undefined;
92
+ title?: string | undefined;
93
+ width?: number | undefined;
94
+ height?: number | undefined;
95
+ x?: number | undefined;
96
+ y?: number | undefined;
97
+ } | {
98
+ items: {
99
+ text: string;
100
+ title?: string | undefined;
101
+ width?: number | undefined;
102
+ height?: number | undefined;
103
+ x?: number | undefined;
104
+ y?: number | undefined;
105
+ }[];
106
+ x?: number | undefined;
107
+ y?: number | undefined;
108
+ gap?: number | undefined;
109
+ direction?: "row" | "column" | undefined;
110
+ } | {
111
+ [x: string]: any;
112
+ } | {
113
+ id: string;
114
+ metadata?: Record<string, unknown> | undefined;
115
+ patch?: Record<string, unknown> | undefined;
116
+ } | {
117
+ text: string;
118
+ id: string;
119
+ title?: string | undefined;
120
+ } | {
121
+ items: {
122
+ id: string;
123
+ x?: number | undefined;
124
+ y?: number | undefined;
125
+ dx?: number | undefined;
126
+ dy?: number | undefined;
127
+ }[];
128
+ } | {
129
+ id: string;
130
+ width: number;
131
+ height: number;
132
+ freeResize?: boolean | undefined;
133
+ } | {
134
+ ids: string[];
135
+ } | {
136
+ connections: {
137
+ fromNodeId: string;
138
+ toNodeId: string;
139
+ }[];
140
+ } | {
141
+ viewport: {
142
+ x: number;
143
+ y: number;
144
+ k: number;
145
+ };
146
+ } | {
147
+ nodeId: string;
148
+ mode?: "image" | "video" | "audio" | "text" | undefined;
149
+ prompt?: string | undefined;
150
+ } | {
151
+ limit?: number | undefined;
152
+ scope?: "image" | "video" | "canvas" | "all" | undefined;
153
+ taskId?: string | undefined;
154
+ nodeIds?: string[] | undefined;
155
+ } | {
156
+ prompt: string;
157
+ count?: number | undefined;
158
+ model?: string | undefined;
159
+ size?: string | undefined;
160
+ quality?: string | undefined;
161
+ run?: boolean | undefined;
162
+ } | {
163
+ prompt: string;
164
+ mode?: "frames" | "reference" | undefined;
165
+ model?: string | undefined;
166
+ size?: string | undefined;
167
+ seconds?: string | undefined;
168
+ generateAudio?: boolean | undefined;
169
+ watermark?: boolean | undefined;
170
+ run?: boolean | undefined;
171
+ resolution?: string | undefined;
172
+ } | {
173
+ kind: "image" | "text";
174
+ title: string;
175
+ source?: string | undefined;
176
+ note?: string | undefined;
177
+ content?: string | undefined;
178
+ tags?: string[] | undefined;
179
+ imageUrl?: string | undefined;
180
+ };
181
+ /** 压缩画布快照,避免向 Agent 返回过长的节点内容。 */
182
+ export declare function compactCanvasState(state: CanvasSnapshot | null): {
183
+ nodes: {
184
+ id: string;
185
+ type: import("./types.js").CanvasNodeType;
186
+ title: string | undefined;
187
+ position: import("./types.js").Position;
188
+ width: number;
189
+ height: number;
190
+ metadata: {
191
+ [x: string]: unknown;
192
+ };
193
+ }[];
194
+ projectId?: string;
195
+ title?: string;
196
+ connections?: import("./types.js").CanvasConnection[];
197
+ selectedNodeIds?: string[];
198
+ viewport?: import("./types.js").Viewport;
199
+ clientId?: string;
200
+ };
201
+ /** 压缩单个画布节点的元数据内容。 */
202
+ export declare function compactNode(node: CanvasNode): {
203
+ id: string;
204
+ type: import("./types.js").CanvasNodeType;
205
+ title: string | undefined;
206
+ position: import("./types.js").Position;
207
+ width: number;
208
+ height: number;
209
+ metadata: {
210
+ [x: string]: unknown;
211
+ };
212
+ };
213
+ /** 计算新节点在当前画布右侧的默认横坐标。 */
214
+ export declare function nextCanvasX(state: CanvasSnapshot | null): number;
@@ -0,0 +1,27 @@
1
+ import { toolInputSchemas, toolNames } from "./schemas.js";
2
+ /** 判断传入名称是否为已注册的画布工具。 */
3
+ export function isToolName(name) {
4
+ return typeof name === "string" && toolNames.includes(name);
5
+ }
6
+ /** 按工具名称校验并解析调用参数。 */
7
+ export function parseToolInput(name, input) {
8
+ return toolInputSchemas[name].parse(input ?? {});
9
+ }
10
+ /** 压缩画布快照,避免向 Agent 返回过长的节点内容。 */
11
+ export function compactCanvasState(state) {
12
+ if (!state)
13
+ throw new Error("当前没有已连接画布");
14
+ return { ...state, nodes: (state.nodes || []).map(compactNode) };
15
+ }
16
+ /** 压缩单个画布节点的元数据内容。 */
17
+ export function compactNode(node) {
18
+ const metadata = { ...(node.metadata || {}) };
19
+ if (typeof metadata.content === "string" && metadata.content.length > 240)
20
+ metadata.content = `${metadata.content.slice(0, 120)}...`;
21
+ return { id: node.id, type: node.type, title: node.title, position: node.position, width: node.width, height: node.height, metadata };
22
+ }
23
+ /** 计算新节点在当前画布右侧的默认横坐标。 */
24
+ export function nextCanvasX(state) {
25
+ const nodes = state?.nodes || [];
26
+ return nodes.length ? Math.max(...nodes.map((node) => node.position.x + node.width)) + 80 : 0;
27
+ }
@@ -0,0 +1,34 @@
1
+ /** 画布坐标。 */
2
+ export type Position = {
3
+ x: number;
4
+ y: number;
5
+ };
6
+ export type Viewport = {
7
+ x: number;
8
+ y: number;
9
+ k: number;
10
+ };
11
+ export type CanvasNodeType = "image" | "text" | "config" | "video" | "audio";
12
+ export type CanvasNode = {
13
+ id: string;
14
+ type: CanvasNodeType;
15
+ title?: string;
16
+ position: Position;
17
+ width: number;
18
+ height: number;
19
+ metadata?: Record<string, unknown>;
20
+ };
21
+ export type CanvasConnection = {
22
+ id: string;
23
+ fromNodeId: string;
24
+ toNodeId: string;
25
+ };
26
+ export type CanvasSnapshot = {
27
+ projectId?: string;
28
+ title?: string;
29
+ nodes?: CanvasNode[];
30
+ connections?: CanvasConnection[];
31
+ selectedNodeIds?: string[];
32
+ viewport?: Viewport;
33
+ clientId?: string;
34
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,30 @@
1
+ export declare const DEFAULT_PORT = 17371;
2
+ export declare const CONFIG_DIR: string;
3
+ export declare const CONFIG_FILE: string;
4
+ export declare const VERSION: string;
5
+ export declare const AGENT_PROMPT: string;
6
+ export type SiteWorkspaceConfig = {
7
+ workspacePath: string;
8
+ activeThreadId?: string;
9
+ pinnedThreadIds?: string[];
10
+ };
11
+ export type CanvasAgentConfig = {
12
+ url: string;
13
+ token: string;
14
+ origins?: string[];
15
+ workspace?: SiteWorkspaceConfig;
16
+ };
17
+ /** 读取本地 Canvas Agent 配置,不存在时生成默认配置。 */
18
+ export declare function loadConfig(create?: boolean): CanvasAgentConfig;
19
+ /** 将 Canvas Agent 配置写入用户配置目录。 */
20
+ export declare function saveConfig(config: CanvasAgentConfig): void;
21
+ /** 写入配置并强制目录 0700、文件 0600,包括纠正已有宽松权限。 */
22
+ export declare function writeConfigFile(dir: string, file: string, config: CanvasAgentConfig): void;
23
+ /** 确保站点级 Codex 工作空间存在并已初始化。 */
24
+ export declare function ensureSiteWorkspace(config: CanvasAgentConfig): {
25
+ workspacePath: string;
26
+ activeThreadId?: string;
27
+ pinnedThreadIds?: string[];
28
+ };
29
+ /** 更新站点级 Codex 工作空间配置。 */
30
+ export declare function updateSiteWorkspace(config: CanvasAgentConfig, patch: Partial<SiteWorkspaceConfig>): SiteWorkspaceConfig;
package/dist/config.js ADDED
@@ -0,0 +1,86 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ export const DEFAULT_PORT = 17371;
6
+ export const CONFIG_DIR = path.join(os.homedir(), ".infinite-canvas");
7
+ export const CONFIG_FILE = path.join(CONFIG_DIR, "canvas-agent.json");
8
+ export const VERSION = readPackageVersion();
9
+ export const AGENT_PROMPT = fs.readFileSync(new URL("../agent-instructions.md", import.meta.url), "utf8");
10
+ const initializedWorkspaces = new Set();
11
+ /** 读取本地 Canvas Agent 配置,不存在时生成默认配置。 */
12
+ export function loadConfig(create = false) {
13
+ try {
14
+ return JSON.parse(fs.readFileSync(CONFIG_FILE, "utf8"));
15
+ }
16
+ catch {
17
+ const config = { url: `http://127.0.0.1:${Number(process.env.PORT) || DEFAULT_PORT}`, token: crypto.randomBytes(18).toString("hex") };
18
+ if (create)
19
+ saveConfig(config);
20
+ return config;
21
+ }
22
+ }
23
+ /** 将 Canvas Agent 配置写入用户配置目录。 */
24
+ export function saveConfig(config) {
25
+ writeConfigFile(CONFIG_DIR, CONFIG_FILE, config);
26
+ }
27
+ /** 写入配置并强制目录 0700、文件 0600,包括纠正已有宽松权限。 */
28
+ export function writeConfigFile(dir, file, config) {
29
+ fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
30
+ fs.writeFileSync(file, JSON.stringify(config, null, 2), { mode: 0o600 });
31
+ fs.chmodSync(dir, 0o700);
32
+ fs.chmodSync(file, 0o600);
33
+ }
34
+ /** 确保站点级 Codex 工作空间存在并已初始化。 */
35
+ export function ensureSiteWorkspace(config) {
36
+ const current = config.workspace;
37
+ if (current?.workspacePath) {
38
+ const workspacePath = resolveWorkspacePath(current.workspacePath);
39
+ initializeWorkspace(workspacePath);
40
+ return { ...current, workspacePath };
41
+ }
42
+ const workspacePath = path.join(CONFIG_DIR, "codex-workspaces", "site");
43
+ config.workspace = { workspacePath };
44
+ initializeWorkspace(workspacePath);
45
+ saveConfig(config);
46
+ return { workspacePath };
47
+ }
48
+ /** 更新站点级 Codex 工作空间配置。 */
49
+ export function updateSiteWorkspace(config, patch) {
50
+ const current = ensureSiteWorkspace(config);
51
+ const workspacePath = patch.workspacePath ? resolveWorkspacePath(patch.workspacePath) : current.workspacePath;
52
+ const next = { ...current, ...patch, workspacePath };
53
+ config.workspace = { workspacePath: next.workspacePath, activeThreadId: next.activeThreadId, pinnedThreadIds: next.pinnedThreadIds };
54
+ initializeWorkspace(workspacePath);
55
+ saveConfig(config);
56
+ return config.workspace;
57
+ }
58
+ /** 创建工作空间目录并写入默认 AGENTS.md。 */
59
+ function initializeWorkspace(workspacePath) {
60
+ if (initializedWorkspaces.has(workspacePath))
61
+ return;
62
+ fs.mkdirSync(workspacePath, { recursive: true });
63
+ const instructionsFile = path.join(workspacePath, "AGENTS.md");
64
+ const current = fs.existsSync(instructionsFile) ? fs.readFileSync(instructionsFile, "utf8") : "";
65
+ if (!current || current.startsWith("# Infinite Canvas Agent"))
66
+ fs.writeFileSync(instructionsFile, AGENT_PROMPT);
67
+ initializedWorkspaces.add(workspacePath);
68
+ }
69
+ /** 将用户输入的工作空间路径解析为绝对路径。 */
70
+ function resolveWorkspacePath(value) {
71
+ if (value === "~")
72
+ return os.homedir();
73
+ if (value.startsWith("~/"))
74
+ return path.join(os.homedir(), value.slice(2));
75
+ return path.resolve(value);
76
+ }
77
+ /** 从当前包信息中读取 Canvas Agent 版本号。 */
78
+ function readPackageVersion() {
79
+ try {
80
+ const pkg = JSON.parse(fs.readFileSync(new URL("../package.json", import.meta.url), "utf8"));
81
+ return pkg.version || "0.0.0";
82
+ }
83
+ catch {
84
+ return "0.0.0";
85
+ }
86
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { startHttpServer } from "./server/http.js";
3
+ import { startMcpServer } from "./server/mcp.js";
4
+ if (process.argv[2] === "mcp")
5
+ await startMcpServer();
6
+ else
7
+ startHttpServer();
@@ -0,0 +1,2 @@
1
+ /** 启动仅监听本机的 Canvas Agent HTTP 服务。 */
2
+ export declare function startHttpServer(): void;