@uru-intelligence/cli 0.3.54 → 0.3.55

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 +8 -0
  2. package/dist/uru.mjs +149 -29
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -54,6 +54,14 @@ bun src/index.ts gems write 'library/Golden Gems/My Gem.gem' main.html --file ./
54
54
  bun src/index.ts library ls library
55
55
  bun src/index.ts library search revenue
56
56
  bun src/index.ts library mkdir 'library/Golden Gems'
57
+ bun src/index.ts library read 'library/Contexts/Client Brief.md'
58
+ bun src/index.ts library write 'library/Contexts/Client Brief.md' --file ./brief.md --create
59
+ bun src/index.ts library write 'library/Prompts/Sales Email.md' --content "Draft the follow-up." --create
60
+ bun src/index.ts library patch 'library/Prompts/Sales Email.md' --stdin
61
+ bun src/index.ts library cp 'library/Notes/Brief.md' 'library/Archive/Brief.md'
62
+ bun src/index.ts library mv 'library/Notes/Draft.md' 'library/Notes/Final.md'
63
+ bun src/index.ts library rm 'library/Notes/Old.md'
64
+ bun src/index.ts library restore 'library/Notes/Old.md'
57
65
  bun src/index.ts datasets query revenue_rows --limit 50 --response-format concise --json
58
66
  bun src/index.ts datasets get --params-json '{"dataset_id":"revenue_rows"}'
59
67
  bun src/index.ts datasets rows-upsert --params-json '{"dataset_id":"revenue_rows","rows":[{"name":"Acme"}]}'
package/dist/uru.mjs CHANGED
@@ -6,7 +6,7 @@ import { spawn as spawn3 } from "node:child_process";
6
6
 
7
7
  // src/types.ts
8
8
  var DEFAULT_API_URL = "https://api.uruintelligence.com";
