claude-canvas 1.0.2 → 1.0.4

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/README.md CHANGED
@@ -69,8 +69,19 @@ It also serves as a **visual Q&A tool** — Claude can send structured questions
69
69
 
70
70
  ```bash
71
71
  npm install -g claude-canvas
72
+ claude-canvas setup
72
73
  ```
73
74
 
75
+ The `setup` command installs the Claude Code skill, which lets Claude automatically use the canvas when it makes sense.
76
+
77
+ ### Updating
78
+
79
+ ```bash
80
+ claude-canvas update
81
+ ```
82
+
83
+ This checks for the latest version, installs it, and automatically updates the Claude Code skill if it has changed.
84
+
74
85
  ### From source
75
86
 
76
87
  ```bash
@@ -79,6 +90,7 @@ cd claude-canvas
79
90
  npm install
80
91
  npm run build
81
92
  npm link # makes `claude-canvas` available globally
93
+ claude-canvas setup
82
94
  ```
83
95
 
84
96
  ### Requirements
@@ -365,10 +377,10 @@ Install the included skill so Claude Code automatically knows when and how to us
365
377
  ### Installation
366
378
 
367
379
  ```bash
368
- cp -r src/skill/claude-canvas ~/.claude/skills/
380
+ claude-canvas setup
369
381
  ```
370
382
 
371
- Or if installed globally via npm:
383
+ This interactively installs (or updates) the skill to `~/.claude/skills/claude-canvas/`. You can also install it manually:
372
384
 
