tines 0.0.285 → 0.0.287

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 (2) hide show
  1. package/dist/index.js +307 -21
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3598,6 +3598,136 @@ var RUN_OUTCOME_BUCKETS = [
3598
3598
  ];
3599
3599
  var LIBRARY_MAX_BYTES = 5 * 1024 * 1024;
3600
3600
 
3601
+ // ../shared/src/permissions.ts
3602
+ var ACCESS_LEVELS = ["none", "read", "write", "delete"];
3603
+ var MAX_PERMISSION_PROJECTS = 1e4;
3604
+ var MAX_PERMISSION_PROJECT_ID_LENGTH = 100;
3605
+ var FULL_API_KEY_PERMISSIONS = Object.freeze({
3606
+ version: 1,
3607
+ projects: Object.freeze({ access: "delete", scope: "all" }),
3608
+ workspace: "delete",
3609
+ control_plane: "delete"
3610
+ });
3611
+ var READ_ONLY_API_KEY_PERMISSIONS = Object.freeze({
3612
+ version: 1,
3613
+ projects: Object.freeze({ access: "read", scope: "all" }),
3614
+ workspace: "read",
3615
+ control_plane: "read"
3616
+ });
3617
+ var PROJECT_AUTOMATION_API_KEY_PERMISSIONS = Object.freeze({
3618
+ version: 1,
3619
+ projects: Object.freeze({ access: "write", scope: Object.freeze([]) }),
3620
+ workspace: "read",
3621
+ control_plane: "none"
3622
+ });
3623
+ var RUNNER_SETUP_API_KEY_PERMISSIONS = Object.freeze({
3624
+ version: 1,
3625
+ projects: Object.freeze({ access: "write", scope: "all" }),
3626
+ workspace: "write",
3627
+ control_plane: "write"
3628
+ });
3629
+ var ApiKeyPermissionsValidationError = class extends Error {
3630
+ constructor(message3, field = "permissions") {
3631
+ super(message3);
3632
+ this.field = field;
3633
+ this.name = "ApiKeyPermissionsValidationError";
3634
+ }
3635
+ field;
3636
+ };
3637
+ function objectAt(value, field) {
3638
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
3639
+ throw new ApiKeyPermissionsValidationError(`"${field}" must be an object`, field);
3640
+ }
3641
+ return value;
3642
+ }
3643
+ function rejectUnknownKeys(value, allowed, field) {
3644
+ const unknown = Object.keys(value).find((key) => !allowed.includes(key));
3645
+ if (unknown !== void 0) {
3646
+ throw new ApiKeyPermissionsValidationError(
3647
+ `"${field}.${unknown}" is not a supported permission field`,
3648
+ `${field}.${unknown}`
3649
+ );
3650
+ }
3651
+ }
3652
+ function accessAt(value, field, allowNone) {
3653
+ if (typeof value !== "string" || !ACCESS_LEVELS.includes(value) || !allowNone && value === "none") {
3654
+ const levels = allowNone ? ACCESS_LEVELS : ACCESS_LEVELS.slice(1);
3655
+ throw new ApiKeyPermissionsValidationError(
3656
+ `"${field}" must be one of ${levels.join(", ")}`,
3657
+ field
3658
+ );
3659
+ }
3660
+ return value;
3661
+ }
3662
+ function projectScopeAt(value) {
3663
+ if (value === "all") return "all";
3664
+ if (!Array.isArray(value)) {
3665
+ throw new ApiKeyPermissionsValidationError(
3666
+ '"permissions.projects.scope" must be "all" or an array of project IDs',
3667
+ "permissions.projects.scope"
3668
+ );
3669
+ }
3670
+ if (value.length > MAX_PERMISSION_PROJECTS) {
3671
+ throw new ApiKeyPermissionsValidationError(
3672
+ `"permissions.projects.scope" must contain at most ${MAX_PERMISSION_PROJECTS} project IDs`,
3673
+ "permissions.projects.scope"
3674
+ );
3675
+ }
3676
+ const seen = /* @__PURE__ */ new Set();
3677
+ for (const id2 of value) {
3678
+ if (typeof id2 !== "string" || id2.length > MAX_PERMISSION_PROJECT_ID_LENGTH || !/^prj_[A-Za-z0-9_-]+$/.test(id2)) {
3679
+ throw new ApiKeyPermissionsValidationError(
3680
+ '"permissions.projects.scope" entries must be valid project IDs',
3681
+ "permissions.projects.scope"
3682
+ );
3683
+ }
3684
+ if (seen.has(id2)) {
3685
+ throw new ApiKeyPermissionsValidationError(
3686
+ `"permissions.projects.scope" contains duplicate project ID "${id2}"`,
3687
+ "permissions.projects.scope"
3688
+ );
3689
+ }
3690
+ seen.add(id2);
3691
+ }
3692
+ return [...seen].sort();
3693
+ }
3694
+ function parseApiKeyPermissions(value) {
3695
+ const policy = objectAt(value, "permissions");
3696
+ rejectUnknownKeys(policy, ["version", "projects", "workspace", "control_plane"], "permissions");
3697
+ if (policy.version !== void 0 && policy.version !== 1) {
3698
+ throw new ApiKeyPermissionsValidationError(
3699
+ '"permissions.version" must be 1',
3700
+ "permissions.version"
3701
+ );
3702
+ }
3703
+ for (const field of ["projects", "workspace", "control_plane"]) {
3704
+ if (!(field in policy)) {
3705
+ throw new ApiKeyPermissionsValidationError(
3706
+ `"permissions.${field}" is required`,
3707
+ `permissions.${field}`
3708
+ );
3709
+ }
3710
+ }
3711
+ const projects = objectAt(policy.projects, "permissions.projects");
3712
+ rejectUnknownKeys(projects, ["access", "scope"], "permissions.projects");
3713
+ if (!("access" in projects) || !("scope" in projects)) {
3714
+ const missing = !("access" in projects) ? "access" : "scope";
3715
+ throw new ApiKeyPermissionsValidationError(
3716
+ `"permissions.projects.${missing}" is required`,
3717
+ `permissions.projects.${missing}`
3718
+ );
3719
+ }
3720
+ return {
3721
+ version: 1,
3722
+ projects: {
3723
+ access: accessAt(projects.access, "permissions.projects.access", false),
3724
+ scope: projectScopeAt(projects.scope)
3725
+ },
3726
+ workspace: accessAt(policy.workspace, "permissions.workspace", true),
3727
+ control_plane: accessAt(policy.control_plane, "permissions.control_plane", true)
3728
+ };
3729
+ }
3730
+
3601
3731
  // ../shared/src/events.ts
