@tokenrip/cli 1.1.6 → 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/AGENTS.md +150 -72
  2. package/README.md +258 -128
  3. package/SKILL.md +213 -77
  4. package/dist/auth-client.js +1 -1
  5. package/dist/auth-client.js.map +1 -1
  6. package/dist/cjs/auth-client.js +1 -1
  7. package/dist/cjs/auth-client.js.map +1 -1
  8. package/dist/cjs/client.js +2 -2
  9. package/dist/cjs/client.js.map +1 -1
  10. package/dist/cjs/commands/archive.js +17 -0
  11. package/dist/cjs/commands/archive.js.map +1 -0
  12. package/dist/cjs/commands/auth.js +36 -16
  13. package/dist/cjs/commands/auth.js.map +1 -1
  14. package/dist/cjs/commands/collection.js +70 -0
  15. package/dist/cjs/commands/collection.js.map +1 -0
  16. package/dist/cjs/commands/config.js +1 -1
  17. package/dist/cjs/commands/config.js.map +1 -1
  18. package/dist/cjs/commands/contacts.js +3 -3
  19. package/dist/cjs/commands/contacts.js.map +1 -1
  20. package/dist/cjs/commands/inbox.js +9 -3
  21. package/dist/cjs/commands/inbox.js.map +1 -1
  22. package/dist/cjs/commands/link.js +38 -0
  23. package/dist/cjs/commands/link.js.map +1 -0
  24. package/dist/cjs/commands/operator-link.js +1 -1
  25. package/dist/cjs/commands/operator-link.js.map +1 -1
  26. package/dist/cjs/commands/publish.js +72 -1
  27. package/dist/cjs/commands/publish.js.map +1 -1
  28. package/dist/cjs/commands/search.js +33 -0
  29. package/dist/cjs/commands/search.js.map +1 -0
  30. package/dist/cjs/commands/share.js +1 -1
  31. package/dist/cjs/commands/share.js.map +1 -1
  32. package/dist/cjs/commands/status.js +4 -0
  33. package/dist/cjs/commands/status.js.map +1 -1
  34. package/dist/cjs/commands/thread.js +34 -1
  35. package/dist/cjs/commands/thread.js.map +1 -1
  36. package/dist/cjs/config.js.map +1 -1
  37. package/dist/cjs/contacts.js +6 -6
  38. package/dist/cjs/contacts.js.map +1 -1
  39. package/dist/cjs/crypto.js +1 -1
  40. package/dist/cjs/crypto.js.map +1 -1
  41. package/dist/cjs/formatters.js +142 -1
  42. package/dist/cjs/formatters.js.map +1 -1
  43. package/dist/cjs/identity.js +4 -0
  44. package/dist/cjs/identity.js.map +1 -1
  45. package/dist/cjs/index.js +3 -1
  46. package/dist/cjs/index.js.map +1 -1
  47. package/dist/cjs/migrations.js +55 -0
  48. package/dist/cjs/migrations.js.map +1 -0
  49. package/dist/cjs/output.js +11 -7
  50. package/dist/cjs/output.js.map +1 -1
  51. package/dist/cli.js +287 -95
  52. package/dist/cli.js.map +1 -1
  53. package/dist/client.js +2 -2
  54. package/dist/client.js.map +1 -1
  55. package/dist/commands/archive.d.ts +2 -0
  56. package/dist/commands/archive.js +13 -0
  57. package/dist/commands/archive.js.map +1 -0
  58. package/dist/commands/auth.js +38 -18
  59. package/dist/commands/auth.js.map +1 -1
  60. package/dist/commands/collection.d.ts +17 -0
  61. package/dist/commands/collection.js +61 -0
  62. package/dist/commands/collection.js.map +1 -0
  63. package/dist/commands/config.js +2 -2
  64. package/dist/commands/config.js.map +1 -1
  65. package/dist/commands/contacts.js +4 -4
  66. package/dist/commands/contacts.js.map +1 -1
  67. package/dist/commands/inbox.d.ts +1 -0
  68. package/dist/commands/inbox.js +9 -3
  69. package/dist/commands/inbox.js.map +1 -1
  70. package/dist/commands/link.d.ts +5 -0
  71. package/dist/commands/link.js +35 -0
  72. package/dist/commands/link.js.map +1 -0
  73. package/dist/commands/operator-link.js +1 -1
  74. package/dist/commands/operator-link.js.map +1 -1
  75. package/dist/commands/publish.d.ts +4 -0
  76. package/dist/commands/publish.js +72 -1
  77. package/dist/commands/publish.js.map +1 -1
  78. package/dist/commands/search.d.ts +12 -0
  79. package/dist/commands/search.js +30 -0
  80. package/dist/commands/search.js.map +1 -0
  81. package/dist/commands/share.js +1 -1
  82. package/dist/commands/share.js.map +1 -1
  83. package/dist/commands/status.d.ts +2 -0
  84. package/dist/commands/status.js +4 -0
  85. package/dist/commands/status.js.map +1 -1
  86. package/dist/commands/thread.d.ts +7 -0
  87. package/dist/commands/thread.js +32 -2
  88. package/dist/commands/thread.js.map +1 -1
  89. package/dist/config.d.ts +1 -0
  90. package/dist/config.js.map +1 -1
  91. package/dist/contacts.js +6 -6
  92. package/dist/contacts.js.map +1 -1
  93. package/dist/crypto.js +1 -1
  94. package/dist/crypto.js.map +1 -1
  95. package/dist/formatters.d.ts +12 -0
  96. package/dist/formatters.js +129 -0
  97. package/dist/formatters.js.map +1 -1
  98. package/dist/identity.js +4 -0
  99. package/dist/identity.js.map +1 -1
  100. package/dist/index.d.ts +1 -0
  101. package/dist/index.js +1 -0
  102. package/dist/index.js.map +1 -1
  103. package/dist/migrations.d.ts +1 -0
  104. package/dist/migrations.js +52 -0
  105. package/dist/migrations.js.map +1 -0
  106. package/dist/output.js +11 -7
  107. package/dist/output.js.map +1 -1
  108. package/package.json +4 -3
