pnote 0.4.0 → 0.4.2

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
@@ -21,7 +21,7 @@ pnote notes
21
21
  pnote notes get abc123
22
22
 
23
23
  # Copy snippet to clipboard
24
- pnote snippet copy abc123
24
+ pnote notes snippet copy abc123
25
25
 
26
26
  # Search
27
27
  pnote search "portrait"
@@ -45,7 +45,9 @@ pnote notes # List all notes
45
45
  pnote notes --tag "AI/art" # Filter by tag
46
46
  pnote notes --archived # Show archived
47
47
  pnote notes --pinned # Show pinned only
48
+ pnote notes --protected # Show only PIN-protected notes
48
49
  pnote notes get <id> # Get note details
50
+ pnote notes get <id> --latest # Get note with latest snippet only
49
51
  pnote notes create "Title" # Create new note
50
52
  pnote notes update <id> --title "New Title" # Update title
51
53
  pnote notes update <id> --tags a b c # Replace tags
@@ -57,12 +59,12 @@ pnote notes delete <id> # Delete note
57
59
  ### Snippets
58
60
 
59
61
  ```bash
60
- pnote snippet <note-id> # Show latest snippet
61
- pnote snippet <note-id> --all # Show all versions
62
- pnote snippet copy <note-id> # Copy to clipboard
63
- echo "content" | pnote snippet add <note-id> # Add new version
64
- echo "updated" | pnote snippet update <snippet-id> # Update existing
65
- pnote snippet favorite <snippet-id> # Toggle favorite
62
+ pnote notes snippet <note-id> # Show latest snippet (pipe-friendly)
63
+ pnote notes snippet list <note-id> # List all versions
64
+ pnote notes snippet copy <note-id> # Copy to clipboard
65
+ echo "content" | pnote notes snippet add <note-id> # Add new version
66
+ echo "updated" | pnote notes snippet update <snippet-id> # Update existing
67
+ pnote notes snippet favorite <snippet-id> # Toggle favorite
66
68
  ```
67
69
 
68
70
  ### Tags
@@ -90,6 +92,38 @@ pnote search "query" --notes-only # Notes only
90
92
  pnote search "query" --limit 50 # Limit results
