@dam-agents/cli 0.2.1-rc3 → 0.2.2-rc1

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/bin.js +688 -160
  2. package/package.json +3 -3
package/dist/bin.js CHANGED
@@ -25484,6 +25484,11 @@ var agentCreateInputSchema = external_exports.object({
25484
25484
  description: external_exports.string().optional(),
25485
25485
  env: external_exports.array(envVarSchema).max(64).optional(),
25486
25486
  secretRef: external_exports.string().optional(),
25487
+ registryCredential: external_exports.object({
25488
+ server: external_exports.string().min(1),
25489
+ username: external_exports.string().min(1),
25490
+ password: external_exports.string().min(1)
25491
+ }).optional(),
25487
25492
  allowedUserEmails: external_exports.array(external_exports.email()).optional(),
25488
25493
  egressPreset: egressPresetSchema.optional(),
25489
25494
  // Optional: clone this public repo (optionally a branch/tag via `ref`) into
@@ -25877,14 +25882,16 @@ var egressInjectContribution = external_exports.object({
25877
25882
  pathPattern: external_exports.string().optional(),
25878
25883
  headerName: external_exports.string().min(1),
25879
25884
  valueFormat: external_exports.string().min(1),
25880
- encoding: external_exports.literal("basic-x-access-token").optional()
25885
+ encoding: external_exports.literal("basic-x-access-token").optional(),
25886
+ // Moves the value into this query param instead of the header; restricted to unreserved chars since the Lua treats it as a trusted literal.
25887
+ queryParamName: external_exports.string().regex(/^[A-Za-z0-9_.~-]+$/).optional()
25881
25888
  });
25882
25889
  var fileContribution = external_exports.object({
25883
25890
  kind: external_exports.literal("file"),
25884
25891
  path: external_exports.string().min(1),
25885
25892
  format: fileFormat,
25886
25893
  mergeMode,
25887
- content: external_exports.unknown()
25894
+ content: external_exports.unknown().optional()
25888
25895
  });
25889
25896
  var mcpEntryContribution = external_exports.object({
25890
25897
  kind: external_exports.literal("mcp-entry"),
@@ -26071,7 +26078,11 @@ var templateInput = external_exports.object({
26071
26078
  name: external_exports.string(),
26072
26079
  state: templateInputState,
26073
26080
  presetValue: external_exports.string().optional(),
26074
- secret: external_exports.boolean().optional()
26081
+ secret: external_exports.boolean().optional(),
26082
+ // Marks a config input the form packs into `configInputs` rather than the typed auth fields.
26083
+ configInput: external_exports.boolean().optional(),
26084
+ label: external_exports.string().optional(),
26085
+ hint: external_exports.string().optional()
26075
26086
  });
26076
26087
  var connectionTemplateView = external_exports.object({
26077
26088
  id: external_exports.string(),
@@ -26145,6 +26156,8 @@ var headerCreateInput = external_exports.object({
26145
26156
  /^[A-Za-z_][A-Za-z0-9_]*$/,
26146
26157
  "env var name must be letters, digits, and underscores (not starting with a digit)"
26147
26158
  ).optional(),
26159
+ // Values for the template's declared config inputs, keyed by input name.
26160
+ configInputs: external_exports.record(external_exports.string(), external_exports.string()).optional(),
26148
26161
  value: external_exports.string().min(1)
26149
26162
  });
26150
26163
  var noneCreateInput = external_exports.object({
@@ -26332,6 +26345,27 @@ var approvalListForOwnerInputSchema = approvalListOptionsSchema.optional();
26332
26345
  var approvalListForInstanceInputSchema = approvalListOptionsSchema.extend({
26333
26346
  agentId: external_exports.string().min(1)
26334
26347
  });
26348
+ var approvalActionRuleSchema = external_exports.object({
26349
+ host: external_exports.string(),
26350
+ method: external_exports.string(),
26351
+ pathPattern: external_exports.string(),
26352
+ verdict: external_exports.enum(["allow", "deny"])
26353
+ });
26354
+ var approvalActionOutcomeSchema = external_exports.object({
26355
+ outcome: external_exports.enum(["applied", "rule_written_expired", "not_actionable"]),
26356
+ rule: approvalActionRuleSchema.nullable()
26357
+ });
26358
+
26359
+ // ../api-server-api/src/modules/approvals/format.ts
26360
+ function describeApprovalPayload(payload) {
26361
+ if (payload.kind === "ext_authz") {
26362
+ return {
26363
+ title: `${payload.method} ${payload.host}`,
26364
+ subtitle: payload.path
26365
+ };
26366
+ }
26367
+ return { title: payload.toolName ?? "tool call", subtitle: "" };
26368
+ }
26335
26369
 
26336
26370
  // ../api-server-api/src/modules/egress-rules/format.ts
26337
26371
  function formatEgressRuleSource(source) {
@@ -26461,6 +26495,32 @@ var e2ePerformFetchInputSchema = external_exports.object({
26461
26495
  headers: external_exports.record(external_exports.string(), external_exports.string()).optional()
26462
26496
  }).strict();
26463
26497
 
26498
+ // ../api-server-api/src/modules/api-keys/schemas.ts
26499
+ var AGENT_SCOPES = [
26500
+ "agents:read",
26501
+ "agents:operate",
26502
+ "agents:manage"
26503
+ ];
26504
+ var CREDENTIAL_SCOPES = [
26505
+ "credentials:read",
26506
+ "credentials:manage"
26507
+ ];
26508
+ var ALL_SCOPES = [...AGENT_SCOPES, ...CREDENTIAL_SCOPES];
26509
+ var scopeSchema = external_exports.enum(ALL_SCOPES);
26510
+ var agentBindingSchema = external_exports.union([
26511
+ external_exports.literal("*"),
26512
+ external_exports.array(external_exports.string().min(1)).min(1).max(256).transform((arr) => Array.from(new Set(arr)))
26513
+ ]);
26514
+ var apiKeyCreateInputSchema = external_exports.object({
26515
+ name: external_exports.string().min(1).max(100),
26516
+ scopes: external_exports.array(scopeSchema).min(1).transform((arr) => Array.from(new Set(arr))),
26517
+ agentIds: agentBindingSchema.default("*"),
26518
+ expiresAt: external_exports.string().datetime().nullable().optional()
26519
+ });
26520
+ var apiKeyRevokeInputSchema = external_exports.object({
26521
+ id: external_exports.string().min(1)
26522
+ });
26523
+
26464
26524
  // src/result.ts
26465
26525
  var ok2 = (value) => ({ ok: true, value });
26466
26526
  var err2 = (error51) => ({ ok: false, error: error51 });
@@ -26682,6 +26742,7 @@ var EXIT_AUTH_STATUS_NO_VALID = 4;
26682
26742
  var EXIT_AGENT_NOT_RESOLVED = 5;
26683
26743
  var EXIT_RULE_NOT_FOUND = 6;
26684
26744
  var EXIT_AGENT_NOT_REACHABLE = 7;
26745
+ var EXIT_APPROVAL_NOT_ACTIONABLE = 8;
26685
26746
  var EXIT_SIGINT = 130;
26686
26747
 
26687
26748
  // src/modules/agent/commands/errors.ts
@@ -28607,6 +28668,14 @@ async function runDelete(ref, opts, deps) {
28607
28668
  process.exit(EXIT_SUCCESS);
28608
28669
  }
28609
28670
 
28671
+ // src/modules/shared/stdout.ts
28672
+ async function writeStdoutAndExit(data, exitCode) {
28673
+ await new Promise((resolve4) => {
28674
+ process.stdout.write(data, () => resolve4());
28675
+ });
28676
+ process.exit(exitCode);
28677
+ }
28678
+
28610
28679
  // src/modules/agent/commands/get.ts
28611
28680
  function buildGetCommand(deps) {
28612
28681
  return new Command("get").description("Show one Agent's details, addressed by name or ID").argument("<ref>", "Agent Ref \u2014 name or 'agent-\u2026' ID").option(
@@ -28631,12 +28700,13 @@ function buildGetCommand(deps) {
28631
28700
  process.exit(exitCodeForResolveError(result.error));
28632
28701
  }
28633
28702
  if (opts.json) {
28634
- process.stdout.write(`${JSON.stringify(result.value)}
28635
- `);
28636
- process.exit(EXIT_SUCCESS);
28703
+ return writeStdoutAndExit(
28704
+ `${JSON.stringify(result.value)}
28705
+ `,
28706
+ EXIT_SUCCESS
28707
+ );
28637
28708
  }
28638
- process.stdout.write(renderAgent(result.value));
28639
- process.exit(EXIT_SUCCESS);
28709
+ return writeStdoutAndExit(renderAgent(result.value), EXIT_SUCCESS);
28640
28710
  });
28641
28711
  }
28642
28712
  function renderAgent(agent) {
@@ -28677,6 +28747,28 @@ function renderTable(rows) {
28677
28747
  ).join(" ")
28678
28748
  ).join("\n") + "\n";
28679
28749
  }
28750
+ var COLUMN_GAP = 3;
28751
+ var MIN_FLEX_WIDTH = 20;
28752
+ var collapse = (s) => s.replace(/\s+/g, " ").trim();
28753
+ function truncate(s, max) {
28754
+ return s.length <= max ? s : `${s.slice(0, Math.max(0, max - 1))}\u2026`;
28755
+ }
28756
+ function renderFittedTable(header, rows, flexCol = header.length - 1) {
28757
+ let fixedWidth = 0;
28758
+ for (let col = 0; col < header.length; col++) {
28759
+ if (col === flexCol) continue;
28760
+ const w3 = Math.max(header[col].length, ...rows.map((r) => r[col].length));
28761
+ fixedWidth += w3 + COLUMN_GAP;
28762
+ }
28763
+ const columns = process.stdout.columns ?? 100;
28764
+ const budget = Math.max(MIN_FLEX_WIDTH, columns - fixedWidth);
28765
+ const clamped = rows.map(
28766
+ (r) => r.map(
28767
+ (cell, col) => col === flexCol ? truncate(collapse(cell), budget) : cell
28768
+ )
28769
+ );
28770
+ return renderTable([[...header], ...clamped]);
28771
+ }
28680
28772
 
28681
28773
  // src/modules/agent/commands/list.ts
28682
28774
  function buildListCommand(deps) {
@@ -28700,9 +28792,11 @@ function buildListCommand(deps) {
28700
28792
  process.exit(EXIT_RUNTIME_FAILURE);
28701
28793
  }
28702
28794
  if (opts.json) {
28703
- process.stdout.write(`${JSON.stringify(result.value)}
28704
- `);
28705
- process.exit(EXIT_SUCCESS);
28795
+ return writeStdoutAndExit(
28796
+ `${JSON.stringify(result.value)}
28797
+ `,
28798
+ EXIT_SUCCESS
28799
+ );
28706
28800
  }
28707
28801
  if (result.value.length === 0) {
28708
28802
  process.stderr.write(
@@ -28713,7 +28807,7 @@ function buildListCommand(deps) {
28713
28807
  const sorted = [...result.value].sort(
28714
28808
  (a, b2) => a.name.localeCompare(b2.name)
28715
28809
  );
28716
- process.stdout.write(
28810
+ return writeStdoutAndExit(
28717
28811
  renderTable([
28718
28812
  ["NAME", "ID", "TEMPLATE", "STATE"],
28719
28813
  ...sorted.map((a) => [
@@ -28722,9 +28816,9 @@ function buildListCommand(deps) {
28722
28816
  a.templateId ?? "<custom>",
28723
28817
  a.state
28724
28818
  ])
28725
- ])
28819
+ ]),
28820
+ EXIT_SUCCESS
28726
28821
  );
28727
- process.exit(EXIT_SUCCESS);
28728
28822
  });
28729
28823
  }
28730
28824
 
@@ -28866,9 +28960,7 @@ function createAgentService(deps) {
28866
28960
  }
28867
28961
  return {
28868
28962
  async list() {
28869
- return trpcCall(
28870
- () => deps.trpc.agents.list.query()
28871
- );
28963
+ return trpcCall(() => deps.trpc.agents.list.query());
28872
28964
  },
28873
28965
  async get(id) {
28874
28966
  try {
@@ -28933,6 +29025,294 @@ function composeAgentModule(opts) {
28933
29025
  return { commands: [parent], exports: { createService } };
28934
29026
  }
28935
29027
 
29028
+ // src/modules/approval/commands/outcome.ts
29029
+ function describeRule(rule) {
29030
+ const hostWide = rule.method === "*" && rule.pathPattern === "*";
29031
+ return `${hostWide ? "host-wide " : ""}egress rule (${formatEgressRuleInline(rule)})`;
29032
+ }
29033
+ function printOutcomeAndExit(outcome, opts, wording) {
29034
+ const exitCode = outcome.outcome === "not_actionable" ? EXIT_APPROVAL_NOT_ACTIONABLE : EXIT_SUCCESS;
29035
+ if (opts.json) {
29036
+ process.stdout.write(`${JSON.stringify(outcome)}
29037
+ `);
29038
+ process.exit(exitCode);
29039
+ }
29040
+ switch (outcome.outcome) {
29041
+ case "applied":
29042
+ if (outcome.rule) {
29043
+ process.stdout.write(
29044
+ `${wording.pastTense} \u2014 wrote permanent ${describeRule(outcome.rule)}. It now appears in \`dam network list <agent>\`.
29045
+ `
29046
+ );
29047
+ } else if (opts.once) {
29048
+ process.stdout.write(`${wording.onceLine}
29049
+ `);
29050
+ } else {
29051
+ process.stdout.write(
29052
+ `${wording.pastTense} \u2014 verdict sent to the harness (tool-call permission; no egress rule involved).
29053
+ `
29054
+ );
29055
+ }
29056
+ break;
29057
+ case "rule_written_expired":
29058
+ process.stdout.write(
29059
+ `Held call already expired \u2014 wrote the durable ${outcome.rule ? describeRule(outcome.rule) : "egress rule"} anyway; ${wording.expiredEffect}
29060
+ `
29061
+ );
29062
+ break;
29063
+ case "not_actionable":
29064
+ process.stderr.write(
29065
+ "error: approval not found or already settled. See `dam approval list --status all`.\n"
29066
+ );
29067
+ break;
29068
+ }
29069
+ process.exit(exitCode);
29070
+ }
29071
+
29072
+ // src/modules/approval/commands/approve.ts
29073
+ function buildApproveCommand(deps) {
29074
+ return new Command("approve").description("Approve a pending request from the inbox").argument("<id>", "approval id (copy from `dam approval list`)").option(
29075
+ "--once",
29076
+ "allow only this held call \u2014 the same request shape re-prompts next time"
29077
+ ).option(
29078
+ "--entire-host",
29079
+ "allow the entire host (any method, any path); network requests only"
29080
+ ).option(
29081
+ "--server <url>",
29082
+ "override the configured server URL for this call"
29083
+ ).option("--json", "emit the raw action outcome as JSON").addHelpText(
29084
+ "after",
29085
+ "\nBare `approve` is durable: for a network (ext_authz) request it writes a\npermanent allow rule \u2014 egress to that host/method/path stays open and the rule\nappears in `dam network list <agent>`. Use --once to allow only the held call.\nTool-call (acp_native) approvals never write an egress rule; the harness owns\nits own permission persistence, and --entire-host falls back to the durable approve.\n"
29086
+ ).action(
29087
+ async (id, opts) => {
29088
+ if (opts.once && opts.entireHost) {
29089
+ process.stderr.write(
29090
+ "error: --once and --entire-host are mutually exclusive\n"
29091
+ );
29092
+ process.exit(EXIT_INVALID_INPUT);
29093
+ }
29094
+ const host = await resolveActiveHost(deps, {
29095
+ flag: opts.server ? { server: opts.server } : void 0,
29096
+ exitCodes: {
29097
+ runtimeFailure: EXIT_RUNTIME_FAILURE,
29098
+ belowFloor: EXIT_BELOW_FLOOR
29099
+ }
29100
+ });
29101
+ const service = deps.createApprovalService(host);
29102
+ const result = await (opts.once ? service.approveOnce(id) : opts.entireHost ? service.approveHost(id) : service.approvePermanent(id));
29103
+ if (!result.ok) {
29104
+ printServiceError(result.error, host);
29105
+ process.exit(EXIT_RUNTIME_FAILURE);
29106
+ }
29107
+ printOutcomeAndExit(result.value, opts, {
29108
+ pastTense: "Approved",
29109
+ onceLine: "Approved this call only \u2014 the same request shape will re-prompt next time.",
29110
+ expiredEffect: "the next request of this shape passes."
29111
+ });
29112
+ }
29113
+ );
29114
+ }
29115
+
29116
+ // src/modules/approval/commands/deny.ts
29117
+ function buildDenyCommand(deps) {
29118
+ return new Command("deny").description("Deny a pending request from the inbox").argument("<id>", "approval id (copy from `dam approval list`)").option(
29119
+ "--once",
29120
+ "deny only this held call \u2014 the same request shape re-prompts next time"
29121
+ ).option(
29122
+ "--server <url>",
29123
+ "override the configured server URL for this call"
29124
+ ).option("--json", "emit the raw action outcome as JSON").addHelpText(
29125
+ "after",
29126
+ "\nBare `deny` is durable: for a network (ext_authz) request it writes a\npermanent deny rule \u2014 future requests of that shape are blocked without\nprompting, and the rule appears in `dam network list <agent>`. Use --once to\ndeny only the held call. Tool-call (acp_native) denials never write an egress\nrule; the verdict goes to the harness.\n"
29127
+ ).action(
29128
+ async (id, opts) => {
29129
+ const host = await resolveActiveHost(deps, {
29130
+ flag: opts.server ? { server: opts.server } : void 0,
29131
+ exitCodes: {
29132
+ runtimeFailure: EXIT_RUNTIME_FAILURE,
29133
+ belowFloor: EXIT_BELOW_FLOOR
29134
+ }
29135
+ });
29136
+ const service = deps.createApprovalService(host);
29137
+ const result = await (opts.once ? service.dismiss(id) : service.denyForever(id));
29138
+ if (!result.ok) {
29139
+ printServiceError(result.error, host);
29140
+ process.exit(EXIT_RUNTIME_FAILURE);
29141
+ }
29142
+ printOutcomeAndExit(result.value, opts, {
29143
+ pastTense: "Denied",
29144
+ onceLine: "Denied this call only \u2014 re-prompts next time.",
29145
+ expiredEffect: "future requests of this shape are blocked."
29146
+ });
29147
+ }
29148
+ );
29149
+ }
29150
+
29151
+ // src/modules/shared/relative-time.ts
29152
+ var MINUTE_MS = 6e4;
29153
+ var HOUR_MS = 36e5;
29154
+ var DAY_MS = 864e5;
29155
+ function formatRelative(iso, now) {
29156
+ const diffMs = Date.parse(iso) - now.getTime();
29157
+ const abs = Math.abs(diffMs);
29158
+ const value = abs >= DAY_MS ? `${Math.floor(abs / DAY_MS)}d` : abs >= HOUR_MS ? `${Math.floor(abs / HOUR_MS)}h` : `${Math.max(1, Math.floor(abs / MINUTE_MS))}m`;
29159
+ return diffMs >= 0 ? `in ${value}` : `${value} ago`;
29160
+ }
29161
+
29162
+ // src/modules/approval/commands/list.ts
29163
+ function buildListCommand2(deps) {
29164
+ return new Command("list").description(
29165
+ "List the HITL approval inbox \u2014 requests your Agents are waiting on"
29166
+ ).argument(
29167
+ "[agent]",
29168
+ "Agent Ref \u2014 name or 'agent-\u2026' ID; omit for all your Agents"
29169
+ ).addOption(
29170
+ new Option(
29171
+ "--status <status>",
29172
+ "filter by status; 'all' includes resolved and expired"
29173
+ ).choices(["pending", "resolved", "expired", "all"]).default("pending")
29174
+ ).option("--limit <n>", "maximum rows (1\u2013500)").option(
29175
+ "--server <url>",
29176
+ "override the configured server URL for this call"
29177
+ ).option("--json", "emit raw JSON instead of the default table").addHelpText(
29178
+ "after",
29179
+ "\nExamples:\n dam approval list\n dam approval list my-agent --status all\n\n`dam network` manages the standing rules (pre-approvals that stop a prompt\nfrom appearing); `dam approval` actions the prompts that did appear.\n"
29180
+ ).action(
29181
+ async (ref, opts) => {
29182
+ let limit;
29183
+ if (opts.limit !== void 0) {
29184
+ const n = Number(opts.limit);
29185
+ if (!Number.isInteger(n) || n <= 0 || n > 500) {
29186
+ process.stderr.write(
29187
+ `error: invalid \`--limit\` value \`${opts.limit}\`; expected integer between 1 and 500
29188
+ `
29189
+ );
29190
+ process.exit(EXIT_INVALID_INPUT);
29191
+ }
29192
+ limit = n;
29193
+ }
29194
+ const host = await resolveActiveHost(deps, {
29195
+ flag: opts.server ? { server: opts.server } : void 0,
29196
+ exitCodes: {
29197
+ runtimeFailure: EXIT_RUNTIME_FAILURE,
29198
+ belowFloor: EXIT_BELOW_FLOOR
29199
+ }
29200
+ });
29201
+ const listOpts = {
29202
+ ...opts.status === "all" ? {} : { status: opts.status },
29203
+ ...limit === void 0 ? {} : { limit }
29204
+ };
29205
+ const service = deps.createApprovalService(host);
29206
+ let result;
29207
+ if (ref === void 0) {
29208
+ result = await service.listForOwner(listOpts);
29209
+ } else {
29210
+ const resolver = createAgentResolver({
29211
+ agentService: deps.createAgentService(host)
29212
+ });
29213
+ const resolved = await resolver.resolve(ref);
29214
+ if (!resolved.ok) {
29215
+ printResolveError(resolved.error, host);
29216
+ process.exit(exitCodeForResolveError(resolved.error));
29217
+ }
29218
+ result = await service.listForInstance(resolved.value.id, listOpts);
29219
+ }
29220
+ if (!result.ok) {
29221
+ printServiceError(result.error, host);
29222
+ process.exit(EXIT_RUNTIME_FAILURE);
29223
+ }
29224
+ if (opts.json) {
29225
+ return writeStdoutAndExit(
29226
+ `${JSON.stringify(result.value)}
29227
+ `,
29228
+ EXIT_SUCCESS
29229
+ );
29230
+ }
29231
+ if (result.value.length === 0) {
29232
+ process.stderr.write(
29233
+ opts.status === "pending" ? "No pending approvals. Use --status all to include resolved and expired.\n" : `No ${opts.status === "all" ? "" : `${opts.status} `}approvals.
29234
+ `
29235
+ );
29236
+ process.exit(EXIT_SUCCESS);
29237
+ }
29238
+ const now = /* @__PURE__ */ new Date();
29239
+ return writeStdoutAndExit(
29240
+ renderFittedTable(
29241
+ ["ID", "TYPE", "AGENT", "REQUEST", "STATUS", "EXPIRES"],
29242
+ result.value.map((row) => {
29243
+ const { title, subtitle } = describeApprovalPayload(row.payload);
29244
+ return [
29245
+ row.id,
29246
+ row.type,
29247
+ row.agentId,
29248
+ title + (subtitle ? ` ${subtitle}` : ""),
29249
+ row.status,
29250
+ row.status === "pending" ? formatRelative(row.expiresAt, now) : "\u2014"
29251
+ ];
29252
+ }),
29253
+ 3
29254
+ ),
29255
+ EXIT_SUCCESS
29256
+ );
29257
+ }
29258
+ );
29259
+ }
29260
+
29261
+ // src/modules/approval/services/approval-service.ts
29262
+ function createApprovalService(deps) {
29263
+ return {
29264
+ async listForOwner(opts) {
29265
+ return trpcCall(() => deps.trpc.approvals.listForOwner.query(opts));
29266
+ },
29267
+ async listForInstance(agentId, opts) {
29268
+ return trpcCall(
29269
+ () => deps.trpc.approvals.listForInstance.query({ agentId, ...opts })
29270
+ );
29271
+ },
29272
+ async approveOnce(id) {
29273
+ return trpcCall(() => deps.trpc.approvals.approveOnce.mutate({ id }));
29274
+ },
29275
+ async approvePermanent(id) {
29276
+ return trpcCall(
29277
+ () => deps.trpc.approvals.approvePermanent.mutate({ id })
29278
+ );
29279
+ },
29280
+ async approveHost(id) {
29281
+ return trpcCall(() => deps.trpc.approvals.approveHost.mutate({ id }));
29282
+ },
29283
+ async denyForever(id) {
29284
+ return trpcCall(() => deps.trpc.approvals.denyForever.mutate({ id }));
29285
+ },
29286
+ async dismiss(id) {
29287
+ return trpcCall(() => deps.trpc.approvals.dismiss.mutate({ id }));
29288
+ }
29289
+ };
29290
+ }
29291
+
29292
+ // src/modules/approval/compose.ts
29293
+ function composeApprovalModule(opts) {
29294
+ const buildTrpc = (host) => createTrpcClient({ host, tokenProvider: opts.tokenProvider });
29295
+ const createService = (host) => createApprovalService({ trpc: buildTrpc(host) });
29296
+ const agentScoped = {
29297
+ compatService: opts.compatService,
29298
+ configService: opts.configService,
29299
+ createAgentService: opts.createAgentService,
29300
+ createApprovalService: createService
29301
+ };
29302
+ const idScoped = {
29303
+ compatService: opts.compatService,
29304
+ configService: opts.configService,
29305
+ createApprovalService: createService
29306
+ };
29307
+ const parent = new Command("approval").description(
29308
+ "Action pending approvals \u2014 the HITL prompts your Agents are waiting on (see `dam network` for the standing rules)"
29309
+ );
29310
+ parent.addCommand(buildListCommand2(agentScoped));
29311
+ parent.addCommand(buildApproveCommand(idScoped));
29312
+ parent.addCommand(buildDenyCommand(idScoped));
29313
+ return { commands: [parent] };
29314
+ }
29315
+
28936
29316
  // src/modules/auth/commands/login.ts
28937
29317
  import { createInterface as createInterface3 } from "readline/promises";
28938
29318
  var EXIT_AUTH_SUCCESS_OR_ABORT = 0;
@@ -29220,6 +29600,154 @@ function printStatusError(e2) {
29220
29600
  }
29221
29601
  }
29222
29602
 
29603
+ // src/modules/auth/commands/token-create.ts
29604
+ function buildTokenCreateCommand(deps) {
29605
+ return new Command("create").description(
29606
+ "Mint a new API key. The plaintext token is printed once on stderr \u2014 copy it now, it cannot be recovered."
29607
+ ).requiredOption("--name <name>", "human-readable label").option(
29608
+ "--scope <scope...>",
29609
+ `permission scope (${ALL_SCOPES.join(" | ")}); repeatable`
29610
+ ).option(
29611
+ "--agent <agent-id...>",
29612
+ "restrict to specific Agent IDs (repeatable); defaults to all owned agents"
29613
+ ).option(
29614
+ "--expires <iso>",
29615
+ "expiration timestamp in ISO 8601, e.g. 2026-12-31T00:00:00Z"
29616
+ ).option("--json", "emit the result as JSON (still warns on stderr)").action(
29617
+ async (opts) => {
29618
+ const scopes = opts.scope ?? ["agents:operate"];
29619
+ const parsedScopes = [];
29620
+ for (const s of scopes) {
29621
+ const r = scopeSchema.safeParse(s);
29622
+ if (!r.success) {
29623
+ process.stderr.write(
29624
+ `error: unknown scope "${s}". Valid: ${ALL_SCOPES.join(", ")}
29625
+ `
29626
+ );
29627
+ process.exit(EXIT_INVALID_INPUT);
29628
+ }
29629
+ parsedScopes.push(r.data);
29630
+ }
29631
+ const resolved = await deps.configService.getResolved({});
29632
+ if (!resolved.ok) {
29633
+ process.stderr.write(
29634
+ "error: no server configured; pass `--server <url>` or run `dam config set server <url>`\n"
29635
+ );
29636
+ process.exit(EXIT_INVALID_INPUT);
29637
+ }
29638
+ const trpc = deps.buildTrpc(resolved.value.server);
29639
+ try {
29640
+ const result = await trpc.apiKeys.create.mutate({
29641
+ name: opts.name,
29642
+ scopes: parsedScopes,
29643
+ agentIds: opts.agent && opts.agent.length > 0 ? opts.agent : "*",
29644
+ ...opts.expires ? { expiresAt: opts.expires } : {}
29645
+ });
29646
+ if (opts.json) {
29647
+ process.stdout.write(
29648
+ `${JSON.stringify({ ...result.key, plaintext: result.plaintext })}
29649
+ `
29650
+ );
29651
+ } else {
29652
+ process.stderr.write(
29653
+ "\u26A0 Copy this token now. It will never be shown again.\n"
29654
+ );
29655
+ process.stderr.write(`${result.plaintext}
29656
+ `);
29657
+ process.stderr.write(`id: ${result.key.id}
29658
+ `);
29659
+ process.stderr.write(`name: ${result.key.name}
29660
+ `);
29661
+ process.stderr.write(`scopes: ${result.key.scopes.join(", ")}
29662
+ `);
29663
+ const binding = result.key.agentIds === "*" ? "all owned agents" : result.key.agentIds.join(", ");
29664
+ process.stderr.write(`agents: ${binding}
29665
+ `);
29666
+ if (result.key.expiresAt)
29667
+ process.stderr.write(`expires: ${result.key.expiresAt}
29668
+ `);
29669
+ }
29670
+ } catch (err3) {
29671
+ process.stderr.write(
29672
+ `error: ${err3 instanceof Error ? err3.message : String(err3)}
29673
+ `
29674
+ );
29675
+ process.exit(EXIT_RUNTIME_FAILURE);
29676
+ }
29677
+ }
29678
+ );
29679
+ }
29680
+
29681
+ // src/modules/auth/commands/token-list.ts
29682
+ function buildTokenListCommand(deps) {
29683
+ return new Command("list").description(
29684
+ "List API keys owned by the current user (plaintext never shown)"
29685
+ ).option("--json", "emit raw JSON").action(async (opts) => {
29686
+ const resolved = await deps.configService.getResolved({});
29687
+ if (!resolved.ok) {
29688
+ process.stderr.write(
29689
+ "error: no server configured; pass `--server <url>` or run `dam config set server <url>`\n"
29690
+ );
29691
+ process.exit(EXIT_INVALID_INPUT);
29692
+ }
29693
+ const trpc = deps.buildTrpc(resolved.value.server);
29694
+ try {
29695
+ const keys = await trpc.apiKeys.list.query();
29696
+ if (opts.json) {
29697
+ process.stdout.write(`${JSON.stringify(keys)}
29698
+ `);
29699
+ return;
29700
+ }
29701
+ if (keys.length === 0) {
29702
+ process.stdout.write("(no api keys)\n");
29703
+ return;
29704
+ }
29705
+ for (const k2 of keys) {
29706
+ const binding = k2.agentIds === "*" ? "*" : k2.agentIds.join(",");
29707
+ const exp = k2.expiresAt ? `exp=${k2.expiresAt}` : "exp=never";
29708
+ const last = k2.lastUsedAt ? `last=${k2.lastUsedAt}` : "last=never";
29709
+ process.stdout.write(
29710
+ `${k2.id} ${k2.name} [${k2.scopes.join(",")}] agents=${binding} ${exp} ${last}
29711
+ `
29712
+ );
29713
+ }
29714
+ } catch (err3) {
29715
+ process.stderr.write(
29716
+ `error: ${err3 instanceof Error ? err3.message : String(err3)}
29717
+ `
29718
+ );
29719
+ process.exit(EXIT_RUNTIME_FAILURE);
29720
+ }
29721
+ });
29722
+ }
29723
+
29724
+ // src/modules/auth/commands/token-revoke.ts
29725
+ function buildTokenRevokeCommand(deps) {
29726
+ return new Command("revoke").description(
29727
+ "Revoke an API key by ID. The key is immediately rejected on the next request."
29728
+ ).argument("<id>", "API key ID (e.g. key-abcdef12)").action(async (id) => {
29729
+ const resolved = await deps.configService.getResolved({});
29730
+ if (!resolved.ok) {
29731
+ process.stderr.write(
29732
+ "error: no server configured; pass `--server <url>` or run `dam config set server <url>`\n"
29733
+ );
29734
+ process.exit(EXIT_INVALID_INPUT);
29735
+ }
29736
+ const trpc = deps.buildTrpc(resolved.value.server);
29737
+ try {
29738
+ await trpc.apiKeys.revoke.mutate({ id });
29739
+ process.stdout.write(`\u2713 Revoked ${id}
29740
+ `);
29741
+ } catch (err3) {
29742
+ process.stderr.write(
29743
+ `error: ${err3 instanceof Error ? err3.message : String(err3)}
29744
+ `
29745
+ );
29746
+ process.exit(EXIT_RUNTIME_FAILURE);
29747
+ }
29748
+ });
29749
+ }
29750
+
29223
29751
  // src/modules/auth/infrastructure/auth-config-probe.ts
29224
29752
  var authConfigSchema2 = external_exports.object({
29225
29753
  issuer: external_exports.string().min(1),
@@ -31686,6 +32214,29 @@ function composeAuthModule(opts) {
31686
32214
  })
31687
32215
  );
31688
32216
  authParent.addCommand(buildStatusCommand({ authService }));
32217
+ const buildTrpc = (host) => createTrpcClient({ host, tokenProvider });
32218
+ const tokenParent = new Command("token").description(
32219
+ "Manage API keys for headless / CI use"
32220
+ );
32221
+ tokenParent.addCommand(
32222
+ buildTokenCreateCommand({
32223
+ configService: opts.configService,
32224
+ buildTrpc
32225
+ })
32226
+ );
32227
+ tokenParent.addCommand(
32228
+ buildTokenListCommand({
32229
+ configService: opts.configService,
32230
+ buildTrpc
32231
+ })
32232
+ );
32233
+ tokenParent.addCommand(
32234
+ buildTokenRevokeCommand({
32235
+ configService: opts.configService,
32236
+ buildTrpc
32237
+ })
32238
+ );
32239
+ authParent.addCommand(tokenParent);
31689
32240
  return {
31690
32241
  commands: [authParent],
31691
32242
  exports: { tokenProvider },
@@ -34188,7 +34739,7 @@ function createProcessEnvReader() {
34188
34739
 
34189
34740
  // src/modules/cli/infrastructure/package-version.ts
34190
34741
  function readPackageVersion() {
34191
- return true ? "0.2.1-rc3" : DEV_VERSION;
34742
+ return true ? "0.2.2-rc1" : DEV_VERSION;
34192
34743
  }
34193
34744
 
34194
34745
  // src/modules/cli/infrastructure/version-probe.ts
@@ -34415,7 +34966,10 @@ function buildConnectCommand(deps) {
34415
34966
  ).option(
34416
34967
  "--auth <mode>",
34417
34968
  "MCP auth mode: oauth | none (default: auto-detect from the server)"
34418
- ).option("--url <url>", "input: url").option("--host <host>", "input: host").option("--client-id <id>", "input: OAuth client id").option("--client-secret <secret>", "input: OAuth client secret").option("--app-slug <slug>", "input: GitHub App slug").option("--header-name <name>", "input: header name").option("--value-format <format>", "input: header value format").option("--value <value>", "input: header secret value").option(
34969
+ ).option("--url <url>", "input: url").option("--host <host>", "input: host").option("--client-id <id>", "input: OAuth client id").option("--client-secret <secret>", "input: OAuth client secret").option("--app-slug <slug>", "input: GitHub App slug").option("--header-name <name>", "input: header name").option("--value-format <format>", "input: header value format").option(
34970
+ "--env-name <name>",
34971
+ "input: expose the credential to the agent as this env var (custom header credentials)"
34972
+ ).option("--value <value>", "input: header secret value").option(
34419
34973
  "--server <url>",
34420
34974
  "override the configured server URL for this call"
34421
34975
  ).option(
@@ -34664,12 +35218,20 @@ function buildPayload(template, name, values) {
34664
35218
  case "header": {
34665
35219
  const value = v2("value");
34666
35220
  if (!value) return { error: "the secret value is required (--value)" };
35221
+ const configInputs = {};
35222
+ for (const input of template.inputs) {
35223
+ if (!input.configInput) continue;
35224
+ const ov = v2(input.name);
35225
+ if (ov) configInputs[input.name] = ov;
35226
+ }
34667
35227
  return {
34668
35228
  ...common,
34669
35229
  authKind: "header",
34670
35230
  ...v2("host") ? { host: v2("host") } : {},
34671
35231
  ...v2("headerName") ? { headerName: v2("headerName") } : {},
34672
35232
  ...v2("valueFormat") ? { valueFormat: v2("valueFormat") } : {},
35233
+ ...v2("envName") ? { envName: v2("envName") } : {},
35234
+ ...Object.keys(configInputs).length > 0 ? { configInputs } : {},
34673
35235
  value
34674
35236
  };
34675
35237
  }
@@ -34752,7 +35314,8 @@ var FIELD_LABELS = {
34752
35314
  value: "Secret value",
34753
35315
  clientId: "Client ID",
34754
35316
  clientSecret: "Client secret",
34755
- appSlug: "GitHub App slug"
35317
+ appSlug: "GitHub App slug",
35318
+ envName: "Env var name"
34756
35319
  };
34757
35320
  function labelFor(key) {
34758
35321
  return FIELD_LABELS[key] ?? key;
@@ -34929,7 +35492,7 @@ function tableFor(views) {
34929
35492
  ])
34930
35493
  ]);
34931
35494
  }
34932
- function buildListCommand2(deps) {
35495
+ function buildListCommand3(deps) {
34933
35496
  return new Command("list").description(
34934
35497
  "List team connections, or the connections granted to one Agent"
34935
35498
  ).argument("[agent]", "Agent Ref \u2014 name or 'agent-\u2026' ID (optional)").option(
@@ -34955,9 +35518,11 @@ function buildListCommand2(deps) {
34955
35518
  process.exit(EXIT_RUNTIME_FAILURE);
34956
35519
  }
34957
35520
  if (opts.json) {
34958
- process.stdout.write(`${JSON.stringify(result.value)}
34959
- `);
34960
- process.exit(EXIT_SUCCESS);
35521
+ return writeStdoutAndExit(
35522
+ `${JSON.stringify(result.value)}
35523
+ `,
35524
+ EXIT_SUCCESS
35525
+ );
34961
35526
  }
34962
35527
  if (result.value.length === 0) {
34963
35528
  process.stderr.write(
@@ -34965,8 +35530,7 @@ function buildListCommand2(deps) {
34965
35530
  );
34966
35531
  process.exit(EXIT_SUCCESS);
34967
35532
  }
34968
- process.stdout.write(tableFor(result.value));
34969
- process.exit(EXIT_SUCCESS);
35533
+ return writeStdoutAndExit(tableFor(result.value), EXIT_SUCCESS);
34970
35534
  }
34971
35535
  const resolver = createAgentResolver({
34972
35536
  agentService: deps.createAgentService(host)
@@ -34997,9 +35561,11 @@ function buildListCommand2(deps) {
34997
35561
  else missing.push(id);
34998
35562
  }
34999
35563
  if (opts.json) {
35000
- process.stdout.write(`${JSON.stringify(matched)}
35001
- `);
35002
- process.exit(EXIT_SUCCESS);
35564
+ return writeStdoutAndExit(
35565
+ `${JSON.stringify(matched)}
35566
+ `,
35567
+ EXIT_SUCCESS
35568
+ );
35003
35569
  }
35004
35570
  if (matched.length === 0 && missing.length === 0) {
35005
35571
  process.stderr.write(
@@ -35008,13 +35574,15 @@ function buildListCommand2(deps) {
35008
35574
  );
35009
35575
  process.exit(EXIT_SUCCESS);
35010
35576
  }
35011
- if (matched.length > 0) process.stdout.write(tableFor(matched));
35012
35577
  if (missing.length > 0) {
35013
35578
  process.stderr.write(
35014
35579
  `note: ${missing.length} granted connection(s) no longer exist: ${missing.join(", ")}
35015
35580
  `
35016
35581
  );
35017
35582
  }
35583
+ if (matched.length > 0) {
35584
+ return writeStdoutAndExit(tableFor(matched), EXIT_SUCCESS);
35585
+ }
35018
35586
  process.exit(EXIT_SUCCESS);
35019
35587
  }
35020
35588
  );
@@ -35153,15 +35721,16 @@ function buildTemplatesCommand(deps) {
35153
35721
  }
35154
35722
  const connectable = result.value.filter((t) => t.category !== "mcp");
35155
35723
  if (opts.json) {
35156
- process.stdout.write(`${JSON.stringify(connectable)}
35157
- `);
35158
- process.exit(EXIT_SUCCESS);
35724
+ return writeStdoutAndExit(
35725
+ `${JSON.stringify(connectable)}
35726
+ `,
35727
+ EXIT_SUCCESS
35728
+ );
35159
35729
  }
35160
- process.stdout.write(tableFor2(connectable));
35161
35730
  process.stderr.write(
35162
35731
  "\nMCP servers are added by URL: dam connection connect https://your-mcp-server\n"
35163
35732
  );
35164
- process.exit(EXIT_SUCCESS);
35733
+ return writeStdoutAndExit(tableFor2(connectable), EXIT_SUCCESS);
35165
35734
  });
35166
35735
  }
35167
35736
 
@@ -35175,14 +35744,10 @@ function createConnectionService(deps) {
35175
35744
  };
35176
35745
  return {
35177
35746
  async list() {
35178
- return trpcCall(
35179
- () => deps.trpc.connections.list.query()
35180
- );
35747
+ return trpcCall(() => deps.trpc.connections.list.query());
35181
35748
  },
35182
35749
  async listTemplates() {
35183
- return trpcCall(
35184
- () => deps.trpc.connections.listTemplates.query()
35185
- );
35750
+ return trpcCall(() => deps.trpc.connections.listTemplates.query());
35186
35751
  },
35187
35752
  async createConnection(input) {
35188
35753
  return trpcCall(() => deps.trpc.connections.create.mutate(input));
@@ -35196,11 +35761,7 @@ function createConnectionService(deps) {
35196
35761
  return trpcCall(() => deps.trpc.connections.discoverMcp.mutate({ url: url2 }));
35197
35762
  },
35198
35763
  async getConnection(id) {
35199
- return trpcCall(
35200
- () => deps.trpc.connections.get.query({
35201
- id
35202
- })
35203
- );
35764
+ return trpcCall(() => deps.trpc.connections.get.query({ id }));
35204
35765
  },
35205
35766
  async agentConnectionIds(agentId) {
35206
35767
  return trpcCall(() => readIds(agentId));
@@ -35249,7 +35810,7 @@ function composeConnectionModule(opts) {
35249
35810
  const parent = new Command("connection").description(
35250
35811
  "Manage OAuth connections and agent connection grants"
35251
35812
  );
35252
- parent.addCommand(buildListCommand2(agentScoped));
35813
+ parent.addCommand(buildListCommand3(agentScoped));
35253
35814
  parent.addCommand(
35254
35815
  buildTemplatesCommand({
35255
35816
  compatService: opts.compatService,
@@ -35413,7 +35974,7 @@ function buildCreateCommand2(deps) {
35413
35974
  }
35414
35975
 
35415
35976
  // src/modules/egress/commands/list.ts
35416
- function buildListCommand3(deps) {
35977
+ function buildListCommand4(deps) {
35417
35978
  return new Command("list").description("List network access rules for an Agent").argument("<agent>", "Agent Ref \u2014 name or 'agent-\u2026' ID").option(
35418
35979
  "--server <url>",
35419
35980
  "override the configured server URL for this call"
@@ -35442,9 +36003,11 @@ function buildListCommand3(deps) {
35442
36003
  process.exit(EXIT_RUNTIME_FAILURE);
35443
36004
  }
35444
36005
  if (opts.json) {
35445
- process.stdout.write(`${JSON.stringify(result.value)}
35446
- `);
35447
- process.exit(EXIT_SUCCESS);
36006
+ return writeStdoutAndExit(
36007
+ `${JSON.stringify(result.value)}
36008
+ `,
36009
+ EXIT_SUCCESS
36010
+ );
35448
36011
  }
35449
36012
  if (result.value.length === 0) {
35450
36013
  process.stderr.write(
@@ -35460,7 +36023,7 @@ function buildListCommand3(deps) {
35460
36023
  if (m !== 0) return m;
35461
36024
  return a.pathPattern.localeCompare(b2.pathPattern);
35462
36025
  });
35463
- process.stdout.write(
36026
+ return writeStdoutAndExit(
35464
36027
  renderTable([
35465
36028
  ["ID", "VERDICT", "METHOD", "HOST", "PATH", "SOURCE"],
35466
36029
  ...sorted.map((r) => [
@@ -35471,9 +36034,9 @@ function buildListCommand3(deps) {
35471
36034
  r.pathPattern,
35472
36035
  formatEgressRuleSource(r.source)
35473
36036
  ])
35474
- ])
36037
+ ]),
36038
+ EXIT_SUCCESS
35475
36039
  );
35476
- process.exit(EXIT_SUCCESS);
35477
36040
  });
35478
36041
  }
35479
36042
 
@@ -35572,14 +36135,10 @@ function buildTrustedHostsCommand(deps) {
35572
36135
  printServiceError(result.error, host);
35573
36136
  process.exit(EXIT_RUNTIME_FAILURE);
35574
36137
  }
35575
- if (opts.json) {
35576
- process.stdout.write(`${JSON.stringify(result.value)}
35577
- `);
35578
- } else if (result.value.length > 0) {
35579
- process.stdout.write(`${result.value.join("\n")}
35580
- `);
35581
- }
35582
- process.exit(EXIT_SUCCESS);
36138
+ const out = opts.json ? `${JSON.stringify(result.value)}
36139
+ ` : result.value.length > 0 ? `${result.value.join("\n")}
36140
+ ` : "";
36141
+ return writeStdoutAndExit(out, EXIT_SUCCESS);
35583
36142
  });
35584
36143
  }
35585
36144
 
@@ -35664,26 +36223,18 @@ function createEgressService(deps) {
35664
36223
  },
35665
36224
  async currentPreset(agentId) {
35666
36225
  return trpcCall(
35667
- () => deps.trpc.egressRules.currentPreset.query({
35668
- agentId
35669
- })
36226
+ () => deps.trpc.egressRules.currentPreset.query({ agentId })
35670
36227
  );
35671
36228
  },
35672
36229
  async trustedHosts() {
35673
- return trpcCall(
35674
- () => deps.trpc.egressRules.trustedHosts.query()
35675
- );
36230
+ return trpcCall(() => deps.trpc.egressRules.trustedHosts.query());
35676
36231
  },
35677
36232
  async create(input) {
35678
- return trpcCall(
35679
- () => deps.trpc.egressRules.create.mutate(input)
35680
- );
36233
+ return trpcCall(() => deps.trpc.egressRules.create.mutate(input));
35681
36234
  },
35682
36235
  async update(input) {
35683
36236
  try {
35684
- const view = await deps.trpc.egressRules.update.mutate(
35685
- input
35686
- );
36237
+ const view = await deps.trpc.egressRules.update.mutate(input);
35687
36238
  return ok2(view);
35688
36239
  } catch (e2) {
35689
36240
  if (e2?.data?.code === "NOT_FOUND") {
@@ -35723,7 +36274,7 @@ function composeEgressModule(opts) {
35723
36274
  const parent = new Command("network").description(
35724
36275
  "Manage per-Agent network access rules (the pre-approvals that let an Agent reach external hosts)"
35725
36276
  );
35726
- parent.addCommand(buildListCommand3(agentScoped));
36277
+ parent.addCommand(buildListCommand4(agentScoped));
35727
36278
  parent.addCommand(buildCreateCommand2(agentScoped));
35728
36279
  parent.addCommand(buildUpdateCommand(idScoped));
35729
36280
  parent.addCommand(buildRevokeCommand2(idScoped));
@@ -35914,16 +36465,10 @@ function buildFileListCommand(deps) {
35914
36465
  printTrpcError(e2, host);
35915
36466
  process.exit(EXIT_RUNTIME_FAILURE);
35916
36467
  }
35917
- if (opts.json) {
35918
- process.stdout.write(`${JSON.stringify(entries)}
35919
- `);
35920
- } else {
35921
- for (const e2 of entries) {
35922
- if (e2.type === "file") process.stdout.write(`${e2.path}
35923
- `);
35924
- }
35925
- }
35926
- process.exit(EXIT_SUCCESS);
36468
+ const out = opts.json ? `${JSON.stringify(entries)}
36469
+ ` : entries.filter((e2) => e2.type === "file").map((e2) => `${e2.path}
36470
+ `).join("");
36471
+ return writeStdoutAndExit(out, EXIT_SUCCESS);
35927
36472
  }
35928
36473
  );
35929
36474
  }
@@ -36467,25 +37012,6 @@ function statusFor(scanned, installed) {
36467
37012
 
36468
37013
  // src/modules/skill/commands/catalog.ts
36469
37014
  var byName = (a, b2) => a.name.localeCompare(b2.name);
36470
- var COLUMN_GAP = 3;
36471
- var MIN_DESCRIPTION = 20;
36472
- var collapse = (s) => s.replace(/\s+/g, " ").trim();
36473
- var truncate = (s, max) => s.length <= max ? s : `${s.slice(0, Math.max(0, max - 1))}\u2026`;
36474
- function renderFittedTable(header, rows) {
36475
- const leadCount = header.length - 1;
36476
- let leadWidth = 0;
36477
- for (let col = 0; col < leadCount; col++) {
36478
- const w3 = Math.max(header[col].length, ...rows.map((r) => r[col].length));
36479
- leadWidth += w3 + COLUMN_GAP;
36480
- }
36481
- const columns = process.stdout.columns ?? 100;
36482
- const budget = Math.max(MIN_DESCRIPTION, columns - leadWidth);
36483
- const clamped = rows.map((r) => [
36484
- ...r.slice(0, -1),
36485
- truncate(collapse(r[r.length - 1]), budget)
36486
- ]);
36487
- return renderTable([[...header], ...clamped]);
36488
- }
36489
37015
  function buildCatalogCommand(deps) {
36490
37016
  return new Command("catalog").description(
36491
37017
  "Scan a skill source's available skills; with --agent, annotate each skill's install status"
@@ -36572,36 +37098,40 @@ function buildCatalogCommand(deps) {
36572
37098
  const installed = installedRes !== null ? installedRes.value : void 0;
36573
37099
  if (installed === void 0) {
36574
37100
  if (opts.json) {
36575
- process.stdout.write(`${JSON.stringify(catalogRes.value)}
36576
- `);
36577
- process.exit(EXIT_SUCCESS);
37101
+ return writeStdoutAndExit(
37102
+ `${JSON.stringify(catalogRes.value)}
37103
+ `,
37104
+ EXIT_SUCCESS
37105
+ );
36578
37106
  }
36579
37107
  const sorted2 = [...catalogRes.value].sort(byName);
36580
- process.stdout.write(
37108
+ return writeStdoutAndExit(
36581
37109
  renderFittedTable(
36582
37110
  ["NAME", "DESCRIPTION"],
36583
37111
  sorted2.map((s) => [s.name, s.description])
36584
- )
37112
+ ),
37113
+ EXIT_SUCCESS
36585
37114
  );
36586
- process.exit(EXIT_SUCCESS);
36587
37115
  }
36588
37116
  const annotated = catalogRes.value.map((s) => ({
36589
37117
  ...s,
36590
37118
  status: statusFor(s, installed)
36591
37119
  }));
36592
37120
  if (opts.json) {
36593
- process.stdout.write(`${JSON.stringify(annotated)}
36594
- `);
36595
- process.exit(EXIT_SUCCESS);
37121
+ return writeStdoutAndExit(
37122
+ `${JSON.stringify(annotated)}
37123
+ `,
37124
+ EXIT_SUCCESS
37125
+ );
36596
37126
  }
36597
37127
  const sorted = [...annotated].sort(byName);
36598
- process.stdout.write(
37128
+ return writeStdoutAndExit(
36599
37129
  renderFittedTable(
36600
37130
  ["NAME", "STATUS", "DESCRIPTION"],
36601
37131
  sorted.map((s) => [s.name, s.status, s.description])
36602
- )
37132
+ ),
37133
+ EXIT_SUCCESS
36603
37134
  );
36604
- process.exit(EXIT_SUCCESS);
36605
37135
  }
36606
37136
  );
36607
37137
  }
@@ -36727,7 +37257,7 @@ function buildInstallCommand(deps) {
36727
37257
  // src/modules/skill/commands/list.ts
36728
37258
  var INSTALLED_HEADER = ["SOURCE", "NAME", "VERSION"];
36729
37259
  var STANDALONE_HEADER = ["NAME", "PUBLISHED"];
36730
- function buildListCommand4(deps) {
37260
+ function buildListCommand5(deps) {
36731
37261
  return new Command("list").description("List the skills on an Agent \u2014 installed and standalone").argument("<agent>", "Agent Ref \u2014 name or 'agent-\u2026' ID").option(
36732
37262
  "--server <url>",
36733
37263
  "override the configured server URL for this call"
@@ -36765,9 +37295,8 @@ function buildListCommand4(deps) {
36765
37295
  }
36766
37296
  const state = stateRes.value;
36767
37297
  if (opts.json) {
36768
- process.stdout.write(`${JSON.stringify(state)}
36769
- `);
36770
- process.exit(EXIT_SUCCESS);
37298
+ return writeStdoutAndExit(`${JSON.stringify(state)}
37299
+ `, EXIT_SUCCESS);
36771
37300
  }
36772
37301
  if (state.installed.length === 0 && state.standalone.length === 0) {
36773
37302
  process.stderr.write(
@@ -36776,14 +37305,15 @@ function buildListCommand4(deps) {
36776
37305
  );
36777
37306
  process.exit(EXIT_SUCCESS);
36778
37307
  }
37308
+ let out = "";
36779
37309
  if (state.installed.length > 0) {
36780
- renderInstalled(state.installed, sourcesRes.value);
37310
+ out += renderInstalled(state.installed, sourcesRes.value);
36781
37311
  }
36782
37312
  if (state.standalone.length > 0) {
36783
- if (state.installed.length > 0) process.stdout.write("\n");
36784
- renderStandalone(state.standalone, state.instancePublishes);
37313
+ if (out.length > 0) out += "\n";
37314
+ out += renderStandalone(state.standalone, state.instancePublishes);
36785
37315
  }
36786
- process.exit(EXIT_SUCCESS);
37316
+ return writeStdoutAndExit(out, EXIT_SUCCESS);
36787
37317
  });
36788
37318
  }
36789
37319
  function renderInstalled(installed, sources) {
@@ -36794,14 +37324,14 @@ function renderInstalled(installed, sources) {
36794
37324
  if (name === void 0) unresolved.add(r.source);
36795
37325
  return [name ?? r.source, r.name, r.version.slice(0, 7)];
36796
37326
  });
36797
- process.stdout.write("Installed skills:\n");
36798
- process.stdout.write(renderTable([INSTALLED_HEADER, ...rows]));
36799
37327
  if (unresolved.size > 0) {
36800
37328
  process.stderr.write(
36801
37329
  `note: ${unresolved.size} source(s) no longer registered, shown by URL: ${[...unresolved].join(", ")}
36802
37330
  `
36803
37331
  );
36804
37332
  }
37333
+ return `Installed skills:
37334
+ ${renderTable([INSTALLED_HEADER, ...rows])}`;
36805
37335
  }
36806
37336
  function renderStandalone(standalone, publishes) {
36807
37337
  const prByName = /* @__PURE__ */ new Map();
@@ -36814,8 +37344,8 @@ function renderStandalone(standalone, publishes) {
36814
37344
  }
36815
37345
  }
36816
37346
  const rows = [...standalone].sort((a, b2) => a.name.localeCompare(b2.name)).map((s) => [s.name, prByName.get(s.name) ?? "\u2014"]);
36817
- process.stdout.write("Standalone skills:\n");
36818
- process.stdout.write(renderTable([STANDALONE_HEADER, ...rows]));
37347
+ return `Standalone skills:
37348
+ ${renderTable([STANDALONE_HEADER, ...rows])}`;
36819
37349
  }
36820
37350
  function bySourceThenName(a, b2) {
36821
37351
  const s = a.source.localeCompare(b2.source);
@@ -37106,9 +37636,11 @@ function buildSourceListCommand(deps) {
37106
37636
  process.exit(EXIT_RUNTIME_FAILURE);
37107
37637
  }
37108
37638
  if (opts.json) {
37109
- process.stdout.write(`${JSON.stringify(result.value)}
37110
- `);
37111
- process.exit(EXIT_SUCCESS);
37639
+ return writeStdoutAndExit(
37640
+ `${JSON.stringify(result.value)}
37641
+ `,
37642
+ EXIT_SUCCESS
37643
+ );
37112
37644
  }
37113
37645
  if (result.value.length === 0) {
37114
37646
  process.stderr.write(
@@ -37116,8 +37648,7 @@ function buildSourceListCommand(deps) {
37116
37648
  );
37117
37649
  process.exit(EXIT_SUCCESS);
37118
37650
  }
37119
- process.stdout.write(tableFor3(result.value));
37120
- process.exit(EXIT_SUCCESS);
37651
+ return writeStdoutAndExit(tableFor3(result.value), EXIT_SUCCESS);
37121
37652
  }
37122
37653
  );
37123
37654
  }
@@ -37373,16 +37904,12 @@ function createSkillsService(deps) {
37373
37904
  return {
37374
37905
  async listSources(agentId) {
37375
37906
  return trpcCall(
37376
- () => deps.trpc.skills.sources.list.query(
37377
- agentId ? { agentId } : void 0
37378
- )
37907
+ () => deps.trpc.skills.sources.list.query(agentId ? { agentId } : void 0)
37379
37908
  );
37380
37909
  },
37381
37910
  async addSource(input) {
37382
37911
  try {
37383
- const created = await deps.trpc.skills.sources.create.mutate(
37384
- input
37385
- );
37912
+ const created = await deps.trpc.skills.sources.create.mutate(input);
37386
37913
  return ok2(created);
37387
37914
  } catch (e2) {
37388
37915
  if (e2?.data?.code === "CONFLICT") {
@@ -37437,15 +37964,11 @@ function createSkillsService(deps) {
37437
37964
  );
37438
37965
  },
37439
37966
  async state(agentId) {
37440
- return trpcCall(
37441
- async () => await deps.trpc.skills.state.query({ agentId })
37442
- );
37967
+ return trpcCall(() => deps.trpc.skills.state.query({ agentId }));
37443
37968
  },
37444
37969
  async install(input) {
37445
37970
  try {
37446
- const refs = await deps.trpc.skills.install.mutate(
37447
- input
37448
- );
37971
+ const refs = await deps.trpc.skills.install.mutate(input);
37449
37972
  return ok2(refs);
37450
37973
  } catch (e2) {
37451
37974
  return classifyWakeError(e2);
@@ -37453,9 +37976,7 @@ function createSkillsService(deps) {
37453
37976
  },
37454
37977
  async uninstall(input) {
37455
37978
  try {
37456
- const refs = await deps.trpc.skills.uninstall.mutate(
37457
- input
37458
- );
37979
+ const refs = await deps.trpc.skills.uninstall.mutate(input);
37459
37980
  return ok2(refs);
37460
37981
  } catch (e2) {
37461
37982
  return classifyWakeError(e2);
@@ -37463,9 +37984,7 @@ function createSkillsService(deps) {
37463
37984
  },
37464
37985
  async publish(input) {
37465
37986
  try {
37466
- const result = await deps.trpc.skills.publish.mutate(
37467
- input
37468
- );
37987
+ const result = await deps.trpc.skills.publish.mutate(input);
37469
37988
  return ok2(result);
37470
37989
  } catch (e2) {
37471
37990
  return classifyPublishError(e2);
@@ -37496,7 +38015,7 @@ function composeSkillModule(opts) {
37496
38015
  sourceGroup.addCommand(buildSourceRefreshCommand(shared));
37497
38016
  parent.addCommand(sourceGroup);
37498
38017
  parent.addCommand(buildCatalogCommand(shared));
37499
- parent.addCommand(buildListCommand4(shared));
38018
+ parent.addCommand(buildListCommand5(shared));
37500
38019
  parent.addCommand(buildInstallCommand(shared));
37501
38020
  parent.addCommand(buildUninstallCommand(shared));
37502
38021
  parent.addCommand(buildPublishCommand(shared));
@@ -38061,7 +38580,7 @@ function composeSshModule(opts) {
38061
38580
 
38062
38581
  // src/modules/template/commands/list.ts
38063
38582
  var DESCRIPTION_MAX = 60;
38064
- function buildListCommand5(deps) {
38583
+ function buildListCommand6(deps) {
38065
38584
  return new Command("list").description("List agent templates available on the active host").option(
38066
38585
  "--server <url>",
38067
38586
  "override the configured server URL for this call"
@@ -38082,9 +38601,11 @@ function buildListCommand5(deps) {
38082
38601
  process.exit(EXIT_RUNTIME_FAILURE);
38083
38602
  }
38084
38603
  if (opts.json) {
38085
- process.stdout.write(`${JSON.stringify(result.value)}
38086
- `);
38087
- process.exit(EXIT_SUCCESS);
38604
+ return writeStdoutAndExit(
38605
+ `${JSON.stringify(result.value)}
38606
+ `,
38607
+ EXIT_SUCCESS
38608
+ );
38088
38609
  }
38089
38610
  if (result.value.length === 0) {
38090
38611
  process.stderr.write(
@@ -38095,7 +38616,7 @@ function buildListCommand5(deps) {
38095
38616
  const sorted = [...result.value].sort(
38096
38617
  (a, b2) => a.name.localeCompare(b2.name)
38097
38618
  );
38098
- process.stdout.write(
38619
+ return writeStdoutAndExit(
38099
38620
  renderTable([
38100
38621
  ["NAME", "ID", "DESCRIPTION"],
38101
38622
  ...sorted.map((t) => [
@@ -38103,9 +38624,9 @@ function buildListCommand5(deps) {
38103
38624
  t.id,
38104
38625
  truncate2(t.description ?? "", DESCRIPTION_MAX)
38105
38626
  ])
38106
- ])
38627
+ ]),
38628
+ EXIT_SUCCESS
38107
38629
  );
38108
- process.exit(EXIT_SUCCESS);
38109
38630
  });
38110
38631
  }
38111
38632
  function truncate2(s, n) {
@@ -38144,7 +38665,7 @@ function composeTemplateModule(opts) {
38144
38665
  "Discover agent templates on the active host"
38145
38666
  );
38146
38667
  parent.addCommand(
38147
- buildListCommand5({
38668
+ buildListCommand6({
38148
38669
  compatService: opts.compatService,
38149
38670
  configService: opts.configService,
38150
38671
  createTemplateService: createService
@@ -38205,6 +38726,12 @@ function compose(opts = {}) {
38205
38726
  compatService: cli.services.compatService,
38206
38727
  createAgentService: agent.exports.createService
38207
38728
  });
38729
+ const approval = composeApprovalModule({
38730
+ tokenProvider: auth.exports.tokenProvider,
38731
+ configService: cli.services.configService,
38732
+ compatService: cli.services.compatService,
38733
+ createAgentService: agent.exports.createService
38734
+ });
38208
38735
  const connection2 = composeConnectionModule({
38209
38736
  tokenProvider: auth.exports.tokenProvider,
38210
38737
  configService: cli.services.configService,
@@ -38235,6 +38762,7 @@ function compose(opts = {}) {
38235
38762
  for (const command of importModule.commands) program3.addCommand(command);
38236
38763
  for (const command of fileModule.commands) program3.addCommand(command);
38237
38764
  for (const command of egress.commands) program3.addCommand(command);
38765
+ for (const command of approval.commands) program3.addCommand(command);
38238
38766
  for (const command of connection2.commands) program3.addCommand(command);
38239
38767
  for (const command of skill.commands) program3.addCommand(command);
38240
38768
  for (const command of ssh.commands) program3.addCommand(command);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dam-agents/cli",
3
3
  "author": "IBM Corp.",
4
- "version": "0.2.1-rc3",
4
+ "version": "0.2.2-rc1",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
7
7
  "homepage": "https://github.com/dam-agents/dam/tree/main/packages/cli#readme",
@@ -42,7 +42,7 @@
42
42
  "ws": "^8.20.0",
43
43
  "zod": "^4.4.3",
44
44
  "agent-runtime-api": "0.0.1",
45
- "dev-config": "0.0.1",
46
- "api-server-api": "0.0.1"
45
+ "api-server-api": "0.0.1",
46
+ "dev-config": "0.0.1"
47
47
  }
48
48
  }