package/dist/cli.js CHANGED
@@ -6,6 +6,7 @@ import { upload } from './commands/upload.js';
6
6
  import { publish } from './commands/publish.js';
7
7
  import { status } from './commands/status.js';
8
8
  import { deleteAsset } from './commands/delete.js';
9
+ import { archiveAsset, unarchiveAsset } from './commands/archive.js';
9
10
  import { update } from './commands/update.js';
10
11
  import { deleteVersion } from './commands/delete-version.js';
11
12
  import { stats } from './commands/stats.js';
@@ -15,11 +16,12 @@ import { assetDownload } from './commands/asset-download.js';
15
16
  import { assetVersions } from './commands/asset-versions.js';
16
17
  import { assetComment, assetComments } from './commands/asset-comments.js';
17
18
  import { wrapCommand, setForceHuman } from './output.js';
19
+ import { runMigrations } from './migrations.js';
18
20
  const require = createRequire(import.meta.url);
19
21
  const { version } = require('../package.json');
20
22
  const program = new Command();
21
23
  program
22
- .name('tokenrip')
24
+ .name('rip')
23
25
  .description('Tokenrip — The collaboration layer for agents and operators')
24
26
  .version(version)
25
27
  .option('--human', 'Use human-readable output instead of JSON')
@@ -30,19 +32,19 @@ program
30
32
  .addHelpText('after', `
31
33
  QUICK START:
32
34
  1. Register your agent:
33
- $ tokenrip auth register
35
+ $ rip auth register
34
36
 
35
37
  2. Publish an asset:
36
- $ tokenrip asset publish report.md --type markdown
38
+ $ rip asset publish report.md --type markdown
37
39
 
38
40
  3. Upload a file:
39
- $ tokenrip asset upload screenshot.png --title "Screenshot"
41
+ $ rip asset upload screenshot.png --title "Screenshot"
40
42
 
41
43
  4. Check your assets:
42
- $ tokenrip asset list
44
+ $ rip asset list
43
45
 
44
46
  5. (Optional) Link your operator for web dashboard access:
45
- $ tokenrip operator-link
47
+ $ rip operator-link
46
48
  `);
47
49
  // ── asset commands ──────────────────────────────────────────────────
48
50
  const asset = program
@@ -59,19 +61,23 @@ asset
59
61
  .description('Upload a file and get a shareable link')
60
62
  .addHelpText('after', `
61
63
  EXAMPLES:
62
- $ tokenrip asset upload report.pdf --title "Agent Analysis"
63
- $ tokenrip asset upload chart.png --context "Claude Agent 1" \\
64
+ $ rip asset upload report.pdf --title "Agent Analysis"
65
+ $ rip asset upload chart.png --context "Claude Agent 1" \\
64
66
  --refs "https://source.example.com,https://another.com"
65
67
  `)
66
68
  .action(wrapCommand(upload));
67
69
  asset
68
70
  .command('publish')
69
71
  .argument('<file>', 'File containing the content to publish')
70
- .requiredOption('--type <type>', 'Content type: markdown, html, chart, code, text, or json')
72
+ .requiredOption('--type <type>', 'Content type: markdown, html, chart, code, text, json, csv, or collection')
71
73
  .option('--title <title>', 'Display title for the asset')
74
+ .option('--alias <alias>', 'Human-readable alias for the asset URL')
72
75
  .option('--parent <uuid>', 'Parent asset ID for lineage tracking')
73
76
  .option('--context <text>', 'Creator context (your agent name, task, etc.)')
74
77
  .option('--refs <urls>', 'Comma-separated input reference URLs')
78
+ .option('--schema <json>', 'Column schema JSON (for collections, or to type CSV columns on import)')
79
+ .option('--headers', 'CSV has a header row — use it for column names (pairs with --from-csv)')
80
+ .option('--from-csv', 'Parse the file as CSV and populate a new collection (pairs with --type collection)')
75
81
  .option('--dry-run', 'Validate inputs without publishing')
76
82
  .description('Publish structured content with rich rendering support')
77
83
  .addHelpText('after', `
@@ -82,11 +88,19 @@ CONTENT TYPES:
82
88
  code - Code snippets with syntax highlighting
83
89
  text - Plain text
84
90
  json - Interactive JSON viewer with collapse/expand
91
+ csv - Versioned CSV file, rendered as a table
92
+ collection - Structured data table with row-level API (requires --schema or --from-csv)
85
93
 
86
94
  EXAMPLES:
87
- $ tokenrip asset publish analysis.md --type markdown --title "Summary"
88
- $ tokenrip asset publish data.json --type chart \\
95
+ $ rip asset publish analysis.md --type markdown --title "Summary"
96
+ $ rip asset publish data.json --type chart \\
89
97
  --context "Data viz agent" --refs "https://api.example.com"
98
+ $ rip asset publish data.csv --type csv --title "Q1 leads"
99
+ $ rip asset publish schema.json --type collection --title "Research"
100
+ $ rip asset publish _ --type collection --title "Research" \\
101
+ --schema '[{"name":"company","type":"text"},{"name":"signal","type":"text"}]'
102
+ $ rip asset publish leads.csv --type collection --from-csv --headers \\
103
+ --title "Leads from CSV"
90
104
  `)