373
385
  ```bash
374
386
  cp -r $(npm root -g)/claude-canvas/src/skill/claude-canvas ~/.claude/skills/
@@ -3179,10 +3179,12 @@ function spawnServer(port) {
3179
3179
  // src/bin/claude-canvas.ts
3180
3180
  var import_node_fs = require("node:fs");
3181
3181
  var import_node_path = require("node:path");
3182
+ var import_node_os = require("node:os");
3183
+ var import_node_readline = require("node:readline");
3182
3184
  var import_node_url = require("node:url");
3183
3185
  var import_meta = {};
3184
3186
  function getVersion() {
3185
- if (true) return "1.0.2";
3187
+ if (true) return "1.0.4";
3186
3188
  try {
3187
3189
  const dir = (0, import_node_path.dirname)((0, import_node_url.fileURLToPath)(import_meta.url));
3188
3190
  const pkg = JSON.parse((0, import_node_fs.readFileSync)((0, import_node_path.resolve)(dir, "../../package.json"), "utf-8"));
@@ -3318,11 +3320,83 @@ program2.command("update").description("Check for updates and install the latest
3318
3320
  const { execSync } = await import("child_process");
3319
3321
  execSync("npm install -g claude-canvas@latest", { stdio: "inherit" });
3320
3322
  console.log(`Successfully updated to ${latest}`);
3323
+ const skillDestDir = (0, import_node_path.join)((0, import_node_os.homedir)(), ".claude", "skills", "claude-canvas");
3324
+ const skillDest = (0, import_node_path.join)(skillDestDir, "SKILL.md");
3325
+ if ((0, import_node_fs.existsSync)(skillDest)) {
3326
+ const skillSourceDir = (0, import_node_path.resolve)((0, import_node_path.dirname)((0, import_node_url.fileURLToPath)(import_meta.url)), "../../src/skill/claude-canvas");
3327
+ const skillSource = (0, import_node_path.join)(skillSourceDir, "SKILL.md");
3328
+ if ((0, import_node_fs.existsSync)(skillSource)) {
3329
+ const installed = (0, import_node_fs.readFileSync)(skillDest, "utf-8");
3330
+ const bundled = (0, import_node_fs.readFileSync)(skillSource, "utf-8");
3331
+ if (installed !== bundled) {
3332
+ (0, import_node_fs.copyFileSync)(skillSource, skillDest);
3333
+ console.log("\x1B[32m\u2713\x1B[0m Claude Code skill updated to the latest version.");
3334
+ }
3335
+ }
3336
+ }
3321
3337
  } catch (err) {
3322
3338
  console.error("Update failed:", err.message);
3323
3339
  process.exit(1);
3324
3340
  }
3325
3341
  });
3342
+ program2.command("setup").description("Install or update the Claude Code skill for canvas").action(async () => {
3343
+ const skillSourceDir = (0, import_node_path.resolve)((0, import_node_path.dirname)((0, import_node_url.fileURLToPath)(import_meta.url)), "../../src/skill/claude-canvas");
3344
+ const skillSource = (0, import_node_path.join)(skillSourceDir, "SKILL.md");
3345
+ const skillDestDir = (0, import_node_path.join)((0, import_node_os.homedir)(), ".claude", "skills", "claude-canvas");
3346
+ const skillDest = (0, import_node_path.join)(skillDestDir, "SKILL.md");
3347
+ const skillUrl = "https://github.com/uditalias/claude-canvas/blob/main/src/skill/claude-canvas/SKILL.md";
3348
+ if (!(0, import_node_fs.existsSync)(skillSource)) {
3349
+ console.error("Skill source not found. Try reinstalling claude-canvas.");
3350
+ process.exit(1);
3351
+ }
3352
+ const bundled = (0, import_node_fs.readFileSync)(skillSource, "utf-8");
3353
+ const installed = (0, import_node_fs.existsSync)(skillDest) ? (0, import_node_fs.readFileSync)(skillDest, "utf-8") : null;
3354
+ console.log("");
3355
+ if (installed && installed === bundled) {
3356
+ console.log(" \x1B[1m\x1B[32m\u2713\x1B[0m Skill is already installed and up to date.");
3357
+ console.log(` \x1B[2m${skillDest}\x1B[0m`);
3358
+ console.log("");
3359
+ return;
3360
+ }
3361
+ const isUpdate = installed !== null;
3362
+ console.log(isUpdate ? " \x1B[1m\x1B[33m\u26A1\x1B[0m A new version of the claude-canvas skill is available." : " \x1B[1m\x1B[36m\u2728\x1B[0m claude-canvas skill setup");
3363
+ console.log("");
3364
+ console.log(" The skill lets Claude Code use the canvas tool automatically.");
3365
+ console.log(" It will be installed to:");
3366
+ console.log(` \x1B[36m${skillDest}\x1B[0m`);
3367
+ console.log("");
3368
+ const rl = (0, import_node_readline.createInterface)({ input: process.stdin, output: process.stdout });
3369
+ const ask = (q) => new Promise((resolve3) => rl.question(q, (a) => resolve3(a.trim().toLowerCase())));
3370
+ const viewSkill = await ask(" Would you like to view the skill before installing? (y/N) ");
3371
+ if (viewSkill === "y" || viewSkill === "yes") {
3372
+ console.log("");
3373
+ console.log(` \x1B[4m${skillUrl}\x1B[0m`);
3374
+ console.log("");
3375
+ }
3376
+ const action = isUpdate ? "Update" : "Install";
3377
+ const confirm = await ask(` ${action} the skill to ~/.claude/skills/? (Y/n) `);
3378
+ if (confirm === "n" || confirm === "no") {
3379
+ console.log("");
3380
+ console.log(" Skipped. You can run this again anytime with:");
3381
+ console.log(" \x1B[33mclaude-canvas setup\x1B[0m");
3382
+ console.log("");
3383
+ } else {
3384
+ try {
3385
+ (0, import_node_fs.mkdirSync)(skillDestDir, { recursive: true });
3386
+ (0, import_node_fs.copyFileSync)(skillSource, skillDest);
3387
+ console.log("");
3388
+ console.log(` \x1B[1m\x1B[32m\u2713\x1B[0m Skill ${isUpdate ? "updated" : "installed"} to \x1B[36m${skillDest}\x1B[0m`);
3389
+ console.log("");
3390
+ } catch (err) {
3391
+ console.log("");
3392
+ console.log(` \x1B[31m\u2717 Failed: ${err.message}\x1B[0m`);
3393
+ console.log(" You can install it manually:");
3394
+ console.log(` \x1B[33mcp -r $(npm root -g)/claude-canvas/src/skill/claude-canvas ~/.claude/skills/\x1B[0m`);
3395
+ console.log("");
3396
+ }
3397
+ }
3398
+ rl.close();
3399
+ });
3326
3400
  program2.parse();
3327
3401
  function fetchLatestVersion() {
3328
3402
  return new Promise((resolve3, reject) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-canvas",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "A shared visual canvas for Claude Code",
5
5
  "license": "MIT",
6
6
  "author": "Udi Talias",
@@ -12,6 +12,11 @@
12
12
  "bugs": {
13
13
  "url": "https://github.com/uditalias/claude-canvas/issues"
14
14
  },
15
+ "publishConfig": {
16
+ "provenance": false,
17
+ "access": "public",
18
+ "registry": "https://registry.npmjs.org/"
19
+ },
15
20
  "keywords": [
16
21
  "claude",
17
22
  "canvas",
@@ -1,126 +1,49 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const readline = require("readline");
4
3
  const fs = require("fs");
5
4
  const path = require("path");
6
5
  const os = require("os");
7
6
 
8
- const SKILL_SOURCE = path.resolve(__dirname, "../src/skill/claude-canvas/SKILL.md");
9
- const SKILL_DEST_DIR = path.join(os.homedir(), ".claude", "skills", "claude-canvas");
10
- const SKILL_DEST = path.join(SKILL_DEST_DIR, "SKILL.md");
11
- const SKILL_URL =
12
- "https://github.com/uditalias/claude-canvas/blob/main/src/skill/claude-canvas/SKILL.md";
13
-
14
- // Skip in CI or non-interactive environments
15
- if (
16
- process.env.CI ||
17
- process.env.NODE_ENV === "test" ||
18
- !process.stdin.isTTY
19
- ) {
7
+ // Skip in CI or test environments
8
+ if (process.env.CI || process.env.NODE_ENV === "test") {
20
9
  process.exit(0);
21
10
  }
22
11
 
23
- const rl = readline.createInterface({
24
- input: process.stdin,
25
- output: process.stdout,
26
- });
27
-
28
- function ask(question) {
29
- return new Promise((resolve) => {
30
- rl.question(question, (answer) => resolve(answer.trim().toLowerCase()));
31
- });
32
- }
33
-
34
- function print(text) {
35
- console.log(text);
36
- }
37
-
38
- async function main() {
39
- print("");
40
- print(" \x1b[1m\x1b[36m✨ claude-canvas installed successfully!\x1b[0m");
41
- print("");
42
- print(
43
- " claude-canvas is a visual canvas tool for \x1b[1mClaude Code\x1b[0m."
44
- );
45
- print(
46
- " Instead of asking questions in the terminal, Claude can draw diagrams,"
47
- );
48
- print(
49
- " wireframes, and mockups on a shared canvas and collect visual feedback"
50
- );
51
- print(" from you directly in the browser.");
52
- print("");
53
- print(" \x1b[1mHow it works:\x1b[0m");
54
- print(
55
- " 1. Claude runs \x1b[33mclaude-canvas start\x1b[0m to open a canvas in your browser"
56
- );
57
- print(
58
- " 2. Claude draws shapes, diagrams, or wireframes on the canvas"
59
- );
60
- print(
61
- " 3. Claude asks you visual questions — you answer by clicking or drawing"
62
- );
63
- print(
64
- " 4. Claude captures your answers with \x1b[33mclaude-canvas screenshot\x1b[0m"
65
- );
66
- print("");
67
- print(" \x1b[1m\x1b[33m⚠ Important:\x1b[0m For Claude to use this tool automatically, you need");
68
- print(" to install the \x1b[1mclaude-canvas skill\x1b[0m into your Claude Code skills folder.");
69
- print("");
70
-
71
- const viewSkill = await ask(
72
- " Would you like to view the skill before installing? (y/N) "
73
- );
74
- if (viewSkill === "y" || viewSkill === "yes") {
75
- print("");
76
- print(` \x1b[4m${SKILL_URL}\x1b[0m`);
77
- print("");
78
- }
79
-
80
- const installSkill = await ask(
81
- " Install the skill to ~/.claude/skills/? (Y/n) "
82
- );
83
-
84
- if (installSkill === "n" || installSkill === "no") {
85
- print("");
86
- print(" Skipped skill installation. You can install it later with:");
87
- print("");
88
- print(
89
- ` \x1b[33mcp -r $(npm root -g)/claude-canvas/src/skill/claude-canvas ~/.claude/skills/\x1b[0m`
90
- );
91
- print("");
92
- } else {
93
- try {
94
- fs.mkdirSync(SKILL_DEST_DIR, { recursive: true });
12
+ const SKILL_DEST = path.join(os.homedir(), ".claude", "skills", "claude-canvas", "SKILL.md");
13
+ const skillInstalled = fs.existsSync(SKILL_DEST);
14
+
15
+ console.log("");
16
+ console.log(" \x1b[1m\x1b[36m✨ claude-canvas installed successfully!\x1b[0m");
17
+ console.log("");
18
+ console.log(" claude-canvas is a visual canvas tool for \x1b[1mClaude Code\x1b[0m.");
19
+ console.log(" Instead of asking questions in the terminal, Claude can draw diagrams,");
20
+ console.log(" wireframes, and mockups on a shared canvas and collect visual feedback");
21
+ console.log(" from you directly in the browser.");
22
+ console.log("");
23
+
24
+ if (skillInstalled) {
25
+ // Check if the skill needs updating
26
+ const SKILL_SOURCE = path.resolve(__dirname, "../src/skill/claude-canvas/SKILL.md");
27
+ try {
28
+ const installed = fs.readFileSync(SKILL_DEST, "utf-8");
29
+ const bundled = fs.readFileSync(SKILL_SOURCE, "utf-8");
30
+ if (installed !== bundled) {
95
31
  fs.copyFileSync(SKILL_SOURCE, SKILL_DEST);
96
- print("");
97
- print(
98
- ` \x1b[1m\x1b[32m✓\x1b[0m Skill installed to \x1b[36m${SKILL_DEST}\x1b[0m`
99
- );
100
- print("");
101
- } catch (err) {
102
- print("");
103
- print(` \x1b[31m✗ Failed to install skill: ${err.message}\x1b[0m`);
104
- print(" You can install it manually:");
105
- print("");
106
- print(
107
- ` \x1b[33mcp -r $(npm root -g)/claude-canvas/src/skill/claude-canvas ~/.claude/skills/\x1b[0m`
108
- );
109
- print("");
32
+ console.log(" \x1b[1m\x1b[32m✓\x1b[0m Skill updated to the latest version.");
33
+ console.log("");
110
34
  }
35
+ } catch {
36
+ // Ignore errors — user can run setup manually
111
37
  }
112
-
113
- print(" \x1b[1mGet started:\x1b[0m");
114
- print(" \x1b[33mclaude-canvas start\x1b[0m Open a new canvas session");
115
- print(
116
- " \x1b[33mclaude-canvas --help\x1b[0m See all available commands"
117
- );
118
- print("");
119
-
120
- rl.close();
38
+ } else {
39
+ console.log(" \x1b[1m\x1b[33m⚠ Important:\x1b[0m To let Claude use this tool automatically,");
40
+ console.log(" install the skill by running:");
41
+ console.log("");
42
+ console.log(" \x1b[33mclaude-canvas setup\x1b[0m");
43
+ console.log("");
121
44
  }
122
45
 
123
- main().catch(() => {
124
- rl.close();
125
- process.exit(0);
126
- });
46
+ console.log(" \x1b[1mGet started:\x1b[0m");
47
+ console.log(" \x1b[33mclaude-canvas start\x1b[0m Open a new canvas session");
48
+ console.log(" \x1b[33mclaude-canvas --help\x1b[0m See all available commands");
49
+ console.log("");