@doist/outline-cli 0.0.1 → 1.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 (67) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +130 -29
  3. package/dist/commands/auth.d.ts +2 -0
  4. package/dist/commands/auth.js +179 -0
  5. package/dist/commands/auth.js.map +1 -0
  6. package/dist/commands/collection.d.ts +2 -0
  7. package/dist/commands/collection.js +120 -0
  8. package/dist/commands/collection.js.map +1 -0
  9. package/dist/commands/document.d.ts +2 -0
  10. package/dist/commands/document.js +209 -0
  11. package/dist/commands/document.js.map +1 -0
  12. package/dist/commands/search.d.ts +2 -0
  13. package/dist/commands/search.js +42 -0
  14. package/dist/commands/search.js.map +1 -0
  15. package/dist/commands/skill.d.ts +2 -0
  16. package/dist/commands/skill.js +82 -0
  17. package/dist/commands/skill.js.map +1 -0
  18. package/dist/index.d.ts +2 -0
  19. package/dist/index.js +27 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/lib/api.d.ts +14 -0
  22. package/dist/lib/api.js +62 -0
  23. package/dist/lib/api.js.map +1 -0
  24. package/dist/lib/auth.d.ts +6 -0
  25. package/dist/lib/auth.js +70 -0
  26. package/dist/lib/auth.js.map +1 -0
  27. package/dist/lib/markdown.d.ts +1 -0
  28. package/dist/lib/markdown.js +7 -0
  29. package/dist/lib/markdown.js.map +1 -0
  30. package/dist/lib/oauth-server.d.ts +14 -0
  31. package/dist/lib/oauth-server.js +203 -0
  32. package/dist/lib/oauth-server.js.map +1 -0
  33. package/dist/lib/oauth.d.ts +17 -0
  34. package/dist/lib/oauth.js +38 -0
  35. package/dist/lib/oauth.js.map +1 -0
  36. package/dist/lib/output.d.ts +11 -0
  37. package/dist/lib/output.js +60 -0
  38. package/dist/lib/output.js.map +1 -0
  39. package/dist/lib/pkce.d.ts +3 -0
  40. package/dist/lib/pkce.js +20 -0
  41. package/dist/lib/pkce.js.map +1 -0
  42. package/dist/lib/refs.d.ts +33 -0
  43. package/dist/lib/refs.js +180 -0
  44. package/dist/lib/refs.js.map +1 -0
  45. package/dist/lib/skills/content.d.ts +3 -0
  46. package/dist/lib/skills/content.js +100 -0
  47. package/dist/lib/skills/content.js.map +1 -0
  48. package/dist/lib/skills/create-installer.d.ts +8 -0
  49. package/dist/lib/skills/create-installer.js +77 -0
  50. package/dist/lib/skills/create-installer.js.map +1 -0
  51. package/dist/lib/skills/index.d.ts +5 -0
  52. package/dist/lib/skills/index.js +40 -0
  53. package/dist/lib/skills/index.js.map +1 -0
  54. package/dist/lib/skills/types.d.ts +10 -0
  55. package/dist/lib/skills/types.js +2 -0
  56. package/dist/lib/skills/types.js.map +1 -0
  57. package/dist/lib/skills/update-installed.d.ts +6 -0
  58. package/dist/lib/skills/update-installed.js +23 -0
  59. package/dist/lib/skills/update-installed.js.map +1 -0
  60. package/dist/lib/spinner.d.ts +13 -0
  61. package/dist/lib/spinner.js +58 -0
  62. package/dist/lib/spinner.js.map +1 -0
  63. package/dist/postinstall.d.ts +1 -0
  64. package/dist/postinstall.js +3 -0
  65. package/dist/postinstall.js.map +1 -0
  66. package/package.json +61 -8
  67. package/scripts/postinstall.js +12 -0
