@letterstory/cli 0.5.0 → 0.5.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 +16 -7
- package/lib/cli.mjs +3 -2
- package/lib/commands/seers.mjs +29 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -273,19 +273,28 @@ letterstory seers apply --file seers.json --dry-run # print the create/update/
|
|
|
273
273
|
letterstory seers apply --file seers.json # apply it
|
|
274
274
|
```
|
|
275
275
|
|
|
276
|
-
Connections
|
|
276
|
+
Connections — both providers connect headlessly (no browser required):
|
|
277
277
|
|
|
278
278
|
```bash
|
|
279
279
|
letterstory seers connections # GitHub + Notion status
|
|
280
280
|
letterstory seers connect github --token <pat> # org-wide token; unlocks private repos
|
|
281
|
-
letterstory seers connect notion # prints
|
|
281
|
+
letterstory seers connect notion # no token: prints how to mint one + which pages to share
|
|
282
|
+
letterstory seers connect notion --token ntn_xxx # store a Notion internal-integration secret
|
|
282
283
|
```
|
|
283
284
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
285
|
+
**Connecting Notion.** Notion uses an _internal integration_ (the direct analogue of a
|
|
286
|
+
GitHub PAT), so it's fully scriptable:
|
|
287
|
+
|
|
288
|
+
1. Create one at [notion.so/my-integrations](https://www.notion.so/my-integrations) → **New integration → Internal**, with the **Read content** capability.
|
|
289
|
+
2. Copy the **Internal Integration Secret** (`ntn_…` / `secret_…`).
|
|
290
|
+
3. In Notion, open each page/database the seer should watch → **••• → Connections →** add your integration. **A Notion integration only sees pages explicitly shared with it** — this step is required, or the seer connects but detects nothing.
|
|
291
|
+
4. `letterstory seers connect notion --token ntn_…`
|
|
292
|
+
|
|
293
|
+
The app's browser OAuth flow (Seers tab → Connect Notion) is an equivalent alternative, not a requirement.
|
|
294
|
+
|
|
295
|
+
> **Remaining gap.** `seers run` executes synchronously server-side (up to ~5 minutes for
|
|
296
|
+
> web-scan providers); there is no start-then-poll variant yet. And `create`'s config takes
|
|
297
|
+
> raw JSON — `seers providers` is the schema reference the server validates against.
|
|
289
298
|
|
|
290
299
|
Content templates (the compose structures seers bind via `config.template_key`):
|
|
291
300
|
|
package/lib/cli.mjs
CHANGED
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
} from "./commands.mjs";
|
|
36
36
|
|
|
37
37
|
// Keep in sync with cli/package.json.
|
|
38
|
-
export const VERSION = "0.5.
|
|
38
|
+
export const VERSION = "0.5.1";
|
|
39
39
|
|
|
40
40
|
// Flags that never take a value. Listing them explicitly means `deploy get --json <id>`
|
|
41
41
|
// can't accidentally swallow the id as --json's value.
|
|
@@ -245,7 +245,8 @@ Seers (event-driven signals -> drafts):
|
|
|
245
245
|
seers release <article-id> | seers discard <article-id>
|
|
246
246
|
seers connections GitHub/Notion connection status
|
|
247
247
|
seers connect github --token <pat> Store an org-wide GitHub token
|
|
248
|
-
seers connect notion
|
|
248
|
+
seers connect notion --token <secret> Store a Notion internal-integration token
|
|
249
|
+
seers connect notion (no token: prints how to mint one + share pages)
|
|
249
250
|
seers export [--file <path>] Dump the org's seers as a manifest
|
|
250
251
|
seers apply --file <path> [--dry-run] Idempotent, name-keyed upsert from a manifest
|
|
251
252
|
(never deletes; --dry-run prints the plan)
|
package/lib/commands/seers.mjs
CHANGED
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
// `seers export` (dump the org's seers as a manifest) and `seers apply` (idempotent,
|
|
5
5
|
// name-keyed diff-then-upsert from a manifest, with --dry-run).
|
|
6
6
|
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
7
|
+
// Connections are both headless: `seers connect github --token` (a PAT) and
|
|
8
|
+
// `seers connect notion --token` (a Notion internal-integration secret; run
|
|
9
|
+
// `seers connect notion` with no token for how to mint one and which pages to share).
|
|
10
|
+
// One thing to know: `seers run` executes synchronously server-side (news/regulation
|
|
11
|
+
// web scans can take minutes) and spends model budget — it is usage-gated per org.
|
|
12
12
|
|
|
13
13
|
import { readFileSync, writeFileSync } from "node:fs";
|
|
14
14
|
import { CliError } from "../client.mjs";
|
|
@@ -292,7 +292,7 @@ async function seersConnections(ctx) {
|
|
|
292
292
|
: `GitHub: not connected${r.github.configured ? " — connect with `seers connect github --token <pat>`" : " (token storage not configured on this deployment)"}`;
|
|
293
293
|
const notion = r.notion.connected
|
|
294
294
|
? `Notion: connected to ${r.notion.workspace_name} (${r.notion.connected_at})`
|
|
295
|
-
:
|
|
295
|
+
: `Notion: not connected${r.notion.configured ? " — connect with `seers connect notion --token <secret>` (run `seers connect notion` for how to get one)" : " (token storage not configured on this deployment)"}`;
|
|
296
296
|
return `${gh}\n${notion}`;
|
|
297
297
|
});
|
|
298
298
|
return 0;
|
|
@@ -310,11 +310,29 @@ async function seersConnect(ctx) {
|
|
|
310
310
|
return 0;
|
|
311
311
|
}
|
|
312
312
|
if (which === "notion") {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
313
|
+
const token = flagStr(rest.flags.token);
|
|
314
|
+
if (!token) {
|
|
315
|
+
// No token yet — print how to mint one and which pages to share. Notion
|
|
316
|
+
// internal integrations only see pages explicitly shared with them, so the
|
|
317
|
+
// share step is load-bearing, not optional.
|
|
318
|
+
rest.io.log("Connect Notion with an internal-integration secret (headless — no browser needed):");
|
|
319
|
+
rest.io.log("");
|
|
320
|
+
rest.io.log(" 1. Go to https://www.notion.so/my-integrations → New integration → Internal.");
|
|
321
|
+
rest.io.log(" 2. Give it the 'Read content' capability, then copy the Internal Integration Secret");
|
|
322
|
+
rest.io.log(" (starts with ntn_ or secret_).");
|
|
323
|
+
rest.io.log(" 3. In Notion, open each page/database the seer should watch → ••• → Connections →");
|
|
324
|
+
rest.io.log(" add your integration. (An integration only sees pages shared with it.)");
|
|
325
|
+
rest.io.log(` 4. Run: ${rest.bin} seers connect notion --token ntn_your_secret`);
|
|
326
|
+
rest.io.log("");
|
|
327
|
+
rest.io.log(
|
|
328
|
+
"The app's browser OAuth flow (Seers tab → Connect Notion) is an alternative, not a requirement."
|
|
329
|
+
);
|
|
330
|
+
return 0;
|
|
331
|
+
}
|
|
332
|
+
const result = await rest.client.callTool("set_notion_connection", { access_token: token });
|
|
333
|
+
ok(rest, `Notion connected${result.workspace_name ? ` to ${result.workspace_name}` : ""}.`);
|
|
334
|
+
ok(rest, "Reminder: the integration only watches pages you've shared with it in Notion.");
|
|
335
|
+
printResult(rest.io, rest.flags, result);
|
|
318
336
|
return 0;
|
|
319
337
|
}
|
|
320
338
|
throw new CliError(`Unknown connect target: ${which ?? "(none)"}. Try: github, notion`);
|