3602
3732
  var text = (t) => ({ kind: "text", text: t });
3603
3733
  var name = (t) => ({ kind: "name", text: str(t) });
@@ -3690,6 +3820,10 @@ var DESCRIBERS = {
3690
3820
  "workflow.updated": (ev, p) => [text(`${action(ev.type)} workflow`), name(p.name)],
3691
3821
  "workflow.deleted": (ev, p) => [text(`${action(ev.type)} workflow`), name(p.name)],
3692
3822
  "api_key.created": (_ev, p) => [text("created API key"), name(p.name)],
3823
+ "api_key.permissions_updated": (_ev, p) => [
3824
+ text("updated permissions for API key"),
3825
+ name(p.name)
3826
+ ],
3693
3827
  "api_key.revoked": (_ev, p) => [text("revoked API key"), name(p.name)],
3694
3828
  "scheduled_task.created": (ev, p) => [text(`${action(ev.type)} schedule`), name(p.name)],
3695
3829
  "scheduled_task.updated": (ev, p) => [text(`${action(ev.type)} schedule`), name(p.name)],
@@ -4229,9 +4363,14 @@ function createApiClient(options) {
4229
4363
  createSupervisorRate: (body) => request("POST", "/api/v1/supervisor/rates", body),
4230
4364
  repriceSupervisorRate: (model, cursor = null) => request("POST", "/api/v1/supervisor/rates/reprice", { model, cursor }),
4231
4365
  deleteSupervisorRate: (id2) => request("DELETE", `/api/v1/supervisor/rates/${id2}`),
4232
- // API keys (create/revoke require a browser session, not a key)
4366
+ // API keys
4233
4367
  listApiKeys: (filters = {}) => get(`/api/v1/api-keys${query(filters)}`),
4368
+ getApiKey: (id2) => get(`/api/v1/api-keys/${id2}`),
4369
+ getCurrentApiKeyAuthority: () => get(
4370
+ "/api/v1/api-keys/current"
4371
+ ),
4234
4372
  createApiKey: (body) => request("POST", "/api/v1/api-keys", body),
4373
+ updateApiKey: (id2, body) => request("PATCH", `/api/v1/api-keys/${id2}`, body),
4235
4374
  revokeApiKey: (id2) => request("DELETE", `/api/v1/api-keys/${id2}`),
4236
4375
  exportWorkflowPackage: (id2, opts = {}) => {
4237
4376
  const params = new URLSearchParams();
@@ -6536,6 +6675,142 @@ function register(program3) {
6536
6675
  });
6537
6676
  }
6538
6677
 
6678
+ // src/commands/api-keys.ts
6679
+ var PRESETS = {
6680
+ full: FULL_API_KEY_PERMISSIONS,
6681
+ "read-only": READ_ONLY_API_KEY_PERMISSIONS,
6682
+ "project-automation": PROJECT_AUTOMATION_API_KEY_PERMISSIONS,
6683
+ "runner-setup": RUNNER_SETUP_API_KEY_PERMISSIONS
6684
+ };
6685
+ function clonePolicy(policy) {
6686
+ return parseApiKeyPermissions(JSON.parse(JSON.stringify(policy)));
6687
+ }
6688
+ function policyFromOptions(opts) {
6689
+ if (Boolean(opts.permissions) === Boolean(opts.preset)) {
6690
+ die("pass exactly one of --permissions or --preset");
6691
+ }
6692
+ if (opts.permissions) {
6693
+ if (opts.projects || opts.allProjects) die("--projects/--all-projects require --preset");
6694
+ try {
6695
+ return parseApiKeyPermissions(JSON.parse(readBodyValue(opts.permissions)));
6696
+ } catch (error) {
6697
+ die(error instanceof Error ? error.message : "invalid permission JSON");
6698
+ }
6699
+ }
6700
+ const preset2 = opts.preset;
6701
+ const policy = clonePolicy(PRESETS[preset2]);
6702
+ if (opts.projects && opts.allProjects) die("pass only one of --projects or --all-projects");
6703
+ if (opts.projects) {
6704
+ policy.projects.scope = opts.projects.split(",").map((id2) => id2.trim()).filter(Boolean);
6705
+ return parseApiKeyPermissions(policy);
6706
+ }
6707
+ if (opts.allProjects) policy.projects.scope = "all";
6708
+ if (preset2 === "project-automation" && policy.projects.scope.length === 0) {
6709
+ die("project-automation requires --projects <id,...> or --all-projects");
6710
+ }
6711
+ return policy;
6712
+ }
6713
+ function scopeLabel(policy) {
6714
+ return policy.projects.scope === "all" ? "all" : policy.projects.scope.length === 0 ? "none" : policy.projects.scope.join(",");
6715
+ }
6716
+ function printKey(key) {
6717
+ table([
6718
+ ["ID", "NAME", "PROJECTS", "WORKSPACE", "CONTROL", "USABLE"],
6719
+ [
6720
+ key.id,
6721
+ key.name,
6722
+ `${key.permissions.projects.access}:${scopeLabel(key.permissions)}`,
6723
+ key.permissions.workspace,
6724
+ key.permissions.control_plane,
6725
+ key.usable === false ? "no" : "yes"
6726
+ ]
6727
+ ]);
6728
+ if (key.run_restrictions) {
6729
+ console.log(
6730
+ `also restricted to run ${key.run_restrictions.run_id}, issue ${key.run_restrictions.issue_id}, project ${key.run_restrictions.project_id}`
6731
+ );
6732
+ }
6733
+ }
6734
+ function addPolicyOptions(command, includePreset) {
6735
+ command.option(
6736
+ "--permissions <json|@file|->",
6737
+ "complete permission policy as JSON, @file, or stdin"
6738
+ );
6739
+ if (includePreset) {
6740
+ command.addOption(
6741
+ new Option("--preset <name>", "permission preset").choices([
6742
+ "full",
6743
+ "read-only",
6744
+ "project-automation",
6745
+ "runner-setup"
6746
+ ])
6747
+ );
6748
+ command.option("--projects <ids>", "comma-separated explicit project IDs");
6749
+ command.option("--all-projects", "explicitly use all projects");
6750
+ }
6751
+ return command;
6752
+ }
6753
+ function register2(program3) {
6754
+ const keys = program3.command("api-keys").description("Manage scoped API keys");
6755
+ withCommon(
6756
+ keys.command("list").addOption(
6757
+ new Option("--run-keys <mode>", "run keys to include").choices(["none", "active", "all"])
6758
+ )
6759
+ ).action(async (opts) => {
6760
+ const response = await client(opts).listApiKeys({ run_keys: opts.runKeys });
6761
+ if (opts.json) return printJson(response);
6762
+ if (response.items.length === 0) return console.log("no API keys");
6763
+ for (const key of response.items) printKey(key);
6764
+ });
6765
+ withCommon(keys.command("show <id>").description("Show stored and effective authority")).action(
6766
+ async (id2, opts) => {
6767
+ const key = await client(opts).getApiKey(id2);
6768
+ if (opts.json) return printJson(key);
6769
+ printKey(key);
6770
+ }
6771
+ );
6772
+ withCommon(keys.command("current").description("Inspect the acting credential authority")).action(
6773
+ async (opts) => {
6774
+ const current = await client(opts).getCurrentApiKeyAuthority();
6775
+ if (opts.json) return printJson(current);
6776
+ console.log(current.key ? `${current.key.name} (${current.key.id})` : "browser session");
6777
+ const policy = current.authority.effective_permissions;
6778
+ console.log(
6779
+ `projects ${policy.projects.access}:${scopeLabel(policy)}; workspace ${policy.workspace}; control ${policy.control_plane}`
6780
+ );
6781
+ }
6782
+ );
6783
+ withCommon(
6784
+ addPolicyOptions(keys.command("create <name>").description("Create a scoped key"), true)
6785
+ ).action(async (name2, opts) => {
6786
+ const created = await client(opts).createApiKey({ name: name2, permissions: policyFromOptions(opts) });
6787
+ if (opts.json) return printJson(created);
6788
+ console.log(created.key);
6789
+ printKey(created);
6790
+ });
6791
+ withCommon(
6792
+ addPolicyOptions(keys.command("update <id>").description("Replace key permissions"), false)
6793
+ ).action(async (id2, opts) => {
6794
+ if (!opts.permissions) die("--permissions is required");
6795
+ const api = client(opts);
6796
+ const current = await api.getApiKey(id2);
6797
+ const permissions = policyFromOptions(opts);
6798
+ const updated = await api.updateApiKey(id2, {
6799
+ permissions,
6800
+ expected_permissions: current.permissions
6801
+ });
6802
+ if (opts.json) return printJson(updated);
6803
+ printKey(updated);
6804
+ });
6805
+ withCommon(keys.command("revoke <id>").description("Revoke a key")).action(
6806
+ async (id2, opts) => {
6807
+ await client(opts).revokeApiKey(id2);
6808
+ if (opts.json) return printJson({ revoked: id2 });
6809
+ console.log(`revoked ${id2}`);
6810
+ }
6811
+ );
6812
+ }
6813
+
6539
6814
  // src/commands/issues.ts
6540
6815
  import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync, readFileSync as readFileSync5, statSync as statSync2, writeFileSync as writeFileSync3 } from "node:fs";