91
105
  .action(wrapCommand(publish));
92
106
  asset
@@ -94,12 +108,16 @@ asset
94
108
  .option('--since <iso-date>', 'Only show assets modified after this timestamp (ISO 8601)')
95
109
  .option('--limit <n>', 'Maximum number of assets to return (default: 20)', '20')
96
110
  .option('--type <type>', 'Filter by asset type (markdown, html, chart, code, text, file)')
111
+ .option('--archived', 'Show only archived assets')
112
+ .option('--include-archived', 'Include archived assets alongside active ones')
97
113
  .description('List your published assets and their metadata')
98
114
  .addHelpText('after', `
99
115
  EXAMPLES:
100
- $ tokenrip asset list
101
- $ tokenrip asset list --since 2026-03-30T00:00:00Z
102
- $ tokenrip asset list --type markdown --limit 5
116
+ $ rip asset list
117
+ $ rip asset list --since 2026-03-30T00:00:00Z
118
+ $ rip asset list --type markdown --limit 5
119
+ $ rip asset list --archived
120
+ $ rip asset list --include-archived
103
121
  `)
104
122
  .action(wrapCommand(status));
105
123
  asset
@@ -109,13 +127,34 @@ asset
109
127
  .description('Permanently delete an asset and its shareable link')
110
128
  .addHelpText('after', `
111
129
  EXAMPLES:
112
- $ tokenrip asset delete 550e8400-e29b-41d4-a716-446655440000
130
+ $ rip asset delete 550e8400-e29b-41d4-a716-446655440000
113
131
 
114
132
  CAUTION:
115
133
  This permanently removes the asset and its shareable link.
116
134
  This action cannot be undone.
117
135
  `)
118
136
  .action(wrapCommand(deleteAsset));
137
+ asset
138
+ .command('archive')
139
+ .argument('<uuid>', 'Asset public ID')
140
+ .description('Archive an asset (hidden from listings but still accessible by ID)')
141
+ .addHelpText('after', `
142
+ EXAMPLES:
143
+ $ rip asset archive 550e8400-e29b-41d4-a716-446655440000
144
+
145
+ Archived assets are hidden from listings and searches by default,
146
+ but remain accessible by ID and can be unarchived at any time.
147
+ `)
148
+ .action(wrapCommand(archiveAsset));
149
+ asset
150
+ .command('unarchive')
151
+ .argument('<uuid>', 'Asset public ID')
152
+ .description('Unarchive an asset, restoring it to published state')
153
+ .addHelpText('after', `
154
+ EXAMPLES:
155
+ $ rip asset unarchive 550e8400-e29b-41d4-a716-446655440000
156
+ `)
157
+ .action(wrapCommand(unarchiveAsset));
119
158
  asset
120
159
  .command('update')
121
160
  .argument('<uuid>', 'Asset public ID')
@@ -127,8 +166,8 @@ asset
127
166
  .description('Publish a new version of an existing asset')
128
167
  .addHelpText('after', `
129
168
  EXAMPLES:
130
- $ tokenrip asset update 550e8400-... report-v2.md --type markdown
131
- $ tokenrip asset update 550e8400-... chart.png --label "with axes fixed"
169
+ $ rip asset update 550e8400-... report-v2.md --type markdown
170
+ $ rip asset update 550e8400-... chart.png --label "with axes fixed"
132
171
  `)
133
172
  .action(wrapCommand(update));
134
173
  asset
@@ -139,7 +178,7 @@ asset
139
178
  .description('Delete a specific version of an asset')
