@theplato/tiro-cli 0.5.0 → 0.6.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 (3) hide show
  1. package/README.md +41 -4
  2. package/dist/bin/tiro.js +128 -2459
  3. package/package.json +1 -1
package/dist/bin/tiro.js CHANGED
@@ -1,288 +1,14 @@
1
1
  #!/usr/bin/env node
2
-
3
- // src/bin/tiro.ts
4
- import { Command as Command19 } from "commander";
5
-
6
- // src/lib/version.ts
7
- import { readFileSync } from "fs";
8
- import { fileURLToPath } from "url";
9
- import { dirname, resolve } from "path";
10
- var HERE = dirname(fileURLToPath(import.meta.url));
11
- var CANDIDATE_PATHS = [
12
- resolve(HERE, "../../package.json"),
13
- resolve(HERE, "../../../package.json")
14
- ];
15
- function readVersion() {
16
- for (const path of CANDIDATE_PATHS) {
17
- try {
18
- const raw = readFileSync(path, "utf8");
19
- const parsed = JSON.parse(raw);
20
- if (typeof parsed.version === "string" && parsed.version.length > 0) {
21
- return parsed.version;
22
- }
23
- } catch {
24
- }
25
- }
26
- return "0.0.0-unknown";
27
- }
28
- var VERSION = readVersion();
29
-
30
- // src/lib/error.ts
31
- var ExitCode = {
32
- Ok: 0,
33
- Generic: 1,
34
- Usage: 2,
35
- AuthRequired: 4,
36
- ExUsage: 64,
37
- ExDataErr: 65,
38
- ExConfig: 78
39
- };
40
- var TiroError = class extends Error {
41
- code;
42
- suggestion;
43
- errorType;
44
- httpStatus;
45
- requestId;
46
- details;
47
- exitCode;
48
- constructor(payload, exitCode = ExitCode.Generic) {
49
- super(payload.message);
50
- this.name = "TiroError";
51
- this.code = payload.code;
52
- this.suggestion = payload.suggestion;
53
- this.errorType = payload.errorType;
54
- this.httpStatus = payload.httpStatus;
55
- this.requestId = payload.requestId;
56
- this.details = payload.details;
57
- this.exitCode = exitCode;
58
- }
59
- toJSON() {
60
- return {
61
- ok: false,
62
- error: {
63
- code: this.code,
64
- message: this.message,
65
- ...this.suggestion !== void 0 && { suggestion: this.suggestion },
66
- ...this.errorType !== void 0 && { errorType: this.errorType },
67
- ...this.httpStatus !== void 0 && { httpStatus: this.httpStatus },
68
- ...this.requestId !== void 0 && { requestId: this.requestId },
69
- ...this.details !== void 0 && { details: this.details }
70
- }
71
- };
72
- }
73
- };
74
- function authRequired() {
75
- return new TiroError(
76
- {
77
- code: "auth_required",
78
- message: "Not authenticated. Run `tiro auth login` to sign in, or set TIRO_TOKEN env var.",
79
- suggestion: "tiro auth login",
80
- errorType: "auth_required"
81
- },
82
- ExitCode.AuthRequired
83
- );
84
- }
85
-
86
- // src/lib/output/tty.ts
87
- function resolveOutputMode(opts) {
88
- if (opts.json) return "json";
89
- if (opts.pretty) return "pretty";
90
- return process.stdout.isTTY ? "pretty" : "json";
91
- }
92
- function colorEnabled(opts) {
93
- if (opts.noColor) return false;
94
- if (process.env["NO_COLOR"]) return false;
95
- if (process.env["FORCE_COLOR"]) return true;
96
- return process.stdout.isTTY === true;
97
- }
98
- var ANSI = {
99
- reset: "\x1B[0m",
100
- bold: "\x1B[1m",
101
- dim: "\x1B[2m",
102
- red: "\x1B[31m",
103
- green: "\x1B[32m",
104
- yellow: "\x1B[33m",
105
- blue: "\x1B[34m",
106
- magenta: "\x1B[35m",
107
- cyan: "\x1B[36m",
108
- gray: "\x1B[90m"
109
- };
110
- function color(text, style, opts = {}) {
111
- if (!colorEnabled(opts)) return text;
112
- return `${ANSI[style]}${text}${ANSI.reset}`;
113
- }
114
-
115
- // src/lib/output/print.ts
116
- function printOutput(value, opts = {}) {
117
- if (opts.quiet) return;
118
- const mode = resolveOutputMode(opts);
119
- if (mode === "json") {
120
- process.stdout.write(`${JSON.stringify(value)}
121
- `);
122
- } else {
123
- process.stdout.write(`${JSON.stringify(value, null, 2)}
124
- `);
125
- }
126
- }
127
- function printError(value) {
128
- process.stderr.write(`${JSON.stringify(value)}
129
- `);
130
- }
131
- function printNdjson(item) {
132
- process.stdout.write(`${JSON.stringify(item)}
133
- `);
134
- }
135
-
136
- // src/commands/auth/index.ts
137
- import "commander";
138
-
139
- // src/commands/auth/login.ts
140
- import "commander";
141
-
142
- // src/lib/auth/flow.ts
143
- import { z } from "zod";
144
-
145
- // src/lib/auth/pkce.ts
146
- import { createHash, randomBytes, timingSafeEqual } from "crypto";
147
- function generatePkce() {
148
- const codeVerifier = base64url(randomBytes(32));
149
- const codeChallenge = base64url(createHash("sha256").update(codeVerifier).digest());
150
- return { codeVerifier, codeChallenge, method: "S256" };
151
- }
152
- function generateState() {
153
- return base64url(randomBytes(24));
154
- }
155
- function verifyState(received, expected) {
156
- const a = Buffer.from(received, "utf8");
157
- const b = Buffer.from(expected, "utf8");
158
- if (a.length !== b.length) return false;
159
- return timingSafeEqual(a, b);
160
- }
161
- function base64url(buf) {
162
- return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
163
- }
164
-
165
- // src/lib/auth/loopback.ts
166
- import http from "http";
167
-
168
- // src/lib/auth/assets.generated.ts
169
- var TIRO_LOGO_BROWN_DATA_URI = "data:image/png;base64,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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACA/78dOBAAAAAAELQ/9SIFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAP3ZeKxkxamrQAAAABJRU5ErkJggg==";
170
-
171
- // src/lib/auth/loopback.ts
172
- async function startLoopbackServer() {
173
- let pendingResolve = null;
174
- let pendingReject = null;
175
- const settle = (fn, arg) => {
176
- pendingResolve = null;
177
- pendingReject = null;
178
- fn(arg);
179
- };
180
- let consumed = false;
181
- const server = http.createServer((req, res) => {
182
- res.setHeader("Connection", "close");
183
- res.setHeader("Cache-Control", "no-store");
184
- if (!req.url) {
185
- res.writeHead(400).end();
186
- return;
187
- }
188
- if (req.method !== "GET") {
189
- res.writeHead(405, { "Content-Type": "text/plain", Allow: "GET" }).end("Method not allowed");
190
- return;
191
- }
192
- const url = new URL(req.url, `http://127.0.0.1`);
193
- if (url.pathname !== "/callback") {
194
- res.writeHead(404, { "Content-Type": "text/plain" }).end("Not found");
195
- return;
196
- }
197
- if (consumed) {
198
- res.writeHead(410, { "Content-Type": "text/plain" }).end("Callback already consumed");
199
- return;
200
- }
201
- const code = url.searchParams.get("code");
202
- const state = url.searchParams.get("state");
203
- const error = url.searchParams.get("error");
204
- const errorDesc = url.searchParams.get("error_description") ?? "";
205
- if (error) {
206
- consumed = true;
207
- const detail = errorDesc ? ` \u2014 ${errorDesc}` : "";
208
- respondError(res, 500, `OAuth error: ${error}${detail}`);
209
- if (pendingReject) settle(pendingReject, new Error(`OAuth error: ${error}${detail}`));
210
- return;
211
- }
212
- if (!code || !state) {
213
- respondError(res, 400, "Missing `code` or `state` in callback URL.");
214
- if (pendingReject) settle(pendingReject, new Error("Missing code or state"));
215
- return;
216
- }
217
- consumed = true;
218
- respondSuccess(res);
219
- if (pendingResolve) settle(pendingResolve, { code, state });
220
- });
221
- await new Promise((resolve4) => {
222
- server.listen(0, "127.0.0.1", () => resolve4());
223
- });
224
- const address = server.address();
225
- const port = address.port;
226
- const redirectUri = `http://127.0.0.1:${port}/callback`;
227
- return {
228
- redirectUri,
229
- port,
230
- waitForCallback(timeoutMs) {
231
- return new Promise((resolve4, reject) => {
232
- const timer = setTimeout(() => {
233
- pendingResolve = null;
234
- pendingReject = null;
235
- reject(new Error(`Timed out waiting for OAuth callback (${timeoutMs}ms)`));
236
- }, timeoutMs);
237
- pendingResolve = (r) => {
238
- clearTimeout(timer);
239
- resolve4(r);
240
- };
241
- pendingReject = (e) => {
242
- clearTimeout(timer);
243
- reject(e);
244
- };
245
- });
246
- },
247
- close() {
248
- server.close();
249
- }
250
- };
251
- }
252
- function escapeHtml(s) {
253
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
254
- }
255
- function respondSuccess(res) {
256
- const html = renderPage({
257
- kind: "success",
258
- title: "You're signed in",
259
- body: "You can close this tab and return to your terminal."
260
- });
261
- res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
262
- res.end(html);
263
- }
264
- function respondError(res, status, body) {
265
- const html = renderPage({
266
- kind: "error",
267
- title: "Login failed",
268
- body
269
- });
270
- res.writeHead(status, { "Content-Type": "text/html; charset=utf-8" });
271
- res.end(html);
272
- }
273
- function renderPage(p) {
274
- const safeTitle = escapeHtml(p.title);
275
- const safeBody = escapeHtml(p.body);
276
- const titleColor = p.kind === "error" ? "var(--error)" : "var(--brown-800)";
277
- const logoOpacity = p.kind === "error" ? "0.4" : "1";
278
- const closeScript = p.kind === "success" ? `<script>setTimeout(function(){try{window.close();}catch(e){}}, 2000);</script>` : "";
279
- const hint = p.kind === "success" ? `<p class="hint">Closing this tab automatically&hellip;</p>` : "";
280
- return `<!doctype html>
2
+ import{Command as Kr}from"commander";import{readFileSync as MA}from"fs";import{fileURLToPath as NA}from"url";import{dirname as GA,resolve as me}from"path";var ge=GA(NA(import.meta.url)),VA=[me(ge,"../../package.json"),me(ge,"../../../package.json")];function UA(){for(let e of VA)try{let A=MA(e,"utf8"),t=JSON.parse(A);if(typeof t.version=="string"&&t.version.length>0)return t.version}catch{}return"0.0.0-unknown"}var fe=UA();var u={Ok:0,Generic:1,Usage:2,AuthRequired:4,ExUsage:64,ExDataErr:65,ExConfig:78},f=class extends Error{code;suggestion;errorType;httpStatus;requestId;details;exitCode;constructor(A,t=u.Generic){super(A.message),this.name="TiroError",this.code=A.code,this.suggestion=A.suggestion,this.errorType=A.errorType,this.httpStatus=A.httpStatus,this.requestId=A.requestId,this.details=A.details,this.exitCode=t}toJSON(){return{ok:!1,error:{code:this.code,message:this.message,...this.suggestion!==void 0&&{suggestion:this.suggestion},...this.errorType!==void 0&&{errorType:this.errorType},...this.httpStatus!==void 0&&{httpStatus:this.httpStatus},...this.requestId!==void 0&&{requestId:this.requestId},...this.details!==void 0&&{details:this.details}}}}};function W(){return new f({code:"auth_required",message:"Not authenticated. Run `tiro auth login` to sign in, or set TIRO_TOKEN env var.",suggestion:"tiro auth login",errorType:"auth_required"},u.AuthRequired)}function y(e){return e.json?"json":e.pretty||process.stdout.isTTY?"pretty":"json"}function jA(e){return e.noColor||process.env.NO_COLOR?!1:process.env.FORCE_COLOR?!0:process.stdout.isTTY===!0}var he={reset:"\x1B[0m",bold:"\x1B[1m",dim:"\x1B[2m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",magenta:"\x1B[35m",cyan:"\x1B[36m",gray:"\x1B[90m"};function a(e,A,t={}){return jA(t)?`${he[A]}${e}${he.reset}`:e}function v(e,A={}){if(A.quiet)return;y(A)==="json"?process.stdout.write(`${JSON.stringify(e)}
3
+ `):process.stdout.write(`${JSON.stringify(e,null,2)}
4
+ `)}function te(e){process.stderr.write(`${JSON.stringify(e)}
5
+ `)}function C(e){process.stdout.write(`${JSON.stringify(e)}
6
+ `)}import"commander";import"commander";import{z as B}from"zod";import{createHash as QA,randomBytes as we,timingSafeEqual as zA}from"crypto";function be(){let e=re(we(32)),A=re(QA("sha256").update(e).digest());return{codeVerifier:e,codeChallenge:A,method:"S256"}}function ye(){return re(we(24))}function ke(e,A){let t=Buffer.from(e,"utf8"),r=Buffer.from(A,"utf8");return t.length!==r.length?!1:zA(t,r)}function re(e){return e.toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}import YA from"http";var Ce="data:image/png;base64,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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACA/78dOBAAAAAAELQ/9SIFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAP3ZeKxkxamrQAAAABJRU5ErkJggg==";async function xe(){let e=null,A=null,t=(d,p)=>{e=null,A=null,d(p)},r=!1,n=YA.createServer((d,p)=>{if(p.setHeader("Connection","close"),p.setHeader("Cache-Control","no-store"),!d.url){p.writeHead(400).end();return}if(d.method!=="GET"){p.writeHead(405,{"Content-Type":"text/plain",Allow:"GET"}).end("Method not allowed");return}let l=new URL(d.url,"http://127.0.0.1");if(l.pathname!=="/callback"){p.writeHead(404,{"Content-Type":"text/plain"}).end("Not found");return}if(r){p.writeHead(410,{"Content-Type":"text/plain"}).end("Callback already consumed");return}let w=l.searchParams.get("code"),b=l.searchParams.get("state"),h=l.searchParams.get("error"),T=l.searchParams.get("error_description")??"";if(h){r=!0;let H=T?` \u2014 ${T}`:"";Te(p,500,`OAuth error: ${h}${H}`),A&&t(A,new Error(`OAuth error: ${h}${H}`));return}if(!w||!b){Te(p,400,"Missing `code` or `state` in callback URL."),A&&t(A,new Error("Missing code or state"));return}r=!0,KA(p),e&&t(e,{code:w,state:b})});await new Promise(d=>{n.listen(0,"127.0.0.1",()=>d())});let s=n.address().port;return{redirectUri:`http://127.0.0.1:${s}/callback`,port:s,waitForCallback(d){return new Promise((p,l)=>{let w=setTimeout(()=>{e=null,A=null,l(new Error(`Timed out waiting for OAuth callback (${d}ms)`))},d);e=b=>{clearTimeout(w),p(b)},A=b=>{clearTimeout(w),l(b)}})},close(){n.close()}}}function ve(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function KA(e){let A=Be({kind:"success",title:"You're signed in",body:"You can close this tab and return to your terminal."});e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(A)}function Te(e,A,t){let r=Be({kind:"error",title:"Login failed",body:t});e.writeHead(A,{"Content-Type":"text/html; charset=utf-8"}),e.end(r)}function Be(e){let A=ve(e.title),t=ve(e.body),r=e.kind==="error"?"var(--error)":"var(--brown-800)",n=e.kind==="error"?"0.4":"1",i=e.kind==="success"?"<script>setTimeout(function(){try{window.close();}catch(e){}}, 2000);</script>":"",s=e.kind==="success"?'<p class="hint">Closing this tab automatically&hellip;</p>':"";return`<!doctype html>
281
7
  <html lang="en">
282
8
  <head>
283
9
  <meta charset="utf-8">
284
10
  <meta name="viewport" content="width=device-width, initial-scale=1">
285
- <title>Tiro \u2014 ${safeTitle}</title>
11
+ <title>Tiro \u2014 ${A}</title>
286
12
  <link rel="preconnect" href="https://fonts.googleapis.com">
287
13
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
288
14
  <link href="https://fonts.googleapis.com/css2?family=Averia+Serif+Libre:wght@300;400;700&display=swap" rel="stylesheet">
@@ -322,14 +48,14 @@ function renderPage(p) {
322
48
  height: auto;
323
49
  margin-bottom: 1.5rem;
324
50
  object-fit: contain;
325
- opacity: ${logoOpacity};
51
+ opacity: ${n};
326
52
  }
327
53
  h1 {
328
54
  font-family: 'Averia Serif Libre', Georgia, 'Times New Roman', serif;
329
55
  font-size: 36px;
330
56
  line-height: 42px;
331
57
  font-weight: 400;
332
- color: ${titleColor};
58
+ color: ${r};
333
59
  }
334
60
  .body {
335
61
  margin-top: 1.5rem;
@@ -358,999 +84,35 @@ function renderPage(p) {
358
84
  <body>
359
85
  <div class="top-spacer"></div>
360
86
  <main>
361
- <img class="logo" src="${TIRO_LOGO_BROWN_DATA_URI}" alt="Tiro">
362
- <h1>${safeTitle}</h1>
363
- <p class="body">${safeBody}</p>
364
- ${hint}
87
+ <img class="logo" src="${Ce}" alt="Tiro">
88
+ <h1>${A}</h1>
89
+ <p class="body">${t}</p>
90
+ ${s}
365
91
  </main>
366
92
  <footer>&copy; 2026 <a href="https://tiro.ooo">The Plato Inc.</a> &mdash; All rights reserved.</footer>
367
- ${closeScript}
93
+ ${i}
368
94
  </body>
369
- </html>`;
370
- }
371
-
372
- // src/lib/auth/browser.ts
373
- import open from "open";
374
- async function openBrowser(url) {
375
- try {
376
- await open(url, { wait: false });
377
- } catch {
378
- }
379
- }
380
-
381
- // src/lib/auth/keychain.ts
382
- import { Entry } from "@napi-rs/keyring";
383
- var SERVICE = "io.tiro.cli";
384
- var ACCOUNT = "default";
385
- function saveToken(token) {
386
- const entry = new Entry(SERVICE, ACCOUNT);
387
- try {
388
- entry.setPassword(JSON.stringify(token));
389
- } catch (err) {
390
- throw new TiroError(
391
- {
392
- code: "keychain_write_failed",
393
- message: `Failed to write to OS keychain: ${err.message}`,
394
- errorType: "internal_error",
395
- suggestion: process.platform === "linux" ? "Linux requires a Secret Service daemon (gnome-keyring or kwallet). Or set TIRO_TOKEN env var." : "Check OS keychain permissions, or set TIRO_TOKEN env var."
396
- },
397
- ExitCode.Generic
398
- );
399
- }
400
- }
401
- function loadToken() {
402
- const entry = new Entry(SERVICE, ACCOUNT);
403
- let raw;
404
- try {
405
- raw = entry.getPassword();
406
- } catch {
407
- return null;
408
- }
409
- if (!raw) return null;
410
- try {
411
- return JSON.parse(raw);
412
- } catch {
413
- return null;
414
- }
415
- }
416
- function deleteToken() {
417
- const entry = new Entry(SERVICE, ACCOUNT);
418
- try {
419
- return entry.deletePassword();
420
- } catch {
421
- return false;
422
- }
423
- }
424
-
425
- // src/lib/auth/token.ts
426
- function resolveToken() {
427
- const envToken = process.env["TIRO_TOKEN"];
428
- if (envToken) {
429
- return { accessToken: envToken, source: "env" };
430
- }
431
- const stored = loadToken();
432
- if (stored) {
433
- return {
434
- accessToken: stored.accessToken,
435
- source: "keychain",
436
- hostname: stored.hostname,
437
- expiresAt: stored.expiresAt,
438
- ...stored.userId !== void 0 && { userId: stored.userId }
439
- };
440
- }
441
- return null;
442
- }
443
- function decodeJwtPayload(token) {
444
- const parts = token.split(".");
445
- if (parts.length !== 3) return null;
446
- try {
447
- const payload = parts[1];
448
- if (!payload) return null;
449
- const json = Buffer.from(payload, "base64url").toString("utf8");
450
- return JSON.parse(json);
451
- } catch {
452
- return null;
453
- }
454
- }
455
-
456
- // src/lib/config.ts
457
- import Conf from "conf";
458
- var DEFAULT_HOSTNAME = "https://api.tiro.ooo";
459
- var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]", "::1"]);
460
- var config = new Conf({
461
- projectName: "tiro",
462
- defaults: {
463
- hostname: DEFAULT_HOSTNAME,
464
- oauthClientId: null,
465
- oauthClientIdRegisteredAt: null,
466
- oauthClientHostname: null,
467
- oauthClientRedirectUri: null,
468
- defaultOutputDir: null
469
- }
470
- });
471
- function validateHostname(input) {
472
- const trimmed = input.trim();
473
- if (trimmed === "") {
474
- throw hostnameError("empty hostname", input);
475
- }
476
- let url;
477
- try {
478
- url = new URL(trimmed);
479
- } catch {
480
- throw hostnameError("not a valid URL", input);
481
- }
482
- if (url.protocol === "https:") {
483
- } else if (url.protocol === "http:" && isLoopback(url.hostname)) {
484
- } else {
485
- throw hostnameError(
486
- `disallowed scheme "${url.protocol}" \u2014 only https:// or http://localhost is permitted`,
487
- input
488
- );
489
- }
490
- if (url.username !== "" || url.password !== "") {
491
- throw hostnameError("URL must not embed credentials", input);
492
- }
493
- if (url.search !== "" || url.hash !== "") {
494
- throw hostnameError("URL must not include query or fragment", input);
495
- }
496
- if (url.pathname !== "" && url.pathname !== "/") {
497
- throw hostnameError("URL must be host root (no path segment)", input);
498
- }
499
- const origin = url.origin;
500
- return stripTrailingSlash(origin);
501
- }
502
- function isLoopback(host) {
503
- if (host.startsWith("[") && host.endsWith("]")) {
504
- host = host.slice(1, -1);
505
- }
506
- return LOOPBACK_HOSTS.has(host);
507
- }
508
- function hostnameError(reason, input) {
509
- return new TiroError(
510
- {
511
- code: "invalid_hostname",
512
- message: `Refusing to use hostname "${input}": ${reason}.`,
513
- errorType: "bad_request",
514
- suggestion: "Use https://<host> (or http://localhost for local dev). If TIRO_HOSTNAME is set in your environment, unset it."
515
- },
516
- ExitCode.Usage
517
- );
518
- }
519
- function getHostname(override) {
520
- if (override !== void 0) return validateHostname(override);
521
- const env = process.env["TIRO_HOSTNAME"];
522
- if (env) return validateHostname(env);
523
- return validateHostname(config.get("hostname"));
524
- }
525
- function getOauthClientId(hostname, currentRedirectUri) {
526
- const id = config.get("oauthClientId");
527
- const registeredAt = config.get("oauthClientIdRegisteredAt");
528
- const cachedHostname = config.get("oauthClientHostname");
529
- const cachedRedirectUri = config.get("oauthClientRedirectUri");
530
- if (!id || !registeredAt) return null;
531
- if (cachedHostname !== hostname) return null;
532
- if (!cachedRedirectUri) return null;
533
- if (!sameRedirectTarget(cachedRedirectUri, currentRedirectUri)) return null;
534
- const ttlMs = 29 * 24 * 60 * 60 * 1e3;
535
- if (Date.now() - registeredAt > ttlMs) return null;
536
- return id;
537
- }
538
- function setOauthClientId(clientId, hostname, redirectUri) {
539
- config.set("oauthClientId", clientId);
540
- config.set("oauthClientIdRegisteredAt", Date.now());
541
- config.set("oauthClientHostname", hostname);
542
- config.set("oauthClientRedirectUri", redirectUri);
543
- }
544
- function clearOauthClientId() {
545
- config.set("oauthClientId", null);
546
- config.set("oauthClientIdRegisteredAt", null);
547
- config.set("oauthClientHostname", null);
548
- config.set("oauthClientRedirectUri", null);
549
- }
550
- function sameRedirectTarget(a, b) {
551
- let pa, pb;
552
- try {
553
- pa = new URL(a);
554
- pb = new URL(b);
555
- } catch {
556
- return false;
557
- }
558
- return pa.protocol === pb.protocol && pa.hostname === pb.hostname && pa.pathname === pb.pathname;
559
- }
560
- function stripTrailingSlash(s) {
561
- return s.endsWith("/") ? s.slice(0, -1) : s;
562
- }
563
-
564
- // src/lib/auth/flow.ts
565
- var RegisterResponseSchema = z.object({
566
- client_id: z.string(),
567
- client_secret: z.string().optional()
568
- });
569
- var TokenResponseSchema = z.object({
570
- access_token: z.string(),
571
- token_type: z.string(),
572
- expires_in: z.number().optional(),
573
- scope: z.string().optional()
574
- });
575
- var CALLBACK_TIMEOUT_MS = 5 * 60 * 1e3;
576
- var DEFAULT_SCOPE = "mcp:notes:read";
577
- async function performLogin(options = {}) {
578
- const hostname = getHostname(options.hostname);
579
- const onPrompt = options.onPrompt ?? ((msg) => process.stderr.write(`${msg}
580
- `));
581
- const loopback = await startLoopbackServer();
582
- try {
583
- const clientId = await ensureOauthClient(hostname, loopback.redirectUri);
584
- const { codeVerifier, codeChallenge } = generatePkce();
585
- const state = generateState();
586
- const authorizeUrl = buildAuthorizeUrl({
587
- hostname,
588
- clientId,
589
- redirectUri: loopback.redirectUri,
590
- state,
591
- codeChallenge,
592
- scope: options.scope ?? DEFAULT_SCOPE
593
- });
594
- if (options.noBrowser) {
595
- onPrompt(`Open this URL in your browser:
596
- ${authorizeUrl}`);
597
- } else {
598
- onPrompt(`Opening browser for sign-in...`);
599
- onPrompt(`If the browser does not open, visit:
600
- ${authorizeUrl}`);
601
- await openBrowser(authorizeUrl);
602
- }
603
- const callback = await loopback.waitForCallback(CALLBACK_TIMEOUT_MS);
604
- if (!verifyState(callback.state, state)) {
605
- throw new TiroError(
606
- {
607
- code: "auth_state_mismatch",
608
- message: "OAuth state mismatch \u2014 possible CSRF. Aborting.",
609
- errorType: "unauthorized"
610
- },
611
- ExitCode.Generic
612
- );
613
- }
614
- const tokenRes = await exchangeToken({
615
- hostname,
616
- clientId,
617
- code: callback.code,
618
- redirectUri: loopback.redirectUri,
619
- codeVerifier
620
- });
621
- const expiresAt = computeExpiry(tokenRes.expires_in);
622
- const payload = decodeJwtPayload(tokenRes.access_token);
623
- const userId = typeof payload?.["sub"] === "string" ? payload["sub"] : void 0;
624
- const stored = {
625
- accessToken: tokenRes.access_token,
626
- tokenType: tokenRes.token_type,
627
- expiresAt,
628
- hostname,
629
- ...tokenRes.scope !== void 0 && { scope: tokenRes.scope },
630
- ...userId !== void 0 && { userId }
631
- };
632
- saveToken(stored);
633
- return { hostname, userId, expiresAt };
634
- } finally {
635
- loopback.close();
636
- }
637
- }
638
- async function ensureOauthClient(hostname, redirectUri) {
639
- const cached = getOauthClientId(hostname, redirectUri);
640
- if (cached) return cached;
641
- const url = `${hostname}/v1/mcp/oauth/register`;
642
- let res;
643
- try {
644
- res = await fetch(url, {
645
- method: "POST",
646
- headers: { "Content-Type": "application/json" },
647
- body: JSON.stringify({
648
- client_name: "tiro-cli",
649
- redirect_uris: [redirectUri],
650
- grant_types: ["authorization_code"],
651
- response_types: ["code"],
652
- token_endpoint_auth_method: "none",
653
- scope: DEFAULT_SCOPE
654
- })
655
- });
656
- } catch (err) {
657
- throw new TiroError(
658
- {
659
- code: "network_error",
660
- message: `Failed to reach ${hostname}: ${err.message}`,
661
- errorType: "network_error",
662
- suggestion: "Check your network connection or --hostname."
663
- },
664
- ExitCode.Generic
665
- );
666
- }
667
- if (!res.ok) {
668
- const detail = await safeText(res);
669
- throw new TiroError(
670
- {
671
- code: "oauth_register_failed",
672
- message: `Dynamic Client Registration failed: HTTP ${res.status}`,
673
- errorType: "internal_error",
674
- httpStatus: res.status,
675
- ...detail !== "" && { suggestion: detail.slice(0, 200) }
676
- },
677
- ExitCode.Generic
678
- );
679
- }
680
- const json = await res.json();
681
- const parsed = RegisterResponseSchema.safeParse(json);
682
- if (!parsed.success) {
683
- throw new TiroError(
684
- {
685
- code: "oauth_register_invalid",
686
- message: "Registration response did not match expected shape.",
687
- errorType: "internal_error"
688
- },
689
- ExitCode.Generic
690
- );
691
- }
692
- setOauthClientId(parsed.data.client_id, hostname, redirectUri);
693
- return parsed.data.client_id;
694
- }
695
- function buildAuthorizeUrl(input) {
696
- const u = new URL(`${input.hostname}/v1/mcp/oauth/authorize`);
697
- u.searchParams.set("response_type", "code");
698
- u.searchParams.set("client_id", input.clientId);
699
- u.searchParams.set("redirect_uri", input.redirectUri);
700
- u.searchParams.set("state", input.state);
701
- u.searchParams.set("code_challenge", input.codeChallenge);
702
- u.searchParams.set("code_challenge_method", "S256");
703
- u.searchParams.set("scope", input.scope);
704
- return u.toString();
705
- }
706
- async function exchangeToken(input) {
707
- const url = `${input.hostname}/v1/mcp/oauth/token`;
708
- const body = new URLSearchParams({
709
- grant_type: "authorization_code",
710
- code: input.code,
711
- redirect_uri: input.redirectUri,
712
- client_id: input.clientId,
713
- code_verifier: input.codeVerifier
714
- });
715
- let res;
716
- try {
717
- res = await fetch(url, {
718
- method: "POST",
719
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
720
- body: body.toString()
721
- });
722
- } catch (err) {
723
- throw new TiroError(
724
- {
725
- code: "network_error",
726
- message: `Failed to reach ${input.hostname}: ${err.message}`,
727
- errorType: "network_error"
728
- },
729
- ExitCode.Generic
730
- );
731
- }
732
- if (!res.ok) {
733
- if (res.status === 400 || res.status === 401) {
734
- clearOauthClientId();
735
- }
736
- const detail = await safeText(res);
737
- throw new TiroError(
738
- {
739
- code: "oauth_token_failed",
740
- message: `Token exchange failed: HTTP ${res.status}`,
741
- errorType: "unauthorized",
742
- httpStatus: res.status,
743
- ...detail !== "" && { suggestion: detail.slice(0, 200) }
744
- },
745
- ExitCode.AuthRequired
746
- );
747
- }
748
- const json = await res.json();
749
- const parsed = TokenResponseSchema.safeParse(json);
750
- if (!parsed.success) {
751
- throw new TiroError(
752
- {
753
- code: "oauth_token_invalid",
754
- message: "Token response did not match expected shape.",
755
- errorType: "internal_error"
756
- },
757
- ExitCode.Generic
758
- );
759
- }
760
- return parsed.data;
761
- }
762
- function computeExpiry(expiresIn) {
763
- const fallbackSeconds = 180 * 24 * 60 * 60;
764
- const seconds = expiresIn ?? fallbackSeconds;
765
- return Date.now() + seconds * 1e3;
766
- }
767
- async function safeText(res) {
768
- try {
769
- return await res.text();
770
- } catch {
771
- return "";
772
- }
773
- }
774
-
775
- // src/commands/auth/login.ts
776
- function registerAuthLogin(parent) {
777
- parent.command("login").description("Sign in to Tiro via OAuth (browser-based, PKCE)").option("--hostname <url>", "API base URL (overrides config / TIRO_HOSTNAME)").option("--no-browser", "Print the URL instead of opening a browser").action(async (opts, cmd) => {
778
- const globalOpts = cmd.optsWithGlobals();
779
- const result = await performLogin({
780
- ...opts.hostname !== void 0 && { hostname: opts.hostname },
781
- noBrowser: opts.noBrowser === true,
782
- onPrompt: (msg) => {
783
- if (globalOpts.quiet) return;
784
- process.stderr.write(`${color(msg, "cyan", globalOpts)}
785
- `);
786
- }
787
- });
788
- const hostname = getHostname(opts.hostname);
789
- const expiresIso = new Date(result.expiresAt).toISOString();
790
- if (globalOpts.json) {
791
- printOutput(
792
- {
793
- ok: true,
794
- data: {
795
- signedIn: true,
796
- hostname,
797
- userId: result.userId ?? null,
798
- expiresAt: expiresIso
799
- }
800
- },
801
- globalOpts
802
- );
803
- } else if (!globalOpts.quiet) {
804
- process.stderr.write(`${color("\u2713", "green", globalOpts)} Signed in to ${hostname}
805
- `);
806
- if (result.userId) {
807
- process.stderr.write(` user: ${result.userId}
808
- `);
809
- }
810
- process.stderr.write(` token expires: ${expiresIso}
811
- `);
812
- }
813
- });
814
- }
815
-
816
- // src/commands/auth/status.ts
817
- import "commander";
818
- function registerAuthStatus(parent) {
819
- parent.command("status").description("Show current authenticated account and scopes").action(async (_opts, cmd) => {
820
- const globalOpts = cmd.optsWithGlobals();
821
- const t = resolveToken();
822
- if (!t) {
823
- throw authRequired();
824
- }
825
- const payload = decodeJwtPayload(t.accessToken);
826
- const sub = typeof payload?.["sub"] === "string" ? payload["sub"] : null;
827
- const exp = typeof payload?.["exp"] === "number" ? payload["exp"] * 1e3 : null;
828
- const scope = typeof payload?.["scope"] === "string" ? payload["scope"] : null;
829
- const expMs = exp ?? t.expiresAt ?? null;
830
- const expired = expMs !== null && Date.now() >= expMs;
831
- const report = {
832
- signedIn: true,
833
- source: t.source,
834
- hostname: t.hostname ?? null,
835
- userId: t.userId ?? sub,
836
- scope,
837
- expiresAt: expMs ? new Date(expMs).toISOString() : null,
838
- expired,
839
- tokenPrefix: `${t.accessToken.slice(0, 4)}...***`
840
- };
841
- if (globalOpts.json || !process.stdout.isTTY) {
842
- printOutput({ ok: true, data: report }, globalOpts);
843
- } else {
844
- const headIcon = expired ? color("!", "yellow", globalOpts) : color("\u2713", "green", globalOpts);
845
- const headText = expired ? "Token expired" : "Signed in";
846
- process.stdout.write(`${headIcon} ${headText}
847
- `);
848
- process.stdout.write(` source: ${report.source}
849
- `);
850
- if (report.hostname) process.stdout.write(` hostname: ${report.hostname}
851
- `);
852
- if (report.userId) process.stdout.write(` user: ${report.userId}
853
- `);
854
- if (report.scope) process.stdout.write(` scope: ${report.scope}
855
- `);
856
- if (report.expiresAt) {
857
- const tag = expired ? color(" (expired)", "red", globalOpts) : "";
858
- process.stdout.write(` expires at: ${report.expiresAt}${tag}
859
- `);
860
- }
861
- process.stdout.write(` token: ${report.tokenPrefix}
862
- `);
863
- if (expired) {
864
- process.stdout.write(
865
- `
866
- ${color("\u2192", "gray", globalOpts)} Run \`tiro auth login\` to refresh.
867
- `
868
- );
869
- }
870
- }
871
- });
872
- }
873
-
874
- // src/commands/auth/logout.ts
875
- import "commander";
876
- function registerAuthLogout(parent) {
877
- parent.command("logout").description("Sign out and clear the stored token").action(async (_opts, cmd) => {
878
- const globalOpts = cmd.optsWithGlobals();
879
- const removed = deleteToken();
880
- clearOauthClientId();
881
- if (globalOpts.json) {
882
- printOutput({ ok: true, data: { signedOut: true, hadToken: removed } }, globalOpts);
883
- } else if (!globalOpts.quiet) {
884
- if (removed) {
885
- process.stderr.write(`${color("\u2713", "green", globalOpts)} Signed out
886
- `);
887
- } else {
888
- process.stderr.write(`${color("\u2022", "gray", globalOpts)} No token was stored
889
- `);
890
- }
891
- }
892
- });
893
- }
894
-
895
- // src/commands/auth/index.ts
896
- function registerAuth(program) {
897
- const auth = program.command("auth").description("Manage authentication");
898
- registerAuthLogin(auth);
899
- registerAuthStatus(auth);
900
- registerAuthLogout(auth);
901
- }
902
-
903
- // src/commands/notes/index.ts
904
- import "commander";
905
-
906
- // src/commands/notes/list.ts
907
- import "commander";
908
-
909
- // src/lib/api/client.ts
910
- import "zod";
911
-
912
- // src/lib/api/types.ts
913
- import { z as z2 } from "zod";
914
- var CollaboratorSchema = z2.object({
915
- guid: z2.string(),
916
- name: z2.string(),
917
- email: z2.string(),
918
- role: z2.enum(["OWNER", "EDITOR", "VIEWER"])
919
- });
920
- var ParticipantSchema = z2.object({
921
- name: z2.string().nullable().optional(),
922
- email: z2.string().nullable().optional()
923
- });
924
- var NoteSchema = z2.object({
925
- guid: z2.string(),
926
- title: z2.string(),
927
- createdAt: z2.string(),
928
- updatedAt: z2.string(),
929
- sourceType: z2.string(),
930
- recordingDurationSeconds: z2.number(),
931
- collaborators: z2.array(CollaboratorSchema).optional().default([]),
932
- participants: z2.array(ParticipantSchema).optional().default([]),
933
- webUrl: z2.string(),
934
- recordingStartAt: z2.string().nullable().optional(),
935
- recordingEndAt: z2.string().nullable().optional()
936
- }).passthrough();
937
- var TextObjectSchema = z2.object({
938
- type: z2.string(),
939
- content: z2.string()
940
- });
941
- var SpeakerInfoSchema = z2.object({
942
- label: z2.string(),
943
- personName: z2.string().nullable().optional()
944
- });
945
- var DiarizedSegmentSchema = z2.object({
946
- content: z2.string(),
947
- speaker: SpeakerInfoSchema
948
- });
949
- var ParagraphSchema = z2.object({
950
- uuid: z2.string(),
951
- transcribeLocale: z2.string().nullable().optional(),
952
- transcript: TextObjectSchema.nullable().optional(),
953
- diarizedSegments: z2.array(DiarizedSegmentSchema).nullable().optional(),
954
- timeFrom: z2.string().nullable().optional(),
955
- timeTo: z2.string().nullable().optional(),
956
- locked: z2.boolean().optional()
957
- }).passthrough();
958
- var McpSegmentSchema = z2.object({
959
- content: z2.string(),
960
- speaker: z2.object({
961
- label: z2.string(),
962
- name: z2.string().nullable()
963
- }).nullable()
964
- });
965
- var McpParagraphSchema = z2.object({
966
- timeFrom: z2.string().nullable(),
967
- timeTo: z2.string().nullable(),
968
- segments: z2.array(McpSegmentSchema)
969
- });
970
- var McpTranscriptSchema = z2.object({
971
- noteGuid: z2.string(),
972
- title: z2.string(),
973
- participants: z2.array(z2.string()),
974
- createdAt: z2.string(),
975
- recordingDurationSeconds: z2.number(),
976
- paragraphs: z2.array(McpParagraphSchema)
977
- });
978
- var PageCursorResponseSchema = (item) => z2.object({
979
- content: z2.array(item),
980
- nextCursor: z2.string().nullable()
981
- });
982
- var SimpleListResponseSchema = (item) => z2.object({
983
- content: z2.array(item)
984
- });
985
- var ApiErrorSchema = z2.object({
986
- error: z2.object({
987
- code: z2.number(),
988
- errorType: z2.string(),
989
- message: z2.string(),
990
- detail: z2.string().nullable().optional()
991
- })
992
- });
993
- var WorkspaceMeSchema = z2.object({
994
- guid: z2.string()
995
- }).passthrough();
996
- var WorkspaceItemSchema = z2.object({
997
- guid: z2.string(),
998
- name: z2.string(),
999
- isWikiEnabled: z2.boolean()
1000
- }).passthrough();
1001
- var WorkspacesListSchema = z2.object({
1002
- workspaces: z2.array(WorkspaceItemSchema)
1003
- }).passthrough();
1004
- var WikiSearchPageSchema = z2.object({
1005
- guid: z2.string(),
1006
- wikiId: z2.number(),
1007
- canonicalName: z2.string(),
1008
- pageType: z2.string(),
1009
- entitySubtype: z2.string().nullable().optional(),
1010
- score: z2.number()
1011
- }).passthrough();
1012
- var WikiSearchPagesResponseSchema = z2.object({
1013
- items: z2.array(WikiSearchPageSchema)
1014
- }).passthrough();
1015
- var WikiMentionSchema = z2.object({
1016
- guid: z2.string(),
1017
- noteId: z2.number(),
1018
- paragraphId: z2.number().nullable().optional(),
1019
- paragraphUuid: z2.string().nullable().optional(),
1020
- kind: z2.string(),
1021
- sourceUserId: z2.number(),
1022
- extractedText: z2.string(),
1023
- confidence: z2.number().nullable().optional(),
1024
- createdAt: z2.string()
1025
- }).passthrough();
1026
- var WikiAliasSchema = z2.object({
1027
- guid: z2.string(),
1028
- alias: z2.string(),
1029
- source: z2.string(),
1030
- sourceMentionGuid: z2.string().nullable().optional(),
1031
- sourceUserId: z2.number().nullable().optional(),
1032
- createdAt: z2.string()
1033
- }).passthrough();
1034
- var WikiLinkSchema = z2.object({
1035
- guid: z2.string(),
1036
- sourcePageGuid: z2.string(),
1037
- sourcePageName: z2.string().nullable().optional(),
1038
- targetPageGuid: z2.string(),
1039
- targetPageName: z2.string().nullable().optional(),
1040
- linkType: z2.string(),
1041
- linkTypeDisplayKo: z2.string().optional(),
1042
- linkTypeDisplayEn: z2.string().optional(),
1043
- isDirectional: z2.boolean(),
1044
- source: z2.string().optional(),
1045
- creatorUserId: z2.number().nullable().optional(),
1046
- createdAt: z2.string().optional(),
1047
- updatedAt: z2.string().optional()
1048
- }).passthrough();
1049
- var WikiPageDetailSchema = z2.object({
1050
- guid: z2.string(),
1051
- wikiId: z2.number(),
1052
- canonicalName: z2.string(),
1053
- description: z2.string().nullable().optional(),
1054
- descriptionStatus: z2.string().nullable().optional(),
1055
- regenerationAvailable: z2.boolean().nullable().optional(),
1056
- pageType: z2.string(),
1057
- entitySubtype: z2.string().nullable().optional(),
1058
- extractionStatus: z2.string(),
1059
- mentionCountVisible: z2.number(),
1060
- mentions: z2.array(WikiMentionSchema),
1061
- aliases: z2.array(WikiAliasSchema),
1062
- links: z2.array(WikiLinkSchema),
1063
- lastUpdatedVisible: z2.string().nullable().optional(),
1064
- createdAt: z2.string(),
1065
- updatedAt: z2.string()
1066
- }).passthrough();
1067
- var WikiMentionListResponseSchema = z2.object({
1068
- items: z2.array(WikiMentionSchema),
1069
- nextCursorCreatedAt: z2.string().nullable(),
1070
- nextCursorId: z2.number().nullable()
1071
- }).passthrough();
1072
- var WikiGraphNodeSchema = z2.object({
1073
- guid: z2.string(),
1074
- canonicalName: z2.string(),
1075
- pageType: z2.string(),
1076
- entitySubtype: z2.string().nullable().optional(),
1077
- extractionStatus: z2.string(),
1078
- mentionCountVisible: z2.number()
1079
- }).passthrough();
1080
- var WikiGraphEdgeSchema = z2.object({
1081
- guid: z2.string(),
1082
- sourcePageGuid: z2.string(),
1083
- targetPageGuid: z2.string(),
1084
- linkType: z2.string(),
1085
- linkTypeDisplayKo: z2.string().optional(),
1086
- linkTypeDisplayEn: z2.string().optional(),
1087
- isDirectional: z2.boolean()
1088
- }).passthrough();
1089
- var WikiGraphResponseSchema = z2.object({
1090
- nodes: z2.array(WikiGraphNodeSchema),
1091
- edges: z2.array(WikiGraphEdgeSchema)
1092
- }).passthrough();
1093
- var WikiPlanRequiredSchema = z2.object({
1094
- // Two gate kinds, relayed verbatim:
1095
- // WIKI_PLAN_REQUIRED → plan ineligible (upsell; required_plans set)
1096
- // WIKI_NOT_ACTIVATED → eligible plan, wiki not activated by an admin (required_plans null)
1097
- error_code: z2.enum(["WIKI_PLAN_REQUIRED", "WIKI_NOT_ACTIVATED"]),
1098
- message: z2.string(),
1099
- current_plan: z2.string().nullable().optional(),
1100
- required_plans: z2.array(z2.string()).nullable().optional(),
1101
- action_url: z2.string().nullable().optional()
1102
- }).passthrough();
1103
-
1104
- // src/lib/api/client.ts
1105
- var TiroApiClient = class {
1106
- constructor(hostname, token) {
1107
- this.hostname = hostname;
1108
- this.token = token;
1109
- }
1110
- hostname;
1111
- token;
1112
- async getJson(path, schema, params) {
1113
- const url = this.buildUrl(path, params);
1114
- const res = await this.fetch(url, { method: "GET" });
1115
- return this.parseJson(res, schema, "GET", path);
1116
- }
1117
- async postJson(path, schema, body) {
1118
- const url = this.buildUrl(path);
1119
- const res = await this.fetch(url, {
1120
- method: "POST",
1121
- headers: { "Content-Type": "application/json" },
1122
- body: JSON.stringify(body)
1123
- });
1124
- return this.parseJson(res, schema, "POST", path);
1125
- }
1126
- async putJson(path, schema, body) {
1127
- const url = this.buildUrl(path);
1128
- const res = await this.fetch(url, {
1129
- method: "PUT",
1130
- headers: { "Content-Type": "application/json" },
1131
- body: JSON.stringify(body)
1132
- });
1133
- return this.parseJson(res, schema, "PUT", path);
1134
- }
1135
- async deleteVoid(path) {
1136
- const url = this.buildUrl(path);
1137
- const res = await this.fetch(url, { method: "DELETE" });
1138
- if (!res.ok) throw await mapHttpError(res, "DELETE", path);
1139
- }
1140
- buildUrl(path, params) {
1141
- return buildApiUrl(this.hostname, path, params);
1142
- }
1143
- async fetch(url, init) {
1144
- const headers = new Headers(init.headers);
1145
- headers.set("Authorization", `Bearer ${this.token}`);
1146
- headers.set("Accept", "application/json");
1147
- try {
1148
- return await fetch(url, { ...init, headers });
1149
- } catch (err) {
1150
- throw new TiroError(
1151
- {
1152
- code: "network_error",
1153
- message: `Network error reaching ${this.hostname}: ${err.message}`,
1154
- errorType: "network_error",
1155
- suggestion: "Check your network or --hostname."
1156
- },
1157
- ExitCode.Generic
1158
- );
1159
- }
1160
- }
1161
- async parseJson(res, schema, method, path) {
1162
- if (!res.ok) throw await mapHttpError(res, method, path);
1163
- let json;
1164
- try {
1165
- json = await res.json();
1166
- } catch (err) {
1167
- throw new TiroError(
1168
- {
1169
- code: "invalid_response",
1170
- message: `Failed to parse JSON from ${method} ${path}: ${err.message}`,
1171
- errorType: "internal_error"
1172
- },
1173
- ExitCode.Generic
1174
- );
1175
- }
1176
- const parsed = schema.safeParse(json);
1177
- if (!parsed.success) {
1178
- throw new TiroError(
1179
- {
1180
- code: "schema_mismatch",
1181
- message: `Response shape did not match expected schema (${method} ${path}).`,
1182
- errorType: "internal_error",
1183
- suggestion: parsed.error.issues.slice(0, 3).map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")
1184
- },
1185
- ExitCode.Generic
1186
- );
1187
- }
1188
- return parsed.data;
1189
- }
1190
- };
1191
- async function mapHttpError(res, method, path) {
1192
- const requestId = res.headers.get("x-request-id") ?? void 0;
1193
- const exitCode = res.status === 401 ? ExitCode.AuthRequired : ExitCode.Generic;
1194
- if (res.status === 402) {
1195
- const gate = await tryParsePlanGate(res);
1196
- if (gate) return planGateError(gate, requestId);
1197
- }
1198
- const apiError = await tryParseApiError(res);
1199
- if (apiError) {
1200
- return new TiroError(
1201
- {
1202
- code: `${apiError.error.errorType}`,
1203
- message: apiError.error.message,
1204
- errorType: apiError.error.errorType,
1205
- httpStatus: res.status,
1206
- ...requestId !== void 0 && { requestId },
1207
- ...res.status === 401 && {
1208
- suggestion: "Run `tiro auth login` to refresh."
1209
- }
1210
- },
1211
- exitCode
1212
- );
1213
- }
1214
- return new TiroError(
1215
- {
1216
- code: "http_error",
1217
- message: `${method} ${path} failed: HTTP ${res.status} ${res.statusText}`,
1218
- errorType: httpStatusToErrorType(res.status),
1219
- httpStatus: res.status,
1220
- ...requestId !== void 0 && { requestId }
1221
- },
1222
- exitCode
1223
- );
1224
- }
1225
- function httpStatusToErrorType(status) {
1226
- if (status === 400) return "bad_request";
1227
- if (status === 401) return "unauthorized";
1228
- if (status === 402) return "payment_required";
1229
- if (status === 403) return "forbidden";
1230
- if (status === 404) return "not_found";
1231
- if (status === 409) return "conflict";
1232
- if (status === 413) return "payload_too_large";
1233
- if (status === 422) return "unprocessable_entity";
1234
- if (status === 429) return "too_many_requests";
1235
- return "internal_error";
1236
- }
1237
- async function tryParseApiError(res) {
1238
- try {
1239
- const json = await res.clone().json();
1240
- const parsed = ApiErrorSchema.safeParse(json);
1241
- return parsed.success ? parsed.data : null;
1242
- } catch {
1243
- return null;
1244
- }
1245
- }
1246
- async function tryParsePlanGate(res) {
1247
- try {
1248
- const json = await res.clone().json();
1249
- const parsed = WikiPlanRequiredSchema.safeParse(json);
1250
- return parsed.success ? parsed.data : null;
1251
- } catch {
1252
- return null;
1253
- }
1254
- }
1255
- function planGateError(gate, requestId) {
1256
- const actionUrl = gate.action_url ?? null;
1257
- return new TiroError(
1258
- {
1259
- // Relay the backend's discriminator (WIKI_PLAN_REQUIRED / WIKI_NOT_ACTIVATED) verbatim.
1260
- code: gate.error_code,
1261
- message: gate.message,
1262
- errorType: "payment_required",
1263
- httpStatus: 402,
1264
- ...actionUrl ? { suggestion: `Upgrade: ${actionUrl}` } : {},
1265
- ...requestId !== void 0 && { requestId },
1266
- details: { ...gate }
1267
- },
1268
- ExitCode.Generic
1269
- );
1270
- }
1271
- function buildApiUrl(hostname, path, params) {
1272
- if (!path.startsWith("/") || path.startsWith("//") || path.startsWith("/\\")) {
1273
- throw new TiroError(
1274
- {
1275
- code: "internal_error",
1276
- message: `API path must start with a single "/": got ${JSON.stringify(path)}`,
1277
- errorType: "internal_error"
1278
- },
1279
- ExitCode.Generic
1280
- );
1281
- }
1282
- const u = new URL(`${hostname}${path}`);
1283
- if (params) {
1284
- for (const [k, v] of Object.entries(params)) {
1285
- if (v !== void 0 && v !== null && v !== "") {
1286
- u.searchParams.set(k, String(v));
1287
- }
1288
- }
1289
- }
1290
- return u.toString();
1291
- }
1292
- function createApiClient(opts = {}) {
1293
- if (opts.tokenOverride) {
1294
- return new TiroApiClient(getHostname(opts.hostnameOverride), opts.tokenOverride);
1295
- }
1296
- const t = resolveToken();
1297
- if (!t) throw authRequired();
1298
- const hostname = getHostname(opts.hostnameOverride ?? t.hostname);
1299
- return new TiroApiClient(hostname, t.accessToken);
1300
- }
1301
-
1302
- // src/lib/util/parseDate.ts
1303
- var RELATIVE_RE = /^(\d+)([smhdw])$/i;
1304
- var UNIT_MS = {
1305
- s: 1e3,
1306
- m: 6e4,
1307
- h: 36e5,
1308
- d: 864e5,
1309
- w: 6048e5
1310
- };
1311
- function parseDate(input) {
1312
- const trimmed = input.trim();
1313
- const rel = trimmed.match(RELATIVE_RE);
1314
- if (rel) {
1315
- const num = parseInt(rel[1] ?? "", 10);
1316
- const unit = (rel[2] ?? "").toLowerCase();
1317
- const factor = UNIT_MS[unit];
1318
- if (!factor || !Number.isFinite(num)) {
1319
- throw invalidDate(input);
1320
- }
1321
- return new Date(Date.now() - num * factor).toISOString();
1322
- }
1323
- const d = new Date(trimmed);
1324
- if (Number.isNaN(d.getTime())) throw invalidDate(input);
1325
- return d.toISOString();
1326
- }
1327
- function invalidDate(input) {
1328
- return new TiroError(
1329
- {
1330
- code: "invalid_date",
1331
- message: `Invalid date: "${input}". Use ISO-8601 (e.g. 2026-04-01T10:00:00Z) or relative (e.g. 7d, 24h, 30m).`,
1332
- errorType: "bad_request"
1333
- },
1334
- ExitCode.Usage
1335
- );
1336
- }
1337
-
1338
- // src/lib/util/noteFilter.ts
1339
- var PLACEHOLDER_TITLE = "Untitled";
1340
- var PLACEHOLDER_SOURCE_TYPES = /* @__PURE__ */ new Set(["onboarding"]);
1341
- function isVisibleNote(note) {
1342
- if (note.title === PLACEHOLDER_TITLE) return false;
1343
- if (note.sourceType !== null && note.sourceType !== void 0 && PLACEHOLDER_SOURCE_TYPES.has(note.sourceType)) {
1344
- return false;
1345
- }
1346
- return true;
1347
- }
1348
-
1349
- // src/commands/notes/list.ts
1350
- var ListResponseSchema = PageCursorResponseSchema(NoteSchema);
1351
- var DEFAULT_PAGE_SIZE = 100;
1352
- var MAX_PAGE_SIZE = 1e3;
1353
- var HELP_AFTER = `
95
+ </html>`}import ZA from"open";async function Le(e){try{await ZA(e,{wait:!1})}catch{}}import{Entry as oe}from"@napi-rs/keyring";var ne="io.tiro.cli",ie="default";function Re(e){let A=new oe(ne,ie);try{A.setPassword(JSON.stringify(e))}catch(t){throw new f({code:"keychain_write_failed",message:`Failed to write to OS keychain: ${t.message}`,errorType:"internal_error",suggestion:process.platform==="linux"?"Linux requires a Secret Service daemon (gnome-keyring or kwallet). Or set TIRO_TOKEN env var.":"Check OS keychain permissions, or set TIRO_TOKEN env var."},u.Generic)}}function Ee(){let e=new oe(ne,ie),A;try{A=e.getPassword()}catch{return null}if(!A)return null;try{return JSON.parse(A)}catch{return null}}function Ie(){let e=new oe(ne,ie);try{return e.deletePassword()}catch{return!1}}function Q(){let e=process.env.TIRO_TOKEN;if(e)return{accessToken:e,source:"env"};let A=Ee();return A?{accessToken:A.accessToken,source:"keychain",hostname:A.hostname,expiresAt:A.expiresAt,...A.userId!==void 0&&{userId:A.userId}}:null}function z(e){let A=e.split(".");if(A.length!==3)return null;try{let t=A[1];if(!t)return null;let r=Buffer.from(t,"base64url").toString("utf8");return JSON.parse(r)}catch{return null}}import JA from"conf";var $A="https://api.tiro.ooo",_A=new Set(["localhost","127.0.0.1","[::1]","::1"]),x=new JA({projectName:"tiro",defaults:{hostname:$A,oauthClientId:null,oauthClientIdRegisteredAt:null,oauthClientHostname:null,oauthClientRedirectUri:null,defaultOutputDir:null}});function se(e){let A=e.trim();if(A==="")throw X("empty hostname",e);let t;try{t=new URL(A)}catch{throw X("not a valid URL",e)}if(t.protocol!=="https:"){if(!(t.protocol==="http:"&&et(t.hostname)))throw X(`disallowed scheme "${t.protocol}" \u2014 only https:// or http://localhost is permitted`,e)}if(t.username!==""||t.password!=="")throw X("URL must not embed credentials",e);if(t.search!==""||t.hash!=="")throw X("URL must not include query or fragment",e);if(t.pathname!==""&&t.pathname!=="/")throw X("URL must be host root (no path segment)",e);let r=t.origin;return tt(r)}function et(e){return e.startsWith("[")&&e.endsWith("]")&&(e=e.slice(1,-1)),_A.has(e)}function X(e,A){return new f({code:"invalid_hostname",message:`Refusing to use hostname "${A}": ${e}.`,errorType:"bad_request",suggestion:"Use https://<host> (or http://localhost for local dev). If TIRO_HOSTNAME is set in your environment, unset it."},u.Usage)}function O(e){if(e!==void 0)return se(e);let A=process.env.TIRO_HOSTNAME;return se(A||x.get("hostname"))}function Oe(e,A){let t=x.get("oauthClientId"),r=x.get("oauthClientIdRegisteredAt"),n=x.get("oauthClientHostname"),i=x.get("oauthClientRedirectUri");if(!t||!r||n!==e||!i||!At(i,A))return null;let s=696*60*60*1e3;return Date.now()-r>s?null:t}function Xe(e,A,t){x.set("oauthClientId",e),x.set("oauthClientIdRegisteredAt",Date.now()),x.set("oauthClientHostname",A),x.set("oauthClientRedirectUri",t)}function Y(){x.set("oauthClientId",null),x.set("oauthClientIdRegisteredAt",null),x.set("oauthClientHostname",null),x.set("oauthClientRedirectUri",null)}function At(e,A){let t,r;try{t=new URL(e),r=new URL(A)}catch{return!1}return t.protocol===r.protocol&&t.hostname===r.hostname&&t.pathname===r.pathname}function tt(e){return e.endsWith("/")?e.slice(0,-1):e}var rt=B.object({client_id:B.string(),client_secret:B.string().optional()}),ot=B.object({access_token:B.string(),token_type:B.string(),expires_in:B.number().optional(),scope:B.string().optional()}),nt=300*1e3,Fe="mcp:notes:read";async function Se(e={}){let A=O(e.hostname),t=e.onPrompt??(n=>process.stderr.write(`${n}
96
+ `)),r=await xe();try{let n=await it(A,r.redirectUri),{codeVerifier:i,codeChallenge:s}=be(),c=ye(),d=st({hostname:A,clientId:n,redirectUri:r.redirectUri,state:c,codeChallenge:s,scope:e.scope??Fe});e.noBrowser?t(`Open this URL in your browser:
97
+ ${d}`):(t("Opening browser for sign-in..."),t(`If the browser does not open, visit:
98
+ ${d}`),await Le(d));let p=await r.waitForCallback(nt);if(!ke(p.state,c))throw new f({code:"auth_state_mismatch",message:"OAuth state mismatch \u2014 possible CSRF. Aborting.",errorType:"unauthorized"},u.Generic);let l=await at({hostname:A,clientId:n,code:p.code,redirectUri:r.redirectUri,codeVerifier:i}),w=ct(l.expires_in),b=z(l.access_token),h=typeof b?.sub=="string"?b.sub:void 0,T={accessToken:l.access_token,tokenType:l.token_type,expiresAt:w,hostname:A,...l.scope!==void 0&&{scope:l.scope},...h!==void 0&&{userId:h}};return Re(T),{hostname:A,userId:h,expiresAt:w}}finally{r.close()}}async function it(e,A){let t=Oe(e,A);if(t)return t;let r=`${e}/v1/mcp/oauth/register`,n;try{n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({client_name:"tiro-cli",redirect_uris:[A],grant_types:["authorization_code"],response_types:["code"],token_endpoint_auth_method:"none",scope:Fe})})}catch(c){throw new f({code:"network_error",message:`Failed to reach ${e}: ${c.message}`,errorType:"network_error",suggestion:"Check your network connection or --hostname."},u.Generic)}if(!n.ok){let c=await De(n);throw new f({code:"oauth_register_failed",message:`Dynamic Client Registration failed: HTTP ${n.status}`,errorType:"internal_error",httpStatus:n.status,...c!==""&&{suggestion:c.slice(0,200)}},u.Generic)}let i=await n.json(),s=rt.safeParse(i);if(!s.success)throw new f({code:"oauth_register_invalid",message:"Registration response did not match expected shape.",errorType:"internal_error"},u.Generic);return Xe(s.data.client_id,e,A),s.data.client_id}function st(e){let A=new URL(`${e.hostname}/v1/mcp/oauth/authorize`);return A.searchParams.set("response_type","code"),A.searchParams.set("client_id",e.clientId),A.searchParams.set("redirect_uri",e.redirectUri),A.searchParams.set("state",e.state),A.searchParams.set("code_challenge",e.codeChallenge),A.searchParams.set("code_challenge_method","S256"),A.searchParams.set("scope",e.scope),A.toString()}async function at(e){let A=`${e.hostname}/v1/mcp/oauth/token`,t=new URLSearchParams({grant_type:"authorization_code",code:e.code,redirect_uri:e.redirectUri,client_id:e.clientId,code_verifier:e.codeVerifier}),r;try{r=await fetch(A,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()})}catch(s){throw new f({code:"network_error",message:`Failed to reach ${e.hostname}: ${s.message}`,errorType:"network_error"},u.Generic)}if(!r.ok){(r.status===400||r.status===401)&&Y();let s=await De(r);throw new f({code:"oauth_token_failed",message:`Token exchange failed: HTTP ${r.status}`,errorType:"unauthorized",httpStatus:r.status,...s!==""&&{suggestion:s.slice(0,200)}},u.AuthRequired)}let n=await r.json(),i=ot.safeParse(n);if(!i.success)throw new f({code:"oauth_token_invalid",message:"Token response did not match expected shape.",errorType:"internal_error"},u.Generic);return i.data}function ct(e){let t=e??15552e3;return Date.now()+t*1e3}async function De(e){try{return await e.text()}catch{return""}}function Pe(e){e.command("login").description("Sign in to Tiro via OAuth (browser-based, PKCE)").option("--hostname <url>","API base URL (overrides config / TIRO_HOSTNAME)").option("--no-browser","Print the URL instead of opening a browser").action(async(A,t)=>{let r=t.optsWithGlobals(),n=await Se({...A.hostname!==void 0&&{hostname:A.hostname},noBrowser:A.noBrowser===!0,onPrompt:c=>{r.quiet||process.stderr.write(`${a(c,"cyan",r)}
99
+ `)}}),i=O(A.hostname),s=new Date(n.expiresAt).toISOString();r.json?v({ok:!0,data:{signedIn:!0,hostname:i,userId:n.userId??null,expiresAt:s}},r):r.quiet||(process.stderr.write(`${a("\u2713","green",r)} Signed in to ${i}
100
+ `),n.userId&&process.stderr.write(` user: ${n.userId}
101
+ `),process.stderr.write(` token expires: ${s}
102
+ `))})}import"commander";import"zod";import{z as o}from"zod";var pt=o.object({guid:o.string(),name:o.string(),email:o.string(),role:o.enum(["OWNER","EDITOR","VIEWER"])}),dt=o.object({name:o.string().nullable().optional(),email:o.string().nullable().optional()}),L=o.object({guid:o.string(),title:o.string(),createdAt:o.string(),updatedAt:o.string(),sourceType:o.string(),recordingDurationSeconds:o.number(),collaborators:o.array(pt).optional().default([]),participants:o.array(dt).optional().default([]),webUrl:o.string(),recordingStartAt:o.string().nullable().optional(),recordingEndAt:o.string().nullable().optional()}).passthrough(),lt=o.object({type:o.string(),content:o.string()}),ut=o.object({label:o.string(),personName:o.string().nullable().optional()}),mt=o.object({content:o.string(),speaker:ut}),F=o.object({uuid:o.string(),transcribeLocale:o.string().nullable().optional(),transcript:lt.nullable().optional(),diarizedSegments:o.array(mt).nullable().optional(),timeFrom:o.string().nullable().optional(),timeTo:o.string().nullable().optional(),locked:o.boolean().optional()}).passthrough(),gt=o.object({content:o.string(),speaker:o.object({label:o.string(),name:o.string().nullable()}).nullable()}),ft=o.object({timeFrom:o.string().nullable(),timeTo:o.string().nullable(),segments:o.array(gt)}),tn=o.object({noteGuid:o.string(),title:o.string(),participants:o.array(o.string()),createdAt:o.string(),recordingDurationSeconds:o.number(),paragraphs:o.array(ft)}),R=e=>o.object({content:o.array(e),nextCursor:o.string().nullable()}),S=e=>o.object({content:o.array(e)}),qe=o.object({error:o.object({code:o.number(),errorType:o.string(),message:o.string(),detail:o.string().nullable().optional()})}),He=o.object({guid:o.string()}).passthrough(),ht=o.object({guid:o.string(),name:o.string(),isWikiEnabled:o.boolean()}).passthrough(),We=o.object({workspaces:o.array(ht)}).passthrough(),Me=o.object({workspaceGuid:o.string().nullable(),userId:o.number().nullable().optional(),apiKeyName:o.string().nullable().optional()}).passthrough(),wt=o.object({guid:o.string(),wikiId:o.number(),canonicalName:o.string(),pageType:o.string(),entitySubtype:o.string().nullable().optional(),score:o.number()}).passthrough(),Ne=o.object({items:o.array(wt)}).passthrough(),Ge=o.object({guid:o.string(),noteId:o.number(),paragraphId:o.number().nullable().optional(),paragraphUuid:o.string().nullable().optional(),kind:o.string(),sourceUserId:o.number(),extractedText:o.string(),confidence:o.number().nullable().optional(),createdAt:o.string()}).passthrough(),bt=o.object({guid:o.string(),alias:o.string(),source:o.string(),sourceMentionGuid:o.string().nullable().optional(),sourceUserId:o.number().nullable().optional(),createdAt:o.string()}).passthrough(),yt=o.object({guid:o.string(),sourcePageGuid:o.string(),sourcePageName:o.string().nullable().optional(),targetPageGuid:o.string(),targetPageName:o.string().nullable().optional(),linkType:o.string(),linkTypeDisplayKo:o.string().optional(),linkTypeDisplayEn:o.string().optional(),isDirectional:o.boolean(),source:o.string().optional(),creatorUserId:o.number().nullable().optional(),createdAt:o.string().optional(),updatedAt:o.string().optional()}).passthrough(),Ve=o.object({guid:o.string(),wikiId:o.number(),canonicalName:o.string(),description:o.string().nullable().optional(),descriptionStatus:o.string().nullable().optional(),regenerationAvailable:o.boolean().nullable().optional(),pageType:o.string(),entitySubtype:o.string().nullable().optional(),extractionStatus:o.string(),mentionCountVisible:o.number(),mentions:o.array(Ge),aliases:o.array(bt),links:o.array(yt),lastUpdatedVisible:o.string().nullable().optional(),createdAt:o.string(),updatedAt:o.string()}).passthrough(),Ue=o.object({items:o.array(Ge),nextCursorCreatedAt:o.string().nullable(),nextCursorId:o.number().nullable()}).passthrough(),kt=o.object({guid:o.string(),canonicalName:o.string(),pageType:o.string(),entitySubtype:o.string().nullable().optional(),extractionStatus:o.string(),mentionCountVisible:o.number()}).passthrough(),Ct=o.object({guid:o.string(),sourcePageGuid:o.string(),targetPageGuid:o.string(),linkType:o.string(),linkTypeDisplayKo:o.string().optional(),linkTypeDisplayEn:o.string().optional(),isDirectional:o.boolean()}).passthrough(),M=o.object({nodes:o.array(kt),edges:o.array(Ct)}).passthrough(),je=o.object({error_code:o.enum(["WIKI_PLAN_REQUIRED","WIKI_NOT_ACTIVATED"]),message:o.string(),current_plan:o.string().nullable().optional(),required_plans:o.array(o.string()).nullable().optional(),action_url:o.string().nullable().optional()}).passthrough(),Qe=o.object({id:o.string(),workspaceGuid:o.string(),title:o.string(),description:o.string(),color:o.string(),sharingType:o.string(),parentId:o.string().nullable().optional(),isTeamFolder:o.boolean(),createdAt:o.string(),updatedAt:o.string()}).passthrough(),ae=o.lazy(()=>o.object({id:o.string(),title:o.string(),parentId:o.string().nullable().optional(),depth:o.number(),isAccessible:o.boolean(),children:o.array(ae)})),ze=o.object({id:o.number(),entry:o.string(),createdAt:o.string()}).passthrough();var K=class{constructor(A,t){this.hostname=A;this.token=t}hostname;token;async getJson(A,t,r){let n=this.buildUrl(A,r),i=await this.fetch(n,{method:"GET"});return this.parseJson(i,t,"GET",A)}async postJson(A,t,r){let n=this.buildUrl(A),i=await this.fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});return this.parseJson(i,t,"POST",A)}async putJson(A,t,r){let n=this.buildUrl(A),i=await this.fetch(n,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});return this.parseJson(i,t,"PUT",A)}async deleteVoid(A){let t=this.buildUrl(A),r=await this.fetch(t,{method:"DELETE"});if(!r.ok)throw await Ye(r,"DELETE",A)}buildUrl(A,t){return Lt(this.hostname,A,t)}async fetch(A,t){let r=new Headers(t.headers);r.set("Authorization",`Bearer ${this.token}`),r.set("Accept","application/json");try{return await fetch(A,{...t,headers:r})}catch(n){throw new f({code:"network_error",message:`Network error reaching ${this.hostname}: ${n.message}`,errorType:"network_error",suggestion:"Check your network or --hostname."},u.Generic)}}async parseJson(A,t,r,n){if(!A.ok)throw await Ye(A,r,n);let i;try{i=await A.json()}catch(c){throw new f({code:"invalid_response",message:`Failed to parse JSON from ${r} ${n}: ${c.message}`,errorType:"internal_error"},u.Generic)}let s=t.safeParse(i);if(!s.success)throw new f({code:"schema_mismatch",message:`Response shape did not match expected schema (${r} ${n}).`,errorType:"internal_error",suggestion:s.error.issues.slice(0,3).map(c=>`${c.path.join(".")||"(root)"}: ${c.message}`).join("; ")},u.Generic);return s.data}};async function Ye(e,A,t){let r=e.headers.get("x-request-id")??void 0,n=e.status===401?u.AuthRequired:u.Generic;if(e.status===402){let s=await xt(e);if(s)return Bt(s,r)}let i=await Tt(e);return i?new f({code:`${i.error.errorType}`,message:i.error.message,errorType:i.error.errorType,httpStatus:e.status,...r!==void 0&&{requestId:r},...e.status===401&&{suggestion:"Run `tiro auth login` to refresh."}},n):new f({code:"http_error",message:`${A} ${t} failed: HTTP ${e.status} ${e.statusText}`,errorType:vt(e.status),httpStatus:e.status,...r!==void 0&&{requestId:r}},n)}function vt(e){return e===400?"bad_request":e===401?"unauthorized":e===402?"payment_required":e===403?"forbidden":e===404?"not_found":e===409?"conflict":e===413?"payload_too_large":e===422?"unprocessable_entity":e===429?"too_many_requests":"internal_error"}async function Tt(e){try{let A=await e.clone().json(),t=qe.safeParse(A);return t.success?t.data:null}catch{return null}}async function xt(e){try{let A=await e.clone().json(),t=je.safeParse(A);return t.success?t.data:null}catch{return null}}function Bt(e,A){let t=e.action_url??null;return new f({code:e.error_code,message:e.message,errorType:"payment_required",httpStatus:402,...t?{suggestion:`Upgrade: ${t}`}:{},...A!==void 0&&{requestId:A},details:{...e}},u.Generic)}function Lt(e,A,t){if(!A.startsWith("/")||A.startsWith("//")||A.startsWith("/\\"))throw new f({code:"internal_error",message:`API path must start with a single "/": got ${JSON.stringify(A)}`,errorType:"internal_error"},u.Generic);let r=new URL(`${e}${A}`);if(t)for(let[n,i]of Object.entries(t))i!=null&&i!==""&&r.searchParams.set(n,String(i));return r.toString()}function k(e={}){if(e.tokenOverride)return new K(O(e.hostnameOverride),e.tokenOverride);let A=Q();if(!A)throw W();let t=O(e.hostnameOverride??A.hostname);return new K(t,A.accessToken)}var Ke=new WeakMap;async function E(e){let A=Ke.get(e);if(A)return A;let t=e.getJson("/v1/external/workspaces/me",He).then(r=>r.guid);return Ke.set(e,t),t}async function Ze(e){return(await e.getJson("/v1/external/workspaces",We)).workspaces}async function ce(e){return e.getJson("/v1/external/auth/me",Me)}async function N(e,A){return A||(await ce(e)).workspaceGuid}var Z="Credential is not bound to a workspace; listing across all your workspaces. Pass --workspace <guid> (see `tiro wiki workspaces`) or use a workspace-scoped API key to target one.";async function D(e,A){let t=await N(e,A);if(!t)throw new f({code:"workspace_required",message:"This command targets a single workspace, but your credential is not bound to one.",errorType:"bad_request",suggestion:"Pass --workspace <guid> (run `tiro wiki workspaces` for guids) or use a workspace-scoped API key."},u.Usage);return t}function Je(e){e.command("status").description("Show current authenticated account and scopes").action(async(A,t)=>{let r=t.optsWithGlobals(),n=Q();if(!n)throw W();let i=z(n.accessToken),s=typeof i?.sub=="string"?i.sub:null,c=typeof i?.exp=="number"?i.exp*1e3:null,d=typeof i?.scope=="string"?i.scope:null,p=c??n.expiresAt??null,l=p!==null&&Date.now()>=p,w=null,b=!1;if(!l)try{let T=k({tokenOverride:n.accessToken,hostnameOverride:r.hostname??n.hostname??void 0});w=(await ce(T)).workspaceGuid,b=!0}catch{}let h={signedIn:!0,source:n.source,hostname:n.hostname??null,userId:n.userId??s,scope:d,...b&&{workspace:w},expiresAt:p?new Date(p).toISOString():null,expired:l,tokenPrefix:`${n.accessToken.slice(0,4)}...***`};if(r.json||!process.stdout.isTTY)v({ok:!0,data:h},r);else{let T=l?a("!","yellow",r):a("\u2713","green",r),H=l?"Token expired":"Signed in";if(process.stdout.write(`${T} ${H}
103
+ `),process.stdout.write(` source: ${h.source}
104
+ `),h.hostname&&process.stdout.write(` hostname: ${h.hostname}
105
+ `),h.userId&&process.stdout.write(` user: ${h.userId}
106
+ `),h.scope&&process.stdout.write(` scope: ${h.scope}
107
+ `),b?process.stdout.write(` workspace: ${w??a("(unbound \u2014 across all workspaces)","gray",r)}
108
+ `):l||process.stdout.write(` workspace: ${a("(unable to verify)","yellow",r)}
109
+ `),h.expiresAt){let Ae=l?a(" (expired)","red",r):"";process.stdout.write(` expires at: ${h.expiresAt}${Ae}
110
+ `)}process.stdout.write(` token: ${h.tokenPrefix}
111
+ `),l&&process.stdout.write(`
112
+ ${a("\u2192","gray",r)} Run \`tiro auth login\` to refresh.
113
+ `)}})}import"commander";function $e(e){e.command("logout").description("Sign out and clear the stored token").action(async(A,t)=>{let r=t.optsWithGlobals(),n=Ie();Y(),r.json?v({ok:!0,data:{signedOut:!0,hadToken:n}},r):r.quiet||(n?process.stderr.write(`${a("\u2713","green",r)} Signed out
114
+ `):process.stderr.write(`${a("\u2022","gray",r)} No token was stored
115
+ `))})}function _e(e){let A=e.command("auth").description("Manage authentication");Pe(A),Je(A),$e(A)}import"commander";import"commander";var Rt=/^(\d+)([smhdw])$/i,Et={s:1e3,m:6e4,h:36e5,d:864e5,w:6048e5};function I(e){let A=e.trim(),t=A.match(Rt);if(t){let n=parseInt(t[1]??"",10),i=(t[2]??"").toLowerCase(),s=Et[i];if(!s||!Number.isFinite(n))throw eA(e);return new Date(Date.now()-n*s).toISOString()}let r=new Date(A);if(Number.isNaN(r.getTime()))throw eA(e);return r.toISOString()}function eA(e){return new f({code:"invalid_date",message:`Invalid date: "${e}". Use ISO-8601 (e.g. 2026-04-01T10:00:00Z) or relative (e.g. 7d, 24h, 30m).`,errorType:"bad_request"},u.Usage)}var It="Untitled",Ot=new Set(["onboarding"]);function J(e){return!(e.title===It||e.sourceType!==null&&e.sourceType!==void 0&&Ot.has(e.sourceType))}var Xt=R(L),AA=100,tA=200,Ft=`
1354
116
  Examples:
1355
117
  tiro notes list --since 7d
1356
118
  tiro notes list --keyword "OKR" --since 30d --json
@@ -1366,101 +128,12 @@ Keyword matching:
1366
128
  Note: placeholder notes (title='Untitled' or sourceType='onboarding') are
1367
129
  filtered out by default. A page of N may return fewer than N visible notes \u2014
1368
130
  keep paginating to fetch more, or pass --include-untitled to surface them.
1369
- `;
1370
- function registerNotesList(parent) {
1371
- parent.command("list").description("List notes (lightweight metadata).").option("--keyword <text>", 'Reorder by full-text relevance for this keyword (e.g. "OKR")').option("--folder <id>", "Restrict to a folder and its descendants").option(
1372
- "--since <date>",
1373
- "Inclusive lower bound on createdAt (ISO-8601 or relative: 7d, 24h, 30m)"
1374
- ).option("--until <date>", "Exclusive upper bound on createdAt").option(
1375
- "--limit <n>",
1376
- `Max results per page (default ${DEFAULT_PAGE_SIZE}, max ${MAX_PAGE_SIZE})`
1377
- ).option("--cursor <token>", "Continue a previous page").option(
1378
- "--include-untitled",
1379
- "Include placeholder notes (title='Untitled' or sourceType='onboarding'). Default: hidden",
1380
- false
1381
- ).addHelpText("after", HELP_AFTER).action(async (opts, cmd) => {
1382
- const globalOpts = cmd.optsWithGlobals();
1383
- const client = createApiClient({
1384
- ...globalOpts.hostname !== void 0 && { hostnameOverride: globalOpts.hostname }
1385
- });
1386
- const params = {};
1387
- if (opts.keyword) params["keyword"] = opts.keyword;
1388
- if (opts.folder) params["folderId"] = opts.folder;
1389
- if (opts.since) params["createdAtFrom"] = parseDate(opts.since);
1390
- if (opts.until) params["createdAtTo"] = parseDate(opts.until);
1391
- const size = clampLimit(opts.limit);
1392
- if (size !== void 0) params["size"] = size;
1393
- if (opts.cursor) params["cursor"] = opts.cursor;
1394
- const res = await client.getJson("/v1/external/notes", ListResponseSchema, params);
1395
- const visible = opts.includeUntitled === true ? res.content : res.content.filter(isVisibleNote);
1396
- const mode = resolveOutputMode(globalOpts);
1397
- if (mode === "json") {
1398
- for (const note of visible) printNdjson(note);
1399
- if (res.nextCursor) printNdjson({ _cursor: res.nextCursor });
1400
- } else {
1401
- printPretty(visible, res.nextCursor, globalOpts);
1402
- }
1403
- });
1404
- }
1405
- function clampLimit(raw) {
1406
- if (!raw) return void 0;
1407
- const n = parseInt(raw, 10);
1408
- if (!Number.isFinite(n) || n <= 0) return DEFAULT_PAGE_SIZE;
1409
- return Math.min(n, MAX_PAGE_SIZE);
1410
- }
1411
- function printPretty(notes, nextCursor2, opts) {
1412
- if (notes.length === 0) {
1413
- process.stdout.write(`${color("(no notes)", "gray", opts)}
1414
- `);
1415
- return;
1416
- }
1417
- const titleWidth = computeTitleWidth();
1418
- for (const n of notes) {
1419
- const date = n.createdAt.slice(0, 10);
1420
- const dur = formatDuration(n.recordingDurationSeconds);
1421
- const title = truncate(n.title, titleWidth);
1422
- process.stdout.write(
1423
- `${color(date, "gray", opts)} ${color(n.guid, "dim", opts)} ${color(dur, "cyan", opts)} ${title}
1424
- `
1425
- );
1426
- }
1427
- if (nextCursor2) {
1428
- process.stdout.write(
1429
- `${color(`
1430
- next: --cursor ${nextCursor2}`, "gray", opts)}
1431
- `
1432
- );
1433
- }
1434
- }
1435
- function computeTitleWidth() {
1436
- const cols = process.stdout.columns;
1437
- if (!cols || cols < 60) return 40;
1438
- return Math.max(20, cols - 60);
1439
- }
1440
- function truncate(s, max) {
1441
- if (s.length <= max) return s;
1442
- return s.slice(0, Math.max(0, max - 1)) + "\u2026";
1443
- }
1444
- function formatDuration(sec) {
1445
- if (!sec || sec <= 0) return "\u2014";
1446
- const m = Math.floor(sec / 60);
1447
- const s = Math.floor(sec % 60);
1448
- if (m > 0) return `${m}m${s.toString().padStart(2, "0")}s`;
1449
- return `${s}s`;
1450
- }
1451
-
1452
- // src/commands/notes/search.ts
1453
- import "commander";
1454
- import { z as z4 } from "zod";
1455
- var SearchResponseSchema = z4.object({
1456
- notes: z4.array(NoteSchema),
1457
- nextCursor: z4.string().nullable(),
1458
- degraded: z4.boolean().optional(),
1459
- degradedReason: z4.string().nullable().optional()
1460
- }).passthrough();
1461
- var DEFAULT_PAGE_SIZE2 = 100;
1462
- var MAX_PAGE_SIZE2 = 1e3;
1463
- var HELP_AFTER2 = `
131
+ `;function rA(e){e.command("list").description("List notes (lightweight metadata).").option("--keyword <text>",'Reorder by full-text relevance for this keyword (e.g. "OKR")').option("--folder <id>","Restrict to a folder and its descendants").option("--since <date>","Inclusive lower bound on createdAt (ISO-8601 or relative: 7d, 24h, 30m)").option("--until <date>","Exclusive upper bound on createdAt").option("--limit <n>",`Max results per page (default ${AA}, max ${tA})`).option("--cursor <token>","Continue a previous page").option("--workspace <guid>","List within one workspace (see `tiro wiki workspaces`). Default: the workspace your API key is bound to, else across all your workspaces").option("--include-untitled","Include placeholder notes (title='Untitled' or sourceType='onboarding'). Default: hidden",!1).addHelpText("after",Ft).action(async(A,t)=>{let r=t.optsWithGlobals(),n=k({...r.hostname!==void 0&&{hostnameOverride:r.hostname}}),i={};A.keyword&&(i.keyword=A.keyword),A.folder&&(i.folderId=A.folder),A.since&&(i.createdAtFrom=I(A.since)),A.until&&(i.createdAtTo=I(A.until));let s=St(A.limit);s!==void 0&&(i.size=s),A.cursor&&(i.cursor=A.cursor);let c=await N(n,A.workspace);!c&&r.quiet!==!0&&process.stderr.write(`${a("\u26A0","yellow",r)} ${Z}
132
+ `);let d=c?`/v1/external/workspaces/${encodeURIComponent(c)}/notes`:"/v1/external/notes",p=await n.getJson(d,Xt,i),l=A.includeUntitled===!0?p.content:p.content.filter(J);if(y(r)==="json"){for(let b of l)C(b);p.nextCursor&&C({_cursor:p.nextCursor})}else Dt(l,p.nextCursor,r)})}function St(e){if(!e)return;let A=parseInt(e,10);return!Number.isFinite(A)||A<=0?AA:Math.min(A,tA)}function Dt(e,A,t){if(e.length===0){process.stdout.write(`${a("(no notes)","gray",t)}
133
+ `);return}let r=Pt();for(let n of e){let i=n.createdAt.slice(0,10),s=Ht(n.recordingDurationSeconds),c=qt(n.title,r);process.stdout.write(`${a(i,"gray",t)} ${a(n.guid,"dim",t)} ${a(s,"cyan",t)} ${c}
134
+ `)}A&&process.stdout.write(`${a(`
135
+ next: --cursor ${A}`,"gray",t)}
136
+ `)}function Pt(){let e=process.stdout.columns;return!e||e<60?40:Math.max(20,e-60)}function qt(e,A){return e.length<=A?e:e.slice(0,Math.max(0,A-1))+"\u2026"}function Ht(e){if(!e||e<=0)return"\u2014";let A=Math.floor(e/60),t=Math.floor(e%60);return A>0?`${A}m${t.toString().padStart(2,"0")}s`:`${t}s`}import"commander";import{z as G}from"zod";var Wt=G.object({notes:G.array(L),nextCursor:G.string().nullable(),degraded:G.boolean().optional(),degradedReason:G.string().nullable().optional()}).passthrough(),oA=100,nA=200,Mt=`
1464
137
  Examples:
1465
138
  tiro notes search "Q3 Planning"
1466
139
  tiro notes search "Acme Corp" --since 7d --json
@@ -1480,344 +153,25 @@ Ordering:
1480
153
 
1481
154
  Note: placeholder notes (title='Untitled' or sourceType='onboarding') are
1482
155
  filtered out by default. Pass --include-untitled to surface them.
1483
- `;
1484
- function registerNotesSearch(parent) {
1485
- parent.command("search [keyword]").description("Deep keyword search \u2014 returns notes hydrated with their primary documents.").option(
1486
- "--keyword <text>",
1487
- 'Alternative to positional keyword (e.g. --keyword "Q3 Planning")'
1488
- ).option("--folder <id>", "Restrict hits to a folder and its descendants").option(
1489
- "--since <date>",
1490
- "Inclusive lower bound on createdAt (ISO-8601 or relative: 7d, 24h, 30m)"
1491
- ).option("--until <date>", "Exclusive upper bound on createdAt").option(
1492
- "--limit <n>",
1493
- `Max results per page (default ${DEFAULT_PAGE_SIZE2}, max ${MAX_PAGE_SIZE2})`
1494
- ).option(
1495
- "--cursor <token>",
1496
- "Continue a previous page (reserved \u2014 backend currently always null)"
1497
- ).option(
1498
- "--include-untitled",
1499
- "Include placeholder notes. Default: hidden",
1500
- false
1501
- ).addHelpText("after", HELP_AFTER2).action(async (positional, opts, cmd) => {
1502
- const globalOpts = cmd.optsWithGlobals();
1503
- const keyword = (positional ?? opts.keyword ?? "").trim();
1504
- if (!keyword) {
1505
- throw new TiroError(
1506
- {
1507
- code: "missing_keyword",
1508
- message: "search requires a keyword (positional or --keyword).",
1509
- errorType: "bad_request",
1510
- suggestion: 'tiro notes search "OKR"'
1511
- },
1512
- ExitCode.Usage
1513
- );
1514
- }
1515
- const filter = {};
1516
- if (opts.folder) filter["folderId"] = opts.folder;
1517
- if (opts.since) filter["createdAtFrom"] = parseDate(opts.since);
1518
- if (opts.until) filter["createdAtTo"] = parseDate(opts.until);
1519
- const pagination = {};
1520
- const size = clampLimit2(opts.limit);
1521
- if (size !== void 0) pagination["size"] = size;
1522
- if (opts.cursor) pagination["cursor"] = opts.cursor;
1523
- const body = { keyword };
1524
- if (Object.keys(filter).length > 0) body["filter"] = filter;
1525
- if (Object.keys(pagination).length > 0) body["pagination"] = pagination;
1526
- const client = createApiClient({
1527
- ...globalOpts.hostname !== void 0 && { hostnameOverride: globalOpts.hostname }
1528
- });
1529
- const res = await client.postJson(
1530
- "/v1/external/notes/search",
1531
- SearchResponseSchema,
1532
- body
1533
- );
1534
- const visible = opts.includeUntitled === true ? res.notes : res.notes.filter(isVisibleNote);
1535
- const mode = resolveOutputMode(globalOpts);
1536
- if (mode === "json") {
1537
- for (const note of visible) printNdjson(note);
1538
- if (res.nextCursor) printNdjson({ _cursor: res.nextCursor });
1539
- if (res.degraded === true) {
1540
- printNdjson({ _degraded: true, _degradedReason: res.degradedReason ?? null });
1541
- }
1542
- } else {
1543
- printPretty2(visible, res.nextCursor, globalOpts);
1544
- if (res.degraded === true && globalOpts.quiet !== true) {
1545
- process.stderr.write(
1546
- `${color("\u26A0", "yellow", globalOpts)} search results are partial${res.degradedReason ? ` (${res.degradedReason})` : ""}
1547
- `
1548
- );
1549
- }
1550
- }
1551
- });
1552
- }
1553
- function clampLimit2(raw) {
1554
- if (!raw) return void 0;
1555
- const n = parseInt(raw, 10);
1556
- if (!Number.isFinite(n) || n <= 0) return DEFAULT_PAGE_SIZE2;
1557
- return Math.min(n, MAX_PAGE_SIZE2);
1558
- }
1559
- function printPretty2(notes, nextCursor2, opts) {
1560
- if (notes.length === 0) {
1561
- process.stdout.write(`${color("(no matches)", "gray", opts)}
1562
- `);
1563
- return;
1564
- }
1565
- for (const n of notes) {
1566
- const date = n.createdAt.slice(0, 10);
1567
- process.stdout.write(
1568
- `${color(date, "gray", opts)} ${color(n.guid, "dim", opts)} ${n.title}
1569
- `
1570
- );
1571
- }
1572
- if (nextCursor2) {
1573
- process.stdout.write(
1574
- `${color(`
1575
- next: --cursor ${nextCursor2}`, "gray", opts)}
1576
- `
1577
- );
1578
- }
1579
- }
1580
-
1581
- // src/commands/notes/get.ts
1582
- import "commander";
1583
-
1584
- // src/lib/output/file.ts
1585
- import { mkdir, rename, stat, writeFile, access } from "fs/promises";
1586
- import { dirname as dirname2, resolve as resolve2, sep } from "path";
1587
- function assertSafeOutputPath(input) {
1588
- if (input.trim() === "") {
1589
- throw outputError("output path is empty", input);
1590
- }
1591
- const segments = input.split(/[\\/]/);
1592
- for (const seg of segments) {
1593
- if (seg === "..") {
1594
- throw outputError("path traversal segment '..' is not allowed", input);
1595
- }
1596
- }
1597
- }
1598
- function outputError(reason, input) {
1599
- return new TiroError(
1600
- {
1601
- code: "unsafe_output_path",
1602
- message: `Refusing to write to ${JSON.stringify(input)}: ${reason}.`,
1603
- errorType: "bad_request",
1604
- suggestion: "Use a path without '..' segments, or pass --force if you really mean it."
1605
- },
1606
- ExitCode.Usage
1607
- );
1608
- }
1609
- async function writeFileAtomic(filepath, content, opts = {}) {
1610
- if (!opts.force) {
1611
- assertSafeOutputPath(filepath);
1612
- }
1613
- const absPath = resolve2(filepath);
1614
- await mkdir(dirname2(absPath), { recursive: true });
1615
- if (!opts.force) {
1616
- const exists = await fileExists(absPath);
1617
- if (exists) {
1618
- throw new TiroError(
1619
- {
1620
- code: "file_exists",
1621
- message: `File already exists: ${absPath}`,
1622
- errorType: "conflict",
1623
- suggestion: "Use --force to overwrite, or pick a different --output."
1624
- },
1625
- ExitCode.Generic
1626
- );
1627
- }
1628
- }
1629
- const tmp = `${absPath}.tmp.${process.pid}.${Date.now()}`;
1630
- await writeFile(tmp, content, "utf8");
1631
- await rename(tmp, absPath);
1632
- const s = await stat(absPath);
1633
- return { path: absPath, size: s.size };
1634
- }
1635
- async function fileExists(p) {
1636
- try {
1637
- await access(p);
1638
- return true;
1639
- } catch {
1640
- return false;
1641
- }
1642
- }
1643
-
1644
- // src/lib/output/transcript.ts
1645
- function buildMcpTranscript(note, paragraphs) {
1646
- return {
1647
- noteGuid: note.guid,
1648
- title: note.title,
1649
- participants: note.participants?.map((p) => p.name || p.email || "").filter((s) => typeof s === "string" && s.length > 0) ?? [],
1650
- createdAt: note.createdAt,
1651
- recordingDurationSeconds: note.recordingDurationSeconds,
1652
- paragraphs: paragraphsToMcp(paragraphs)
1653
- };
1654
- }
1655
- function paragraphsToMcp(paragraphs) {
1656
- return paragraphs.map((p) => ({
1657
- timeFrom: p.timeFrom ?? null,
1658
- timeTo: p.timeTo ?? null,
1659
- segments: paragraphToSegments(p)
1660
- })).filter((p) => p.segments.length > 0);
1661
- }
1662
- function paragraphToSegments(p) {
1663
- const ds = p.diarizedSegments;
1664
- if (ds && ds.length > 0) {
1665
- return ds.map((s) => ({
1666
- content: stripHtml(s.content),
1667
- speaker: {
1668
- label: s.speaker.label,
1669
- name: s.speaker.personName ? stripHtml(s.speaker.personName) : null
1670
- }
1671
- })).filter((s) => s.content.length > 0);
1672
- }
1673
- const plain = stripHtml(p.transcript?.content ?? "");
1674
- return plain ? [{ content: plain, speaker: null }] : [];
1675
- }
1676
- function renderTranscriptJson(t) {
1677
- return `${JSON.stringify(t, null, 2)}
1678
- `;
1679
- }
1680
- function renderTranscriptMarkdown(t, opts = {}) {
1681
- const showTs = opts.timestamps !== false;
1682
- const anchor = showTs ? anchorTime(t) : null;
1683
- const lines = [];
1684
- lines.push(`# ${t.title}`, "");
1685
- if (t.participants.length > 0) {
1686
- lines.push(`**Participants**: ${t.participants.join(", ")}`, "");
1687
- }
1688
- lines.push("## Transcript", "");
1689
- for (const p of t.paragraphs) {
1690
- if (showTs) {
1691
- const ts = elapsed(p.timeFrom, anchor);
1692
- if (ts) lines.push(`### ${ts}`, "");
1693
- }
1694
- for (const s of p.segments) {
1695
- const who = s.speaker?.name ?? s.speaker?.label ?? "Unknown";
1696
- lines.push(`**${who}**: ${s.content}`);
1697
- }
1698
- lines.push("");
1699
- }
1700
- return `${lines.join("\n").trimEnd()}
1701
- `;
1702
- }
1703
- function renderTranscriptText(t) {
1704
- const lines = [];
1705
- for (const p of t.paragraphs) {
1706
- for (const s of p.segments) {
1707
- const who = s.speaker?.name ?? s.speaker?.label ?? "Unknown";
1708
- lines.push(`[${who}] ${s.content}`);
1709
- }
1710
- }
1711
- return `${lines.join("\n")}
1712
- `;
1713
- }
1714
- function anchorTime(t) {
1715
- for (const p of t.paragraphs) {
1716
- if (p.timeFrom) return p.timeFrom;
1717
- }
1718
- return null;
1719
- }
1720
- function elapsed(currentIso, anchorIso) {
1721
- if (!currentIso || !anchorIso) return "";
1722
- const cur = Date.parse(currentIso);
1723
- const anc = Date.parse(anchorIso);
1724
- if (!Number.isFinite(cur) || !Number.isFinite(anc)) return "";
1725
- const seconds = Math.max(0, Math.floor((cur - anc) / 1e3));
1726
- const h = Math.floor(seconds / 3600);
1727
- const m = Math.floor(seconds % 3600 / 60);
1728
- const s = seconds % 60;
1729
- if (h > 0) return `${pad(h)}:${pad(m)}:${pad(s)}`;
1730
- return `${pad(m)}:${pad(s)}`;
1731
- }
1732
- function pad(n) {
1733
- return n.toString().padStart(2, "0");
1734
- }
1735
- function stripHtml(s) {
1736
- return s.replace(/<[^>]*>/g, "").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").trim();
1737
- }
1738
-
1739
- // src/lib/output/format.ts
1740
- function formatNote(note, format, opts = {}) {
1741
- switch (format) {
1742
- case "md":
1743
- return formatMarkdown(note, opts);
1744
- case "json":
1745
- return formatJson(note, opts);
1746
- case "txt":
1747
- return formatText(note, opts);
1748
- }
1749
- }
1750
- function formatMarkdown(note, opts) {
1751
- const fm = [
1752
- "---",
1753
- `guid: ${escapeYaml(note.guid)}`,
1754
- `title: ${escapeYaml(note.title)}`,
1755
- `createdAt: ${note.createdAt}`,
1756
- `updatedAt: ${note.updatedAt}`,
1757
- `sourceType: ${note.sourceType}`,
1758
- `recordingDurationSeconds: ${note.recordingDurationSeconds}`,
1759
- `webUrl: ${note.webUrl}`
1760
- ];
1761
- if (note.recordingStartAt) fm.push(`recordingStartAt: ${note.recordingStartAt}`);
1762
- if (note.recordingEndAt) fm.push(`recordingEndAt: ${note.recordingEndAt}`);
1763
- fm.push("---", "");
1764
- const parts = [fm.join("\n"), `# ${note.title}`, ""];
1765
- if (note.participants && note.participants.length > 0) {
1766
- parts.push("## Participants", "");
1767
- for (const p of note.participants) {
1768
- const name = p.name ?? "(no name)";
1769
- const email = p.email ? ` <${p.email}>` : "";
1770
- parts.push(`- ${name}${email}`);
1771
- }
1772
- parts.push("");
1773
- }
1774
- if (opts.includeTranscript && opts.paragraphs && opts.paragraphs.length > 0) {
1775
- const mcp = buildMcpTranscript(note, opts.paragraphs);
1776
- const transcriptBody = renderTranscriptMarkdown(mcp);
1777
- const startsWithHeader = transcriptBody.startsWith(`# ${note.title}`);
1778
- const trimmed = startsWithHeader ? transcriptBody.slice(transcriptBody.indexOf("\n") + 1) : transcriptBody;
1779
- parts.push(trimmed.replace(/^\s*\n+/, ""));
1780
- }
1781
- return `${parts.join("\n").trimEnd()}
1782
- `;
1783
- }
1784
- function formatJson(note, opts) {
1785
- const out = { ...note };
1786
- if (opts.includeTranscript && opts.paragraphs) {
1787
- out["transcript"] = { paragraphs: paragraphsToMcp(opts.paragraphs) };
1788
- }
1789
- return `${JSON.stringify(out, null, 2)}
1790
- `;
1791
- }
1792
- function formatText(note, opts) {
1793
- if (!opts.paragraphs || opts.paragraphs.length === 0) {
1794
- return `${note.title}
1795
- ${note.webUrl}
1796
- `;
1797
- }
1798
- const mcp = buildMcpTranscript(note, opts.paragraphs);
1799
- return renderTranscriptText(mcp);
1800
- }
1801
- function escapeYaml(s) {
1802
- if (/[:#\n"']/.test(s)) {
1803
- return JSON.stringify(s);
1804
- }
1805
- return s;
1806
- }
1807
-
1808
- // src/commands/notes/get.ts
1809
- var ALLOWED_INCLUDES = /* @__PURE__ */ new Set(["transcript"]);
1810
- var ParagraphsListSchema = SimpleListResponseSchema(ParagraphSchema);
1811
- var ParagraphsCursorSchema = PageCursorResponseSchema(ParagraphSchema);
1812
- function registerNotesGet(parent) {
1813
- parent.command("get <guid>").description("Get a single note. Outputs to stdout, or saves to a file with --output.").option("--output <path>", "Write to file (stdout becomes a single metadata line)").option(
1814
- "--format <md|json|txt>",
1815
- "Output format (default: md for TTY, json when piped)"
1816
- ).option(
1817
- "--include <items>",
1818
- "Comma-separated extras (v0.2 supports: transcript)",
1819
- ""
1820
- ).option("--force", "Overwrite existing file at --output path").addHelpText("after", `
156
+ `;function iA(e){e.command("search [keyword]").description("Deep keyword search \u2014 returns notes hydrated with their primary documents.").option("--keyword <text>",'Alternative to positional keyword (e.g. --keyword "Q3 Planning")').option("--folder <id>","Restrict hits to a folder and its descendants").option("--since <date>","Inclusive lower bound on createdAt (ISO-8601 or relative: 7d, 24h, 30m)").option("--until <date>","Exclusive upper bound on createdAt").option("--limit <n>",`Max results per page (default ${oA}, max ${nA})`).option("--cursor <token>","Continue a previous page (reserved \u2014 backend currently always null)").option("--workspace <guid>","Search within one workspace (see `tiro wiki workspaces`). Default: the workspace your API key is bound to, else across all your workspaces").option("--include-untitled","Include placeholder notes. Default: hidden",!1).addHelpText("after",Mt).action(async(A,t,r)=>{let n=r.optsWithGlobals(),i=(A??t.keyword??"").trim();if(!i)throw new f({code:"missing_keyword",message:"search requires a keyword (positional or --keyword).",errorType:"bad_request",suggestion:'tiro notes search "OKR"'},u.Usage);let s={};t.folder&&(s.folderId=t.folder),t.since&&(s.createdAtFrom=I(t.since)),t.until&&(s.createdAtTo=I(t.until));let c={},d=Nt(t.limit);d!==void 0&&(c.size=d),t.cursor&&(c.cursor=t.cursor);let p={keyword:i};Object.keys(s).length>0&&(p.filter=s),Object.keys(c).length>0&&(p.pagination=c);let l=k({...n.hostname!==void 0&&{hostnameOverride:n.hostname}}),w=await N(l,t.workspace);!w&&n.quiet!==!0&&process.stderr.write(`${a("\u26A0","yellow",n)} ${Z}
157
+ `);let b=w?`/v1/external/workspaces/${encodeURIComponent(w)}/notes/search`:"/v1/external/notes/search",h=await l.postJson(b,Wt,p),T=t.includeUntitled===!0?h.notes:h.notes.filter(J);if(y(n)==="json"){for(let Ae of T)C(Ae);h.nextCursor&&C({_cursor:h.nextCursor}),h.degraded===!0&&C({_degraded:!0,_degradedReason:h.degradedReason??null})}else Gt(T,h.nextCursor,n),h.degraded===!0&&n.quiet!==!0&&process.stderr.write(`${a("\u26A0","yellow",n)} search results are partial${h.degradedReason?` (${h.degradedReason})`:""}
158
+ `)})}function Nt(e){if(!e)return;let A=parseInt(e,10);return!Number.isFinite(A)||A<=0?oA:Math.min(A,nA)}function Gt(e,A,t){if(e.length===0){process.stdout.write(`${a("(no matches)","gray",t)}
159
+ `);return}for(let r of e){let n=r.createdAt.slice(0,10);process.stdout.write(`${a(n,"gray",t)} ${a(r.guid,"dim",t)} ${r.title}
160
+ `)}A&&process.stdout.write(`${a(`
161
+ next: --cursor ${A}`,"gray",t)}
162
+ `)}import"commander";import{mkdir as Vt,rename as Ut,stat as jt,writeFile as Qt,access as zt}from"fs/promises";import{dirname as Yt,resolve as Kt,sep as ki}from"path";function Zt(e){if(e.trim()==="")throw sA("output path is empty",e);let A=e.split(/[\\/]/);for(let t of A)if(t==="..")throw sA("path traversal segment '..' is not allowed",e)}function sA(e,A){return new f({code:"unsafe_output_path",message:`Refusing to write to ${JSON.stringify(A)}: ${e}.`,errorType:"bad_request",suggestion:"Use a path without '..' segments, or pass --force if you really mean it."},u.Usage)}async function $(e,A,t={}){t.force||Zt(e);let r=Kt(e);if(await Vt(Yt(r),{recursive:!0}),!t.force&&await Jt(r))throw new f({code:"file_exists",message:`File already exists: ${r}`,errorType:"conflict",suggestion:"Use --force to overwrite, or pick a different --output."},u.Generic);let n=`${r}.tmp.${process.pid}.${Date.now()}`;await Qt(n,A,"utf8"),await Ut(n,r);let i=await jt(r);return{path:r,size:i.size}}async function Jt(e){try{return await zt(e),!0}catch{return!1}}function U(e,A){return{noteGuid:e.guid,title:e.title,participants:e.participants?.map(t=>t.name||t.email||"").filter(t=>typeof t=="string"&&t.length>0)??[],createdAt:e.createdAt,recordingDurationSeconds:e.recordingDurationSeconds,paragraphs:j(A)}}function j(e){return e.map(A=>({timeFrom:A.timeFrom??null,timeTo:A.timeTo??null,segments:$t(A)})).filter(A=>A.segments.length>0)}function $t(e){let A=e.diarizedSegments;if(A&&A.length>0)return A.map(r=>({content:pe(r.content),speaker:{label:r.speaker.label,name:r.speaker.personName?pe(r.speaker.personName):null}})).filter(r=>r.content.length>0);let t=pe(e.transcript?.content??"");return t?[{content:t,speaker:null}]:[]}function de(e){return`${JSON.stringify(e,null,2)}
163
+ `}function _(e,A={}){let t=A.timestamps!==!1,r=t?_t(e):null,n=[];n.push(`# ${e.title}`,""),e.participants.length>0&&n.push(`**Participants**: ${e.participants.join(", ")}`,""),n.push("## Transcript","");for(let i of e.paragraphs){if(t){let s=er(i.timeFrom,r);s&&n.push(`### ${s}`,"")}for(let s of i.segments){let c=s.speaker?.name??s.speaker?.label??"Unknown";n.push(`**${c}**: ${s.content}`)}n.push("")}return`${n.join(`
164
+ `).trimEnd()}
165
+ `}function ee(e){let A=[];for(let t of e.paragraphs)for(let r of t.segments){let n=r.speaker?.name??r.speaker?.label??"Unknown";A.push(`[${n}] ${r.content}`)}return`${A.join(`
166
+ `)}
167
+ `}function _t(e){for(let A of e.paragraphs)if(A.timeFrom)return A.timeFrom;return null}function er(e,A){if(!e||!A)return"";let t=Date.parse(e),r=Date.parse(A);if(!Number.isFinite(t)||!Number.isFinite(r))return"";let n=Math.max(0,Math.floor((t-r)/1e3)),i=Math.floor(n/3600),s=Math.floor(n%3600/60),c=n%60;return i>0?`${V(i)}:${V(s)}:${V(c)}`:`${V(s)}:${V(c)}`}function V(e){return e.toString().padStart(2,"0")}function pe(e){return e.replace(/<[^>]*>/g,"").replace(/&nbsp;/g," ").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").trim()}function cA(e,A,t={}){switch(A){case"md":return Ar(e,t);case"json":return tr(e,t);case"txt":return rr(e,t)}}function Ar(e,A){let t=["---",`guid: ${aA(e.guid)}`,`title: ${aA(e.title)}`,`createdAt: ${e.createdAt}`,`updatedAt: ${e.updatedAt}`,`sourceType: ${e.sourceType}`,`recordingDurationSeconds: ${e.recordingDurationSeconds}`,`webUrl: ${e.webUrl}`];e.recordingStartAt&&t.push(`recordingStartAt: ${e.recordingStartAt}`),e.recordingEndAt&&t.push(`recordingEndAt: ${e.recordingEndAt}`),t.push("---","");let r=[t.join(`
168
+ `),`# ${e.title}`,""];if(e.participants&&e.participants.length>0){r.push("## Participants","");for(let n of e.participants){let i=n.name??"(no name)",s=n.email?` <${n.email}>`:"";r.push(`- ${i}${s}`)}r.push("")}if(A.includeTranscript&&A.paragraphs&&A.paragraphs.length>0){let n=U(e,A.paragraphs),i=_(n),c=i.startsWith(`# ${e.title}`)?i.slice(i.indexOf(`
169
+ `)+1):i;r.push(c.replace(/^\s*\n+/,""))}return`${r.join(`
170
+ `).trimEnd()}
171
+ `}function tr(e,A){let t={...e};return A.includeTranscript&&A.paragraphs&&(t.transcript={paragraphs:j(A.paragraphs)}),`${JSON.stringify(t,null,2)}
172
+ `}function rr(e,A){if(!A.paragraphs||A.paragraphs.length===0)return`${e.title}
173
+ ${e.webUrl}
174
+ `;let t=U(e,A.paragraphs);return ee(t)}function aA(e){return/[:#\n"']/.test(e)?JSON.stringify(e):e}var or=new Set(["transcript"]),nr=S(F),pA=R(F);function dA(e){e.command("get <guid>").description("Get a single note. Outputs to stdout, or saves to a file with --output.").option("--output <path>","Write to file (stdout becomes a single metadata line)").option("--format <md|json|txt>","Output format (default: md for TTY, json when piped)").option("--include <items>","Comma-separated extras (v0.2 supports: transcript)","").option("--force","Overwrite existing file at --output path").addHelpText("after",`
1821
175
  Examples:
1822
176
  tiro notes get <guid> # markdown to stdout
1823
177
  tiro notes get <guid> --include transcript # add speaker-attributed paragraphs
@@ -1827,142 +181,10 @@ Examples:
1827
181
  Tip for agents: prefer --output <path>. The actual content goes to disk
1828
182
  and stdout collapses to a single metadata line, keeping your context
1829
183
  window light.
1830
- `).action(async (guid, opts, cmd) => {
1831
- const globalOpts = cmd.optsWithGlobals();
1832
- const includes = parseIncludes(opts.include);
1833
- validateIncludes(includes);
1834
- const format = pickFormat(opts.format, opts.output);
1835
- const client = createApiClient({
1836
- ...globalOpts.hostname !== void 0 && { hostnameOverride: globalOpts.hostname }
1837
- });
1838
- const note = await client.getJson(`/v1/external/notes/${guid}`, NoteSchema);
1839
- let paragraphs;
1840
- if (includes.has("transcript") || format === "txt") {
1841
- paragraphs = await fetchAllParagraphs(client, guid);
1842
- }
1843
- const content = formatNote(note, format, {
1844
- includeTranscript: includes.has("transcript"),
1845
- ...paragraphs !== void 0 && { paragraphs }
1846
- });
1847
- if (opts.output) {
1848
- const result = await writeFileAtomic(opts.output, content, {
1849
- ...opts.force === true && { force: true }
1850
- });
1851
- printOutput(
1852
- {
1853
- ok: true,
1854
- data: {
1855
- saved: result.path,
1856
- size: result.size,
1857
- format,
1858
- guid: note.guid,
1859
- title: note.title
1860
- }
1861
- },
1862
- globalOpts
1863
- );
1864
- return;
1865
- }
1866
- const mode = resolveOutputMode(globalOpts);
1867
- if (mode === "json" && format !== "json") {
1868
- printOutput(
1869
- {
1870
- ok: true,
1871
- data: {
1872
- ...note,
1873
- ...paragraphs && { transcript: { paragraphs: paragraphsToMcp(paragraphs) } }
1874
- }
1875
- },
1876
- globalOpts
1877
- );
1878
- } else if (format === "json") {
1879
- process.stdout.write(content);
1880
- } else {
1881
- if (process.stdout.isTTY && format === "txt") {
1882
- process.stdout.write(`${color(`# ${note.title}`, "bold", globalOpts)}
184
+ `).action(async(A,t,r)=>{let n=r.optsWithGlobals(),i=sr(t.include);ar(i);let s=cr(t.format,t.output),c=k({...n.hostname!==void 0&&{hostnameOverride:n.hostname}}),d=await c.getJson(`/v1/external/notes/${A}`,L),p;(i.has("transcript")||s==="txt")&&(p=await ir(c,A));let l=cA(d,s,{includeTranscript:i.has("transcript"),...p!==void 0&&{paragraphs:p}});if(t.output){let b=await $(t.output,l,{...t.force===!0&&{force:!0}});v({ok:!0,data:{saved:b.path,size:b.size,format:s,guid:d.guid,title:d.title}},n);return}y(n)==="json"&&s!=="json"?v({ok:!0,data:{...d,...p&&{transcript:{paragraphs:j(p)}}}},n):(s==="json"||process.stdout.isTTY&&s==="txt"&&process.stdout.write(`${a(`# ${d.title}`,"bold",n)}
1883
185
 
1884
- `);
1885
- }
1886
- process.stdout.write(content);
1887
- }
1888
- });
1889
- }
1890
- async function fetchAllParagraphs(client, guid) {
1891
- const first = await client.getJson(
1892
- `/v1/external/notes/${guid}/paragraphs`,
1893
- ParagraphsCursorSchema.or(ParagraphsListSchema)
1894
- );
1895
- const all = [...first.content];
1896
- if ("nextCursor" in first) {
1897
- let cursor = first.nextCursor;
1898
- while (cursor) {
1899
- const next = await client.getJson(
1900
- `/v1/external/notes/${guid}/paragraphs`,
1901
- ParagraphsCursorSchema,
1902
- { cursor }
1903
- );
1904
- all.push(...next.content);
1905
- cursor = next.nextCursor;
1906
- }
1907
- }
1908
- return all;
1909
- }
1910
- function parseIncludes(raw) {
1911
- if (!raw) return /* @__PURE__ */ new Set();
1912
- return new Set(
1913
- raw.split(",").map((s) => s.trim().toLowerCase()).filter((s) => s.length > 0)
1914
- );
1915
- }
1916
- function validateIncludes(includes) {
1917
- for (const inc of includes) {
1918
- if (!ALLOWED_INCLUDES.has(inc)) {
1919
- throw new TiroError(
1920
- {
1921
- code: "invalid_include",
1922
- message: `Invalid --include "${inc}". v0.2.0 supports: transcript.`,
1923
- errorType: "bad_request",
1924
- suggestion: "Use --include transcript"
1925
- },
1926
- ExitCode.Usage
1927
- );
1928
- }
1929
- }
1930
- }
1931
- function pickFormat(format, output) {
1932
- const allowed = ["md", "json", "txt"];
1933
- if (format) {
1934
- const f = format.toLowerCase();
1935
- if (!allowed.includes(f)) {
1936
- throw new TiroError(
1937
- {
1938
- code: "invalid_format",
1939
- message: `Invalid --format "${format}". Allowed: md, json, txt.`,
1940
- errorType: "bad_request"
1941
- },
1942
- ExitCode.Usage
1943
- );
1944
- }
1945
- return f;
1946
- }
1947
- if (output) {
1948
- if (output.endsWith(".json")) return "json";
1949
- if (output.endsWith(".txt")) return "txt";
1950
- return "md";
1951
- }
1952
- return process.stdout.isTTY ? "md" : "json";
1953
- }
1954
-
1955
- // src/commands/notes/transcript.ts
1956
- import "commander";
1957
- var ParagraphsListSchema2 = SimpleListResponseSchema(ParagraphSchema);
1958
- var ParagraphsCursorSchema2 = PageCursorResponseSchema(ParagraphSchema);
1959
- function registerNotesTranscript(parent) {
1960
- parent.command("transcript <guid>").description(
1961
- "Get the full transcript of a note as speaker-attributed paragraphs.\nJSON output matches MCP get_note_transcript shape exactly."
1962
- ).option("--output <path>", "Write to file (stdout = single metadata line)").option(
1963
- "--format <md|json|txt>",
1964
- "Output format (default: md if TTY, txt when piped; json mirrors MCP)"
1965
- ).option("--force", "Overwrite existing file at --output path").option("--no-timestamps", "Omit paragraph timestamp headers (md format only)").addHelpText("after", `
186
+ `),process.stdout.write(l))})}async function ir(e,A){let t=await e.getJson(`/v1/external/notes/${A}/paragraphs`,pA.or(nr)),r=[...t.content];if("nextCursor"in t){let n=t.nextCursor;for(;n;){let i=await e.getJson(`/v1/external/notes/${A}/paragraphs`,pA,{cursor:n});r.push(...i.content),n=i.nextCursor}}return r}function sr(e){return e?new Set(e.split(",").map(A=>A.trim().toLowerCase()).filter(A=>A.length>0)):new Set}function ar(e){for(let A of e)if(!or.has(A))throw new f({code:"invalid_include",message:`Invalid --include "${A}". v0.2.0 supports: transcript.`,errorType:"bad_request",suggestion:"Use --include transcript"},u.Usage)}function cr(e,A){let t=["md","json","txt"];if(e){let r=e.toLowerCase();if(!t.includes(r))throw new f({code:"invalid_format",message:`Invalid --format "${e}". Allowed: md, json, txt.`,errorType:"bad_request"},u.Usage);return r}return A?A.endsWith(".json")?"json":A.endsWith(".txt")?"txt":"md":process.stdout.isTTY?"md":"json"}import"commander";var pr=S(F),lA=R(F);function uA(e){e.command("transcript <guid>").description(`Get the full transcript of a note as speaker-attributed paragraphs.
187
+ JSON output matches MCP get_note_transcript shape exactly.`).option("--output <path>","Write to file (stdout = single metadata line)").option("--format <md|json|txt>","Output format (default: md if TTY, txt when piped; json mirrors MCP)").option("--force","Overwrite existing file at --output path").option("--no-timestamps","Omit paragraph timestamp headers (md format only)").addHelpText("after",`
1966
188
  Examples:
1967
189
  tiro notes transcript <guid> # md in TTY, txt in pipe
1968
190
  tiro notes transcript <guid> --format md --output ./t.md
@@ -1972,124 +194,39 @@ Examples:
1972
194
 
1973
195
  The --format json output is byte-for-byte identical to MCP's
1974
196
  get_note_transcript so agents can swap surfaces without changing parsers.
1975
- `).action(async (guid, opts, cmd) => {
1976
- const globalOpts = cmd.optsWithGlobals();
1977
- const format = pickFormat2(opts.format, opts.output, globalOpts);
1978
- const client = createApiClient({
1979
- ...globalOpts.hostname !== void 0 && { hostnameOverride: globalOpts.hostname }
1980
- });
1981
- const note = await client.getJson(`/v1/external/notes/${guid}`, NoteSchema);
1982
- const paragraphs = await fetchAllParagraphs2(client, guid);
1983
- const mcp = buildMcpTranscript(note, paragraphs);
1984
- const content = format === "json" ? renderTranscriptJson(mcp) : format === "md" ? renderTranscriptMarkdown(mcp, { timestamps: opts.timestamps !== false }) : renderTranscriptText(mcp);
1985
- if (opts.output) {
1986
- const result = await writeFileAtomic(opts.output, content, {
1987
- ...opts.force === true && { force: true }
1988
- });
1989
- printOutput(
1990
- {
1991
- ok: true,
1992
- data: {
1993
- saved: result.path,
1994
- size: result.size,
1995
- format,
1996
- guid: note.guid,
1997
- paragraphCount: mcp.paragraphs.length,
1998
- segmentCount: mcp.paragraphs.reduce((sum, p) => sum + p.segments.length, 0)
1999
- }
2000
- },
2001
- globalOpts
2002
- );
2003
- return;
2004
- }
2005
- const mode = resolveOutputMode(globalOpts);
2006
- if (mode === "json" && format !== "json") {
2007
- printOutput({ ok: true, data: mcp }, globalOpts);
2008
- } else {
2009
- process.stdout.write(content);
2010
- }
2011
- });
2012
- }
2013
- async function fetchAllParagraphs2(client, guid) {
2014
- const first = await client.getJson(
2015
- `/v1/external/notes/${guid}/paragraphs`,
2016
- ParagraphsCursorSchema2.or(ParagraphsListSchema2)
2017
- );
2018
- const all = [...first.content];
2019
- if ("nextCursor" in first) {
2020
- let cursor = first.nextCursor;
2021
- while (cursor) {
2022
- const next = await client.getJson(
2023
- `/v1/external/notes/${guid}/paragraphs`,
2024
- ParagraphsCursorSchema2,
2025
- { cursor }
2026
- );
2027
- all.push(...next.content);
2028
- cursor = next.nextCursor;
2029
- }
2030
- }
2031
- return all;
2032
- }
2033
- function pickFormat2(format, output, globalOpts) {
2034
- const allowed = ["md", "json", "txt"];
2035
- if (format) {
2036
- const f = format.toLowerCase();
2037
- if (!allowed.includes(f)) {
2038
- throw new TiroError(
2039
- {
2040
- code: "invalid_format",
2041
- message: `Invalid --format "${format}". Allowed: md, json, txt.`,
2042
- errorType: "bad_request"
2043
- },
2044
- ExitCode.Usage
2045
- );
2046
- }
2047
- return f;
2048
- }
2049
- if (output) {
2050
- if (output.endsWith(".json")) return "json";
2051
- if (output.endsWith(".md")) return "md";
2052
- if (output.endsWith(".txt")) return "txt";
2053
- return "md";
2054
- }
2055
- if (globalOpts.json) return "json";
2056
- if (globalOpts.pretty) return "md";
2057
- return process.stdout.isTTY ? "md" : "txt";
2058
- }
2059
-
2060
- // src/commands/notes/index.ts
2061
- function registerNotes(program) {
2062
- const notes = program.command("notes").description("List, search, and download notes");
2063
- registerNotesList(notes);
2064
- registerNotesSearch(notes);
2065
- registerNotesGet(notes);
2066
- registerNotesTranscript(notes);
2067
- }
2068
-
2069
- // src/commands/wiki/index.ts
2070
- import "commander";
2071
-
2072
- // src/commands/wiki/search.ts
2073
- import "commander";
2074
-
2075
- // src/lib/api/workspace.ts
2076
- var cache = /* @__PURE__ */ new WeakMap();
2077
- async function resolveWorkspaceGuid(client) {
2078
- const cached = cache.get(client);
2079
- if (cached) return cached;
2080
- const promise = client.getJson("/v1/external/workspaces/me", WorkspaceMeSchema).then((res) => res.guid);
2081
- cache.set(client, promise);
2082
- return promise;
2083
- }
2084
- async function listWorkspaces(client) {
2085
- const res = await client.getJson("/v1/external/workspaces", WorkspacesListSchema);
2086
- return res.workspaces;
2087
- }
2088
-
2089
- // src/commands/wiki/search.ts
2090
- var MAX_SIZE = 100;
2091
- var MAX_QUERY_LENGTH = 500;
2092
- var HELP_AFTER3 = `
197
+ `).action(async(A,t,r)=>{let n=r.optsWithGlobals(),i=lr(t.format,t.output,n),s=k({...n.hostname!==void 0&&{hostnameOverride:n.hostname}}),c=await s.getJson(`/v1/external/notes/${A}`,L),d=await dr(s,A),p=U(c,d),l=i==="json"?de(p):i==="md"?_(p,{timestamps:t.timestamps!==!1}):ee(p);if(t.output){let b=await $(t.output,l,{...t.force===!0&&{force:!0}});v({ok:!0,data:{saved:b.path,size:b.size,format:i,guid:c.guid,paragraphCount:p.paragraphs.length,segmentCount:p.paragraphs.reduce((h,T)=>h+T.segments.length,0)}},n);return}y(n)==="json"&&i!=="json"?v({ok:!0,data:p},n):process.stdout.write(l)})}async function dr(e,A){let t=await e.getJson(`/v1/external/notes/${A}/paragraphs`,lA.or(pr)),r=[...t.content];if("nextCursor"in t){let n=t.nextCursor;for(;n;){let i=await e.getJson(`/v1/external/notes/${A}/paragraphs`,lA,{cursor:n});r.push(...i.content),n=i.nextCursor}}return r}function lr(e,A,t){let r=["md","json","txt"];if(e){let n=e.toLowerCase();if(!r.includes(n))throw new f({code:"invalid_format",message:`Invalid --format "${e}". Allowed: md, json, txt.`,errorType:"bad_request"},u.Usage);return n}return A?A.endsWith(".json")?"json":A.endsWith(".md")?"md":A.endsWith(".txt")?"txt":"md":t.json?"json":t.pretty||process.stdout.isTTY?"md":"txt"}function mA(e){let A=e.command("notes").description("List, search, and download notes");rA(A),iA(A),dA(A),uA(A)}import"commander";import"commander";import{z as ur}from"zod";var mr=ur.array(Qe),gr=`
198
+ Examples:
199
+ tiro folders list
200
+ tiro folders list --workspace <guid> --json
201
+
202
+ Lists the folders in a workspace (flat). sharingType is PRIVATE / ALL_MEMBER_VIEWER
203
+ / ALL_MEMBER_EDITOR / LIMITED. Pass a folder id to 'tiro notes list --folder <id>'.
204
+ The workspace resolves from --workspace, else your API key's bound workspace; an
205
+ unbound credential must pass --workspace (run 'tiro wiki workspaces' for guids).
206
+ `;function gA(e){e.command("list").description("List folders in a workspace.").option("--workspace <guid>","Workspace to list folders from (see `tiro wiki workspaces`). Default: your API key's bound workspace").addHelpText("after",gr).action(async(A,t)=>{let r=t.optsWithGlobals(),n=k({...r.hostname!==void 0&&{hostnameOverride:r.hostname}}),i=await D(n,A.workspace),s=await n.getJson(`/v1/external/workspaces/${encodeURIComponent(i)}/folders`,mr);if(y(r)==="json")for(let d of s)C(d);else fr(s,r)})}function fr(e,A){if(e.length===0){process.stdout.write(`${a("(no folders)","gray",A)}
207
+ `);return}for(let t of e)process.stdout.write(`${a(t.id,"dim",A)} ${a(t.sharingType,"gray",A)} ${t.title}
208
+ `)}import"commander";var hr=S(ae),wr=`
209
+ Examples:
210
+ tiro folders tree
211
+ tiro folders tree --workspace <guid> --json
212
+
213
+ Returns the folder hierarchy for a workspace. In JSON mode each root folder is one
214
+ NDJSON line with nested children; in pretty mode the tree is indented by depth.
215
+ `;function fA(e){e.command("tree").description("Show the folder hierarchy of a workspace.").option("--workspace <guid>","Workspace to read the tree from (see `tiro wiki workspaces`). Default: your API key's bound workspace").addHelpText("after",wr).action(async(A,t)=>{let r=t.optsWithGlobals(),n=k({...r.hostname!==void 0&&{hostnameOverride:r.hostname}}),i=await D(n,A.workspace),s=await n.getJson(`/v1/external/workspaces/${encodeURIComponent(i)}/folders/tree`,hr);if(y(r)==="json")for(let d of s.content)C(d);else br(s.content,r)})}function br(e,A){if(e.length===0){process.stdout.write(`${a("(no folders)","gray",A)}
216
+ `);return}for(let t of e)hA(t,A)}function hA(e,A){let t=" ".repeat(e.depth),r=e.isAccessible?e.title:a(`${e.title} (no access)`,"gray",A);process.stdout.write(`${t}${a(e.id,"dim",A)} ${r}
217
+ `);for(let n of e.children)hA(n,A)}function wA(e){let A=e.command("folders").description("List workspace folders (flat or as a tree) to scope note queries");gA(A),fA(A)}import"commander";import"commander";var yr=R(ze),bA=1e3,kr=`
218
+ Examples:
219
+ tiro word-memories list
220
+ tiro word-memories list --workspace <guid> --json
221
+
222
+ Lists a workspace's custom word memories (vocabulary that biases transcription).
223
+ The workspace resolves from --workspace, else your API key's bound workspace; an
224
+ unbound credential must pass --workspace (run 'tiro wiki workspaces' for guids).
225
+ `;function yA(e){e.command("list").description("List a workspace's custom word memories.").option("--workspace <guid>","Workspace to list from (see `tiro wiki workspaces`). Default: your API key's bound workspace").option("--limit <n>",`Max results per page (max ${bA})`).option("--cursor <token>","Continue a previous page").addHelpText("after",kr).action(async(A,t)=>{let r=t.optsWithGlobals(),n=k({...r.hostname!==void 0&&{hostnameOverride:r.hostname}}),i=await D(n,A.workspace),s={},c=Cr(A.limit);c!==void 0&&(s.size=c),A.cursor&&(s.cursor=A.cursor);let d=await n.getJson(`/v1/external/workspaces/${encodeURIComponent(i)}/word-memories`,yr,s);if(y(r)==="json"){for(let l of d.content)C(l);d.nextCursor&&C({_cursor:d.nextCursor})}else vr(d.content,d.nextCursor,r)})}function Cr(e){if(!e)return;let A=parseInt(e,10);if(!(!Number.isFinite(A)||A<=0))return Math.min(A,bA)}function vr(e,A,t){if(e.length===0){process.stdout.write(`${a("(no word memories)","gray",t)}
226
+ `);return}for(let r of e)process.stdout.write(`${a(String(r.id),"dim",t)} ${r.entry}
227
+ `);A&&process.stdout.write(`${a(`
228
+ next: --cursor ${A}`,"gray",t)}
229
+ `)}function kA(e){let A=e.command("word-memories").description("List a workspace's custom word memories (transcription vocabulary)");yA(A)}import"commander";import"commander";var vA=100,CA=500,Tr=`
2093
230
  Examples:
2094
231
  tiro wiki search "onboarding"
2095
232
  tiro wiki search "payment gateway" --size 50 --json
@@ -2099,68 +236,9 @@ The workspace defaults to the one implicit in your API key. Pass --workspace
2099
236
  to target a specific workspace (get guids from 'tiro wiki workspaces').
2100
237
  Results are ranked wiki pages (pageGuid, name, type, relevance). Pass a
2101
238
  pageGuid to 'tiro wiki page', 'tiro wiki mentions', or 'tiro wiki graph'.
2102
- `;
2103
- function registerWikiSearch(parent) {
2104
- parent.command("search <query>").description("Search the workspace wiki for pages matching a keyword.").option("--size <n>", `Max results (default: backend default, max ${MAX_SIZE})`).option("--workspace <guid>", "Target a specific workspace (from `tiro wiki workspaces`); defaults to your default workspace").addHelpText("after", HELP_AFTER3).action(async (query, opts, cmd) => {
2105
- const globalOpts = cmd.optsWithGlobals();
2106
- const keyword = query.trim();
2107
- if (!keyword) {
2108
- throw new TiroError(
2109
- {
2110
- code: "missing_query",
2111
- message: "wiki search requires a query.",
2112
- errorType: "bad_request",
2113
- suggestion: 'tiro wiki search "onboarding"'
2114
- },
2115
- ExitCode.Usage
2116
- );
2117
- }
2118
- const client = createApiClient({
2119
- ...globalOpts.hostname !== void 0 && { hostnameOverride: globalOpts.hostname }
2120
- });
2121
- const workspaceGuid = opts.workspace ?? await resolveWorkspaceGuid(client);
2122
- const clampedKeyword = keyword.length > MAX_QUERY_LENGTH ? keyword.slice(0, MAX_QUERY_LENGTH) : keyword;
2123
- const params = { q: clampedKeyword };
2124
- const size = clampSize(opts.size);
2125
- if (size !== void 0) params["size"] = size;
2126
- const res = await client.getJson(
2127
- // Fix 1: encode workspaceGuid so path-traversal sequences (../, ?, #) are neutralised.
2128
- `/v1/external/workspaces/${encodeURIComponent(workspaceGuid)}/wiki/search/pages`,
2129
- WikiSearchPagesResponseSchema,
2130
- params
2131
- );
2132
- const mode = resolveOutputMode(globalOpts);
2133
- if (mode === "json") {
2134
- for (const item of res.items) printNdjson(item);
2135
- } else {
2136
- printPretty3(res.items, globalOpts);
2137
- }
2138
- });
2139
- }
2140
- function clampSize(raw) {
2141
- if (!raw) return void 0;
2142
- const n = parseInt(raw, 10);
2143
- if (!Number.isFinite(n) || n <= 0) return void 0;
2144
- return Math.min(n, MAX_SIZE);
2145
- }
2146
- function printPretty3(items, opts) {
2147
- if (items.length === 0) {
2148
- process.stdout.write(`${color("(no matches)", "gray", opts)}
2149
- `);
2150
- return;
2151
- }
2152
- for (const it of items) {
2153
- const score = it.score.toFixed(2);
2154
- process.stdout.write(
2155
- `${color(score, "cyan", opts)} ${color(it.guid, "dim", opts)} ${color(it.pageType, "gray", opts)} ${it.canonicalName}
2156
- `
2157
- );
2158
- }
2159
- }
2160
-
2161
- // src/commands/wiki/page.ts
2162
- import "commander";
2163
- var HELP_AFTER4 = `
239
+ `;function TA(e){e.command("search <query>").description("Search the workspace wiki for pages matching a keyword.").option("--size <n>",`Max results (default: backend default, max ${vA})`).option("--workspace <guid>","Target a specific workspace (from `tiro wiki workspaces`); defaults to your default workspace").addHelpText("after",Tr).action(async(A,t,r)=>{let n=r.optsWithGlobals(),i=A.trim();if(!i)throw new f({code:"missing_query",message:"wiki search requires a query.",errorType:"bad_request",suggestion:'tiro wiki search "onboarding"'},u.Usage);let s=k({...n.hostname!==void 0&&{hostnameOverride:n.hostname}}),c=t.workspace??await E(s),p={q:i.length>CA?i.slice(0,CA):i},l=xr(t.size);l!==void 0&&(p.size=l);let w=await s.getJson(`/v1/external/workspaces/${encodeURIComponent(c)}/wiki/search/pages`,Ne,p);if(y(n)==="json")for(let h of w.items)C(h);else Br(w.items,n)})}function xr(e){if(!e)return;let A=parseInt(e,10);if(!(!Number.isFinite(A)||A<=0))return Math.min(A,vA)}function Br(e,A){if(e.length===0){process.stdout.write(`${a("(no matches)","gray",A)}
240
+ `);return}for(let t of e){let r=t.score.toFixed(2);process.stdout.write(`${a(r,"cyan",A)} ${a(t.guid,"dim",A)} ${a(t.pageType,"gray",A)} ${t.canonicalName}
241
+ `)}}import"commander";var Lr=`
2164
242
  Examples:
2165
243
  tiro wiki page <pageGuid>
2166
244
  tiro wiki page <pageGuid> --json
@@ -2169,53 +247,15 @@ Examples:
2169
247
  Returns the page body (per-user description) plus metadata, mentions,
2170
248
  aliases, and links. The workspace defaults to the one implicit in your API
2171
249
  key; pass --workspace to target a specific workspace (from 'tiro wiki workspaces').
2172
- `;
2173
- function registerWikiPage(parent) {
2174
- parent.command("page <pageGuid>").description("Get a single wiki page: body, metadata, mentions, aliases, and links.").option("--workspace <guid>", "Target a specific workspace (from `tiro wiki workspaces`); defaults to your default workspace").addHelpText("after", HELP_AFTER4).action(async (pageGuid, opts, cmd) => {
2175
- const globalOpts = cmd.optsWithGlobals();
2176
- const client = createApiClient({
2177
- ...globalOpts.hostname !== void 0 && { hostnameOverride: globalOpts.hostname }
2178
- });
2179
- const workspaceGuid = opts.workspace ?? await resolveWorkspaceGuid(client);
2180
- const page = await client.getJson(
2181
- `/v1/external/workspaces/${encodeURIComponent(workspaceGuid)}/wiki/pages/${encodeURIComponent(pageGuid)}`,
2182
- WikiPageDetailSchema
2183
- );
2184
- const mode = resolveOutputMode(globalOpts);
2185
- if (mode === "json") {
2186
- printOutput({ ok: true, data: page }, globalOpts);
2187
- } else {
2188
- printPretty4(page, globalOpts);
2189
- }
2190
- });
2191
- }
2192
- function printPretty4(page, opts) {
2193
- const w = process.stdout.write.bind(process.stdout);
2194
- w(`${color(page.canonicalName, "bold", opts)} ${color(`(${page.pageType})`, "gray", opts)}
2195
- `);
2196
- w(`${color(page.guid, "dim", opts)}
2197
-
2198
- `);
2199
- if (page.description) {
2200
- w(`${page.description}
250
+ `;function xA(e){e.command("page <pageGuid>").description("Get a single wiki page: body, metadata, mentions, aliases, and links.").option("--workspace <guid>","Target a specific workspace (from `tiro wiki workspaces`); defaults to your default workspace").addHelpText("after",Lr).action(async(A,t,r)=>{let n=r.optsWithGlobals(),i=k({...n.hostname!==void 0&&{hostnameOverride:n.hostname}}),s=t.workspace??await E(i),c=await i.getJson(`/v1/external/workspaces/${encodeURIComponent(s)}/wiki/pages/${encodeURIComponent(A)}`,Ve);y(n)==="json"?v({ok:!0,data:c},n):Rr(c,n)})}function Rr(e,A){let t=process.stdout.write.bind(process.stdout);if(t(`${a(e.canonicalName,"bold",A)} ${a(`(${e.pageType})`,"gray",A)}
251
+ `),t(`${a(e.guid,"dim",A)}
2201
252
 
2202
- `);
2203
- } else {
2204
- const status = page.descriptionStatus ?? "none";
2205
- w(`${color(`(no description \u2014 status: ${status})`, "gray", opts)}
253
+ `),e.description)t(`${e.description}
2206
254
 
2207
- `);
2208
- }
2209
- w(
2210
- `${color("mentions", "gray", opts)} ${page.mentionCountVisible} ${color("aliases", "gray", opts)} ${page.aliases.length} ${color("links", "gray", opts)} ${page.links.length}
2211
- `
2212
- );
2213
- }
255
+ `);else{let r=e.descriptionStatus??"none";t(`${a(`(no description \u2014 status: ${r})`,"gray",A)}
2214
256
 
2215
- // src/commands/wiki/mentions.ts
2216
- import "commander";
2217
- var MAX_LIMIT = 200;
2218
- var HELP_AFTER5 = `
257
+ `)}t(`${a("mentions","gray",A)} ${e.mentionCountVisible} ${a("aliases","gray",A)} ${e.aliases.length} ${a("links","gray",A)} ${e.links.length}
258
+ `)}import"commander";var BA=200,Er=`
2219
259
  Examples:
2220
260
  tiro wiki mentions <pageGuid>
2221
261
  tiro wiki mentions <pageGuid> --limit 100 --json
@@ -2226,66 +266,9 @@ Lists the note paragraphs that reference a wiki page. In JSON mode a trailing
2226
266
  cursor token back via --cursor to fetch the next page. The workspace defaults
2227
267
  to the one implicit in your API key; pass --workspace to target a specific
2228
268
  workspace (from 'tiro wiki workspaces').
2229
- `;
2230
- function registerWikiMentions(parent) {
2231
- parent.command("mentions <pageGuid>").description("List the note mentions that reference a single wiki page.").option("--limit <n>", `Max mentions per page (max ${MAX_LIMIT})`).option("--cursor <token>", "Continue from a previous page's cursor token.").option("--workspace <guid>", "Target a specific workspace (from `tiro wiki workspaces`); defaults to your default workspace").addHelpText("after", HELP_AFTER5).action(async (pageGuid, opts, cmd) => {
2232
- const globalOpts = cmd.optsWithGlobals();
2233
- const client = createApiClient({
2234
- ...globalOpts.hostname !== void 0 && { hostnameOverride: globalOpts.hostname }
2235
- });
2236
- const workspaceGuid = opts.workspace ?? await resolveWorkspaceGuid(client);
2237
- const params = {};
2238
- const limit = clampLimit3(opts.limit);
2239
- if (limit !== void 0) params["limit"] = limit;
2240
- if (opts.cursor) params["cursor"] = opts.cursor;
2241
- const res = await client.getJson(
2242
- `/v1/external/workspaces/${encodeURIComponent(workspaceGuid)}/wiki/pages/${encodeURIComponent(pageGuid)}/mentions`,
2243
- WikiMentionListResponseSchema,
2244
- params
2245
- );
2246
- const mode = resolveOutputMode(globalOpts);
2247
- if (mode === "json") {
2248
- for (const item of res.items) printNdjson(item);
2249
- const next = nextCursor(res.nextCursorCreatedAt, res.nextCursorId);
2250
- if (next) printNdjson({ _cursor: next });
2251
- } else {
2252
- printPretty5(res.items, globalOpts);
2253
- }
2254
- });
2255
- }
2256
- function clampLimit3(raw) {
2257
- if (!raw) return void 0;
2258
- const n = parseInt(raw, 10);
2259
- if (!Number.isFinite(n) || n <= 0) return void 0;
2260
- return Math.min(n, MAX_LIMIT);
2261
- }
2262
- function nextCursor(createdAt, id) {
2263
- if (createdAt === null || id === null) return null;
2264
- const millis = Date.parse(createdAt);
2265
- if (Number.isNaN(millis)) return null;
2266
- return `${millis}_${id}`;
2267
- }
2268
- function printPretty5(items, opts) {
2269
- if (items.length === 0) {
2270
- process.stdout.write(`${color("(no mentions)", "gray", opts)}
2271
- `);
2272
- return;
2273
- }
2274
- for (const m of items) {
2275
- const date = m.createdAt.slice(0, 10);
2276
- process.stdout.write(
2277
- `${color(date, "gray", opts)} ${color(m.kind, "cyan", opts)} ${m.extractedText}
2278
- `
2279
- );
2280
- }
2281
- }
2282
-
2283
- // src/commands/wiki/graph.ts
2284
- import "commander";
2285
- var MODES = ["seed", "expand", "around", "links"];
2286
- var MAX_QUERY_LENGTH2 = 500;
2287
- var GRAPH_CAP_DEFAULT = 50;
2288
- var HELP_AFTER6 = `
269
+ `;function LA(e){e.command("mentions <pageGuid>").description("List the note mentions that reference a single wiki page.").option("--limit <n>",`Max mentions per page (max ${BA})`).option("--cursor <token>","Continue from a previous page's cursor token.").option("--workspace <guid>","Target a specific workspace (from `tiro wiki workspaces`); defaults to your default workspace").addHelpText("after",Er).action(async(A,t,r)=>{let n=r.optsWithGlobals(),i=k({...n.hostname!==void 0&&{hostnameOverride:n.hostname}}),s=t.workspace??await E(i),c={},d=Ir(t.limit);d!==void 0&&(c.limit=d),t.cursor&&(c.cursor=t.cursor);let p=await i.getJson(`/v1/external/workspaces/${encodeURIComponent(s)}/wiki/pages/${encodeURIComponent(A)}/mentions`,Ue,c);if(y(n)==="json"){for(let b of p.items)C(b);let w=Or(p.nextCursorCreatedAt,p.nextCursorId);w&&C({_cursor:w})}else Xr(p.items,n)})}function Ir(e){if(!e)return;let A=parseInt(e,10);if(!(!Number.isFinite(A)||A<=0))return Math.min(A,BA)}function Or(e,A){if(e===null||A===null)return null;let t=Date.parse(e);return Number.isNaN(t)?null:`${t}_${A}`}function Xr(e,A){if(e.length===0){process.stdout.write(`${a("(no mentions)","gray",A)}
270
+ `);return}for(let t of e){let r=t.createdAt.slice(0,10);process.stdout.write(`${a(r,"gray",A)} ${a(t.kind,"cyan",A)} ${t.extractedText}
271
+ `)}}import"commander";var le=["seed","expand","around","links"],RA=500,Fr=50,Sr=`
2289
272
  Modes (--mode, default: around):
2290
273
  around Neighborhood around <pageGuid> (--radius hops, default 2)
2291
274
  expand Outward expansion from <pageGuid> (--depth hops, default 1)
@@ -2302,292 +285,28 @@ Examples:
2302
285
  Returns a node+edge slice of the workspace wiki graph. The workspace defaults
2303
286
  to the one implicit in your API key; pass --workspace to target a specific
2304
287
  workspace (from 'tiro wiki workspaces').
2305
- `;
2306
- function registerWikiGraph(parent) {
2307
- parent.command("graph [pageGuid]").description("Get a node+edge slice of the wiki link graph around a page.").option("--mode <mode>", `Graph mode: ${MODES.join(" | ")} (default: around)`).option("--depth <n>", "expand mode: link-hops to traverse outward (default 1)").option("--radius <n>", "around mode: neighborhood radius in hops (default 2)").option("--limit <n>", "Max nodes to return (max 200)").option("--page <guid>", "links mode: additional page guid (repeatable)", collect, []).option("--type <type>", "seed mode: restrict to a page type (CONCEPT|DECISION|ENTITY)").option("--since <date>", "seed mode: only pages updated at/after this date").option("--query <keyword>", "seed mode: keyword to seed the overview graph").option("--workspace <guid>", "Target a specific workspace (from `tiro wiki workspaces`); defaults to your default workspace").addHelpText("after", HELP_AFTER6).action(async (pageGuid, opts, cmd) => {
2308
- const globalOpts = cmd.optsWithGlobals();
2309
- const mode = parseMode(opts.mode);
2310
- if ((mode === "expand" || mode === "around") && !pageGuid) {
2311
- throw new TiroError(
2312
- {
2313
- code: "missing_page_guid",
2314
- message: `--mode ${mode} requires a <pageGuid> positional argument.`,
2315
- errorType: "bad_request",
2316
- suggestion: `tiro wiki graph <pageGuid> --mode ${mode}`
2317
- },
2318
- ExitCode.Usage
2319
- );
2320
- }
2321
- const client = createApiClient({
2322
- ...globalOpts.hostname !== void 0 && { hostnameOverride: globalOpts.hostname }
2323
- });
2324
- const workspaceGuid = opts.workspace ?? await resolveWorkspaceGuid(client);
2325
- const effectiveLimit = mode === "links" ? void 0 : clampInt(opts.limit, 200) ?? GRAPH_CAP_DEFAULT;
2326
- const raw = await fetchGraph(client, workspaceGuid, mode, pageGuid ?? "", opts, effectiveLimit);
2327
- const res = applyGraphCap(raw, effectiveLimit ?? raw.nodes.length);
2328
- const mode2 = resolveOutputMode(globalOpts);
2329
- if (mode2 === "json") {
2330
- printOutput({ ok: true, data: res }, globalOpts);
2331
- } else {
2332
- printPretty6(res, globalOpts);
2333
- }
2334
- });
2335
- }
2336
- async function fetchGraph(client, workspaceGuid, mode, pageGuid, opts, limit) {
2337
- const base = `/v1/external/workspaces/${encodeURIComponent(workspaceGuid)}/wiki/graph`;
2338
- if (mode === "expand") {
2339
- return client.getJson(`${base}/expand`, WikiGraphResponseSchema, {
2340
- pageGuid,
2341
- depth: clampInt(opts.depth, 200),
2342
- limit
2343
- });
2344
- }
2345
- if (mode === "around") {
2346
- return client.getJson(`${base}/around`, WikiGraphResponseSchema, {
2347
- pageGuid,
2348
- radius: clampInt(opts.radius, 200),
2349
- limit
2350
- });
2351
- }
2352
- if (mode === "links") {
2353
- const guids = [pageGuid, ...opts.page ?? []].filter((g) => g && g.length > 0);
2354
- return client.getJson(`${base}/links`, WikiGraphResponseSchema, {
2355
- pageGuids: guids.join(",")
2356
- });
2357
- }
2358
- const rawQuery = opts.query;
2359
- const clampedQuery = rawQuery && rawQuery.length > MAX_QUERY_LENGTH2 ? rawQuery.slice(0, MAX_QUERY_LENGTH2) : rawQuery;
2360
- return client.getJson(`${base}/seed`, WikiGraphResponseSchema, {
2361
- type: opts.type,
2362
- since: opts.since ? parseDate(opts.since) : void 0,
2363
- q: clampedQuery,
2364
- limit
2365
- });
2366
- }
2367
- function parseMode(raw) {
2368
- if (!raw) return "around";
2369
- const m = raw.toLowerCase();
2370
- if (MODES.includes(m)) return m;
2371
- throw new TiroError(
2372
- {
2373
- code: "invalid_mode",
2374
- message: `Invalid --mode "${raw}". Allowed: ${MODES.join(", ")}.`,
2375
- errorType: "bad_request",
2376
- suggestion: "tiro wiki graph <pageGuid> --mode around"
2377
- },
2378
- ExitCode.Usage
2379
- );
2380
- }
2381
- function clampInt(raw, max) {
2382
- if (!raw) return void 0;
2383
- const n = parseInt(raw, 10);
2384
- if (!Number.isFinite(n) || n <= 0) return void 0;
2385
- return Math.min(n, max);
2386
- }
2387
- function collect(value, prev) {
2388
- return [...prev, value];
2389
- }
2390
- function applyGraphCap(graph, limit) {
2391
- const keptNodes = graph.nodes.slice(0, limit);
2392
- const keptGuids = new Set(keptNodes.map((n) => n.guid));
2393
- const keptEdges = graph.edges.filter(
2394
- (e) => keptGuids.has(e.sourcePageGuid) && keptGuids.has(e.targetPageGuid)
2395
- );
2396
- const truncated = graph.nodes.length > limit || keptEdges.length < graph.edges.length;
2397
- return { ...graph, nodes: keptNodes, edges: keptEdges, truncated };
2398
- }
2399
- function printPretty6(res, opts) {
2400
- const w = process.stdout.write.bind(process.stdout);
2401
- w(
2402
- `${color("nodes", "gray", opts)} ${res.nodes.length} ${color("edges", "gray", opts)} ${res.edges.length}
2403
- `
2404
- );
2405
- if (res.truncated) {
2406
- w(
2407
- `${color(`(truncated \u2014 showing first ${res.nodes.length} nodes; narrow with --query / --type / smaller --radius)`, "gray", opts)}
2408
- `
2409
- );
2410
- }
2411
- w("\n");
2412
- for (const n of res.nodes) {
2413
- w(`${color("\u25CF", "cyan", opts)} ${color(n.guid, "dim", opts)} ${n.canonicalName}
2414
- `);
2415
- }
2416
- if (res.edges.length > 0) w("\n");
2417
- for (const e of res.edges) {
2418
- const arrow = e.isDirectional ? "\u2192" : "\u2014";
2419
- w(
2420
- `${color(e.sourcePageGuid, "dim", opts)} ${arrow} ${color(e.targetPageGuid, "dim", opts)} ${color(e.linkType, "gray", opts)}
2421
- `
2422
- );
2423
- }
2424
- }
2425
-
2426
- // src/commands/wiki/workspaces.ts
2427
- import "commander";
2428
- var HELP_AFTER7 = `
288
+ `;function EA(e){e.command("graph [pageGuid]").description("Get a node+edge slice of the wiki link graph around a page.").option("--mode <mode>",`Graph mode: ${le.join(" | ")} (default: around)`).option("--depth <n>","expand mode: link-hops to traverse outward (default 1)").option("--radius <n>","around mode: neighborhood radius in hops (default 2)").option("--limit <n>","Max nodes to return (max 200)").option("--page <guid>","links mode: additional page guid (repeatable)",qr,[]).option("--type <type>","seed mode: restrict to a page type (CONCEPT|DECISION|ENTITY)").option("--since <date>","seed mode: only pages updated at/after this date").option("--query <keyword>","seed mode: keyword to seed the overview graph").option("--workspace <guid>","Target a specific workspace (from `tiro wiki workspaces`); defaults to your default workspace").addHelpText("after",Sr).action(async(A,t,r)=>{let n=r.optsWithGlobals(),i=Pr(t.mode);if((i==="expand"||i==="around")&&!A)throw new f({code:"missing_page_guid",message:`--mode ${i} requires a <pageGuid> positional argument.`,errorType:"bad_request",suggestion:`tiro wiki graph <pageGuid> --mode ${i}`},u.Usage);let s=k({...n.hostname!==void 0&&{hostnameOverride:n.hostname}}),c=t.workspace??await E(s),d=i==="links"?void 0:ue(t.limit,200)??Fr,p=await Dr(s,c,i,A??"",t,d),l=Hr(p,d??p.nodes.length);y(n)==="json"?v({ok:!0,data:l},n):Wr(l,n)})}async function Dr(e,A,t,r,n,i){let s=`/v1/external/workspaces/${encodeURIComponent(A)}/wiki/graph`;if(t==="expand")return e.getJson(`${s}/expand`,M,{pageGuid:r,depth:ue(n.depth,200),limit:i});if(t==="around")return e.getJson(`${s}/around`,M,{pageGuid:r,radius:ue(n.radius,200),limit:i});if(t==="links"){let p=[r,...n.page??[]].filter(l=>l&&l.length>0);return e.getJson(`${s}/links`,M,{pageGuids:p.join(",")})}let c=n.query,d=c&&c.length>RA?c.slice(0,RA):c;return e.getJson(`${s}/seed`,M,{type:n.type,since:n.since?I(n.since):void 0,q:d,limit:i})}function Pr(e){if(!e)return"around";let A=e.toLowerCase();if(le.includes(A))return A;throw new f({code:"invalid_mode",message:`Invalid --mode "${e}". Allowed: ${le.join(", ")}.`,errorType:"bad_request",suggestion:"tiro wiki graph <pageGuid> --mode around"},u.Usage)}function ue(e,A){if(!e)return;let t=parseInt(e,10);if(!(!Number.isFinite(t)||t<=0))return Math.min(t,A)}function qr(e,A){return[...A,e]}function Hr(e,A){let t=e.nodes.slice(0,A),r=new Set(t.map(s=>s.guid)),n=e.edges.filter(s=>r.has(s.sourcePageGuid)&&r.has(s.targetPageGuid)),i=e.nodes.length>A||n.length<e.edges.length;return{...e,nodes:t,edges:n,truncated:i}}function Wr(e,A){let t=process.stdout.write.bind(process.stdout);t(`${a("nodes","gray",A)} ${e.nodes.length} ${a("edges","gray",A)} ${e.edges.length}
289
+ `),e.truncated&&t(`${a(`(truncated \u2014 showing first ${e.nodes.length} nodes; narrow with --query / --type / smaller --radius)`,"gray",A)}
290
+ `),t(`
291
+ `);for(let r of e.nodes)t(`${a("\u25CF","cyan",A)} ${a(r.guid,"dim",A)} ${r.canonicalName}
292
+ `);e.edges.length>0&&t(`
293
+ `);for(let r of e.edges){let n=r.isDirectional?"\u2192":"\u2014";t(`${a(r.sourcePageGuid,"dim",A)} ${n} ${a(r.targetPageGuid,"dim",A)} ${a(r.linkType,"gray",A)}
294
+ `)}}import"commander";var Mr=`
2429
295
  Examples:
2430
296
  tiro wiki workspaces
2431
297
  tiro wiki workspaces --json
2432
298
 
2433
299
  Lists all workspaces you are a member of. Use the guid with --workspace on
2434
300
  any other wiki command to target a non-default workspace.
2435
- `;
2436
- function registerWikiWorkspaces(parent) {
2437
- parent.command("workspaces").description("List all workspaces you are a member of (use guid with --workspace).").addHelpText("after", HELP_AFTER7).action(async (_opts, cmd) => {
2438
- const globalOpts = cmd.optsWithGlobals();
2439
- const client = createApiClient({
2440
- ...globalOpts.hostname !== void 0 && { hostnameOverride: globalOpts.hostname }
2441
- });
2442
- const workspaces = await listWorkspaces(client);
2443
- const mode = resolveOutputMode(globalOpts);
2444
- if (mode === "json") {
2445
- for (const ws of workspaces) printNdjson(ws);
2446
- } else {
2447
- printPretty7(workspaces, globalOpts);
2448
- }
2449
- });
2450
- }
2451
- function printPretty7(workspaces, opts) {
2452
- if (workspaces.length === 0) {
2453
- process.stdout.write(`${color("(no workspaces)", "gray", opts)}
2454
- `);
2455
- return;
2456
- }
2457
- for (const ws of workspaces) {
2458
- const wikiStatus = ws.isWikiEnabled ? color("wiki:on", "green", opts) : color("wiki:off", "gray", opts);
2459
- process.stdout.write(
2460
- `${color(ws.guid, "dim", opts)} ${wikiStatus} ${ws.name}
2461
- `
2462
- );
2463
- }
2464
- }
2465
-
2466
- // src/commands/wiki/index.ts
2467
- function registerWiki(program) {
2468
- const wiki = program.command("wiki").description("Search and explore the workspace wiki (pages, mentions, link graph)");
2469
- registerWikiSearch(wiki);
2470
- registerWikiPage(wiki);
2471
- registerWikiMentions(wiki);
2472
- registerWikiGraph(wiki);
2473
- registerWikiWorkspaces(wiki);
2474
- }
301
+ `;function IA(e){e.command("workspaces").description("List all workspaces you are a member of (use guid with --workspace).").addHelpText("after",Mr).action(async(A,t)=>{let r=t.optsWithGlobals(),n=k({...r.hostname!==void 0&&{hostnameOverride:r.hostname}}),i=await Ze(n);if(y(r)==="json")for(let c of i)C(c);else Nr(i,r)})}function Nr(e,A){if(e.length===0){process.stdout.write(`${a("(no workspaces)","gray",A)}
302
+ `);return}for(let t of e){let r=t.isWikiEnabled?a("wiki:on","green",A):a("wiki:off","gray",A);process.stdout.write(`${a(t.guid,"dim",A)} ${r} ${t.name}
303
+ `)}}function OA(e){let A=e.command("wiki").description("Search and explore the workspace wiki (pages, mentions, link graph)");TA(A),xA(A),LA(A),EA(A),IA(A)}import"commander";import"commander";function XA(e){e.command("info").description("Show Tiro MCP endpoint and connection instructions").action((A,t)=>{let r=t.optsWithGlobals();v({ok:!0,data:{name:q,transport:"http",url:P,docs:FA,install:{claudeCode:`claude mcp add --transport http ${q} ${P}`}}},r)})}import"commander";function SA(e){e.command("install").description("Print the one-line command to add Tiro MCP to Claude Code").option("--print","Print the raw `claude mcp add ...` command to stdout (default behavior)").action((A,t)=>{let r=t.optsWithGlobals(),n=`claude mcp add --transport http ${q} ${P}`;if(r.json){v({ok:!0,data:{command:n,name:q,url:P}},r);return}process.stdout.isTTY&&A.print!==!0&&process.stderr.write(`Run this in your terminal to register Tiro MCP with Claude Code:
2475
304
 
2476
- // src/commands/mcp/index.ts
2477
- import "commander";
305
+ `),process.stdout.write(`${n}
306
+ `)})}var P="https://mcp.tiro.ooo/mcp",q="tiro",FA="https://api-docs.tiro.ooo/mcp";function DA(e){let A=e.command("mcp").description("Connect Tiro MCP from agent clients (Claude Code, etc.)");XA(A),SA(A)}import Gr from"update-notifier";import{readFile as Vr}from"fs/promises";import{fileURLToPath as Ur}from"url";import{dirname as jr,resolve as PA}from"path";var qA=jr(Ur(import.meta.url)),Qr=[PA(qA,"../../package.json"),PA(qA,"../../../package.json")],zr=1440*60*1e3;async function HA(){if(process.env.NO_UPDATE_NOTIFIER==="1"||process.env.CI||process.stdout.isTTY!==!0)return null;let e=await Yr();if(!e)return null;try{return Gr({pkg:e,updateCheckInterval:zr,shouldNotifyInNpmScript:!1})}catch{return null}}function WA(e){e&&e.update&&e.notify({isGlobal:!0,defer:!1,message:`Update available {currentVersion} \u2192 {latestVersion}
307
+ Run npm install -g {packageName} to update
2478
308
 
2479
- // src/commands/mcp/info.ts
2480
- import "commander";
2481
- function registerMcpInfo(parent) {
2482
- parent.command("info").description("Show Tiro MCP endpoint and connection instructions").action((_opts, cmd) => {
2483
- const globalOpts = cmd.optsWithGlobals();
2484
- printOutput(
2485
- {
2486
- ok: true,
2487
- data: {
2488
- name: HOSTED_MCP_NAME,
2489
- transport: "http",
2490
- url: HOSTED_MCP_URL,
2491
- docs: HOSTED_MCP_DOCS,
2492
- install: {
2493
- claudeCode: `claude mcp add --transport http ${HOSTED_MCP_NAME} ${HOSTED_MCP_URL}`
2494
- }
2495
- }
2496
- },
2497
- globalOpts
2498
- );
2499
- });
2500
- }
2501
-
2502
- // src/commands/mcp/install.ts
2503
- import "commander";
2504
- function registerMcpInstall(parent) {
2505
- parent.command("install").description("Print the one-line command to add Tiro MCP to Claude Code").option(
2506
- "--print",
2507
- "Print the raw `claude mcp add ...` command to stdout (default behavior)"
2508
- ).action((opts, cmd) => {
2509
- const globalOpts = cmd.optsWithGlobals();
2510
- const command = `claude mcp add --transport http ${HOSTED_MCP_NAME} ${HOSTED_MCP_URL}`;
2511
- if (globalOpts.json) {
2512
- printOutput(
2513
- { ok: true, data: { command, name: HOSTED_MCP_NAME, url: HOSTED_MCP_URL } },
2514
- globalOpts
2515
- );
2516
- return;
2517
- }
2518
- if (process.stdout.isTTY && opts.print !== true) {
2519
- process.stderr.write(
2520
- "Run this in your terminal to register Tiro MCP with Claude Code:\n\n"
2521
- );
2522
- }
2523
- process.stdout.write(`${command}
2524
- `);
2525
- });
2526
- }
2527
-
2528
- // src/commands/mcp/index.ts
2529
- var HOSTED_MCP_URL = "https://mcp.tiro.ooo/mcp";
2530
- var HOSTED_MCP_NAME = "tiro";
2531
- var HOSTED_MCP_DOCS = "https://api-docs.tiro.ooo/mcp";
2532
- function registerMcp(program) {
2533
- const mcp = program.command("mcp").description("Connect Tiro MCP from agent clients (Claude Code, etc.)");
2534
- registerMcpInfo(mcp);
2535
- registerMcpInstall(mcp);
2536
- }
2537
-
2538
- // src/lib/updateCheck.ts
2539
- import updateNotifier from "update-notifier";
2540
- import { readFile } from "fs/promises";
2541
- import { fileURLToPath as fileURLToPath2 } from "url";
2542
- import { dirname as dirname3, resolve as resolve3 } from "path";
2543
- var HERE2 = dirname3(fileURLToPath2(import.meta.url));
2544
- var CANDIDATE_PATHS2 = [
2545
- resolve3(HERE2, "../../package.json"),
2546
- resolve3(HERE2, "../../../package.json")
2547
- ];
2548
- var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
2549
- async function startUpdateCheck() {
2550
- if (process.env["NO_UPDATE_NOTIFIER"] === "1") return null;
2551
- if (process.env["CI"]) return null;
2552
- if (process.stdout.isTTY !== true) return null;
2553
- const pkg = await loadPkg();
2554
- if (!pkg) return null;
2555
- try {
2556
- const factory = updateNotifier;
2557
- return factory({
2558
- pkg,
2559
- updateCheckInterval: ONE_DAY_MS,
2560
- shouldNotifyInNpmScript: false
2561
- });
2562
- } catch {
2563
- return null;
2564
- }
2565
- }
2566
- function emitUpdateBanner(notifier) {
2567
- if (!notifier) return;
2568
- if (!notifier.update) return;
2569
- notifier.notify({
2570
- isGlobal: true,
2571
- defer: false,
2572
- message: "Update available {currentVersion} \u2192 {latestVersion}\nRun npm install -g {packageName} to update\n\nChangelog: https://www.npmjs.com/package/{packageName}?activeTab=versions"
2573
- });
2574
- }
2575
- async function loadPkg() {
2576
- for (const path of CANDIDATE_PATHS2) {
2577
- try {
2578
- const raw = await readFile(path, "utf8");
2579
- const parsed = JSON.parse(raw);
2580
- if (typeof parsed.name === "string" && typeof parsed.version === "string" && parsed.name.length > 0 && parsed.version.length > 0) {
2581
- return { name: parsed.name, version: parsed.version };
2582
- }
2583
- } catch {
2584
- }
2585
- }
2586
- return null;
2587
- }
2588
-
2589
- // src/bin/tiro.ts
2590
- var EXAMPLES = `
309
+ Changelog: https://www.npmjs.com/package/{packageName}?activeTab=versions`})}async function Yr(){for(let e of Qr)try{let A=await Vr(e,"utf8"),t=JSON.parse(A);if(typeof t.name=="string"&&typeof t.version=="string"&&t.name.length>0&&t.version.length>0)return{name:t.name,version:t.version}}catch{}return null}var Zr=`
2591
310
  EXAMPLES
2592
311
  $ tiro auth login
2593
312
  $ tiro notes list --since 7d
@@ -2595,6 +314,7 @@ EXAMPLES
2595
314
  $ tiro notes get <guid> --output ./meeting.md --include transcript
2596
315
  $ tiro notes transcript <guid> --format md --output ./transcript.md
2597
316
  $ tiro notes transcript <guid> --format md --no-timestamps --output ./clean.md
317
+ $ tiro folders list --workspace <guid>
2598
318
  $ tiro wiki search "onboarding" --json
2599
319
  $ tiro wiki graph <pageGuid> --mode around --radius 2
2600
320
  $ tiro mcp install # one-line setup for Claude Code
@@ -2607,60 +327,9 @@ ENVIRONMENT
2607
327
 
2608
328
  DOCS
2609
329
  https://api-docs.tiro.ooo/cli
2610
- `;
2611
- function buildProgram() {
2612
- const program = new Command19();
2613
- program.name("tiro").description("Tiro AI notes & transcripts \u2014 agent-first command line").version(VERSION, "-v, --version", "Print version").option("--hostname <url>", "API base URL (default: https://api.tiro.ooo)").option("--json", "Force JSON output").option("--pretty", "Force pretty (human) output").option("--quiet", "Suppress non-error output").option("--verbose", "Verbose logging to stderr").option("--no-color", "Disable ANSI colors").addHelpText("after", EXAMPLES);
2614
- program.showHelpAfterError("(run `tiro --help` for available commands)");
2615
- registerAuth(program);
2616
- registerNotes(program);
2617
- registerWiki(program);
2618
- registerMcp(program);
2619
- return program;
2620
- }
2621
- async function main() {
2622
- const program = buildProgram();
2623
- const notifier = await startUpdateCheck();
2624
- try {
2625
- await program.parseAsync(process.argv);
2626
- emitUpdateBanner(notifier);
2627
- } catch (err) {
2628
- handleError(err, program);
2629
- }
2630
- }
2631
- function handleError(err, program) {
2632
- const opts = program.opts();
2633
- if (err instanceof TiroError) {
2634
- if (opts.json) {
2635
- printError(err.toJSON());
2636
- } else if (!opts.quiet) {
2637
- process.stderr.write(`${color("\u2717", "red", opts)} ${err.message}
2638
- `);
2639
- if (err.suggestion) {
2640
- process.stderr.write(` ${color("\u2192", "gray", opts)} ${err.suggestion}
2641
- `);
2642
- }
2643
- }
2644
- process.exit(err.exitCode);
2645
- }
2646
- if (err instanceof Error) {
2647
- if (opts.json) {
2648
- printError({
2649
- ok: false,
2650
- error: { code: "internal_error", message: err.message, errorType: "internal_error" }
2651
- });
2652
- } else if (!opts.quiet) {
2653
- process.stderr.write(`${color("\u2717", "red", opts)} ${err.message}
2654
- `);
2655
- }
2656
- process.exit(ExitCode.Generic);
2657
- }
2658
- process.stderr.write(`Unknown error: ${String(err)}
2659
- `);
2660
- process.exit(ExitCode.Generic);
2661
- }
2662
- main().catch((err) => {
2663
- process.stderr.write(`Fatal: ${String(err)}
2664
- `);
2665
- process.exit(ExitCode.Generic);
2666
- });
330
+ `;function Jr(){let e=new Kr;return e.name("tiro").description("Tiro AI notes & transcripts \u2014 agent-first command line").version(fe,"-v, --version","Print version").option("--hostname <url>","API base URL (default: https://api.tiro.ooo)").option("--json","Force JSON output").option("--pretty","Force pretty (human) output").option("--quiet","Suppress non-error output").option("--verbose","Verbose logging to stderr").option("--no-color","Disable ANSI colors").addHelpText("after",Zr),e.showHelpAfterError("(run `tiro --help` for available commands)"),_e(e),mA(e),wA(e),kA(e),OA(e),DA(e),e}async function $r(){let e=Jr(),A=await HA();try{await e.parseAsync(process.argv),WA(A)}catch(t){_r(t,e)}}function _r(e,A){let t=A.opts();e instanceof f&&(t.json?te(e.toJSON()):t.quiet||(process.stderr.write(`${a("\u2717","red",t)} ${e.message}
331
+ `),e.suggestion&&process.stderr.write(` ${a("\u2192","gray",t)} ${e.suggestion}
332
+ `)),process.exit(e.exitCode)),e instanceof Error&&(t.json?te({ok:!1,error:{code:"internal_error",message:e.message,errorType:"internal_error"}}):t.quiet||process.stderr.write(`${a("\u2717","red",t)} ${e.message}
333
+ `),process.exit(u.Generic)),process.stderr.write(`Unknown error: ${String(e)}
334
+ `),process.exit(u.Generic)}$r().catch(e=>{process.stderr.write(`Fatal: ${String(e)}
335
+ `),process.exit(u.Generic)});