6541
6816
  import { basename, dirname as dirname2, join as join3 } from "node:path";
@@ -7286,7 +7561,7 @@ function printIssueDetail(issue) {
7286
7561
  console.log(`${issue.project_name}/#${issue.number} ${issue.title}`);
7287
7562
  const dup = issue.duplicate_of;
7288
7563
  console.log(
7289
- `state: ${issue.effective_state.name} (${issue.effective_state.category})${dup ? ` (via ${issueRef(dup)} \u2014 duplicate)` : ""} workflow: ${issue.workflow.name} updated: ${timestamp(issue.updated_at)}`
7564
+ `state: ${issue.effective_state.name} (${issue.effective_state.category})${dup ? ` (via ${issueRef(dup)} \u2014 duplicate)` : ""} workflow: ${issue.workflow?.name ?? "restricted"} updated: ${timestamp(issue.updated_at)}`
7290
7565
  );
7291
7566
  if (dup) {
7292
7567
  console.log(
@@ -7419,7 +7694,7 @@ matched rule: ${ex.matched_rule.scope_label}`);
7419
7694
  );
7420
7695
  }
7421
7696
  }
7422
- function register2(program3) {
7697
+ function register3(program3) {
7423
7698
  const issues = program3.command("issues").description("Work with issues");
7424
7699
  withList(
7425
7700
  issues.command("list").description("List issues across projects (hides done and duplicate issues unless included)").option("-p, --project <name>", "filter by project name or id").option("-s, --state <name>", "filter by state name or id").option("-c, --category <cat>", "filter by state category").option("-w, --workflow <id-or-name>", "filter by workflow").option("-a, --all", "include issues in done states").option("--show-duplicates", "include issues marked as duplicates").option(
@@ -7584,7 +7859,8 @@ function register2(program3) {
7584
7859
  const notes = [];
7585
7860
  if (body.title !== void 0) notes.push(`title "${updated.title}"`);
7586
7861
  if (body.description !== void 0) notes.push("description");
7587
- if (body.workflow_id !== void 0) notes.push(`workflow "${updated.workflow.name}"`);
7862
+ if (body.workflow_id !== void 0)
7863
+ notes.push(`workflow "${updated.workflow?.name ?? body.workflow_id}"`);
7588
7864
  if (updated.state.id !== issue.state.id) {
7589
7865
  notes.push(`state ${issue.state.name} \u2192 ${updated.state.name}`);
7590
7866
  }
@@ -8282,6 +8558,15 @@ async function resolveJournal(api, ref, stateRef2) {
8282
8558
  return { issue, scope, note, item };
8283
8559
  } catch (err) {
8284
8560
  if (!(err instanceof ApiError) || err.status !== 404) throw err;
8561
+ if (!issue.workflow)
8562
+ throw new ApiError(
8563
+ 403,
8564
+ {
8565
+ code: "insufficient_permissions",
8566
+ message: "Journal fallback requires workspace read access"
8567
+ },
8568
+ "Journal fallback requires workspace read access"
8569
+ );
8285
8570
  const scope = stateScope(issue, issue.state, issue.workflow);
8286
8571
  return { issue, scope, note: null, item: await journalItemAt(api, scope) };
8287
8572
  }
@@ -8289,7 +8574,7 @@ async function resolveJournal(api, ref, stateRef2) {
8289
8574
  function printNote(note) {
8290
8575
  if (note) console.error(`note: ${note}`);
8291
8576
  }
8292
- function register3(program3) {
8577
+ function register4(program3) {
8293
8578
  const journal = program3.command("journal").description(
8294
8579
  "An issue's stage journal: shared notes for its project + the stage your run was launched in"
8295
8580
  );
@@ -8376,7 +8661,7 @@ function parseLabelColor(value) {
8376
8661
  }
8377
8662
  return value;
8378
8663
  }
8379
- function register4(program3) {
8664
+ function register5(program3) {
8380
8665
  const labels = program3.command("labels").description("Manage the label library");
8381
8666
  withCommon(
8382
8667
  labels.command("list").description("List labels with how many issues carry each")
@@ -8473,7 +8758,7 @@ function readKeyArg(value) {
8473
8758
  if (!key) die("no API key on stdin");
8474
8759
  return key;
8475
8760
  }
8476
- function register5(program3) {
8761
+ function register6(program3) {
8477
8762
  program3.command("login").description("Store the API URL and key for this machine, so commands need no env vars").option("-u, --url <url>", `base URL of the Tines API to store (default ${DEFAULT_URL})`).option("--api-key <key>", 'API key from Settings \u2192 API keys ("-" reads it from stdin)').option("--no-verify", "store without checking the key against the API").action(async (opts) => {
8478
8763
  if (!opts.url && !opts.apiKey) die("pass --url and/or --api-key");
8479
8764
  const dir = defaultConfigDir();
@@ -8570,7 +8855,7 @@ function registerEvents(program3) {
8570
8855
  }
8571
8856
 
8572
8857
  // src/commands/projects.ts
8573
- function register6(program3) {
8858
+ function register7(program3) {
8574
8859
  const projects = program3.command("projects").description("Manage projects");
8575
8860
  withCommon(
8576
8861
  projects.command("starters").description("List built-in project starters and their inputs")
@@ -8821,7 +9106,7 @@ async function resolveRoutingScope(api, opts) {
8821
9106
  if (opts.label) parts.push(`label ${opts.label}`);
8822
9107
  return { projectId, stateId, labelId, label: parts.length > 0 ? parts.join(" \xB7 ") : "global" };
8823
9108
  }
8824
- function register7(program3) {
9109
+ function register8(program3) {
8825
9110
  const routing = program3.command("routing").description(
8826
9111
  "Scoped routing rules: which runner takes which issues (most specific scope wins)"
8827
9112
  );
@@ -11910,7 +12195,7 @@ function printTierTable(runner) {
11910
12195
  );
11911
12196
  }
11912
12197
  }
11913
- function register8(program3) {
12198
+ function register9(program3) {
11914
12199
  const runners = program3.command("runners").description("Manage the runner registry");
11915
12200
  withCommon(runners.command("list").description("List runners")).action(
11916
12201
  async (opts) => {
@@ -12458,7 +12743,7 @@ title template: ${s.title_template}`);
12458
12743
  for (const line of s.description_template.split("\n")) console.log(` ${line}`);
12459
12744
  }
12460
12745
  }