91
93
  ```
92
94
 
95
+
96
+ ### PIN Protection
97
+
98
+ Notes can be PIN-protected (encrypted server-side). Set your PIN in the PromptNote web app under Settings.
99
+
100
+ ```bash
101
+ pnote pin status # Check PIN configuration and cache status
102
+ pnote pin list # List protected notes (metadata only)
103
+
104
+ # Access protected notes
105
+ PNOTE_PIN=1234 pnote notes --protected
106
+ PNOTE_PIN=1234 pnote notes get <protected-note-id>
107
+ echo "1234" | pnote notes get <id> --pin-stdin
108
+ ```
109
+
110
+ **PIN resolution order:** `-p` flag → `--pin-stdin` → `PNOTE_PIN` env var → 5-min session cache → interactive prompt (TTY only).
111
+
112
+ ### Agent Skills Sync
113
+
114
+ Sync agent skill files between PromptNote cloud and your local agent directories.
115
+
116
+ ```bash
117
+ pnote skills # List skills in cloud
118
+ pnote skills pull # Pull all globally (~/.agents/skills/ + symlinks)
119
+ pnote skills pull <name> # Pull a specific skill globally
120
+ pnote skills pull --project # Pull project-level (.agents/skills/ + symlinks)
121
+ pnote skills pull --dry-run # Preview without writing files
122
+ pnote skills push <dir> # Upload local skill directory to cloud
123
+ ```
124
+
125
+ Skills are written to `.agents/skills/<name>/` (canonical store) and symlinked into `.claude/skills/`, `.windsurf/skills/`, and other installed agent directories automatically.
126
+
93
127
  ## Global Options
94
128
 
95
129
  | Option | Description |
@@ -105,6 +139,7 @@ pnote search "query" --limit 50 # Limit results
105
139
  | Variable | Description |
106
140
  |----------|-------------|
107
141
  | `PNOTE_TOKEN` | PAT token (overrides stored credentials) |
142
+ | `PNOTE_PIN` | PIN for accessing protected notes |
108
143
  | `NO_COLOR` | Disable colors |
109
144
  | `PNOTE_API_ENDPOINT` | Custom API endpoint |
110
145
 
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { Command as Command10 } from "commander";
4
+ import { Command as Command12 } from "commander";
5
5
 
6
6
  // src/lib/errors.ts
7
7
  import pc from "picocolors";
@@ -957,10 +957,10 @@ async function confirm(message) {
957
957
  input: process.stdin,
958
958
  output: process.stdout
959
959
  });
960
- return new Promise((resolve2) => {
960
+ return new Promise((resolve3) => {
961
961
  rl.question(message + " [y/N] ", (answer) => {
962
962
  rl.close();
963
- resolve2(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
963
+ resolve3(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
964
964
  });
965
965
  });
966
966
  }
@@ -1284,7 +1284,7 @@ async function promptForPin(noteTitle, hint, maxAttempts = PIN_MAX_ATTEMPTS) {
1284
1284
  return null;
1285
1285
  }
1286
1286
  async function readPinHidden(prompt) {
1287
- return new Promise((resolve2) => {
1287
+ return new Promise((resolve3) => {
1288
1288
  const rl = createInterface2({
1289
1289
  input: process.stdin,
1290
1290
  output: process.stderr,
@@ -1300,7 +1300,7 @@ async function readPinHidden(prompt) {
1300
1300
  if (char === "\r" || char === "\n") {
1301
1301
  process.stderr.write("\n");
1302
1302
  cleanup();
1303
- resolve2(pin);
1303
+ resolve3(pin);
1304
1304
  } else if (char === "") {
1305
1305
  process.stderr.write("\n");
1306
1306
  cleanup();
@@ -1831,63 +1831,172 @@ import * as fs from "fs";
1831
1831
  import * as path from "path";
1832
1832
  import * as os from "os";
1833
1833
  import pc11 from "picocolors";
1834
+ var AGENTS_STORE = ".agents/skills";
1835
+ var AGENT_SYMLINK_DIRS = [
1836
+ ".claude/skills",
1837
+ ".windsurf/skills",
1838
+ ".augment/skills",
1839
+ ".agent/skills"
1840
+ ];
1841
+ function makeColors(useColor) {
1842
+ if (useColor) {
1843
+ return {
1844
+ green: pc11.green,
1845
+ dim: pc11.dim,
1846
+ yellow: pc11.yellow,
1847
+ bold: pc11.bold,
1848
+ red: pc11.red
1849
+ };
1850
+ }
1851
+ return {
1852
+ green: (s) => s,
1853
+ dim: (s) => s,
1854
+ yellow: (s) => s,
1855
+ bold: (s) => s,
1856
+ red: (s) => s
1857
+ };
1858
+ }
1859
+ function resolveMode(options) {
1860
+ if (options.dir) return { mode: "custom", root: path.resolve(options.dir) };
1861
+ if (options.project) return { mode: "project", root: process.cwd() };
1862
+ return { mode: "global", root: os.homedir() };
1863
+ }
1864
+ function ensureSymlink(linkPath, skillName, dryRun, c, log) {
1865
+ const relTarget = path.join("..", "..", AGENTS_STORE, skillName);
1866
+ if (dryRun) {
1867
+ log(` ${c.dim("would link")} ${linkPath} \u2192 ${relTarget}`);
1868
+ return;
1869
+ }
1870
+ fs.mkdirSync(path.dirname(linkPath), { recursive: true });
1871
+ let existingStat = null;
1872
+ try {
1873
+ existingStat = fs.lstatSync(linkPath);
1874
+ } catch {
1875
+ }
1876
+ if (existingStat) {
1877
+ if (existingStat.isSymbolicLink()) {
1878
+ if (fs.readlinkSync(linkPath) === relTarget) return;
1879
+ fs.unlinkSync(linkPath);
1880
+ } else if (existingStat.isDirectory()) {
1881
+ fs.rmSync(linkPath, { recursive: true });
1882
+ log(` ${c.yellow("\u2197")} migrated ${c.dim(linkPath)} (replaced directory with symlink)`);
1883
+ } else {
1884
+ fs.unlinkSync(linkPath);
1885
+ }
1886
+ }
1887
+ fs.symlinkSync(relTarget, linkPath);
1888
+ log(` ${c.dim("\u21E2")} ${linkPath}`);
1889
+ }
1890
+ function installSkill(root, mode, skillName, files, dryRun, c, log) {
1891
+ const home = os.homedir();
1892
+ if (mode === "custom") {
1893
+ for (const { fileName, content } of files) {
1894
+ const destPath = path.join(root, skillName, fileName);
1895
+ if (dryRun) {
1896
+ log(` ${c.dim("would write")} ${destPath}`);
1897
+ } else {
1898
+ fs.mkdirSync(path.dirname(destPath), { recursive: true });
1899
+ fs.writeFileSync(destPath, content, "utf-8");
1900
+ log(` ${c.green("\u2713")} ${destPath}`);
1901
+ }
1902
+ }
1903
+ return [];
1904
+ }
1905
+ for (const { fileName, content } of files) {
1906
+ const destPath = path.join(root, AGENTS_STORE, skillName, fileName);
1907
+ if (dryRun) {
1908
+ log(` ${c.dim("would write")} ${destPath}`);
1909
+ } else {
1910
+ fs.mkdirSync(path.dirname(destPath), { recursive: true });
1911
+ fs.writeFileSync(destPath, content, "utf-8");
1912
+ log(` ${c.green("\u2713")} ${destPath}`);
1913
+ }
1914
+ }
1915
+ const linkedAgents = [];
1916
+ for (const agentSkillsDir of AGENT_SYMLINK_DIRS) {
1917
+ const agentRootDir = agentSkillsDir.split("/")[0];
1918
+ const isClaude = agentRootDir === ".claude";
1919
+ if (!isClaude && !fs.existsSync(path.join(home, agentRootDir))) continue;
1920
+ const linkPath = path.join(root, agentSkillsDir, skillName);
1921
+ ensureSymlink(linkPath, skillName, dryRun, c, log);
1922
+ linkedAgents.push(agentRootDir);
1923
+ }
1924
+ return linkedAgents;
1925
+ }
1834
1926
  async function pullSkillsAction(skillName, options, ctx) {
1835
1927
  try {
1836
- const baseDir = options.dir || path.join(os.homedir(), ".claude", "skills");
1928
+ const { mode, root } = resolveMode(options);
1929
+ const useColor = !ctx.noColor && process.stdout.isTTY;
1930
+ const c = makeColors(useColor);
1931
+ const log = ctx.json ? (_msg) => {
1932
+ } : (msg) => console.log(msg);
1837
1933
  const result = await listNotes(
1838
1934
  { note_type: "skill", limit: 200 },
1839
1935
  { pin: ctx.pin }
1840
1936
  );
1841
1937
  let skills = result.notes;
1842
1938
  if (skillName) {
1843
- skills = skills.filter((n) => {
1844
- const prefix = n.title.split("/")[0];
1845
- return prefix === skillName;
1846
- });
1939
+ skills = skills.filter((n) => n.title.split("/")[0] === skillName);
1847
1940
  if (skills.length === 0) {
1848
1941
  console.error(pc11.red(`No skill found with name "${skillName}"`));
1849
1942
  process.exit(1);
1850
1943
  }
1851
1944
  }
1852
1945
  if (skills.length === 0) {
1853
- console.log(pc11.dim("No skills to pull."));
1946
+ if (!ctx.json) console.log(c.dim("No skills to pull."));
1947
+ if (ctx.json) outputJson({ pulled: 0, skipped: 0, mode, root, skills: {} });
1854
1948
  return;
1855
1949
  }
1856
- let pulled = 0;
1857
- let skipped = 0;
1950
+ const grouped = /* @__PURE__ */ new Map();
1858
1951
  for (const note of skills) {
1859
1952
  const slashIdx = note.title.indexOf("/");
1860
1953
  if (slashIdx <= 0) {
1861
- logStatus(`Skipping "${note.title}" (invalid title format, expected "name/file")`);
1862
- skipped++;
1954
+ if (!ctx.json) console.error(`Skipping "${note.title}" (invalid title format, expected "name/file")`);
1863
1955
  continue;
1864
1956
  }
1865
- const skillDir = note.title.slice(0, slashIdx);
1957
+ const sName = note.title.slice(0, slashIdx);
1866
1958
  const fileName = note.title.slice(slashIdx + 1);
1867
- const filePath = path.join(baseDir, skillDir, fileName);
1868
- const noteData = await getNote(note.id, { pin: ctx.pin });
1869
- const content = noteData.latest_snippet?.content;
1870
- if (!content) {
1871
- logStatus(`Skipping "${note.title}" (no snippet content)`);
1872
- skipped++;
1873
- continue;
1959
+ if (!grouped.has(sName)) grouped.set(sName, []);
1960
+ grouped.get(sName).push({ fileName, noteId: note.id });
1961
+ }
1962
+ let totalPulled = 0;
1963
+ let totalSkipped = 0;
1964
+ const jsonResults = {};
1965
+ for (const [sName, fileEntries] of grouped) {
1966
+ log(`
1967
+ ${c.bold(sName)}`);
1968
+ const files = [];
1969
+ for (const { fileName, noteId } of fileEntries) {
1970
+ const noteData = await getNote(noteId, { pin: ctx.pin });
1971
+ const content = noteData.latest_snippet?.content;
1972
+ if (!content) {
1973
+ if (!ctx.json) console.error(` Skipping "${sName}/${fileName}" (no snippet content)`);
1974
+ totalSkipped++;
1975
+ continue;
1976
+ }
1977
+ files.push({ fileName, content });
1874
1978
  }
1979
+ if (files.length === 0) continue;
1980
+ const linkedAgents = installSkill(root, mode, sName, files, options.dryRun ?? false, c, log);
1981
+ totalPulled += files.length;
1982
+ jsonResults[sName] = {
1983
+ files: files.map((f) => f.fileName),
1984
+ agents: linkedAgents
1985
+ };
1986
+ }
1987
+ if (!ctx.json) {
1988
+ console.log("");
1875
1989
  if (options.dryRun) {
1876
- console.log(`${pc11.dim("would write")} ${filePath} ${pc11.dim(`(${content.length} chars)`)}`);
1877
- pulled++;
1878
- continue;
1990
+ console.log(c.dim(`Dry run: ${totalPulled} file(s) would be pulled, ${totalSkipped} skipped`));
1991
+ } else {
1992
+ const scopeLabel = mode === "custom" ? root : mode === "project" ? "project (.agents/skills/)" : "global (~/.agents/skills/)";
1993
+ console.log(
1994
+ `Pulled ${totalPulled} file(s) \u2014 ${scopeLabel}` + (totalSkipped > 0 ? `, ${totalSkipped} skipped` : "")
1995
+ );
1879
1996
  }
1880
- const dir = path.dirname(filePath);
1881
- fs.mkdirSync(dir, { recursive: true });
1882
- fs.writeFileSync(filePath, content, "utf-8");
1883
- console.log(`${pc11.green("\u2713")} ${filePath}`);
1884
- pulled++;
1885
1997
  }
1886
- console.log("");
1887
- if (options.dryRun) {
1888
- console.log(pc11.dim(`Dry run: ${pulled} file(s) would be written, ${skipped} skipped`));
1889
- } else {
1890
- console.log(`Pulled ${pulled} file(s) to ${baseDir}` + (skipped > 0 ? `, ${skipped} skipped` : ""));
1998
+ if (ctx.json) {
1999
+ outputJson({ pulled: totalPulled, skipped: totalSkipped, mode, root, skills: jsonResults });
1891
2000
  }
1892
2001
  } catch (error) {
1893
2002
  handleError(error, ctx.noColor);
@@ -1994,16 +2103,20 @@ var skillsCommand = new Command8("skills").description("Manage agent skills (syn
1994
2103
  "after",
1995
2104
  `
