notas 0.0.0 → 26.2.1
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 +115 -0
- package/bin/install.js +63 -0
- package/bin/install.sh +24 -0
- package/bin/notas +15 -0
- package/package.json +43 -4
- package/skills/notion/SKILL.md +157 -0
- package/index.js +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# notas
|
|
2
|
+
|
|
3
|
+
Multi-provider notes & docs CLI. Notion is the first supported provider.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Homebrew
|
|
9
|
+
brew install circlesac/tap/notas
|
|
10
|
+
|
|
11
|
+
# npm
|
|
12
|
+
npx @circlesac/notas
|
|
13
|
+
|
|
14
|
+
# From source
|
|
15
|
+
bun install
|
|
16
|
+
bun run build
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Authenticate (opens browser for OAuth)
|
|
23
|
+
notas notion auth login
|
|
24
|
+
|
|
25
|
+
# Or use an integration token
|
|
26
|
+
notas notion auth login --token ntn_xxx
|
|
27
|
+
|
|
28
|
+
# List databases
|
|
29
|
+
notas notion db list
|
|
30
|
+
|
|
31
|
+
# Query a database
|
|
32
|
+
notas notion db query <database-id>
|
|
33
|
+
|
|
34
|
+
# Search
|
|
35
|
+
notas notion search <query>
|
|
36
|
+
|
|
37
|
+
# Output as JSON
|
|
38
|
+
notas notion db list --output json
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Commands
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
notas notion auth login, logout, status, refresh
|
|
45
|
+
notas notion databases list, get, query, create, update, delete
|
|
46
|
+
notas notion pages get, create, update, archive, restore
|
|
47
|
+
notas notion blocks list, get, append, update, delete
|
|
48
|
+
notas notion users list, get, me
|
|
49
|
+
notas notion search <query>
|
|
50
|
+
notas notion comments list, create
|
|
51
|
+
notas notion api <method> <endpoint> [--body json]
|
|
52
|
+
notas notion version
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`db` is an alias for `databases`.
|
|
56
|
+
|
|
57
|
+
## Development
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Run locally
|
|
61
|
+
bun run dev -- notion db list
|
|
62
|
+
|
|
63
|
+
# Lint (oxlint + eslint + prettier + biome + tsc)
|
|
64
|
+
bun run lint
|
|
65
|
+
|
|
66
|
+
# Type check
|
|
67
|
+
bun run type-check
|
|
68
|
+
|
|
69
|
+
# Test
|
|
70
|
+
bun run test
|
|
71
|
+
|
|
72
|
+
# Build native binary
|
|
73
|
+
bun run build
|
|
74
|
+
|
|
75
|
+
# Full pre-merge check
|
|
76
|
+
bun run pre-merge
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Project Structure
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
src/
|
|
83
|
+
index.ts CLI entry point
|
|
84
|
+
lib/ Shared utilities (credentials, output, errors)
|
|
85
|
+
platforms/notion/ Notion provider
|
|
86
|
+
auth/ login, logout, status, refresh
|
|
87
|
+
databases/ CRUD + query
|
|
88
|
+
pages/ CRUD + archive/restore
|
|
89
|
+
blocks/ CRUD + append
|
|
90
|
+
users/ list, get, me
|
|
91
|
+
search/ full-text search
|
|
92
|
+
comments/ list, create
|
|
93
|
+
api.ts raw API passthrough
|
|
94
|
+
client.ts Notion client factory
|
|
95
|
+
properties.ts property formatting
|
|
96
|
+
types/ shared types
|
|
97
|
+
worker/ Cloudflare Worker (OAuth callback relay at notas.circles.ac)
|
|
98
|
+
npm/ npm distribution (shim + installer)
|
|
99
|
+
homebrew/ Homebrew formula template
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Deploy
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Deploy OAuth callback worker
|
|
106
|
+
bun run deploy:worker
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Release
|
|
110
|
+
|
|
111
|
+
Releases are triggered via `workflow_dispatch` in GitHub Actions. The workflow runs tests, bumps the version (CalVer via `@circlesac/oneup`), builds native binaries for 4 platforms, creates a GitHub Release, publishes to npm, and updates the Homebrew formula.
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
gh workflow run release.yml
|
|
115
|
+
```
|
package/bin/install.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import https from "https";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { execSync } from "child_process";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
import { createRequire } from "module";
|
|
7
|
+
|
|
8
|
+
const require = createRequire(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
|
|
11
|
+
const REPO = "circlesac/notas-cli";
|
|
12
|
+
|
|
13
|
+
const PLATFORMS = {
|
|
14
|
+
"darwin-x64": { artifact: "notas-darwin-x64", ext: ".tar.gz" },
|
|
15
|
+
"darwin-arm64": { artifact: "notas-darwin-arm64", ext: ".tar.gz" },
|
|
16
|
+
"linux-x64": { artifact: "notas-linux-x64", ext: ".tar.gz" },
|
|
17
|
+
"linux-arm64": { artifact: "notas-linux-arm64", ext: ".tar.gz" },
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function download(url) {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
https.get(url, (res) => {
|
|
23
|
+
if (res.statusCode === 302 || res.statusCode === 301) {
|
|
24
|
+
return download(res.headers.location).then(resolve).catch(reject);
|
|
25
|
+
}
|
|
26
|
+
if (res.statusCode !== 200) return reject(new Error(`HTTP ${res.statusCode}`));
|
|
27
|
+
const chunks = [];
|
|
28
|
+
res.on("data", (c) => chunks.push(c));
|
|
29
|
+
res.on("end", () => resolve(Buffer.concat(chunks)));
|
|
30
|
+
res.on("error", reject);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const nativeDir = path.join(__dirname, "native");
|
|
36
|
+
const binPath = path.join(nativeDir, "notas");
|
|
37
|
+
|
|
38
|
+
if (!fs.existsSync(binPath)) {
|
|
39
|
+
const { version } = require("../package.json");
|
|
40
|
+
if (version) {
|
|
41
|
+
const platform = `${process.platform}-${process.arch}`;
|
|
42
|
+
const info = PLATFORMS[platform];
|
|
43
|
+
if (!info) {
|
|
44
|
+
console.error(`Unsupported platform: ${platform}`);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const { artifact, ext } = info;
|
|
49
|
+
const url = `https://github.com/${REPO}/releases/download/v${version}/${artifact}${ext}`;
|
|
50
|
+
console.info(`Downloading notas v${version} for ${platform}...`);
|
|
51
|
+
|
|
52
|
+
const data = await download(url);
|
|
53
|
+
fs.mkdirSync(nativeDir, { recursive: true });
|
|
54
|
+
|
|
55
|
+
const tmp = path.join(nativeDir, `tmp${ext}`);
|
|
56
|
+
fs.writeFileSync(tmp, data);
|
|
57
|
+
execSync(`tar xzf "${tmp}"`, { cwd: nativeDir });
|
|
58
|
+
fs.unlinkSync(tmp);
|
|
59
|
+
|
|
60
|
+
fs.chmodSync(binPath, 0o755);
|
|
61
|
+
console.info("Installed successfully.");
|
|
62
|
+
}
|
|
63
|
+
}
|
package/bin/install.sh
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
REPO="circlesac/notas-cli"
|
|
5
|
+
INSTALL_DIR="${INSTALL_DIR:-/usr/local/bin}"
|
|
6
|
+
|
|
7
|
+
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
|
|
8
|
+
ARCH=$(uname -m)
|
|
9
|
+
|
|
10
|
+
case "$OS-$ARCH" in
|
|
11
|
+
darwin-arm64) NAME="notas-darwin-arm64" ;;
|
|
12
|
+
darwin-x86_64) NAME="notas-darwin-x64" ;;
|
|
13
|
+
linux-aarch64) NAME="notas-linux-arm64" ;;
|
|
14
|
+
linux-x86_64) NAME="notas-linux-x64" ;;
|
|
15
|
+
*) echo "Unsupported platform: $OS-$ARCH"; exit 1 ;;
|
|
16
|
+
esac
|
|
17
|
+
|
|
18
|
+
VERSION=$(curl -fsSL "https://api.github.com/repos/$REPO/releases/latest" | grep '"tag_name"' | cut -d'"' -f4)
|
|
19
|
+
URL="https://github.com/$REPO/releases/download/$VERSION/${NAME}.tar.gz"
|
|
20
|
+
|
|
21
|
+
echo "Installing notas $VERSION..."
|
|
22
|
+
curl -fsSL "$URL" | tar xz -C "$INSTALL_DIR"
|
|
23
|
+
chmod +x "$INSTALL_DIR/notas"
|
|
24
|
+
echo "Installed to $INSTALL_DIR/notas"
|
package/bin/notas
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawnSync } from "child_process";
|
|
4
|
+
import { existsSync } from "fs";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
import path from "path";
|
|
7
|
+
|
|
8
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const bin = path.join(__dirname, "native", "notas");
|
|
10
|
+
|
|
11
|
+
if (!existsSync(bin)) {
|
|
12
|
+
await import("./install.js");
|
|
13
|
+
}
|
|
14
|
+
const result = spawnSync(bin, process.argv.slice(2), { stdio: "inherit" });
|
|
15
|
+
process.exit(result.status ?? 1);
|
package/package.json
CHANGED
|
@@ -1,7 +1,46 @@
|
|
|
1
1
|
{
|
|
2
|
+
"bin": {
|
|
3
|
+
"notas": "bin/notas"
|
|
4
|
+
},
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@notionhq/client": "^5.9.0",
|
|
7
|
+
"citty": "^0.2.1"
|
|
8
|
+
},
|
|
9
|
+
"description": "Multi-provider notes & docs CLI",
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"@types/bun": "latest",
|
|
12
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
13
|
+
"vitest": "^4.0.18"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"bin",
|
|
17
|
+
"skills"
|
|
18
|
+
],
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"module": "src/index.ts",
|
|
2
21
|
"name": "notas",
|
|
3
|
-
"
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
"
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"typescript": "^5"
|
|
24
|
+
},
|
|
25
|
+
"pi": {
|
|
26
|
+
"skills": [
|
|
27
|
+
"./skills"
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/circlesac/notas-cli"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "bun build --compile --outfile=dist/notas src/index.ts",
|
|
36
|
+
"deploy:worker": "cd worker && npx wrangler deploy",
|
|
37
|
+
"dev": "bun run src/index.ts",
|
|
38
|
+
"lint": "npx @circlesac/lint --all",
|
|
39
|
+
"postinstall": "node bin/install.js",
|
|
40
|
+
"pre-merge": "bun run lint && bun run type-check && bun run test && bun run build",
|
|
41
|
+
"test": "vitest run",
|
|
42
|
+
"type-check": "npx tsc --noEmit"
|
|
43
|
+
},
|
|
44
|
+
"type": "module",
|
|
45
|
+
"version": "26.2.1"
|
|
7
46
|
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: notion
|
|
3
|
+
description: Reference guide for the notas CLI Notion provider. Use this when working with Notion pages, databases, blocks, users, comments, or search.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# notas CLI Reference
|
|
7
|
+
|
|
8
|
+
## Quick Start
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
notas notion auth login # OAuth login (opens browser)
|
|
12
|
+
notas notion search "meeting" # Search across workspace
|
|
13
|
+
notas notion db list # List all databases
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Global Flags
|
|
17
|
+
|
|
18
|
+
| Flag | Alias | Description |
|
|
19
|
+
|------|-------|-------------|
|
|
20
|
+
| `--workspace` | `-w` | Select workspace (when multiple configured) |
|
|
21
|
+
| `--json` | | Output as JSON |
|
|
22
|
+
| `--plain` | | Output as tab-separated plain text |
|
|
23
|
+
|
|
24
|
+
## Authentication
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
notas notion auth login # OAuth flow (default)
|
|
28
|
+
notas notion auth login --token ntn_xxx # Manual token
|
|
29
|
+
notas notion auth login --name work # Name the workspace
|
|
30
|
+
notas notion auth status # Show all workspaces
|
|
31
|
+
notas notion auth logout --name work # Remove a workspace
|
|
32
|
+
notas notion auth refresh # Refresh OAuth token
|
|
33
|
+
notas notion auth rename old-name new-name # Rename workspace
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Environment variable: `NOTION_TOKEN` overrides stored credentials.
|
|
37
|
+
|
|
38
|
+
## Databases
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
notas notion db list
|
|
42
|
+
notas notion db get <database-id>
|
|
43
|
+
notas notion db query <database-id>
|
|
44
|
+
notas notion db query <database-id> --filter '{"property":"Status","select":{"equals":"Done"}}'
|
|
45
|
+
notas notion db query <database-id> --sort '[{"property":"Created","direction":"descending"}]'
|
|
46
|
+
notas notion db query <database-id> --columns "Name,Status,Date"
|
|
47
|
+
notas notion db create <parent-page-id> --title "My Database"
|
|
48
|
+
notas notion db update <database-id> --title "New Title" --description "Updated"
|
|
49
|
+
notas notion db delete <database-id>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Pagination: `--limit 10`, `--all`, `--cursor <cursor>`
|
|
53
|
+
|
|
54
|
+
## Pages
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
notas notion pages get <page-id>
|
|
58
|
+
notas notion pages create <parent-id> --title "New Page"
|
|
59
|
+
notas notion pages create <parent-id> --title "Page" --content "Body text"
|
|
60
|
+
notas notion pages create <parent-id> --title "Page" --icon "📝"
|
|
61
|
+
notas notion pages create <db-id> --parent-type database --title "Row" --properties '{"Status":{"select":{"name":"Draft"}}}'
|
|
62
|
+
notas notion pages update <page-id> --title "Updated Title"
|
|
63
|
+
notas notion pages archive <page-id>
|
|
64
|
+
notas notion pages restore <page-id>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Stdin support:
|
|
68
|
+
```bash
|
|
69
|
+
cat notes.md | notas notion pages create <parent-id> --title "From File" --stdio
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Blocks
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
notas notion blocks list <page-id>
|
|
76
|
+
notas notion blocks list <page-id> --recursive # All nested blocks
|
|
77
|
+
notas notion blocks get <block-id>
|
|
78
|
+
notas notion blocks append <page-id> --text "Hello world"
|
|
79
|
+
notas notion blocks append <page-id> --type heading_1 --text "Title"
|
|
80
|
+
notas notion blocks append <page-id> --type code --text "console.log('hi')" --language javascript
|
|
81
|
+
notas notion blocks append <page-id> --type to_do --text "Task" --checked
|
|
82
|
+
notas notion blocks append <page-id> --type bookmark --url "https://example.com"
|
|
83
|
+
notas notion blocks append <page-id> --type divider
|
|
84
|
+
notas notion blocks append <page-id> --blocks '[{"object":"block","type":"paragraph","paragraph":{"rich_text":[{"type":"text","text":{"content":"Complex block"}}]}}]'
|
|
85
|
+
notas notion blocks update <block-id> --text "Updated text"
|
|
86
|
+
notas notion blocks update <block-id> --body '{"paragraph":{"rich_text":[{"type":"text","text":{"content":"Raw update"}}]}}'
|
|
87
|
+
notas notion blocks delete <block-id>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Block types: `paragraph`, `heading_1`, `heading_2`, `heading_3`, `bulleted_list_item`, `numbered_list_item`, `to_do`, `toggle`, `code`, `quote`, `callout`, `divider`, `bookmark`
|
|
91
|
+
|
|
92
|
+
Stdin support:
|
|
93
|
+
```bash
|
|
94
|
+
cat code.py | notas notion blocks append <page-id> --type code --language python --stdio
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Search
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
notas notion search "query"
|
|
101
|
+
notas notion search "query" --type page
|
|
102
|
+
notas notion search "query" --type database
|
|
103
|
+
notas notion search --sort ascending
|
|
104
|
+
notas notion search # List all (no query)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Users
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
notas notion users list
|
|
111
|
+
notas notion users list --filter "john"
|
|
112
|
+
notas notion users get <user-id>
|
|
113
|
+
notas notion users me
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Comments
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
notas notion comments list <page-id>
|
|
120
|
+
notas notion comments create --page-id <page-id> --text "New comment"
|
|
121
|
+
notas notion comments create --discussion-id <id> --text "Reply"
|
|
122
|
+
echo "Comment from pipe" | notas notion comments create --page-id <id> --stdio
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Raw API
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
notas notion api GET /v1/users
|
|
129
|
+
notas notion api POST /v1/search --body '{"query":"test"}'
|
|
130
|
+
notas notion api POST /v1/databases/<id>/query '{"page_size":5}'
|
|
131
|
+
notas notion api PATCH /v1/pages/<id> --body '{"archived":true}'
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Common Workflows
|
|
135
|
+
|
|
136
|
+
### Create a page with content from a file
|
|
137
|
+
```bash
|
|
138
|
+
cat document.md | notas notion pages create <parent-id> --title "My Doc" --stdio
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Query a database and pipe to jq
|
|
142
|
+
```bash
|
|
143
|
+
notas notion db query <db-id> --json | jq '.results[].properties.Name.title[0].plain_text'
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Append multiple blocks from a script
|
|
147
|
+
```bash
|
|
148
|
+
notas notion blocks append <page-id> --type heading_1 --text "Section Title"
|
|
149
|
+
notas notion blocks append <page-id> --text "Paragraph content"
|
|
150
|
+
cat snippet.py | notas notion blocks append <page-id> --type code --language python --stdio
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Search and get page content
|
|
154
|
+
```bash
|
|
155
|
+
PAGE_ID=$(notas notion search "meeting notes" --json | jq -r '.results[0].id')
|
|
156
|
+
notas notion blocks list $PAGE_ID --recursive --plain
|
|
157
|
+
```
|
package/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|