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 +42 -7
- package/dist/index.js +250 -49
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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>
|
|
61
|
-
pnote snippet <note-id>
|
|
62
|
-
pnote snippet copy <note-id>
|
|
63
|
-
echo "content" | pnote snippet add <note-id>
|
|
64
|
-
echo "updated" | pnote snippet update <snippet-id>
|
|
65
|
-
pnote snippet favorite <snippet-id>
|
|
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
|
|
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((
|
|
960
|
+
return new Promise((resolve3) => {
|
|
961
961
|
rl.question(message + " [y/N] ", (answer) => {
|
|
962
962
|
rl.close();
|
|
963
|
-
|
|
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((
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
1862
|
-
skipped++;
|
|
1954
|
+
if (!ctx.json) console.error(`Skipping "${note.title}" (invalid title format, expected "name/file")`);
|
|
1863
1955
|
continue;
|
|
1864
1956
|
}
|
|
1865
|
-
const
|
|
1957
|
+
const sName = note.title.slice(0, slashIdx);
|
|
1866
1958
|
const fileName = note.title.slice(slashIdx + 1);
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
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(
|
|
1877
|
-
|
|
1878
|
-
|
|
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
|
-
|
|
1887
|
-
|
|
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
|
|
1998
|
-
$ pnote skills pull
|
|
1999
|
-
$ pnote skills pull myskill
|
|
2000
|
-
$ pnote skills
|
|
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
|
|
2003
|
-
|
|
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 (
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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
|
|
2278
|
-
program.name("pnote").description("pnote - The PromptNote CLI").version("0.4.
|
|
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.
|
|
2512
|
+
await checkAndNotifyUpdate("0.4.2", "pnote");
|
|
2312
2513
|
});
|
|
2313
2514
|
process.on("SIGINT", () => {
|
|
2314
2515
|
console.error("\nInterrupted");
|