1996
2105
  Examples:
1997
- $ pnote skills List all skills in cloud
1998
- $ pnote skills pull Download all skills to ~/.claude/skills/
1999
- $ pnote skills pull myskill Download a specific skill
2000
- $ pnote skills push ./my-skill Upload a local skill directory
2106
+ $ pnote skills List all skills in cloud
2107
+ $ pnote skills pull Pull all skills globally (~/.agents/skills/ + symlinks)
2108
+ $ pnote skills pull myskill Pull a specific skill globally
2109
+ $ pnote skills pull --project Pull project-level (.agents/skills/ + .claude/skills/ etc.)
2110
+ $ pnote skills pull --dry-run Preview without writing files
2111
+ $ pnote skills push ./my-skill Upload a local skill directory
2001
2112
 
2002
- Skills are notes with type "skill" and title format "skill-name/filename.md".
2003
- They sync to ~/.claude/skills/<skill-name>/<filename> for use with Claude Code.
2113
+ Skills are stored as notes with type "skill" and title "skill-name/filename.md".
2114
+ Pull writes to the canonical .agents/skills/ store and symlinks into each installed
2115
+ agent's directory (.claude/skills/, .windsurf/skills/, .augment/skills/, etc.),
2116
+ matching the layout used by npx skills for seamless coexistence.
2004
2117
  `
2005
2118
  );
2006
- skillsCommand.command("pull").description("Download skills from cloud to local (~/.claude/skills/)").argument("[skill-name]", "Specific skill to pull (pulls all if omitted)").option("--dir <path>", "Custom output directory (default: ~/.claude/skills)").option("--dry-run", "Show what would be downloaded without writing files").action(async (skillName, options, cmd) => {
2119
+ skillsCommand.command("pull").description("Download skills from cloud to local (global by default)").argument("[skill-name]", "Specific skill to pull (pulls all if omitted)").option("--project", "Install project-level (./agents/skills/ + .claude/skills/ etc.)").option("--dir <path>", "Custom output directory \u2014 direct write, no symlinks").option("--dry-run", "Show what would be downloaded without writing files").action(async (skillName, options, cmd) => {
2007
2120
  const globalOpts = cmd.parent?.parent?.opts() || {};
2008
2121
  const ctx = await buildContext6(globalOpts);
2009
2122
  await pullSkillsAction(skillName, options, ctx);
@@ -2175,7 +2288,7 @@ pinCommand.command("list").description("List all PIN-protected notes (metadata o
2175
2288
  });
2176
2289
 
2177
2290
  // src/lib/update-check.ts
2178
- import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3 } from "fs";
2291
+ import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3 } from "fs";
2179
2292
  import { join as join5 } from "path";
2180
2293
  import pc15 from "picocolors";
2181
2294
  var CACHE_FILE = "update-check.json";
@@ -2187,7 +2300,7 @@ function getCachePath() {
2187
2300
  function readCache() {
2188
2301
  try {
2189
2302
  const path3 = getCachePath();
2190
- if (!existsSync4(path3)) return null;
2303
+ if (!existsSync5(path3)) return null;
2191
2304
  return JSON.parse(readFileSync4(path3, "utf-8"));
2192
2305
  } catch {
2193
2306
  return null;
@@ -2196,7 +2309,7 @@ function readCache() {
2196
2309
  function writeCache(cache) {
2197
2310
  try {
2198
2311
  const dir = getConfigDir();
2199
- if (!existsSync4(dir)) {
2312
+ if (!existsSync5(dir)) {
2200
2313
  mkdirSync3(dir, { recursive: true, mode: 448 });
2201
2314
  }
2202
2315
  writeFileSync4(getCachePath(), JSON.stringify(cache), "utf-8");
@@ -2273,9 +2386,95 @@ async function checkAndNotifyUpdate(currentVersion, packageName) {
2273
2386
  }
2274
2387
  }
2275
2388
 
2389
+ // src/commands/update.ts
2390
+ import { Command as Command10 } from "commander";
2391
+ import { spawnSync } from "child_process";
2392
+ import pc16 from "picocolors";
2393
+ function isOlderVersion2(current, latest) {
2394
+ const parse = (v) => v.split(".").map(Number);
2395
+ const [cMaj, cMin, cPat] = parse(current);
2396
+ const [lMaj, lMin, lPat] = parse(latest);
2397
+ if (cMaj !== lMaj) return cMaj < lMaj;
2398
+ if (cMin !== lMin) return cMin < lMin;
2399
+ return cPat < lPat;
2400
+ }
2401
+ function detectPackageManager() {
2402
+ const ua = process.env.npm_config_user_agent ?? "";
2403
+ if (ua.startsWith("pnpm")) return "pnpm";
2404
+ return "npm";
2405
+ }
2406
+ var updateCommand = new Command10("update").description("Check for updates and upgrade to the latest version").action(async () => {
2407
+ const noColor = !process.stderr.isTTY || !!process.env.NO_COLOR || process.env.TERM === "dumb";
2408
+ const bold = noColor ? (s) => s : pc16.bold;
2409
+ const dim = noColor ? (s) => s : pc16.dim;
2410
+ const green = noColor ? (s) => s : pc16.green;
2411
+ try {
2412
+ process.stderr.write(dim("Checking for updates\u2026") + "\n");
2413
+ const res = await fetch(
2414
+ `https://registry.npmjs.org/${"pnote"}/latest`,
2415
+ { signal: AbortSignal.timeout(5e3) }
2416
+ );
2417
+ if (!res.ok) throw new Error(`Registry returned ${res.status}`);
2418
+ const data = await res.json();
2419
+ const latest = data.version;
2420
+ const current = "0.4.2";
2421
+ if (!isOlderVersion2(current, latest)) {
2422
+ console.log(green("\u2713") + ` Already on the latest version (${bold("v" + current)})`);
2423
+ return;
2424
+ }
2425
+ const pm = detectPackageManager();
2426
+ const installArgs = pm === "pnpm" ? ["add", "-g", "pnote"] : ["install", "-g", "pnote"];
2427
+ const installCmd = `${pm} ${installArgs.join(" ")}`;
2428
+ console.log(`Update available: ${dim("v" + current)} \u2192 ${bold("v" + latest)}`);
2429
+ console.log(dim("Running: ") + bold(installCmd));
2430
+ console.log("");
2431
+ const result = spawnSync(pm, installArgs, { stdio: "inherit" });
2432
+ if (result.status !== 0) {
2433
+ process.exit(result.status ?? 1);
2434
+ }
2435
+ console.log("");
2436
+ console.log(green("\u2713") + ` Updated to ${bold("v" + latest)}`);
2437
+ } catch (err) {
2438
+ handleError(err);
2439
+ }
2440
+ });
2441
+
2442
+ // src/commands/schema.ts
2443
+ import { Command as Command11 } from "commander";
2444
+ function mapOption(opt) {
2445
+ const result = {
2446
+ flags: opt.flags,
2447
+ description: opt.description
2448
+ };
2449
+ if (opt.defaultValue !== void 0) {
2450
+ result.defaultValue = opt.defaultValue;
2451
+ }
2452
+ return result;
2453
+ }
2454
+ function mapCommand(cmd) {
2455
+ return {
2456
+ name: cmd.name(),
2457
+ description: cmd.description(),
2458
+ aliases: cmd.aliases(),
2459
+ options: cmd.options.map(mapOption),
2460
+ subcommands: cmd.commands.map(mapCommand)
2461
+ };
2462
+ }
2463
+ var schemaCommand = new Command11("schema").description("Output full command schema as JSON (for AI agent discovery)").action((_opts, cmd) => {
2464
+ const root = cmd.parent ?? cmd;
2465
+ const schema = {
2466
+ name: root.name(),
2467
+ version: "0.4.2",
2468
+ description: root.description(),
2469
+ globalOptions: root.options.map(mapOption),
2470
+ commands: root.commands.map(mapCommand)
2471
+ };
2472
+ console.log(JSON.stringify(schema, null, 2));
2473
+ });
2474
+
2276
2475
  // src/index.ts