12461
- function register9(program3) {
12746
+ function register10(program3) {
12462
12747
  const schedules = program3.command("schedules").description("Manage scheduled tasks (addressed as <project>/<name>)");
12463
12748
  withList(
12464
12749
  schedules.command("list").description("List scheduled tasks (hides paused schedules unless --all)").option("-p, --project <name>", "filter by project name or id").option("-a, --all", "include paused schedules")
@@ -12712,7 +12997,7 @@ function statsLevers() {
12712
12997
  " sent back tines context show <wf>/<state> instructions"
12713
12998
  ];
12714
12999
  }
12715
- function register10(program3) {
13000
+ function register11(program3) {
12716
13001
  const supervisor = program3.command("supervisor").description("The automation kill switch, quota policy, and attempt limit");
12717
13002
  withCommon(
12718
13003
  supervisor.command("status").description("One-screen overview: kill switch, quota, utilization, runners").option("--project <name-or-id>", "filter waiting work to one project")
@@ -13729,7 +14014,7 @@ function printWorkflowDetail(wf, lib) {
13729
14014
  for (const w of wf.warnings ?? []) console.log(`
13730
14015
  warning: ${w}`);
13731
14016
  }
13732
- function register11(program3) {
14017
+ function register12(program3) {
13733
14018
  const workflows = program3.command("workflows").description("Manage the workflow library");
13734
14019
  registerPackageCommands(workflows);
13735
14020
  withList(workflows.command("list").description("List the workflow library")).action(
@@ -14351,7 +14636,7 @@ function printReport(report) {
14351
14636
  for (const line of usageAggregateLines("Scope", scope)) console.log(line);
14352
14637
  for (const line of usageAggregateLines("Matching", total)) console.log(line);
14353
14638
  }
14354
- function register12(program3) {
14639
+ function register13(program3) {
14355
14640
  withCommon(
14356
14641
  program3.command("usage").description("Compare finalized run spend for a period").addOption(
14357
14642
  new Option("--window <window>", "today, 7d, or 30d").choices(["today", "7d", "30d"])
@@ -14543,18 +14828,19 @@ function register12(program3) {
14543
14828
  var program2 = new Command();
14544
14829
  program2.name("tines").description("CLI for Tines").version(cliVersion()).enablePositionalOptions();
14545
14830
  registerTime(program2);
14546
- register5(program2);
14547
14831
  register6(program2);
14548
- register11(program2);
14549
14832
  register2(program2);
14550
- register4(program2);
14551
- register(program2);
14833
+ register7(program2);
14834
+ register12(program2);
14552
14835
  register3(program2);
14836
+ register5(program2);
14837
+ register(program2);
14838
+ register4(program2);
14839
+ register10(program2);
14553
14840
  register9(program2);
14554
14841
  register8(program2);
14555
- register7(program2);
14556
- register10(program2);
14557
- register12(program2);
14842
+ register11(program2);
14843
+ register13(program2);
14558
14844
  registerEvents(program2);
14559
14845
 
14560
14846
  // src/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tines",
3
- "version": "0.0.285",
3
+ "version": "0.0.287",
4
4
  "description": "CLI for Tines, an orchestration layer for AI agents",
5
5
  "repository": {
6
6
  "type": "git",