9
- var CLI_VERSION = "0.3.54";
9
+ var CLI_VERSION = "0.3.55";
10
10
  var ExitCode = {
11
11
  Ok: 0,
12
12
  Failure: 1,
@@ -241,8 +241,12 @@ function buildOperationGroups(op) {
241
241
  const libraryOperations = [
242
242
  op("library.ls", "library", "List visible Library folders and resources.", "library_query", "ls", "read"),
243
243
  op("library.stat", "library", "Read metadata for a visible Library path.", "library_query", "stat", "read"),
244
+ op("library.read", "library", "Read a visible text-backed Library resource by path.", "library_query", "read", "read"),
244
245
  op("library.search", "library", "Search visible Library resources server-side.", "library_query", "search", "read"),
245
246
  op("library.mkdir", "library", "Create a Library folder.", "library_fs", "mkdir", "write"),
247
+ op("library.write", "library", "Create or replace a text-backed Library resource by path.", "library_fs", "write", "write"),
248
+ op("library.patch", "library", "Replace text content for a text-backed Library resource by path.", "library_fs", "patch", "write"),
249
+ op("library.cp", "library", "Copy a supported Library item when the backing resource supports copy semantics.", "library_fs", "cp", "write"),
246
250
  op("library.mv", "library", "Move or rename a Library item.", "library_fs", "mv", "write"),
247
251
  op("library.move_workspace", "library", "Move a Library item to another workspace.", "library_fs", "move_workspace", "destructive"),
248
252
  op("library.rm", "library", "Trash a Library item.", "library_fs", "rm", "destructive"),
@@ -250,10 +254,7 @@ function buildOperationGroups(op) {
250
254
  op("library.empty_trash", "library", "Permanently empty Library trash.", "library_fs", "empty_trash", "destructive"),
251
255
  op("library.upload_preflight", "library", "Preflight a Library upload.", "library_upload", "preflight", "read"),
252
256
  op("library.upload_create_session", "library", "Create a direct Library upload session.", "library_upload", "create_session", "write"),
253
- op("library.upload_complete_session", "library", "Complete a direct Library upload session.", "library_upload", "complete_session", "write"),
254
- op("context.manage", "library", "Manage typed Context Library metadata such as workspace-default, teams, category, and favorite state.", "context_manage", undefined, "write"),
255
- op("prompt.render", "library", "Render a typed Prompt Library resource with supplied variables.", "prompt_render", undefined, "read"),
256
- op("persona.query", "library", "Query typed Persona Library resources and linked prompt/context resources.", "persona_query", undefined, "read")
257
+ op("library.upload_complete_session", "library", "Complete a direct Library upload session.", "library_upload", "complete_session", "write")
257
258
  ];
258
259
  const sharingOperations = [
259
260
  op("sharing.share", "sharing", "Share a Library resource with a user, team, or workspace.", "library_collab", "share", "write"),
@@ -416,7 +417,7 @@ function buildOperationGroups(op) {
416
417
  op("file.download_for_user", "files", "Prepare a file download for the user.", "DOWNLOAD_FILE_FOR_USER", undefined, "read")
417
418
  ];
418
419
  const businessSqlOperations = [
419
- op("business_sql.transcript", "business_sql", "Query transcript SQL.", "TRANSCRIPT_SQL", undefined, "read"),
420
+ op("business_sql.transcript", "business_sql", "Query transcript SQL.", "transcript_sql", undefined, "read"),
420
421
  op("business_sql.maguire", "business_sql", "Query Maguire SQL.", "MAGUIRE_SQL", undefined, "read"),
421
422
  op("business_sql.tyler", "business_sql", "Query Tyler SQL.", "TYLER_SQL", undefined, "read"),
422
423
  op("business_sql.cfo", "business_sql", "Query CFO SQL.", "CFO_SQL", undefined, "read"),
@@ -473,7 +474,6 @@ var internalOnlyPlatformToolIds = new Set([
473
474
  "MAGUIRE_WRITE_SQL",
474
475
  "PEREGRINE_SQL",
475
476
  "RESTORE_DATASET_ROWS",
476
- "TRANSCRIPT_SQL",
477
477
  "TYLER_SQL",
478
478
  "UPSERT_DATASET_ROWS"
479
479
  ]);
@@ -1184,6 +1184,12 @@ LIBRARY / DATASETS / TOOLS
1184
1184
  uru library ls [path] List Library items
1185
1185
  uru library search <query> Search Library items
1186
1186
  uru library mkdir <path> Create a Library folder
1187
+ uru library read <path> Print a text-backed Library resource
1188
+ uru library write <path> --file ./note.md --create Create/replace text-backed Library content
1189
+ uru library patch <path> --content "..." Replace text-backed Library content
1190
+ uru library cp|mv <path> <target-path> Copy or move visible Library items
1191
+ uru library rm <path> [--permanent --yes] Trash or permanently delete Library items
1192
+ uru library restore <path> Restore a trashed Library item
1187
1193
  # Prompts, personas, contexts: use typed Library paths such as library/Prompts/Foo.prompt.md
1188
1194
  uru datasets query <dataset-slug> [--limit 50] Query dataset rows; add --response-format concise for compact output
1189
1195
  uru automations ls|get|create|enable|disable Manage automations without raw JSON parameters
@@ -1400,8 +1406,20 @@ the check a release gate; security also accepts --deep.
1400
1406
  library: `Usage: uru library ls [path]
1401
1407
  uru library search <query>
1402
1408
  uru library mkdir <path>
1409
+ uru library read <path>
1410
+ uru library write <path> (--file <local-path>|--content <text>|--stdin) [--create]
1411
+ uru library patch <path> (--file <local-path>|--content <text>|--stdin)
1412
+ uru library cp <path> <target-path>
1413
+ uru library mv <path> <target-path>
1414
+ uru library rm <path> [--permanent] [--yes]
1415
+ uru library restore <path>
1416
+ uru library empty-trash --yes
1403
1417
 
1404
- Operate on Library items through platform tools.
1418
+ Operate on Library items through platform tools. Use write --create to create
1419
+ text-backed Context, Prompt, Persona, note, and plain .md/.txt resources at
1420
+ visible Library paths. For binary files, use library_upload through
1421
+ \`uru operations run\` or \`uru tools run\`; for Gem child source files, use
1422
+ \`uru gems read|write\`.
1405
1423
  `,
1406
1424
  datasets: `Usage: uru datasets query <dataset-slug> [--limit 50] [--offset 0] [--response-format detailed|concise]
1407
1425
 
@@ -3184,8 +3202,8 @@ async function switchWorkspace(ctx, workspaceId) {
3184
3202
  }
3185
3203
 
3186
3204
  // src/local-commands.ts
3187
- import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
3188
- import { dirname as dirname3 } from "node:path";
3205
+ import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises";
3206
+ import { dirname as dirname3, resolve as resolve2 } from "node:path";
3189
3207
  var GENERIC_FAMILY_COMMANDS = {
3190
3208
  workspace: "workspace",
3191
3209
  sharing: "sharing",
@@ -3414,7 +3432,109 @@ async function dispatchLibrary(ctx, sub, args) {
3414
3432
  });
3415
3433
  return;
3416
3434
  }
3417
- throw new CliError("Usage: uru library ls|search|mkdir");
3435
+ if (sub === "read" || sub === "cat") {
3436
+ await emitTool(ctx, "library.read", {
3437
+ path: requireCommandValue(args[0], "Usage: uru library read <path>")
3438
+ }, { textExtractor: extractLibraryTextContent });
3439
+ return;
3440
+ }
3441
+ if (sub === "write") {
3442
+ const flags = parseLocalFlags(args);
3443
+ const path = requireCommandValue(flags.positionals[0], "Usage: uru library write <path> (--file <local-path>|--content <text>|--stdin) [--create]");
3444
+ await emitTool(ctx, "library.write", {
3445
+ path,
3446
+ content: await libraryTextFromFlags(ctx, flags, "write"),
3447
+ create: flags.booleans.has("--create")
3448
+ });
3449
+ return;
3450
+ }
3451
+ if (sub === "patch") {
3452
+ const flags = parseLocalFlags(args);
3453
+ const path = requireCommandValue(flags.positionals[0], "Usage: uru library patch <path> (--file <local-path>|--content <text>|--stdin)");
3454
+ await emitTool(ctx, "library.patch", {
3455
+ path,
3456
+ content: await libraryTextFromFlags(ctx, flags, "patch")
3457
+ });
3458
+ return;
3459
+ }
3460
+ if (sub === "cp" || sub === "copy") {
3461
+ const [path, targetPath] = args;
3462
+ await emitTool(ctx, "library.cp", {
3463
+ path: requireCommandValue(path, "Usage: uru library cp <path> <target-path>"),
3464
+ target_path: requireCommandValue(targetPath, "Usage: uru library cp <path> <target-path>")
3465
+ });
3466
+ return;
3467
+ }
3468
+ if (sub === "mv" || sub === "move" || sub === "rename") {
3469
+ const [path, targetPath] = args;
3470
+ await emitTool(ctx, "library.mv", {
3471
+ path: requireCommandValue(path, "Usage: uru library mv <path> <target-path>"),
3472
+ target_path: requireCommandValue(targetPath, "Usage: uru library mv <path> <target-path>")
3473
+ });
3474
+ return;
3475
+ }
3476
+ if (sub === "rm" || sub === "remove" || sub === "delete") {
3477
+ const flags = parseLocalFlags(args);
3478
+ if ((flags.booleans.has("--permanent") || flags.booleans.has("--hard-delete")) && !ctx.yes && !flags.booleans.has("--yes")) {
3479
+ throw new CliError("Permanent Library deletion cannot be undone. Re-run with --yes to confirm.");
3480
+ }
3481
+ const path = requireCommandValue(flags.positionals[0], "Usage: uru library rm <path> [--permanent] [--yes]");
3482
+ await emitTool(ctx, "library.rm", {
3483
+ path,
3484
+ permanent: flags.booleans.has("--permanent") || flags.booleans.has("--hard-delete")
3485
+ });
3486
+ return;
3487
+ }
3488
+ if (sub === "restore") {
3489
+ await emitTool(ctx, "library.restore", {
3490
+ path: requireCommandValue(args[0], "Usage: uru library restore <path>"),
3491
+ include_trashed: true
3492
+ });
3493
+ return;
3494
+ }
3495
+ if (sub === "empty-trash") {
3496
+ const flags = parseLocalFlags(args);
3497
+ if (!ctx.yes && !flags.booleans.has("--yes")) {
3498
+ throw new CliError("Emptying Library trash permanently deletes all trashed items. Re-run with --yes to confirm.");
3499
+ }
3500
+ await emitTool(ctx, "library.empty_trash", {});
3501
+ return;
3502
+ }
3503
+ throw new CliError("Usage: uru library ls|search|mkdir|read|write|patch|cp|mv|rm|restore|empty-trash");
3504
+ }
3505
+ async function libraryTextFromFlags(ctx, flags, verb) {
3506
+ const content = flags.values["--content"];
3507
+ const file = flags.values["--file"];
3508
+ const fromStdin = flags.booleans.has("--stdin");
3509
+ const sources = [content !== undefined, file !== undefined, fromStdin].filter(Boolean).length;
3510
+ if (sources !== 1) {
3511
+ throw new CliError(`Library ${verb} requires exactly one of --file <path>, --content <text>, or --stdin.`);
3512
+ }
3513
+ if (content !== undefined) {
3514
+ return content;
3515
+ }
3516
+ if (file !== undefined) {
3517
+ return await readFile4(resolve2(ctx.cwd, file), "utf8");
3518
+ }
3519
+ return await readStdinText(ctx.stdin ?? process.stdin);
3520
+ }
3521
+ async function readStdinText(stdin) {
3522
+ const chunks = [];
3523
+ for await (const chunk of stdin) {
3524
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
3525
+ }
3526
+ return Buffer.concat(chunks).toString("utf8");
3527
+ }
3528
+ function extractLibraryTextContent(value) {
3529
+ if (!isJsonObject2(value)) {
3530
+ return;
3531
+ }
3532
+ const content = value["content"];
3533
+ if (typeof content === "string") {
3534
+ return content;
3535
+ }
3536
+ const text = value["text"];
3537
+ return typeof text === "string" ? text : undefined;
3418
3538
  }
3419
3539
  async function dispatchDatasets(ctx, sub, args) {
3420
3540
  if (sub !== "query") {
@@ -3623,9 +3743,9 @@ function levenshtein(left, right) {
3623
3743
  }
3624
3744
 
3625
3745
  // src/gem-lifecycle-commands.ts
3626
- import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "node:fs/promises";
3746
+ import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4 } from "node:fs/promises";
3627
3747
  import { setTimeout as sleep } from "node:timers/promises";
3628
- import { join as join3, resolve as resolve2 } from "node:path";
3748
+ import { join as join3, resolve as resolve3 } from "node:path";
3629
3749
  async function dispatchGems(ctx, sub, args, linkedProject) {
3630
3750
  const gemPath = () => gemPathFromArgs(args, linkedProject);
3631
3751
  if (sub === "inspect") {
@@ -3678,7 +3798,7 @@ async function gemInit(ctx, args) {
3678
3798
  params["content"] = flags.values["--content"];
3679
3799
  }
3680
3800
  if (flags.values["--file"] !== undefined) {
3681
- params["content"] = await readFile4(flags.values["--file"], "utf8");
3801
+ params["content"] = await readFile5(flags.values["--file"], "utf8");
3682
3802
  }
3683
3803
  await emitGemTool(ctx, "gem.init", params);
3684
3804
  }
@@ -4022,7 +4142,7 @@ async function gemWrite(ctx, args) {
4022
4142
  const flags = parseLocalFlags(args);
4023
4143
  const gemPath = requireCommandValue(flags.positionals[0], "Usage: uru gems write <gem-path> <file> --content <text>|--file <local-file>");
4024
4144
  const filePath = requireCommandValue(flags.positionals[1], "Usage: uru gems write <gem-path> <file> --content <text>|--file <local-file>");
4025
- const content = flags.values["--content"] ?? (flags.values["--file"] === undefined ? undefined : await readFile4(flags.values["--file"], "utf8"));
4145
+ const content = flags.values["--content"] ?? (flags.values["--file"] === undefined ? undefined : await readFile5(flags.values["--file"], "utf8"));
4026
4146
  if (content === undefined) {
4027
4147
  throw new CliError("Gem write requires --content or --file.");
4028
4148
  }
@@ -4179,7 +4299,7 @@ function localFlagNames(flags) {
4179
4299
  async function writeBuildManifest(ctx, outdir, buildResult) {
4180
4300
  const manifest = gemBuildManifestFromBuildResult(buildResult);
4181
4301
  const providerDecision = gemProviderDecisionFromBuildResult(buildResult, manifest);
4182
- const absoluteOutdir = resolve2(ctx.cwd, outdir);
4302
+ const absoluteOutdir = resolve3(ctx.cwd, outdir);
4183
4303
  await mkdir4(absoluteOutdir, { recursive: true });
4184
4304
  await writeFile4(join3(absoluteOutdir, "gem-build-manifest.json"), `${JSON.stringify(manifest, null, 2)}
4185
4305
  `, { mode: 384 });
@@ -4378,7 +4498,7 @@ function trimLeadingSlashes(value) {
4378
4498
 
4379
4499
  // src/gem-source-commands.ts
4380
4500
  import { mkdir as mkdir5, rm as rm3, writeFile as writeFile5 } from "node:fs/promises";
4381
- import { dirname as dirname4, join as join4, resolve as resolve3 } from "node:path";
4501
+ import { dirname as dirname4, join as join4, resolve as resolve4 } from "node:path";
4382
4502
  async function gemSourcePull(ctx, args, linkedProject) {
4383
4503
  const flags = parseLocalFlags(args);
4384
4504
  const gemPath = gemPathFromArgs(flags.positionals, linkedProject);
@@ -4541,7 +4661,7 @@ async function pruneRemoteDeletedSourceFiles(cwd, previousLock, localFilesBefore
4541
4661
  preserved.push(projectPath2);
4542
4662
  continue;
4543
4663
  }
4544
- await rm3(join4(resolve3(cwd), ...safePath.split("/")), { force: true });
4664
+ await rm3(join4(resolve4(cwd), ...safePath.split("/")), { force: true });
4545
4665
  deleted.push(projectPath2);
4546
4666
  }
4547
4667
  return { deleted, preserved };
@@ -4762,7 +4882,7 @@ async function writePulledSourceFile(cwd, projectPath2, content) {
4762
4882
  if (safePath === null) {
4763
4883
  throw new CliError(`Refusing to write unsafe Gem source path: ${projectPath2}`);
4764
4884
  }
4765
- const localPath = join4(resolve3(cwd), ...safePath.split("/"));
4885
+ const localPath = join4(resolve4(cwd), ...safePath.split("/"));
4766
4886
  await mkdir5(dirname4(localPath), { recursive: true });
4767
4887
  await writeFile5(localPath, content);
4768
4888
  }
@@ -4817,8 +4937,8 @@ function isConflictLikeError(error) {
4817
4937
 
4818
4938
  // src/token-env-secret-commands.ts
4819
4939
  import { spawn as spawn2 } from "node:child_process";
4820
- import { chmod, mkdir as mkdir6, readFile as readFile5, writeFile as writeFile6 } from "node:fs/promises";
4821
- import { dirname as dirname5, resolve as resolve4 } from "node:path";
4940
+ import { chmod, mkdir as mkdir6, readFile as readFile6, writeFile as writeFile6 } from "node:fs/promises";
4941
+ import { dirname as dirname5, resolve as resolve5 } from "node:path";
4822
4942
  async function dispatchTokens(ctx, sub, args, linkedProject) {
4823
4943
  if (sub === "create") {
4824
4944
  const flags = parseLocalFlags(args);
@@ -4932,7 +5052,7 @@ async function dispatchEnv(ctx, sub, args, linkedProject) {
4932
5052
  })));
4933
5053
  const secrets = extractSecretRows(result);
4934
5054
  const content = formatEnvTemplate(secrets);
4935
- const absolutePath = resolve4(ctx.cwd, outputPath);
5055
+ const absolutePath = resolve5(ctx.cwd, outputPath);
4936
5056
  await mkdir6(dirname5(absolutePath), { recursive: true });
4937
5057
  await writeFile6(absolutePath, content, { mode: 384 });
4938
5058
  await chmod(absolutePath, 384);
@@ -4949,8 +5069,8 @@ async function dispatchEnv(ctx, sub, args, linkedProject) {
4949
5069
  }
4950
5070
  if (sub === "run") {
4951
5071
  const parsed = parseEnvRunArgs(args);
4952
- const envFilePath = resolve4(ctx.cwd, parsed.envFile);
4953
- const envVars = parseEnvFile(await readFile5(envFilePath, "utf8"));
5072
+ const envFilePath = resolve5(ctx.cwd, parsed.envFile);
5073
+ const envVars = parseEnvFile(await readFile6(envFilePath, "utf8"));
4954
5074
  await runEnvCommand(ctx, parsed.command, envVars);
4955
5075
  return;
4956
5076
  }
@@ -4970,10 +5090,10 @@ async function secretValueFromFlags(ctx, flags) {
4970
5090
  }
4971
5091
  const valueFile = flags.values["--value-file"];
4972
5092
  if (valueFile !== undefined) {
4973
- return (await readFile5(resolve4(ctx.cwd, valueFile), "utf8")).trimEnd();
5093
+ return (await readFile6(resolve5(ctx.cwd, valueFile), "utf8")).trimEnd();
4974
5094
  }
4975
5095
  if (flags.booleans.has("--value-stdin")) {
4976
- return await readStdinText(ctx.stdin ?? process.stdin);
5096
+ return await readStdinText2(ctx.stdin ?? process.stdin);
4977
5097
  }
4978
5098
  throw new CliError("Secret put requires --value-file <path> or --value-stdin. Values are never printed by the CLI.");
4979
5099
  }
@@ -5118,7 +5238,7 @@ function redactValues2(content, values) {
5118
5238
  }
5119
5239
  return redacted;
5120
5240
  }
5121
- async function readStdinText(stdin) {
5241
+ async function readStdinText2(stdin) {
5122
5242
  const chunks = [];
5123
5243
  for await (const chunk of stdin) {
5124
5244
  chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
@@ -5594,14 +5714,14 @@ function writeSystemClipboard(text) {
5594
5714
  const platform = process.platform;
5595
5715
  const command = platform === "darwin" ? "pbcopy" : platform === "win32" ? "clip" : "xclip";
5596
5716
  const args = platform === "linux" ? ["-selection", "clipboard"] : [];
5597
- return new Promise((resolve5, reject) => {
5717
+ return new Promise((resolve6, reject) => {
5598
5718
  const child = spawn3(command, args, { stdio: ["pipe", "ignore", "ignore"] });
5599
5719
  child.on("error", (error) => {
5600
5720
  reject(new CliError("Could not copy login URL to clipboard. Re-run without --clipboard to print the URL.", { cause: error }));
5601
5721
  });
5602
5722
  child.on("close", (code) => {
5603
5723
  if (code === 0) {
5604
- resolve5();
5724
+ resolve6();
5605
5725
  return;
5606
5726
  }
5607
5727
  reject(new CliError(`Could not copy login URL to clipboard (${command} exited ${code ?? "unknown"}). Re-run without --clipboard to print the URL.`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uru-intelligence/cli",
3
- "version": "0.3.54",
3
+ "version": "0.3.55",
4
4
  "private": false,
5
5
  "description": "Uru full-platform command line interface",
6
6
  "type": "module",