2277
- var program = new Command10();
2278
- program.name("pnote").description("pnote - The PromptNote CLI").version("0.4.0", "-V, --version", "Show version number").option("--json", "Output as JSON (for scripting)").option("--no-color", "Disable colored output").option("--plain", "Force plain text output (no formatting)").option("-p, --pin <pin>", "PIN for accessing protected notes").option("--pin-stdin", "Read PIN from stdin (first line only)").configureHelp({
2476
+ var program = new Command12();
2477
+ program.name("pnote").description("pnote - The PromptNote CLI").version("0.4.2", "-V, --version", "Show version number").option("--json", "Output as JSON (for scripting)").option("--no-color", "Disable colored output").option("--plain", "Force plain text output (no formatting)").option("-p, --pin <pin>", "PIN for accessing protected notes").option("--pin-stdin", "Read PIN from stdin (first line only)").configureHelp({
2279
2478
  sortSubcommands: true,
2280
2479
  sortOptions: true
2281
2480
  }).addHelpText(
@@ -2307,8 +2506,10 @@ program.addCommand(searchCommand);
2307
2506
  program.addCommand(shareCommand);
2308
2507
  program.addCommand(pinCommand);
2309
2508
  program.addCommand(skillsCommand);
2509
+ program.addCommand(updateCommand);
2510
+ program.addCommand(schemaCommand);
2310
2511
  program.hook("preAction", async () => {
2311
- await checkAndNotifyUpdate("0.4.0", "pnote");
2512
+ await checkAndNotifyUpdate("0.4.2", "pnote");
2312
2513
  });
2313
2514
  process.on("SIGINT", () => {
2314
2515
  console.error("\nInterrupted");