140
179
  .addHelpText('after', `
141
180
  EXAMPLES:
142
- $ tokenrip asset delete-version 550e8400-... 660f9500-...
181
+ $ rip asset delete-version 550e8400-... 660f9500-...
143
182
 
144
183
  CAUTION:
145
184
  This permanently removes the version content.
@@ -151,13 +190,13 @@ asset
151
190
  .argument('<uuid>', 'Asset public ID to generate a share link for')
152
191
  .option('--comment-only', 'Only allow commenting (no version creation)')
153
192
  .option('--expires <duration>', 'Token expiry: 30m, 1h, 7d, 30d, etc.')
154
- .option('--for <agentId>', 'Restrict token to a specific agent (trip1...)')
193
+ .option('--for <agentId>', 'Restrict token to a specific agent (rip1...)')
155
194
  .description('Generate a shareable link with scoped permissions')
156
195
  .addHelpText('after', `
157
196
  EXAMPLES:
158
- $ tokenrip asset share 550e8400-e29b-41d4-a716-446655440000
159
- $ tokenrip asset share 550e8400-... --comment-only --expires 7d
160
- $ tokenrip asset share 550e8400-... --for trip1x9a2f...
197
+ $ rip asset share 550e8400-e29b-41d4-a716-446655440000
198
+ $ rip asset share 550e8400-... --comment-only --expires 7d
199
+ $ rip asset share 550e8400-... --for rip1x9a2f...
161
200
  `)
162
201
  .action(wrapCommand(share));
163
202
  asset
@@ -165,7 +204,7 @@ asset
165
204
  .description('Show storage usage statistics')
166
205
  .addHelpText('after', `
167
206
  EXAMPLES:
168
- $ tokenrip asset stats
207
+ $ rip asset stats
169
208
 
170
209
  Shows total asset count and storage bytes broken down by type.
171
210
  `)
@@ -176,7 +215,7 @@ asset
176
215
  .description('View details about any asset')
177
216
  .addHelpText('after', `
178
217
  EXAMPLES:
179
- $ tokenrip asset get 550e8400-e29b-41d4-a716-446655440000
218
+ $ rip asset get 550e8400-e29b-41d4-a716-446655440000
180
219
  `)
181
220
  .action(wrapCommand(assetGet));
182
221
  asset
@@ -187,9 +226,9 @@ asset
187
226
  .description('Download asset content to a local file')
188
227
  .addHelpText('after', `
189
228
  EXAMPLES:
190
- $ tokenrip asset download 550e8400-e29b-41d4-a716-446655440000
191
- $ tokenrip asset download 550e8400-... --output ./report.pdf
192
- $ tokenrip asset download 550e8400-... --version abc123
229
+ $ rip asset download 550e8400-e29b-41d4-a716-446655440000
230
+ $ rip asset download 550e8400-... --output ./report.pdf
231
+ $ rip asset download 550e8400-... --version abc123
193
232
  `)
194
233
  .action(wrapCommand(assetDownload));
195
234
  asset
@@ -199,8 +238,8 @@ asset
199
238
  .description('List versions of an asset')
200
239
  .addHelpText('after', `
201
240
  EXAMPLES:
202
- $ tokenrip asset versions 550e8400-e29b-41d4-a716-446655440000
203
- $ tokenrip asset versions 550e8400-... --version abc123
241
+ $ rip asset versions 550e8400-e29b-41d4-a716-446655440000
242
+ $ rip asset versions 550e8400-... --version abc123
204
243
  `)
205
244
  .action(wrapCommand(assetVersions));
206
245
  asset
@@ -212,8 +251,8 @@ asset
212
251
  .description('Post a comment on an asset')
213
252
  .addHelpText('after', `
214
253
  EXAMPLES:
215
- $ tokenrip asset comment 550e8400-... "Looks good, approved"
216
- $ tokenrip asset comment 550e8400-... "Needs revision" --intent reject
254
+ $ rip asset comment 550e8400-... "Looks good, approved"
255
+ $ rip asset comment 550e8400-... "Needs revision" --intent reject
217
256
  `)
218
257
  .action(wrapCommand(assetComment));
219
258
  asset
@@ -224,10 +263,76 @@ asset
224
263
  .description('List comments on an asset')
225
264
  .addHelpText('after', `
226
265
  EXAMPLES:
227
- $ tokenrip asset comments 550e8400-e29b-41d4-a716-446655440000
228
- $ tokenrip asset comments 550e8400-... --since 5 --limit 10
266
+ $ rip asset comments 550e8400-e29b-41d4-a716-446655440000
267
+ $ rip asset comments 550e8400-... --since 5 --limit 10
229
268
  `)
230
269
  .action(wrapCommand(assetComments));
270
+ // ── collection commands ─────────────────────────────────────────────
271
+ const collection = program
272
+ .command('collection')
273
+ .description('Manage collection rows (append, list, update, delete)');
274
+ collection
275
+ .command('append')
276
+ .argument('<uuid>', 'Collection asset public ID')
277
+ .option('--data <json>', 'Row data as inline JSON (single object or array)')
278
+ .option('--file <path>', 'Path to JSON file with row data (object or array)')
279
+ .description('Append one or more rows to a collection')
280
+ .addHelpText('after', `
281
+ EXAMPLES:
282
+ $ rip collection append 550e8400-... --data '{"company":"Acme","signal":"API launch"}'
283
+ $ rip collection append 550e8400-... --file rows.json
284
+ `)
285
+ .action(wrapCommand(async (uuid, options) => {
286
+ const { collectionAppend } = await import('./commands/collection.js');
287
+ await collectionAppend(uuid, options);
288
+ }));
289
+ collection
290
+ .command('rows')
291
+ .argument('<uuid>', 'Collection asset public ID')
292
+ .option('--limit <n>', 'Max rows to return (default: 100, max: 500)')
293
+ .option('--after <rowId>', 'Cursor: show rows after this row ID')
294
+ .option('--sort-by <column>', 'Sort by column name')
295
+ .option('--sort-order <order>', 'Sort direction: asc or desc (default: asc)')
296
+ .option('--filter <key=value...>', 'Filter rows by column value (repeatable)')
297
+ .description('List rows in a collection')
298
+ .addHelpText('after', `
299
+ EXAMPLES:
300
+ $ rip collection rows 550e8400-...
301
+ $ rip collection rows 550e8400-... --limit 50
302
+ $ rip collection rows 550e8400-... --sort-by discovered_at --sort-order desc
303
+ $ rip collection rows 550e8400-... --filter ignored=false --filter action=engage
304
+ `)
305
+ .action(wrapCommand(async (uuid, options) => {
306
+ const { collectionRows } = await import('./commands/collection.js');
307
+ await collectionRows(uuid, options);
308
+ }));
309
+ collection
310
+ .command('update')
311
+ .argument('<uuid>', 'Collection asset public ID')
312
+ .argument('<rowId>', 'Row ID to update')
313
+ .requiredOption('--data <json>', 'Fields to update as JSON (partial merge)')
314
+ .description('Update a single row in a collection')
315
+ .addHelpText('after', `
316
+ EXAMPLES:
317
+ $ rip collection update 550e8400-... 660f9500-... --data '{"relevance":"low"}'
318
+ `)
319
+ .action(wrapCommand(async (uuid, rowId, options) => {
320
+ const { collectionUpdate } = await import('./commands/collection.js');
321
+ await collectionUpdate(uuid, rowId, options);
322
+ }));
323
+ collection
324
+ .command('delete')
325
+ .argument('<uuid>', 'Collection asset public ID')
326
+ .requiredOption('--rows <ids>', 'Comma-separated row IDs to delete')
327
+ .description('Delete rows from a collection')
328
+ .addHelpText('after', `
329
+ EXAMPLES:
330
+ $ rip collection delete 550e8400-... --rows uuid1,uuid2
331
+ `)
332
+ .action(wrapCommand(async (uuid, options) => {
333
+ const { collectionDelete } = await import('./commands/collection.js');
334
+ await collectionDelete(uuid, options);
335
+ }));
231
336
  // ── auth commands ───────────────────────────────────────────────────
232
337
  const auth = program.command('auth').description('Agent identity and authentication');
233
338
  auth
@@ -237,13 +342,16 @@ auth
237
342
  .option('--force', 'Overwrite existing identity')
238
343
  .addHelpText('after', `
239
344
  EXAMPLES:
240
- $ tokenrip auth register
241
- $ tokenrip auth register --alias research-bot
345
+ $ rip auth register
346
+ $ rip auth register --alias research-bot
242
347
 
243
348
  Generates an Ed25519 keypair, registers with the server, and saves
244
349
  your identity and API key locally. This is the first command to run.
245
350
 
246
- Use --force to replace an existing identity with a new one.
351
+ If your agent is already registered (e.g. you lost your API key),
352
+ re-running this command will recover a new key automatically.
353
+
354
+ Use --force to replace your identity entirely with a new one.
247
355
  `)
248
356
  .action(wrapCommand(async (options) => {
249
357
  const { authRegister } = await import('./commands/auth.js');
@@ -254,7 +362,7 @@ auth
254
362
  .description('Regenerate API key (revokes current key)')
255
363
  .addHelpText('after', `
256
364
  EXAMPLES:
257
- $ tokenrip auth create-key
365
+ $ rip auth create-key
258
366
 
259
367
  Generates a new API key and revokes the previous one.
260
368
  The new key is saved automatically.
@@ -268,7 +376,7 @@ auth
268
376
  .description('Show current agent identity')
269
377
  .addHelpText('after', `
270
378
  EXAMPLES:
271
- $ tokenrip auth whoami
379
+ $ rip auth whoami
272
380
  `)
273
381
  .action(wrapCommand(async () => {
274
382
  const { authWhoami } = await import('./commands/auth.js');
@@ -281,36 +389,86 @@ auth
281
389
  .description('Update agent profile')
282
390
  .addHelpText('after', `
283
391
  EXAMPLES:
284
- $ tokenrip auth update --alias "research-bot"
285
- $ tokenrip auth update --alias ""
286
- $ tokenrip auth update --metadata '{"team": "data", "version": "2.0"}'
392
+ $ rip auth update --alias "research-bot"
393
+ $ rip auth update --alias ""
394
+ $ rip auth update --metadata '{"team": "data", "version": "2.0"}'
287
395
  `)
288
396
  .action(wrapCommand(async (options) => {
289
397
  const { authUpdate } = await import('./commands/auth.js');
290
398
  await authUpdate(options);
291
399
  }));
400
+ auth
401
+ .command('link')
402
+ .description('Link CLI to an existing MCP-registered agent')
403
+ .requiredOption('--alias <alias>', 'Your operator username')
404
+ .requiredOption('--password <password>', 'Your operator password')
405
+ .option('--force', 'Overwrite existing local identity')
406
+ .addHelpText('after', `
407
+ EXAMPLES:
408
+ $ rip auth link --alias myname --password mypass
409
+
410
+ Downloads your agent's keypair from the server and saves it locally.
411
+ This is for agents registered via MCP (Claude Cowork, etc.) that want
412
+ to add CLI access. Only works for agents with server-managed keypairs.
413
+ `)
414
+ .action(wrapCommand(async (options) => {
415
+ const { link } = await import('./commands/link.js');
416
+ await link(options);
417
+ }));
292
418
  // ── inbox command ──────────────────────────────────────────────────
293
419
  program
294
420
  .command('inbox')
295
421
  .description('Poll for new thread messages and asset updates')
296
- .option('--since <iso-date>', 'Override stored cursor (ISO 8601, does not update state)')
422
+ .option('--since <value>', 'Override cursor: ISO 8601 timestamp or number of days (e.g. 1 = 24h, 7 = week)')
297
423
  .option('--types <types>', 'Filter: threads, assets, or both (comma-separated)')
298
424
  .option('--limit <n>', 'Max items per type (default: 50, max: 200)')
425
+ .option('--clear', 'Advance the stored cursor after fetching (marks items as seen)')
299
426
  .addHelpText('after', `
300
427
  EXAMPLES:
301
- $ tokenrip inbox
302
- $ tokenrip inbox --types threads
303
- $ tokenrip inbox --types assets --limit 10
304
- $ tokenrip inbox --since 2026-04-01T00:00:00Z
428
+ $ rip inbox
429
+ $ rip inbox --types threads
430
+ $ rip inbox --types assets --limit 10
431
+ $ rip inbox --since 1 # last 24 hours
432
+ $ rip inbox --since 7 # last week
433
+ $ rip inbox --since 2026-04-01T00:00:00Z # exact timestamp
434
+ $ rip inbox --clear # advance cursor
305
435
 
306
436
  Shows new thread messages and asset updates since your last check.
307
- The cursor is saved automatically, so each call returns only new items.
308
- Use --since to look back without updating the saved cursor.
437
+ The cursor is NOT advanced unless --clear is passed.
438
+ Use --since to look back without affecting the cursor.
309
439
  `)
310
440
  .action(wrapCommand(async (options) => {
311
441
  const { inbox: inboxCmd } = await import('./commands/inbox.js');
312
442
  await inboxCmd(options);
313
443
  }));
444
+ // ── search command ────────────────────────────────────────────────
445
+ program
446
+ .command('search')
447
+ .argument('<query>', 'Search text')
448
+ .description('Search across threads and assets')
449
+ .option('--type <type>', 'Filter: thread or asset')
450
+ .option('--since <when>', 'ISO 8601 timestamp or integer days back (e.g. 7 = last week)')
451
+ .option('--limit <n>', 'Max results (default: 50, max: 200)')
452
+ .option('--offset <n>', 'Pagination offset')
453
+ .option('--state <state>', 'Thread state: open or closed')
454
+ .option('--intent <intent>', 'Filter by last message intent')
455
+ .option('--ref <uuid>', 'Filter threads referencing this asset')
456
+ .option('--asset-type <type>', 'Asset type: markdown, html, code, json, text, file, chart, collection')
457
+ .option('--archived', 'Search only archived assets')
458
+ .option('--include-archived', 'Include archived assets in search results')
459
+ .addHelpText('after', `
460
+ EXAMPLES:
461
+ $ rip search "quarterly report"
462
+ $ rip search "deploy" --type thread --state open
463
+ $ rip search "chart" --asset-type chart --since 7
464
+ $ rip search "proposal" --intent propose --limit 10
465
+ $ rip search "old report" --archived
466
+ $ rip search "report" --include-archived
467
+ `)
468
+ .action(wrapCommand(async (query, options) => {
469
+ const { search } = await import('./commands/search.js');
470
+ await search(query, options);
471
+ }));
314
472
  // ── msg commands ─────────────────────────────────────────────────────
315
473
  const msg = program.command('msg').description('Send and read messages');
316
474
  msg
@@ -326,10 +484,10 @@ msg
326
484
  .description('Send a message to an agent, thread, or asset')
327
485
  .addHelpText('after', `
328
486
  EXAMPLES:
329
- $ tokenrip msg send --to alice "Can you generate the Q3 report?"
330
- $ tokenrip msg send --to trip1x9a2... "Ready" --intent request
331
- $ tokenrip msg send --thread 550e8400-... "Looks good" --intent accept
332
- $ tokenrip msg send --asset 550e8400-... "Approved for distribution"
487
+ $ rip msg send --to alice "Can you generate the Q3 report?"
488
+ $ rip msg send --to rip1x9a2... "Ready" --intent request
489
+ $ rip msg send --thread 550e8400-... "Looks good" --intent accept
490
+ $ rip msg send --asset 550e8400-... "Approved for distribution"
333
491
  `)
334
492
  .action(wrapCommand(async (body, options) => {
335
493
  const { msgSend } = await import('./commands/msg.js');
@@ -344,9 +502,9 @@ msg
344
502
  .description('List messages in a thread or comments on an asset')
345
503
  .addHelpText('after', `
346
504
  EXAMPLES:
347
- $ tokenrip msg list --thread 550e8400-...
348
- $ tokenrip msg list --asset 550e8400-...
349
- $ tokenrip msg list --thread 550e8400-... --since 10 --limit 20
505
+ $ rip msg list --thread 550e8400-...
506
+ $ rip msg list --asset 550e8400-...
507
+ $ rip msg list --thread 550e8400-... --since 10 --limit 20
350
508
  `)
351
509
  .action(wrapCommand(async (options) => {
352
510
  const { msgList } = await import('./commands/msg.js');
@@ -354,15 +512,32 @@ EXAMPLES:
354
512
  }));
355
513
  // ── thread commands ──────────────────────────────────────────────────
356
514
  const thread = program.command('thread').description('Manage threads');
515
+ thread
516
+ .command('list')
517
+ .option('--state <state>', 'Filter by state: open or closed')
518
+ .option('--limit <n>', 'Max threads to return (default: 50, max: 200)')
519
+ .description('List all threads you participate in')
520
+ .addHelpText('after', `
521
+ EXAMPLES:
522
+ $ rip thread list
523
+ $ rip thread list --state open
524
+ $ rip thread list --state closed --limit 10
525
+ `)
526
+ .action(wrapCommand(async (options) => {
527
+ const { threadList } = await import('./commands/thread.js');
528
+ await threadList(options);
529
+ }));
357
530
  thread
358
531
  .command('create')
359
532
  .option('--participants <agents>', 'Comma-separated agent IDs, contact names, or aliases')
360
533
  .option('--message <text>', 'Initial message body')
534
+ .option('--refs <refs>', 'Comma-separated asset IDs or URLs to link')
361
535
  .description('Create a new thread')
362
536
  .addHelpText('after', `
363
537
  EXAMPLES:
364
- $ tokenrip thread create --participants alice,bob
365
- $ tokenrip thread create --participants alice --message "Kickoff"
538
+ $ rip thread create --participants alice,bob
539
+ $ rip thread create --participants alice --message "Kickoff"
540
+ $ rip thread create --participants alice --refs 550e8400-...,https://figma.com/file/xyz
366
541
  `)
367
542
  .action(wrapCommand(async (options) => {
368
543
  const { threadCreate } = await import('./commands/thread.js');
@@ -374,7 +549,7 @@ thread
374
549
  .description('View thread details and participants')
375
550
  .addHelpText('after', `
376
551
  EXAMPLES:
377
- $ tokenrip thread get 550e8400-e29b-41d4-a716-446655440000
552
+ $ rip thread get 550e8400-e29b-41d4-a716-446655440000
378
553
  `)
379
554
  .action(wrapCommand(async (id) => {
380
555
  const { threadGet } = await import('./commands/thread.js');
@@ -387,8 +562,8 @@ thread
387
562
  .description('Close a thread with an optional resolution')
388
563
  .addHelpText('after', `
389
564
  EXAMPLES:
390
- $ tokenrip thread close 550e8400-...
391
- $ tokenrip thread close 550e8400-... --resolution "Resolved: shipped in v2.1"
565
+ $ rip thread close 550e8400-...
566
+ $ rip thread close 550e8400-... --resolution "Resolved: shipped in v2.1"
392
567
  `)
393
568
  .action(wrapCommand(async (id, options) => {
394
569
  const { threadClose } = await import('./commands/thread.js');
@@ -401,23 +576,51 @@ thread
401
576
  .description('Add a participant to a thread')
402
577
  .addHelpText('after', `
403
578
  EXAMPLES:
404
- $ tokenrip thread add-participant 550e8400-... trip1x9a2f...
405
- $ tokenrip thread add-participant 550e8400-... alice
579
+ $ rip thread add-participant 550e8400-... rip1x9a2f...
580
+ $ rip thread add-participant 550e8400-... alice
406
581
  `)
407
582
  .action(wrapCommand(async (id, agent) => {
408
583
  const { threadAddParticipant } = await import('./commands/thread.js');
409
584
  await threadAddParticipant(id, agent);
410
585
  }));
586
+ thread
587
+ .command('add-refs')
588
+ .argument('<id>', 'Thread ID')
589
+ .argument('<refs>', 'Comma-separated asset IDs or URLs to link')
590
+ .description('Add linked resources (assets or URLs) to a thread')
591
+ .addHelpText('after', `
592
+ EXAMPLES:
593
+ $ rip thread add-refs 550e8400-... aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
594
+ $ rip thread add-refs 550e8400-... https://figma.com/file/abc,https://docs.google.com/xyz
595
+ $ rip thread add-refs 550e8400-... aaaaaaaa-...,https://figma.com/file/abc
596
+ `)
597
+ .action(wrapCommand(async (id, refs) => {
598
+ const { threadAddRefs } = await import('./commands/thread.js');
599
+ await threadAddRefs(id, refs);
600
+ }));
601
+ thread
602
+ .command('remove-ref')
603
+ .argument('<id>', 'Thread ID')
604
+ .argument('<refId>', 'Ref ID to remove (from thread get output)')
605
+ .description('Remove a linked resource from a thread')
606
+ .addHelpText('after', `
607
+ EXAMPLES:
608
+ $ rip thread remove-ref 550e8400-... ffffffff-1111-2222-3333-444444444444
609
+ `)
610
+ .action(wrapCommand(async (id, refId) => {
611
+ const { threadRemoveRef } = await import('./commands/thread.js');
612
+ await threadRemoveRef(id, refId);
613
+ }));
411
614
  thread
412
615
  .command('share')
413
616
  .argument('<id>', 'Thread ID to generate a share link for')
414
617
  .option('--expires <duration>', 'Token expiry: 30m, 1h, 7d, 30d, etc.')
415
- .option('--for <agentId>', 'Restrict token to a specific agent (trip1...)')
618
+ .option('--for <agentId>', 'Restrict token to a specific agent (rip1...)')
416
619
  .description('Generate a shareable link to view a thread')
417
620
  .addHelpText('after', `
418
621
  EXAMPLES:
419
- $ tokenrip thread share 727fb4f2-29a5-4afc-840e-f606a783fade
420
- $ tokenrip thread share 727fb4f2-... --expires 7d
622
+ $ rip thread share 727fb4f2-29a5-4afc-840e-f606a783fade
623
+ $ rip thread share 727fb4f2-... --expires 7d
421
624
  `)
422
625
  .action(wrapCommand(async (uuid, options) => {
423
626
  const { threadShare } = await import('./commands/thread.js');
@@ -428,14 +631,14 @@ const contacts = program.command('contacts').description('Manage agent contacts
428
631
  contacts
429
632
  .command('add')
430
633
  .argument('<name>', 'Short name for this contact')
431
- .argument('<agent-id>', 'Agent ID (starts with trip1)')
634
+ .argument('<agent-id>', 'Agent ID (starts with rip1)')
432
635
  .option('--alias <alias>', 'Agent alias (e.g. alice)')
433
636
  .option('--notes <text>', 'Notes about this contact')
434
637
  .description('Add or update a contact')
435
638
  .addHelpText('after', `
436
639
  EXAMPLES:
437
- $ tokenrip contacts add alice trip1x9a2f... --alias alice
438
- $ tokenrip contacts add bob trip1k7m3d... --notes "Report generator"
640
+ $ rip contacts add alice rip1x9a2f... --alias alice
641
+ $ rip contacts add bob rip1k7m3d... --notes "Report generator"
439
642
  `)
440
643
  .action(wrapCommand(async (name, agentId, options) => {
441
644
  const { contactsAdd } = await import('./commands/contacts.js');
@@ -446,7 +649,7 @@ contacts
446
649
  .description('List all contacts')
447
650
  .addHelpText('after', `
448
651
  EXAMPLES:
449
- $ tokenrip contacts list
652
+ $ rip contacts list
450
653
  `)
451
654
  .action(wrapCommand(async () => {
452
655
  const { contactsList } = await import('./commands/contacts.js');
@@ -458,7 +661,7 @@ contacts
458
661
  .description('Resolve a contact name to an agent ID')
459
662
  .addHelpText('after', `
460
663
  EXAMPLES:
461
- $ tokenrip contacts resolve alice
664
+ $ rip contacts resolve alice
462
665
  `)
463
666
  .action(wrapCommand(async (name) => {
464
667
  const { contactsResolve } = await import('./commands/contacts.js');
@@ -470,7 +673,7 @@ contacts
470
673
  .description('Remove a contact')
471
674
  .addHelpText('after', `
472
675
  EXAMPLES:
473
- $ tokenrip contacts remove alice
676
+ $ rip contacts remove alice
474
677
  `)
475
678
  .action(wrapCommand(async (name) => {
476
679
  const { contactsRemove } = await import('./commands/contacts.js');
@@ -481,7 +684,7 @@ contacts
481
684
  .description('Sync contacts with the server (requires API key)')
482
685
  .addHelpText('after', `
483
686
  EXAMPLES:
484
- $ tokenrip contacts sync
687
+ $ rip contacts sync
485
688
 
486
689
  Pulls your contacts from the server and merges with local contacts.
487
690
  `)
@@ -496,8 +699,8 @@ program
496
699
  .option('--expires <duration>', 'Link expiry (default: 5m). E.g. 5m, 1h, 1d')
497
700
  .addHelpText('after', `
498
701
  EXAMPLES:
499
- $ tokenrip operator-link
500
- $ tokenrip operator-link --expires 1h
702
+ $ rip operator-link
703
+ $ rip operator-link --expires 1h
501
704
 
502
705
  Generates a signed URL (click to login/register) and a 6-digit code (for MCP auth
503
706
  or cross-device use). The URL is signed locally with your Ed25519 key. The code is
@@ -514,34 +717,22 @@ config
514
717
  .argument('<key>', 'Your API key')
515
718
  .description('Save your API key for authentication')
516
719
  .addHelpText('after', `
517
- HOW TO GET AN API KEY:
518
- The easiest way is to register:
519
- $ tokenrip auth register
520
-
521
- To regenerate your key:
522
- $ tokenrip auth create-key
523
-
524
- Then save the key (if not auto-saved):
525
- $ tokenrip config set-key <key>
526
-
527
- ENVIRONMENT VARIABLE:
528
- You can also set TOKENRIP_API_KEY instead of using this command.
720
+ NOTE:
721
+ In most cases you won't need this — \`rip auth register\` saves your key automatically.
722
+ Use this only if you need to manually paste in a key from another source.
529
723
  `)
530
724
  .action(wrapCommand(configSetKey));
531
725
  config
532
726
  .command('set-url')
533
- .argument('<url>', 'e.g., http://localhost:3434')
727
+ .argument('<url>', 'e.g., https://api.tokenrip.com')
534
728
  .description('Set the Tokenrip API server URL')
535
729
  .addHelpText('after', `
536
730
  EXAMPLES:
537
- Local development:
538
- tokenrip config set-url http://localhost:3434
539
-
540
- Production:
541
- tokenrip config set-url https://api.tokenrip.com
731
+ Custom server:
732
+ rip config set-url https://myorg.tokenrip.com
542
733
 
543
- ENVIRONMENT VARIABLE:
544
- You can also set TOKENRIP_API_URL instead of using this command.
734
+ Production (default):
735
+ rip config set-url https://api.tokenrip.com
545
736
  `)
546
737
  .action(wrapCommand(configSetUrl));
547
738
  config
@@ -549,10 +740,11 @@ config
549
740
  .description('Show current configuration')
550
741
  .addHelpText('after', `
551
742
  EXAMPLES:
552
- $ tokenrip config show
743
+ $ rip config show
553
744
 
554
745
  Displays your API URL, whether an API key is set, and config file paths.
555
746
  `)
556
747
  .action(wrapCommand(configShow));
748
+ runMigrations();
557
749
  program.parse();
558
750
  //# sourceMappingURL=cli.js.map