@todoist/outline-cli 0.0.1 → 3.0.0

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.
Files changed (108) hide show
  1. package/CHANGELOG.md +359 -0
  2. package/README.md +145 -29
  3. package/dist/commands/account.d.ts +2 -0
  4. package/dist/commands/account.js +107 -0
  5. package/dist/commands/account.js.map +1 -0
  6. package/dist/commands/auth.d.ts +2 -0
  7. package/dist/commands/auth.js +169 -0
  8. package/dist/commands/auth.js.map +1 -0
  9. package/dist/commands/changelog.d.ts +2 -0
  10. package/dist/commands/changelog.js +15 -0
  11. package/dist/commands/changelog.js.map +1 -0
  12. package/dist/commands/collection.d.ts +2 -0
  13. package/dist/commands/collection.js +106 -0
  14. package/dist/commands/collection.js.map +1 -0
  15. package/dist/commands/document.d.ts +2 -0
  16. package/dist/commands/document.js +291 -0
  17. package/dist/commands/document.js.map +1 -0
  18. package/dist/commands/search.d.ts +2 -0
  19. package/dist/commands/search.js +49 -0
  20. package/dist/commands/search.js.map +1 -0
  21. package/dist/commands/skill.d.ts +2 -0
  22. package/dist/commands/skill.js +80 -0
  23. package/dist/commands/skill.js.map +1 -0
  24. package/dist/commands/update/index.d.ts +2 -0
  25. package/dist/commands/update/index.js +14 -0
  26. package/dist/commands/update/index.js.map +1 -0
  27. package/dist/index.d.ts +2 -0
  28. package/dist/index.js +56 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/lib/api.d.ts +18 -0
  31. package/dist/lib/api.js +107 -0
  32. package/dist/lib/api.js.map +1 -0
  33. package/dist/lib/auth-constants.d.ts +18 -0
  34. package/dist/lib/auth-constants.js +25 -0
  35. package/dist/lib/auth-constants.js.map +1 -0
  36. package/dist/lib/auth-output.d.ts +21 -0
  37. package/dist/lib/auth-output.js +38 -0
  38. package/dist/lib/auth-output.js.map +1 -0
  39. package/dist/lib/auth-pages.d.ts +2 -0
  40. package/dist/lib/auth-pages.js +101 -0
  41. package/dist/lib/auth-pages.js.map +1 -0
  42. package/dist/lib/auth-provider.d.ts +85 -0
  43. package/dist/lib/auth-provider.js +363 -0
  44. package/dist/lib/auth-provider.js.map +1 -0
  45. package/dist/lib/auth.d.ts +73 -0
  46. package/dist/lib/auth.js +188 -0
  47. package/dist/lib/auth.js.map +1 -0
  48. package/dist/lib/config.d.ts +45 -0
  49. package/dist/lib/config.js +20 -0
  50. package/dist/lib/config.js.map +1 -0
  51. package/dist/lib/errors.d.ts +8 -0
  52. package/dist/lib/errors.js +9 -0
  53. package/dist/lib/errors.js.map +1 -0
  54. package/dist/lib/global-args.d.ts +30 -0
  55. package/dist/lib/global-args.js +66 -0
  56. package/dist/lib/global-args.js.map +1 -0
  57. package/dist/lib/markdown.d.ts +2 -0
  58. package/dist/lib/markdown.js +12 -0
  59. package/dist/lib/markdown.js.map +1 -0
  60. package/dist/lib/migrate-auth.d.ts +11 -0
  61. package/dist/lib/migrate-auth.js +92 -0
  62. package/dist/lib/migrate-auth.js.map +1 -0
  63. package/dist/lib/outline-account.d.ts +32 -0
  64. package/dist/lib/outline-account.js +22 -0
  65. package/dist/lib/outline-account.js.map +1 -0
  66. package/dist/lib/output.d.ts +15 -0
  67. package/dist/lib/output.js +85 -0
  68. package/dist/lib/output.js.map +1 -0
  69. package/dist/lib/refs.d.ts +33 -0
  70. package/dist/lib/refs.js +182 -0
  71. package/dist/lib/refs.js.map +1 -0
  72. package/dist/lib/skills/content.d.ts +3 -0
  73. package/dist/lib/skills/content.js +160 -0
  74. package/dist/lib/skills/content.js.map +1 -0
  75. package/dist/lib/skills/create-installer.d.ts +9 -0
  76. package/dist/lib/skills/create-installer.js +77 -0
  77. package/dist/lib/skills/create-installer.js.map +1 -0
  78. package/dist/lib/skills/index.d.ts +5 -0
  79. package/dist/lib/skills/index.js +40 -0
  80. package/dist/lib/skills/index.js.map +1 -0
  81. package/dist/lib/skills/types.d.ts +10 -0
  82. package/dist/lib/skills/types.js +2 -0
  83. package/dist/lib/skills/types.js.map +1 -0
  84. package/dist/lib/skills/update-installed.d.ts +6 -0
  85. package/dist/lib/skills/update-installed.js +23 -0
  86. package/dist/lib/skills/update-installed.js.map +1 -0
  87. package/dist/lib/spinner.d.ts +2 -0
  88. package/dist/lib/spinner.js +5 -0
  89. package/dist/lib/spinner.js.map +1 -0
  90. package/dist/lib/user-records.d.ts +21 -0
  91. package/dist/lib/user-records.js +126 -0
  92. package/dist/lib/user-records.js.map +1 -0
  93. package/dist/lib/user-ref-store.d.ts +16 -0
  94. package/dist/lib/user-ref-store.js +37 -0
  95. package/dist/lib/user-ref-store.js.map +1 -0
  96. package/dist/postinstall.d.ts +1 -0
  97. package/dist/postinstall.js +16 -0
  98. package/dist/postinstall.js.map +1 -0
  99. package/dist/transport/fetch-with-retry.d.ts +15 -0
  100. package/dist/transport/fetch-with-retry.js +144 -0
  101. package/dist/transport/fetch-with-retry.js.map +1 -0
  102. package/dist/transport/http-dispatcher.d.ts +37 -0
  103. package/dist/transport/http-dispatcher.js +95 -0
  104. package/dist/transport/http-dispatcher.js.map +1 -0
  105. package/package.json +71 -8
  106. package/scripts/check-skill-sync.js +40 -0
  107. package/scripts/postinstall.js +12 -0
  108. package/scripts/sync-skill.js +30 -0