@@ -0,0 +1,203 @@
1
+ import http from "node:http";
2
+ export const DEFAULT_OAUTH_CALLBACK_PORT = 54969;
3
+ function escapeHtml(text) {
4
+ return text
5
+ .replaceAll("&", "&")
6
+ .replaceAll("<", "&lt;")
7
+ .replaceAll(">", "&gt;")
8
+ .replaceAll('"', "&quot;")
9
+ .replaceAll("'", "&#39;");
10
+ }
11
+ function renderPage(title, subtitle, body) {
12
+ return `<!doctype html>
13
+ <html lang="en">
14
+ <head>
15
+ <meta charset="utf-8">
16
+ <meta name="viewport" content="width=device-width, initial-scale=1">
17
+ <title>${escapeHtml(title)} - Outline CLI</title>
18
+ <style>
19
+ :root {
20
+ --bg: #f5f7fb;
21
+ --surface: #ffffff;
22
+ --border: #e6e9f0;
23
+ --text: #1e2430;
24
+ --muted: #586178;
25
+ --ok: #15803d;
26
+ --ok-soft: #dcfce7;
27
+ --err: #b91c1c;
28
+ --err-soft: #fee2e2;
29
+ --radius: 14px;
30
+ }
31
+ * { box-sizing: border-box; }
32
+ body {
33
+ margin: 0;
34
+ min-height: 100vh;
35
+ display: grid;
36
+ place-items: center;
37
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
38
+ background: radial-gradient(1200px 500px at 50% -10%, #dbeafe 0%, var(--bg) 60%);
39
+ color: var(--text);
40
+ line-height: 1.5;
41
+ padding: 20px;
42
+ }
43
+ .card {
44
+ width: min(560px, 100%);
45
+ background: var(--surface);
46
+ border: 1px solid var(--border);
47
+ border-radius: var(--radius);
48
+ padding: 24px;
49
+ box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
50
+ }
51
+ h1 {
52
+ margin: 0 0 8px;
53
+ font-size: 24px;
54
+ letter-spacing: -0.01em;
55
+ }
56
+ .subtitle {
57
+ margin: 0 0 16px;
58
+ color: var(--muted);
59
+ font-size: 15px;
60
+ }
61
+ .message {
62
+ border-radius: 12px;
63
+ padding: 14px 16px;
64
+ font-size: 14px;
65
+ }
66
+ .success {
67
+ background: var(--ok-soft);
68
+ color: #14532d;
69
+ }
70
+ .error {
71
+ background: var(--err-soft);
72
+ color: #7f1d1d;
73
+ }
74
+ .hint {
75
+ margin-top: 14px;
76
+ color: var(--muted);
77
+ font-size: 13px;
78
+ }
79
+ code {
80
+ font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
81
+ background: #eef2ff;
82
+ border-radius: 6px;
83
+ padding: 2px 6px;
84
+ }
85
+ </style>
86
+ </head>
87
+ <body>
88
+ <main class="card">
89
+ <h1>${escapeHtml(title)}</h1>
90
+ <p class="subtitle">${escapeHtml(subtitle)}</p>
91
+ ${body}
92
+ <p class="hint">Return to your terminal and continue with <code>ol</code> commands.</p>
93
+ </main>
94
+ </body>
95
+ </html>`;
96
+ }
97
+ function renderSuccessPage() {
98
+ return renderPage("Login complete", "Outline CLI is now authenticated.", '<div class="message success">You can close this tab now.</div>');
99
+ }
100
+ function renderErrorPage(message) {
101
+ return renderPage("Authentication failed", "Outline CLI could not finish OAuth login.", `<div class="message error">${escapeHtml(message)}</div>`);
102
+ }
103
+ export async function startOAuthCallbackServer(options) {
104
+ const { state, timeoutMs = 3 * 60 * 1000, port = DEFAULT_OAUTH_CALLBACK_PORT, } = options;
105
+ let origin = "http://localhost";
106
+ let resolved = false;
107
+ let resolveCode;
108
+ let rejectCode;
109
+ const waitForCode = new Promise((resolve, reject) => {
110
+ resolveCode = resolve;
111
+ rejectCode = reject;
112
+ });
113
+ const server = http.createServer((req, res) => {
114
+ if (resolved) {
115
+ res.writeHead(409, { "Content-Type": "text/html; charset=utf-8" });
116
+ res.end(renderErrorPage("Authorization was already received."));
117
+ return;
118
+ }
119
+ if (req.method !== "GET" || !req.url) {
120
+ res.writeHead(405, { "Content-Type": "text/html; charset=utf-8" });
121
+ res.end(renderErrorPage("Invalid callback request method."));
122
+ return;
123
+ }
124
+ const url = new URL(req.url, origin);
125
+ if (url.pathname !== "/callback") {
126
+ res.writeHead(404, { "Content-Type": "text/html; charset=utf-8" });
127
+ res.end(renderErrorPage("Unknown callback path."));
128
+ return;
129
+ }
130
+ // Check for OAuth error response first
131
+ const error = url.searchParams.get("error");
132
+ if (error) {
133
+ const errorDescription = url.searchParams.get("error_description") || error;
134
+ res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
135
+ res.end(renderErrorPage(`Authorization failed: ${errorDescription}`));
136
+ rejectCode(new Error(`OAuth authorization denied: ${errorDescription}`));
137
+ resolved = true;
138
+ return;
139
+ }
140
+ const code = url.searchParams.get("code");
141
+ const returnedState = url.searchParams.get("state");
142
+ if (!code || !returnedState) {
143
+ res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
144
+ res.end(renderErrorPage("Missing OAuth code or state parameter."));
145
+ rejectCode(new Error("Missing OAuth authorization code."));
146
+ resolved = true;
147
+ return;
148
+ }
149
+ if (returnedState !== state) {
150
+ res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
151
+ res.end(renderErrorPage("Invalid OAuth state parameter."));
152
+ rejectCode(new Error("OAuth state mismatch."));
153
+ resolved = true;
154
+ return;
155
+ }
156
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
157
+ res.end(renderSuccessPage());
158
+ resolved = true;
159
+ resolveCode(code);
160
+ });
161
+ server.on("error", (err) => {
162
+ if (resolved)
163
+ return;
164
+ resolved = true;
165
+ rejectCode(err);
166
+ });
167
+ await new Promise((resolve, reject) => {
168
+ const onListening = () => {
169
+ server.off("error", onError);
170
+ resolve();
171
+ };
172
+ const onError = (err) => {
173
+ server.off("listening", onListening);
174
+ reject(err);
175
+ };
176
+ server.once("listening", onListening);
177
+ server.once("error", onError);
178
+ server.listen(port, "127.0.0.1");
179
+ });
180
+ const { port: listeningPort } = server.address();
181
+ origin = `http://localhost:${listeningPort}`;
182
+ const redirectUri = `${origin}/callback`;
183
+ const timeout = setTimeout(() => {
184
+ if (resolved)
185
+ return;
186
+ resolved = true;
187
+ rejectCode(new Error("Timed out waiting for OAuth callback."));
188
+ server.close();
189
+ }, timeoutMs);
190
+ const close = () => {
191
+ clearTimeout(timeout);
192
+ server.close();
193
+ };
194
+ waitForCode.then(() => {
195
+ clearTimeout(timeout);
196
+ server.close();
197
+ }, () => {
198
+ clearTimeout(timeout);
199
+ server.close();
200
+ });
201
+ return { port: listeningPort, redirectUri, waitForCode, close };
202
+ }
203
+ //# sourceMappingURL=oauth-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth-server.js","sourceRoot":"","sources":["../../src/lib/oauth-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ interface AuthorizationUrlOptions {
2
+ baseUrl: string;
3
+ clientId: string;
4
+ redirectUri: string;
5
+ codeChallenge: string;
6
+ state: string;
7
+ }
8
+ interface TokenExchangeOptions {
9
+ baseUrl: string;
10
+ clientId: string;
11
+ redirectUri: string;
12
+ codeVerifier: string;
13
+ code: string;
14
+ }
15
+ export declare function buildAuthorizationUrl(options: AuthorizationUrlOptions): string;
16
+ export declare function exchangeCodeForToken(options: TokenExchangeOptions): Promise<string>;
17
+ export {};
@@ -0,0 +1,38 @@
1
+ export function buildAuthorizationUrl(options) {
2
+ const { baseUrl, clientId, redirectUri, codeChallenge, state } = options;
3
+ const url = new URL(`${baseUrl}/oauth/authorize`);
4
+ url.searchParams.set("client_id", clientId);
5
+ url.searchParams.set("response_type", "code");
6
+ url.searchParams.set("code_challenge", codeChallenge);
7
+ url.searchParams.set("code_challenge_method", "S256");
8
+ url.searchParams.set("redirect_uri", redirectUri);
9
+ url.searchParams.set("state", state);
10
+ return url.toString();
11
+ }
12
+ export async function exchangeCodeForToken(options) {
13
+ const { baseUrl, clientId, redirectUri, codeVerifier, code } = options;
14
+ const params = new URLSearchParams({
15
+ grant_type: "authorization_code",
16
+ client_id: clientId,
17
+ redirect_uri: redirectUri,
18
+ code_verifier: codeVerifier,
19
+ code,
20
+ });
21
+ const res = await fetch(`${baseUrl}/oauth/token`, {
22
+ method: "POST",
23
+ headers: {
24
+ "Content-Type": "application/x-www-form-urlencoded",
25
+ },
26
+ body: params.toString(),
27
+ });
28
+ const json = (await res.json());
29
+ if (!res.ok) {
30
+ const message = json.error_description || json.message || json.error || res.statusText;
31
+ throw new Error(`OAuth token exchange failed: ${message}`);
32
+ }
33
+ if (!json.access_token) {
34
+ throw new Error("OAuth token exchange did not return an access token.");
35
+ }
36
+ return json.access_token;
37
+ }
38
+ //# sourceMappingURL=oauth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/lib/oauth.ts"],"names":[],"mappings":"AAuBA,MAAM,UAAU,qBAAqB,CACpC,OAAgC;IAEhC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;IACzE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,OAAO,kBAAkB,CAAC,CAAC;IAClD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IAC5C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IAC9C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC;IACtD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAAC;IACtD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;IAClD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACvB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACzC,OAA6B;IAE7B,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IACvE,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;QAClC,UAAU,EAAE,oBAAoB;QAChC,SAAS,EAAE,QAAQ;QACnB,YAAY,EAAE,WAAW;QACzB,aAAa,EAAE,YAAY;QAC3B,IAAI;KACJ,CAAC,CAAC;IAEH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,cAAc,EAAE;QACjD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACR,cAAc,EAAE,mCAAmC;SACnD;QACD,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE;KACvB,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAkB,CAAC;IACjD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACb,MAAM,OAAO,GACZ,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,IAAI,GAAG,CAAC,UAAU,CAAC;QACxE,MAAM,IAAI,KAAK,CAAC,gCAAgC,OAAO,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IACzE,CAAC;IAED,OAAO,IAAI,CAAC,YAAY,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Pagination } from "./api.js";
2
+ interface OutputOptions {
3
+ json?: boolean;
4
+ ndjson?: boolean;
5
+ full?: boolean;
6
+ }
7
+ export declare function getOutputOptions(opts: Record<string, unknown>): OutputOptions;
8
+ export declare function outputItem<T extends object>(item: T, humanFormatter: (item: T) => string, essentialKeys?: (keyof T)[], opts?: OutputOptions): void;
9
+ export declare function outputList<T extends object>(items: T[], humanFormatter: (item: T) => string, essentialKeys?: (keyof T)[], opts?: OutputOptions, pagination?: Pagination): void;
10
+ export declare function formatError(code: string, message: string, hints?: string[]): string;
11
+ export {};
@@ -0,0 +1,60 @@
1
+ import chalk from "chalk";
2
+ export function getOutputOptions(opts) {
3
+ return {
4
+ json: Boolean(opts.json),
5
+ ndjson: Boolean(opts.ndjson),
6
+ full: Boolean(opts.full),
7
+ };
8
+ }
9
+ export function outputItem(item, humanFormatter, essentialKeys, opts = {}) {
10
+ if (opts.ndjson) {
11
+ const data = opts.full || !essentialKeys ? item : pick(item, essentialKeys);
12
+ console.log(JSON.stringify(data));
13
+ return;
14
+ }
15
+ if (opts.json) {
16
+ const data = opts.full || !essentialKeys ? item : pick(item, essentialKeys);
17
+ console.log(JSON.stringify(data, null, 2));
18
+ return;
19
+ }
20
+ console.log(humanFormatter(item));
21
+ }
22
+ export function outputList(items, humanFormatter, essentialKeys, opts = {}, pagination) {
23
+ if (opts.ndjson) {
24
+ for (const item of items) {
25
+ const data = opts.full || !essentialKeys ? item : pick(item, essentialKeys);
26
+ console.log(JSON.stringify(data));
27
+ }
28
+ }
29
+ else if (opts.json) {
30
+ const data = items.map((item) => opts.full || !essentialKeys ? item : pick(item, essentialKeys));
31
+ console.log(JSON.stringify(data, null, 2));
32
+ }
33
+ else {
34
+ for (const item of items) {
35
+ console.log(humanFormatter(item));
36
+ }
37
+ }
38
+ if (pagination?.nextPath && !opts.ndjson) {
39
+ console.log(chalk.dim(`\n(more results available — use --offset ${pagination.offset + pagination.limit})`));
40
+ }
41
+ }
42
+ function pick(obj, keys) {
43
+ const result = {};
44
+ for (const key of keys) {
45
+ if (key in obj)
46
+ result[key] = obj[key];
47
+ }
48
+ return result;
49
+ }
50
+ export function formatError(code, message, hints) {
51
+ const lines = [`Error: ${code}`, message];
52
+ if (hints && hints.length > 0) {
53
+ lines.push("");
54
+ for (const hint of hints) {
55
+ lines.push(` - ${hint}`);
56
+ }
57
+ }
58
+ return chalk.red(lines.join("\n"));
59
+ }
60
+ //# 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,3 @@
1
+ export declare function generateCodeVerifier(): string;
2
+ export declare function generateCodeChallenge(codeVerifier: string): string;
3
+ export declare function generateState(): string;
@@ -0,0 +1,20 @@
1
+ import { createHash, randomBytes } from "node:crypto";
2
+ function base64UrlEncode(buffer) {
3
+ return buffer
4
+ .toString("base64")
5
+ .replace(/\+/g, "-")
6
+ .replace(/\//g, "_")
7
+ .replace(/=+$/, "");
8
+ }
9
+ export function generateCodeVerifier() {
10
+ // 64 bytes => 86 chars, within 43-128 requirement.
11
+ return base64UrlEncode(randomBytes(64));
12
+ }
13
+ export function generateCodeChallenge(codeVerifier) {
14
+ const hash = createHash("sha256").update(codeVerifier).digest();
15
+ return base64UrlEncode(hash);
16
+ }
17
+ export function generateState() {
18
+ return base64UrlEncode(randomBytes(32));
19
+ }
20
+ //# sourceMappingURL=pkce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.js","sourceRoot":"","sources":["../../src/lib/pkce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEtD,SAAS,eAAe,CAAC,MAAc;IACtC,OAAO,MAAM;SACX,QAAQ,CAAC,QAAQ,CAAC;SAClB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,oBAAoB;IACnC,mDAAmD;IACnD,OAAO,eAAe,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,YAAoB;IACzD,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,EAAE,CAAC;IAChE,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,aAAa;IAC5B,OAAO,eAAe,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;AACzC,CAAC"}
@@ -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,180 @@
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
+ * Preserves full UUIDs and raw IDs
26
+ */
27
+ function extractDocumentIdFromSlug(input) {
28
+ // Preserve UUIDs as-is
29
+ if (isUuid(input)) {
30
+ return input;
31
+ }
32
+ // If it looks like a URL, extract the slug suffix
33
+ const parts = input.replace(/\/$/, "").split("/");
34
+ const last = parts[parts.length - 1];
35
+ // Outline URL IDs are the part after the last hyphen in the slug
36
+ // Only extract if it's a slug with hyphen, not just a raw ID
37
+ const match = last.match(/-([a-zA-Z0-9]+)$/);
38
+ if (match)
39
+ return match[1];
40
+ return input;
41
+ }
42
+ /**
43
+ * Format suggestions for error messages
44
+ */
45
+ function formatSuggestions(items, getName, getDisplayId, max = 5) {
46
+ const suggestions = items.slice(0, max);
47
+ return suggestions
48
+ .map((item) => ` - "${getName(item)}" (${getDisplayId(item)})`)
49
+ .join("\n");
50
+ }
51
+ /**
52
+ * Generic fuzzy reference resolver
53
+ */
54
+ async function resolveRef(options) {
55
+ const { ref, fetchById, fetchAllPaginated, getName, getDisplayId, entityType, extractSlugId, } = options;
56
+ // Try direct ID lookup first if it looks like an ID
57
+ // Only extract slug ID for documents, not collections
58
+ const extractedId = extractSlugId ? extractDocumentIdFromSlug(ref) : ref;
59
+ if (looksLikeId(extractedId)) {
60
+ try {
61
+ return await fetchById(extractedId);
62
+ }
63
+ catch {
64
+ // If direct ID lookup fails, fall through to name matching
65
+ }
66
+ }
67
+ // Fetch all items with pagination and search by name
68
+ const items = await fetchAllPaginated();
69
+ const refLower = ref.toLowerCase();
70
+ // Try exact match first (case-insensitive)
71
+ const exactMatches = items.filter((item) => getName(item).toLowerCase() === refLower);
72
+ if (exactMatches.length === 1) {
73
+ return exactMatches[0];
74
+ }
75
+ // Multiple exact matches are ambiguous
76
+ if (exactMatches.length > 1) {
77
+ const suggestions = formatSuggestions(exactMatches, getName, getDisplayId);
78
+ throw new Error(`Ambiguous ${entityType} reference "${ref}". Multiple items have this exact name:\n${suggestions}`);
79
+ }
80
+ // Try partial match
81
+ const partialMatches = items.filter((item) => getName(item).toLowerCase().includes(refLower));
82
+ if (partialMatches.length === 1) {
83
+ return partialMatches[0];
84
+ }
85
+ if (partialMatches.length > 1) {
86
+ const suggestions = formatSuggestions(partialMatches, getName, getDisplayId);
87
+ throw new Error(`Ambiguous ${entityType} reference "${ref}". Did you mean:\n${suggestions}`);
88
+ }
89
+ // No matches found
90
+ throw new Error(`${entityType} not found: "${ref}"`);
91
+ }
92
+ /**
93
+ * Fetch all documents with pagination
94
+ */
95
+ async function fetchAllDocuments() {
96
+ const allDocs = [];
97
+ const limit = 100;
98
+ let offset = 0;
99
+ while (true) {
100
+ const { data } = await apiRequest("documents.list", {
101
+ limit,
102
+ offset,
103
+ });
104
+ allDocs.push(...data);
105
+ if (data.length < limit) {
106
+ break;
107
+ }
108
+ offset += limit;
109
+ }
110
+ return allDocs;
111
+ }
112
+ /**
113
+ * Fetch all collections with pagination
114
+ */
115
+ async function fetchAllCollections() {
116
+ const allCollections = [];
117
+ const limit = 100;
118
+ let offset = 0;
119
+ while (true) {
120
+ const { data } = await apiRequest("collections.list", {
121
+ limit,
122
+ offset,
123
+ });
124
+ allCollections.push(...data);
125
+ if (data.length < limit) {
126
+ break;
127
+ }
128
+ offset += limit;
129
+ }
130
+ return allCollections;
131
+ }
132
+ /**
133
+ * Resolve a document reference by ID, URL, or name
134
+ */
135
+ export async function resolveDocumentRef(ref) {
136
+ return resolveRef({
137
+ ref,
138
+ fetchById: async (id) => {
139
+ const { data } = await apiRequest("documents.info", { id });
140
+ return data;
141
+ },
142
+ fetchAllPaginated: fetchAllDocuments,
143
+ getName: (doc) => doc.title,
144
+ getDisplayId: (doc) => doc.urlId,
145
+ entityType: "Document",
146
+ extractSlugId: true,
147
+ });
148
+ }
149
+ /**
150
+ * Resolve a document reference and return just the ID
151
+ */
152
+ export async function resolveDocumentId(ref) {
153
+ const doc = await resolveDocumentRef(ref);
154
+ return doc.id;
155
+ }
156
+ /**
157
+ * Resolve a collection reference by ID or name
158
+ */
159
+ export async function resolveCollectionRef(ref) {
160
+ return resolveRef({
161
+ ref,
162
+ fetchById: async (id) => {
163
+ const { data } = await apiRequest("collections.info", { id });
164
+ return data;
165
+ },
166
+ fetchAllPaginated: fetchAllCollections,
167
+ getName: (col) => col.name,
168
+ getDisplayId: (col) => col.id,
169
+ entityType: "Collection",
170
+ extractSlugId: false,
171
+ });
172
+ }
173
+ /**
174
+ * Resolve a collection reference and return just the ID
175
+ */
176
+ export async function resolveCollectionId(ref) {
177
+ const col = await resolveCollectionRef(ref);
178
+ return col.id;
179
+ }
180
+ //# 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";
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\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## 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\" --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\" --collection <id> --file ./doc.md\nol doc update <id> --title \"New Title\"\nol doc update <id> --file ./updated.md\nol doc move <id> --collection <target-id>\nol doc archive <id>\nol doc unarchive <id>\nol doc delete <id> --confirm\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 # Configure API token and base URL\nol auth status # Show current auth state\nol auth logout # Clear saved credentials\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### 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";