@@ -0,0 +1,85 @@
1
+ import { formatJson, formatNdjson, printEmpty } from '@todoist/cli-core';
2
+ import chalk from 'chalk';
3
+ import { BaseCliError } from './errors.js';
4
+ export function getOutputOptions(opts) {
5
+ return {
6
+ json: Boolean(opts.json),
7
+ ndjson: Boolean(opts.ndjson),
8
+ full: Boolean(opts.full),
9
+ };
10
+ }
11
+ export function outputItem(item, humanFormatter, essentialKeys, opts = {}) {
12
+ if (opts.ndjson) {
13
+ const data = opts.full || !essentialKeys ? item : pick(item, essentialKeys);
14
+ console.log(formatNdjson([data]));
15
+ return;
16
+ }
17
+ if (opts.json) {
18
+ const data = opts.full || !essentialKeys ? item : pick(item, essentialKeys);
19
+ console.log(formatJson(data));
20
+ return;
21
+ }
22
+ console.log(humanFormatter(item));
23
+ }
24
+ export function outputList(items, humanFormatter, essentialKeys, opts = {}, pagination, emptyMessage) {
25
+ if (items.length === 0 && emptyMessage !== undefined) {
26
+ printEmpty({ options: opts, message: emptyMessage });
27
+ return;
28
+ }
29
+ const project = (item) => (opts.full || !essentialKeys ? item : pick(item, essentialKeys));
30
+ if (opts.ndjson) {
31
+ // Stream item-by-item: avoids buffering the whole list and matches
32
+ // the canonical NDJSON contract (one record per write).
33
+ for (const item of items) {
34
+ console.log(formatNdjson([project(item)]));
35
+ }
36
+ }
37
+ else if (opts.json) {
38
+ console.log(formatJson(items.map(project)));
39
+ }
40
+ else {
41
+ for (const item of items) {
42
+ console.log(humanFormatter(item));
43
+ }
44
+ }
45
+ if (pagination?.nextPath && !opts.ndjson) {
46
+ const hint = chalk.dim(`\n(more results available — use --offset ${pagination.offset + pagination.limit})`);
47
+ // In JSON mode stdout holds the JSON itself, so the hint goes to stderr to keep it parseable.
48
+ if (opts.json) {
49
+ console.error(hint);
50
+ }
51
+ else {
52
+ console.log(hint);
53
+ }
54
+ }
55
+ }
56
+ function pick(obj, keys) {
57
+ const result = {};
58
+ for (const key of keys) {
59
+ if (key in obj)
60
+ result[key] = obj[key];
61
+ }
62
+ return result;
63
+ }
64
+ function toCliError(codeOrError, message, hints) {
65
+ if (typeof codeOrError === 'string') {
66
+ return new BaseCliError(codeOrError, message ?? '', { hints });
67
+ }
68
+ return codeOrError;
69
+ }
70
+ export function formatError(codeOrError, message, hints) {
71
+ const err = toCliError(codeOrError, message, hints);
72
+ const lines = [`Error: ${err.code}`, err.message];
73
+ if (err.hints && err.hints.length > 0) {
74
+ lines.push('');
75
+ for (const hint of err.hints) {
76
+ lines.push(` - ${hint}`);
77
+ }
78
+ }
79
+ return chalk.red(lines.join('\n'));
80
+ }
81
+ export function formatErrorJson(codeOrError, message, hints) {
82
+ const err = toCliError(codeOrError, message, hints);
83
+ return JSON.stringify({ error: { code: err.code, message: err.message, hints: err.hints } });
84
+ }
85
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ export interface Document {
2
+ id: string;
3
+ title: string;
4
+ url: string;
5
+ urlId: string;
6
+ text?: string;
7
+ }
8
+ export interface Collection {
9
+ id: string;
10
+ name: string;
11
+ description?: string;
12
+ color?: string;
13
+ permission?: string;
14
+ createdAt?: string;
15
+ updatedAt?: string;
16
+ documentCount?: number;
17
+ }
18
+ /**
19
+ * Resolve a document reference by ID, URL, or name
20
+ */
21
+ export declare function resolveDocumentRef(ref: string): Promise<Document>;
22
+ /**
23
+ * Resolve a document reference and return just the ID
24
+ */
25
+ export declare function resolveDocumentId(ref: string): Promise<string>;
26
+ /**
27
+ * Resolve a collection reference by ID or name
28
+ */
29
+ export declare function resolveCollectionRef(ref: string): Promise<Collection>;
30
+ /**
31
+ * Resolve a collection reference and return just the ID
32
+ */
33
+ export declare function resolveCollectionId(ref: string): Promise<string>;
@@ -0,0 +1,182 @@
1
+ import { apiRequest } from './api.js';
2
+ /**
3
+ * Check if the input looks like a UUID
4
+ */
5
+ function isUuid(input) {
6
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(input);
7
+ }
8
+ /**
9
+ * Check if the input looks like an Outline ID (UUID or URL ID format)
10
+ */
11
+ function looksLikeId(input) {
12
+ // UUID format
13
+ if (isUuid(input)) {
14
+ return true;
15
+ }
16
+ // Short alphanumeric ID (like urlId) - must be 6+ chars and no spaces
17
+ if (/^[a-zA-Z0-9]{6,}$/.test(input) && !/\s/.test(input)) {
18
+ return true;
19
+ }
20
+ return false;
21
+ }
22
+ /**
23
+ * Extract document ID from URL or slug (document-only)
24
+ * Only extracts from slugs (e.g., "my-doc-abc123" -> "abc123")
25
+ * In URLs, the slug is the segment after `/doc/`; trailing paths
26
+ * (`/edit`, `/history/...`), `?query` and `#anchor` are ignored, and a
27
+ * slug without a title (`/doc/<urlId>`) is the ID itself
28
+ * Preserves full UUIDs and raw IDs
29
+ */
30
+ function extractDocumentIdFromSlug(input) {
31
+ // Preserve UUIDs as-is
32
+ if (isUuid(input)) {
33
+ return input;
34
+ }
35
+ // If it looks like a URL, extract the slug suffix
36
+ const docSlug = input.match(/\/doc\/([^/?#]+)/)?.[1];
37
+ const parts = input.replace(/\/$/, '').split('/');
38
+ const last = docSlug ?? parts[parts.length - 1];
39
+ // Outline URL IDs are the part after the last hyphen in the slug
40
+ // Only extract if it's a slug with hyphen, not just a raw ID
41
+ const match = last.match(/-([a-zA-Z0-9]+)$/);
42
+ if (match)
43
+ return match[1];
44
+ return docSlug ?? input;
45
+ }
46
+ /**
47
+ * Format suggestions for error messages
48
+ */
49
+ function formatSuggestions(items, getName, getDisplayId, max = 5) {
50
+ const suggestions = items.slice(0, max);
51
+ return suggestions.map((item) => ` - "${getName(item)}" (${getDisplayId(item)})`).join('\n');
52
+ }
53
+ /**
54
+ * Generic fuzzy reference resolver
55
+ */
56
+ async function resolveRef(options) {
57
+ const { ref, fetchById, fetchAllPaginated, getName, getDisplayId, entityType, extractSlugId } = options;
58
+ // Try direct ID lookup first if it looks like an ID
59
+ // Only extract slug ID for documents, not collections
60
+ const extractedId = extractSlugId ? extractDocumentIdFromSlug(ref) : ref;
61
+ if (looksLikeId(extractedId)) {
62
+ try {
63
+ return await fetchById(extractedId);
64
+ }
65
+ catch {
66
+ // If direct ID lookup fails, fall through to name matching
67
+ }
68
+ }
69
+ // Fetch all items with pagination and search by name
70
+ const items = await fetchAllPaginated();
71
+ const refLower = ref.toLowerCase();
72
+ // Try exact match first (case-insensitive)
73
+ const exactMatches = items.filter((item) => getName(item).toLowerCase() === refLower);
74
+ if (exactMatches.length === 1) {
75
+ return exactMatches[0];
76
+ }
77
+ // Multiple exact matches are ambiguous
78
+ if (exactMatches.length > 1) {
79
+ const suggestions = formatSuggestions(exactMatches, getName, getDisplayId);
80
+ throw new Error(`Ambiguous ${entityType} reference "${ref}". Multiple items have this exact name:\n${suggestions}`);
81
+ }
82
+ // Try partial match
83
+ const partialMatches = items.filter((item) => getName(item).toLowerCase().includes(refLower));
84
+ if (partialMatches.length === 1) {
85
+ return partialMatches[0];
86
+ }
87
+ if (partialMatches.length > 1) {
88
+ const suggestions = formatSuggestions(partialMatches, getName, getDisplayId);
89
+ throw new Error(`Ambiguous ${entityType} reference "${ref}". Did you mean:\n${suggestions}`);
90
+ }
91
+ // No matches found
92
+ throw new Error(`${entityType} not found: "${ref}"`);
93
+ }
94
+ /**
95
+ * Fetch all documents with pagination
96
+ */
97
+ async function fetchAllDocuments() {
98
+ const allDocs = [];
99
+ const limit = 100;
100
+ let offset = 0;
101
+ while (true) {
102
+ const { data } = await apiRequest('documents.list', {
103
+ limit,
104
+ offset,
105
+ });
106
+ allDocs.push(...data);
107
+ if (data.length < limit) {
108
+ break;
109
+ }
110
+ offset += limit;
111
+ }
112
+ return allDocs;
113
+ }
114
+ /**
115
+ * Fetch all collections with pagination
116
+ */
117
+ async function fetchAllCollections() {
118
+ const allCollections = [];
119
+ const limit = 100;
120
+ let offset = 0;
121
+ while (true) {
122
+ const { data } = await apiRequest('collections.list', {
123
+ limit,
124
+ offset,
125
+ });
126
+ allCollections.push(...data);
127
+ if (data.length < limit) {
128
+ break;
129
+ }
130
+ offset += limit;
131
+ }
132
+ return allCollections;
133
+ }
134
+ /**
135
+ * Resolve a document reference by ID, URL, or name
136
+ */
137
+ export async function resolveDocumentRef(ref) {
138
+ return resolveRef({
139
+ ref,
140
+ fetchById: async (id) => {
141
+ const { data } = await apiRequest('documents.info', { id });
142
+ return data;
143
+ },
144
+ fetchAllPaginated: fetchAllDocuments,
145
+ getName: (doc) => doc.title,
146
+ getDisplayId: (doc) => doc.urlId,
147
+ entityType: 'Document',
148
+ extractSlugId: true,
149
+ });
150
+ }
151
+ /**
152
+ * Resolve a document reference and return just the ID
153
+ */
154
+ export async function resolveDocumentId(ref) {
155
+ const doc = await resolveDocumentRef(ref);
156
+ return doc.id;
157
+ }
158
+ /**
159
+ * Resolve a collection reference by ID or name
160
+ */
161
+ export async function resolveCollectionRef(ref) {
162
+ return resolveRef({
163
+ ref,
164
+ fetchById: async (id) => {
165
+ const { data } = await apiRequest('collections.info', { id });
166
+ return data;
167
+ },
168
+ fetchAllPaginated: fetchAllCollections,
169
+ getName: (col) => col.name,
170
+ getDisplayId: (col) => col.id,
171
+ entityType: 'Collection',
172
+ extractSlugId: false,
173
+ });
174
+ }
175
+ /**
176
+ * Resolve a collection reference and return just the ID
177
+ */
178
+ export async function resolveCollectionId(ref) {
179
+ const col = await resolveCollectionRef(ref);
180
+ return col.id;
181
+ }
182
+ //# sourceMappingURL=refs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refs.js","sourceRoot":"","sources":["../../src/lib/refs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare const SKILL_NAME = "outline-cli";
2
+ export declare const SKILL_DESCRIPTION = "Search and manage Outline wiki documents and collections via the ol CLI";
3
+ export declare const SKILL_CONTENT = "# Outline CLI (ol)\n\nUse this skill when the user wants to interact with their Outline wiki/knowledge base.\n\n## Quick Reference\n\n- `ol search \"query\"` - Search documents\n- `ol doc list` - List documents\n- `ol doc get <id>` - Read a document\n- `ol doc open <id>` - Open document in browser\n- `ol doc create --title \"Title\" --collection <id>` - Create document\n- `ol col list` - List collections\n- `ol account` - List stored accounts; `ol account use <id|name>` sets the default\n\n## Output Formats\n\nAll list commands support:\n- `--json` - JSON output (essential fields)\n- `--ndjson` - Newline-delimited JSON (streaming)\n- `--full` - Include all fields in JSON\n\n## Global Options\n\n- `--user <id|name>` - Act as a specific stored account, matched by Outline user ID or display name. Each `ol auth login` stores an account (accounts can live on different Outline instances), and `--user` selects which one a command runs as; the token, base URL, and OAuth client ID all resolve from that account. Must be placed **before** the command, e.g. `ol --user scott@example.com doc list`. Omitted, commands use the default account. Overridden by `OUTLINE_API_TOKEN` when set.\n\n## Document References\n\nDocuments can be referenced by:\n- URL ID (the slug suffix after the last hyphen)\n- Full Outline URL (auto-extracted)\n- Document ID\n\n## Commands\n\n### Search\n```bash\nol search \"query\"\nol search \"query\" --limit 10\nol search \"query\" --offset 25 # next page of results\nol search \"query\" --collection <id>\nol search \"query\" --status published\nol search \"query\" --json\n```\n\n### Documents\n```bash\nol doc list --collection <id> --limit 25\nol doc list --sort title --direction ASC\nol doc get <id> # Rendered markdown\nol doc get <id> --raw # Raw markdown\nol doc get <id> --json\nol doc open <id> # Open in browser\nol doc create --title \"Title\" --collection <id> --text \"# Content\"\nol doc create --title \"Title\" --parent <ref> --text \"# Content\" # Nest under parent (collection inferred)\nol doc create --title \"Title\" --collection <id> --file ./doc.md\nol doc update <id> --title \"New Title\"\nol doc update <id> --file ./updated.md\ngenerate-notes | ol doc update <id> --stdin # Read markdown from stdin (create and update)\nol doc update <id> --publish # Publish a draft (create makes drafts unless --publish)\nol doc update <id> --publish --collection <ref> # Publish a draft that has no collection (web UI drafts)\nol doc update <id> --file ./doc.md --if-updated-at <updatedAt> # Fail if the doc was saved since <updatedAt> (see Examples)\nol doc move <id> --collection <target-id> # Move to collection root\nol doc move <id> --parent <ref> # Nest under parent (collection inferred)\nol doc archive <id>\nol doc unarchive <id>\nol doc delete <id> --confirm\nol doc restore <id> # Restore from trash (ID or URL; trashed docs aren't found by title)\nol doc restore <id> --collection <ref> # Restore into another collection (required if the original is gone)\n```\n\n### Collections\n```bash\nol col list\nol col get <id>\nol col create --name \"Name\" --description \"Desc\" --color \"#hex\"\nol col create --name \"Private\" --private\nol col update <id> --name \"New Name\"\nol col delete <id> --confirm\n```\n\n### Authentication\n```bash\nol auth login # OAuth login (opens browser); prompts for base URL + client ID if needed\nol auth login --base-url <url> # Specify Outline base URL for this login (saved for future use)\nol auth login --client-id <id> # Specify OAuth client ID for this login (saved for future use)\nol auth login --callback-port <port> # Override local OAuth callback port\nol auth login --read-only # Request read-only scopes (where supported by the Outline instance)\nol auth login --json | --ndjson # Machine-readable success envelope\nol auth status # Show current auth state\nol auth status --json | --ndjson # Machine-readable status envelope ({id, team, baseUrl, source})\nol auth logout # Clear saved credentials\nol auth logout --json | --ndjson # Machine-readable logout envelope ({ok: true}; --ndjson is silent)\nol auth token <token> # Save a personal API token (validates via auth.info, resolves identity)\nol auth token <token> --base-url <url> # Save a token for a specific Outline instance\nol auth token # Prompt for the token (hidden input; errors in non-interactive shells)\nol auth token view # Print the bare stored token to stdout for scripts (refreshes an expiring OAuth token first; no newline when piped; refuses when OUTLINE_API_TOKEN is set)\nol --user <id|name> auth token view # Print a specific stored account's token (--user is a root flag, before the command)\n```\n\n### Accounts\n```bash\nol account # List stored accounts (default subcommand)\nol account list # List stored accounts, default marked\nol account list --json | --ndjson # Machine-readable list ({accounts, default}; --ndjson streams one per line)\nol account current # Show the active account (honours --user and OUTLINE_API_TOKEN)\nol account current --json | --ndjson # Discriminated by source: {source:\"stored\", account:{id, label, teamName, baseUrl, isDefault}} | {source:\"env\"} | {source:\"legacy\"}\nol account use <id|name> # Set the default account used when --user is omitted\nol account use <id|name> --json # Machine-readable envelope ({ok: true, default: <id>}; --ndjson is silent)\nol account remove <id|name> # Remove a stored account (clears keyring + config entry)\nol account remove <id|name> --json # Machine-readable envelope ({ok: true, removed: <id>}; --ndjson is silent)\n```\n\n### Update & Changelog\n```bash\nol update # Update CLI to latest version\nol update --check # Check for updates without installing, show channel\nol update --check --json # Check for updates as a JSON envelope\nol update --check --ndjson # Check for updates as NDJSON output\nol update --channel # Show current update channel\nol update switch --stable # Switch to stable release channel\nol update switch --pre-release # Switch to pre-release (next) channel\nol changelog # Show recent changelog entries\nol changelog -n 3 # Show last 3 versions\n```\n\n## Examples\n\n### Find and read a document\n```bash\nol search \"onboarding\" --json | jq '.[0].document.urlId'\nol doc get <urlId>\n```\n\n### Create a document from a file\n```bash\nol doc create --title \"Meeting Notes\" --collection <id> --file ./notes.md --publish\n```\n\n### Edit a document without overwriting someone else's changes\n```bash\nts=$(ol doc get <id> --json | jq -r '.updatedAt')\nol doc get <id> --raw > doc.md # then edit doc.md\nol doc update <id> --file doc.md --if-updated-at \"$ts\"\n```\nIf the document was saved after `$ts`, the update fails with `DOCUMENT_CHANGED`, or with Outline's \"Document has been modified since the provided revision\" when the save lands during the update; re-read and retry. Edits not yet saved from an open editor are not detected.\n\n### List all collections and their documents\n```bash\nol col list --json\nol doc list --collection <id> --sort title --direction ASC\n```\n\n### Bulk export with ndjson\n```bash\nol doc list --ndjson --full | jq -r '.title'\n```\n";
@@ -0,0 +1,160 @@
1
+ export const SKILL_NAME = 'outline-cli';
2
+ export const SKILL_DESCRIPTION = 'Search and manage Outline wiki documents and collections via the ol CLI';
3
+ export const SKILL_CONTENT = `# Outline CLI (ol)
4
+
5
+ Use this skill when the user wants to interact with their Outline wiki/knowledge base.
6
+
7
+ ## Quick Reference
8
+
9
+ - \`ol search "query"\` - Search documents
10
+ - \`ol doc list\` - List documents
11
+ - \`ol doc get <id>\` - Read a document
12
+ - \`ol doc open <id>\` - Open document in browser
13
+ - \`ol doc create --title "Title" --collection <id>\` - Create document
14
+ - \`ol col list\` - List collections
15
+ - \`ol account\` - List stored accounts; \`ol account use <id|name>\` sets the default
16
+
17
+ ## Output Formats
18
+
19
+ All list commands support:
20
+ - \`--json\` - JSON output (essential fields)
21
+ - \`--ndjson\` - Newline-delimited JSON (streaming)
22
+ - \`--full\` - Include all fields in JSON
23
+
24
+ ## Global Options
25
+
26
+ - \`--user <id|name>\` - Act as a specific stored account, matched by Outline user ID or display name. Each \`ol auth login\` stores an account (accounts can live on different Outline instances), and \`--user\` selects which one a command runs as; the token, base URL, and OAuth client ID all resolve from that account. Must be placed **before** the command, e.g. \`ol --user scott@example.com doc list\`. Omitted, commands use the default account. Overridden by \`OUTLINE_API_TOKEN\` when set.
27
+
28
+ ## Document References
29
+
30
+ Documents can be referenced by:
31
+ - URL ID (the slug suffix after the last hyphen)
32
+ - Full Outline URL (auto-extracted)
33
+ - Document ID
34
+
35
+ ## Commands
36
+
37
+ ### Search
38
+ \`\`\`bash
39
+ ol search "query"
40
+ ol search "query" --limit 10
41
+ ol search "query" --offset 25 # next page of results
42
+ ol search "query" --collection <id>
43
+ ol search "query" --status published
44
+ ol search "query" --json
45
+ \`\`\`
46
+
47
+ ### Documents
48
+ \`\`\`bash
49
+ ol doc list --collection <id> --limit 25
50
+ ol doc list --sort title --direction ASC
51
+ ol doc get <id> # Rendered markdown
52
+ ol doc get <id> --raw # Raw markdown
53
+ ol doc get <id> --json
54
+ ol doc open <id> # Open in browser
55
+ ol doc create --title "Title" --collection <id> --text "# Content"
56
+ ol doc create --title "Title" --parent <ref> --text "# Content" # Nest under parent (collection inferred)
57
+ ol doc create --title "Title" --collection <id> --file ./doc.md
58
+ ol doc update <id> --title "New Title"
59
+ ol doc update <id> --file ./updated.md
60
+ generate-notes | ol doc update <id> --stdin # Read markdown from stdin (create and update)
61
+ ol doc update <id> --publish # Publish a draft (create makes drafts unless --publish)
62
+ ol doc update <id> --publish --collection <ref> # Publish a draft that has no collection (web UI drafts)
63
+ ol doc update <id> --file ./doc.md --if-updated-at <updatedAt> # Fail if the doc was saved since <updatedAt> (see Examples)
64
+ ol doc move <id> --collection <target-id> # Move to collection root
65
+ ol doc move <id> --parent <ref> # Nest under parent (collection inferred)
66
+ ol doc archive <id>
67
+ ol doc unarchive <id>
68
+ ol doc delete <id> --confirm
69
+ ol doc restore <id> # Restore from trash (ID or URL; trashed docs aren't found by title)
70
+ ol doc restore <id> --collection <ref> # Restore into another collection (required if the original is gone)
71
+ \`\`\`
72
+
73
+ ### Collections
74
+ \`\`\`bash
75
+ ol col list
76
+ ol col get <id>
77
+ ol col create --name "Name" --description "Desc" --color "#hex"
78
+ ol col create --name "Private" --private
79
+ ol col update <id> --name "New Name"
80
+ ol col delete <id> --confirm
81
+ \`\`\`
82
+
83
+ ### Authentication
84
+ \`\`\`bash
85
+ ol auth login # OAuth login (opens browser); prompts for base URL + client ID if needed
86
+ ol auth login --base-url <url> # Specify Outline base URL for this login (saved for future use)
87
+ ol auth login --client-id <id> # Specify OAuth client ID for this login (saved for future use)
88
+ ol auth login --callback-port <port> # Override local OAuth callback port
89
+ ol auth login --read-only # Request read-only scopes (where supported by the Outline instance)
90
+ ol auth login --json | --ndjson # Machine-readable success envelope
91
+ ol auth status # Show current auth state
92
+ ol auth status --json | --ndjson # Machine-readable status envelope ({id, team, baseUrl, source})
93
+ ol auth logout # Clear saved credentials
94
+ ol auth logout --json | --ndjson # Machine-readable logout envelope ({ok: true}; --ndjson is silent)
95
+ ol auth token <token> # Save a personal API token (validates via auth.info, resolves identity)
96
+ ol auth token <token> --base-url <url> # Save a token for a specific Outline instance
97
+ ol auth token # Prompt for the token (hidden input; errors in non-interactive shells)
98
+ ol auth token view # Print the bare stored token to stdout for scripts (refreshes an expiring OAuth token first; no newline when piped; refuses when OUTLINE_API_TOKEN is set)
99
+ ol --user <id|name> auth token view # Print a specific stored account's token (--user is a root flag, before the command)
100
+ \`\`\`
101
+
102
+ ### Accounts
103
+ \`\`\`bash
104
+ ol account # List stored accounts (default subcommand)
105
+ ol account list # List stored accounts, default marked
106
+ ol account list --json | --ndjson # Machine-readable list ({accounts, default}; --ndjson streams one per line)
107
+ ol account current # Show the active account (honours --user and OUTLINE_API_TOKEN)
108
+ ol account current --json | --ndjson # Discriminated by source: {source:"stored", account:{id, label, teamName, baseUrl, isDefault}} | {source:"env"} | {source:"legacy"}
109
+ ol account use <id|name> # Set the default account used when --user is omitted
110
+ ol account use <id|name> --json # Machine-readable envelope ({ok: true, default: <id>}; --ndjson is silent)
111
+ ol account remove <id|name> # Remove a stored account (clears keyring + config entry)
112
+ ol account remove <id|name> --json # Machine-readable envelope ({ok: true, removed: <id>}; --ndjson is silent)
113
+ \`\`\`
114
+
115
+ ### Update & Changelog
116
+ \`\`\`bash
117
+ ol update # Update CLI to latest version
118
+ ol update --check # Check for updates without installing, show channel
119
+ ol update --check --json # Check for updates as a JSON envelope
120
+ ol update --check --ndjson # Check for updates as NDJSON output
121
+ ol update --channel # Show current update channel
122
+ ol update switch --stable # Switch to stable release channel
123
+ ol update switch --pre-release # Switch to pre-release (next) channel
124
+ ol changelog # Show recent changelog entries
125
+ ol changelog -n 3 # Show last 3 versions
126
+ \`\`\`
127
+
128
+ ## Examples
129
+
130
+ ### Find and read a document
131
+ \`\`\`bash
132
+ ol search "onboarding" --json | jq '.[0].document.urlId'
133
+ ol doc get <urlId>
134
+ \`\`\`
135
+
136
+ ### Create a document from a file
137
+ \`\`\`bash
138
+ ol doc create --title "Meeting Notes" --collection <id> --file ./notes.md --publish
139
+ \`\`\`
140
+
141
+ ### Edit a document without overwriting someone else's changes
142
+ \`\`\`bash
143
+ ts=$(ol doc get <id> --json | jq -r '.updatedAt')
144
+ ol doc get <id> --raw > doc.md # then edit doc.md
145
+ ol doc update <id> --file doc.md --if-updated-at "$ts"
146
+ \`\`\`
147
+ If the document was saved after \`$ts\`, the update fails with \`DOCUMENT_CHANGED\`, or with Outline's "Document has been modified since the provided revision" when the save lands during the update; re-read and retry. Edits not yet saved from an open editor are not detected.
148
+
149
+ ### List all collections and their documents
150
+ \`\`\`bash
151
+ ol col list --json
152
+ ol doc list --collection <id> --sort title --direction ASC
153
+ \`\`\`
154
+
155
+ ### Bulk export with ndjson
156
+ \`\`\`bash
157
+ ol doc list --ndjson --full | jq -r '.title'
158
+ \`\`\`
159
+ `;
160
+ //# sourceMappingURL=content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.js","sourceRoot":"","sources":["../../../src/lib/skills/content.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,UAAU,GAAG,aAAa,CAAA;AACvC,MAAM,CAAC,MAAM,iBAAiB,GAC1B,yEAAyE,CAAA;AAE7E,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4J5B,CAAA"}
@@ -0,0 +1,9 @@
1
+ import type { SkillInstaller } from './types.js';
2
+ interface InstallerConfig {
3
+ name: string;
4
+ description: string;
5
+ dirName: string;
6
+ }
7
+ export declare function generateSkillFile(): string;
8
+ export declare function createInstaller(config: InstallerConfig): SkillInstaller;
9
+ export {};
@@ -0,0 +1,77 @@
1
+ import { access, mkdir, readdir, rmdir, unlink, writeFile } from 'node:fs/promises';
2
+ import { homedir } from 'node:os';
3
+ import { dirname, join } from 'node:path';
4
+ import { SKILL_CONTENT, SKILL_DESCRIPTION, SKILL_NAME } from './content.js';
5
+ export function generateSkillFile() {
6
+ const frontmatter = `---
7
+ name: ${SKILL_NAME}
8
+ description: ${JSON.stringify(SKILL_DESCRIPTION)}
9
+ ---
10
+
11
+ `;
12
+ return frontmatter + SKILL_CONTENT;
13
+ }
14
+ export function createInstaller(config) {
15
+ function getInstallPath(local) {
16
+ const base = local ? process.cwd() : homedir();
17
+ return join(base, config.dirName, 'skills', SKILL_NAME, 'SKILL.md');
18
+ }
19
+ return {
20
+ name: config.name,
21
+ description: config.description,
22
+ getInstallPath,
23
+ generateContent() {
24
+ return generateSkillFile();
25
+ },
26
+ async isInstalled(local) {
27
+ try {
28
+ await access(getInstallPath(local));
29
+ return true;
30
+ }
31
+ catch {
32
+ return false;
33
+ }
34
+ },
35
+ async install(local, force) {
36
+ if (!local && config.dirName !== '.agents') {
37
+ const agentDir = join(homedir(), config.dirName);
38
+ try {
39
+ await access(agentDir);
40
+ }
41
+ catch {
42
+ throw new Error(`${config.name} does not appear to be installed (${agentDir} not found)`);
43
+ }
44
+ }
45
+ const filepath = getInstallPath(local);
46
+ const exists = await this.isInstalled(local);
47
+ if (exists && !force) {
48
+ throw new Error(`Skill file already exists at ${filepath}. Use --force to overwrite.`);
49
+ }
50
+ await mkdir(dirname(filepath), { recursive: true });
51
+ await writeFile(filepath, this.generateContent(), 'utf-8');
52
+ },
53
+ async update(local) {
54
+ const filepath = getInstallPath(local);
55
+ await writeFile(filepath, this.generateContent(), 'utf-8');
56
+ },
57
+ async uninstall(local) {
58
+ const filepath = getInstallPath(local);
59
+ const exists = await this.isInstalled(local);
60
+ if (!exists) {
61
+ throw new Error(`Skill file not found at ${filepath}`);
62
+ }
63
+ await unlink(filepath);
64
+ const dir = dirname(filepath);
65
+ try {
66
+ const files = await readdir(dir);
67
+ if (files.length === 0) {
68
+ await rmdir(dir);
69
+ }
70
+ }
71
+ catch {
72
+ // ignore errors when cleaning up empty directory
73
+ }
74
+ },
75
+ };
76
+ }
77
+ //# sourceMappingURL=create-installer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-installer.js","sourceRoot":"","sources":["../../../src/lib/skills/create-installer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { SkillInstaller } from './types.js';
2
+ export declare const skillInstallers: Record<string, SkillInstaller>;
3
+ export declare function getInstaller(agent: string): SkillInstaller | undefined;
4
+ export declare function listAgents(): string[];
5
+ export type { SkillInstaller } from './types.js';
@@ -0,0 +1,40 @@
1
+ import { createInstaller } from './create-installer.js';
2
+ export const skillInstallers = {
3
+ 'claude-code': createInstaller({
4
+ name: 'claude-code',
5
+ description: 'Claude Code skill for Outline CLI',
6
+ dirName: '.claude',
7
+ }),
8
+ codex: createInstaller({
9
+ name: 'codex',
10
+ description: 'Codex skill for Outline CLI',
11
+ dirName: '.codex',
12
+ }),
13
+ cursor: createInstaller({
14
+ name: 'cursor',
15
+ description: 'Cursor skill for Outline CLI',
16
+ dirName: '.cursor',
17
+ }),
18
+ gemini: createInstaller({
19
+ name: 'gemini',
20
+ description: 'Gemini CLI skill for Outline CLI',
21
+ dirName: '.gemini',
22
+ }),
23
+ pi: createInstaller({
24
+ name: 'pi',
25
+ description: 'Pi skill for Outline CLI',
26
+ dirName: '.pi',
27
+ }),
28
+ universal: createInstaller({
29
+ name: 'universal',
30
+ description: 'Universal agent skill for Outline CLI',
31
+ dirName: '.agents',
32
+ }),
33
+ };
34
+ export function getInstaller(agent) {
35
+ return skillInstallers[agent];
36
+ }
37
+ export function listAgents() {
38
+ return Object.keys(skillInstallers);
39
+ }
40
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/skills/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAGvD,MAAM,CAAC,MAAM,eAAe,GAAmC;IAC3D,aAAa,EAAE,eAAe,CAAC;QAC3B,IAAI,EAAE,aAAa;QACnB,WAAW,EAAE,mCAAmC;QAChD,OAAO,EAAE,SAAS;KACrB,CAAC;IACF,KAAK,EAAE,eAAe,CAAC;QACnB,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,6BAA6B;QAC1C,OAAO,EAAE,QAAQ;KACpB,CAAC;IACF,MAAM,EAAE,eAAe,CAAC;QACpB,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,8BAA8B;QAC3C,OAAO,EAAE,SAAS;KACrB,CAAC;IACF,MAAM,EAAE,eAAe,CAAC;QACpB,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,kCAAkC;QAC/C,OAAO,EAAE,SAAS;KACrB,CAAC;IACF,EAAE,EAAE,eAAe,CAAC;QAChB,IAAI,EAAE,IAAI;QACV,WAAW,EAAE,0BAA0B;QACvC,OAAO,EAAE,KAAK;KACjB,CAAC;IACF,SAAS,EAAE,eAAe,CAAC;QACvB,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,uCAAuC;QACpD,OAAO,EAAE,SAAS;KACrB,CAAC;CACL,CAAA;AAED,MAAM,UAAU,YAAY,CAAC,KAAa;IACtC,OAAO,eAAe,CAAC,KAAK,CAAC,CAAA;AACjC,CAAC;AAED,MAAM,UAAU,UAAU;IACtB,OAAO,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;AACvC,CAAC"}
@@ -0,0 +1,10 @@
1
+ export interface SkillInstaller {
2
+ name: string;
3
+ description: string;
4
+ getInstallPath(local: boolean): string;
5
+ generateContent(): string;
6
+ isInstalled(local: boolean): Promise<boolean>;
7
+ install(local: boolean, force: boolean): Promise<void>;
8
+ update(local: boolean): Promise<void>;
9
+ uninstall(local: boolean): Promise<void>;
10
+ }