@dam-agents/cli 0.2.12 → 0.2.13-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 +483 -59
  2. package/package.json +3 -3
package/dist/bin.js CHANGED
@@ -13,7 +13,11 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
13
13
  throw Error('Dynamic require of "' + x + '" is not supported');
14
14
  });
15
15
  var __commonJS = (cb, mod) => function __require2() {
16
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
16
+ try {
17
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
18
+ } catch (e2) {
19
+ throw mod = 0, e2;
20
+ }
17
21
  };
18
22
  var __export = (target, all) => {
19
23
  for (var name in all)
@@ -26749,7 +26753,33 @@ var skillSchema = external_exports.object({
26749
26753
  name: external_exports.string(),
26750
26754
  description: external_exports.string(),
26751
26755
  version: external_exports.string(),
26752
- contentHash: external_exports.string()
26756
+ contentHash: external_exports.string(),
26757
+ /** Repo-relative directory the skill was found in, whichever Source Root it
26758
+ * came from — what a raw-file URL needs. Distinct from `skillSourceSchema.path`,
26759
+ * which is the source's optional subdir; `dir` is this one skill's actual
26760
+ * location under it. Optional: the agent-runtime clone scan (private /
26761
+ * non-GitHub sources) doesn't report it. */
26762
+ dir: external_exports.string().optional()
26763
+ });
26764
+ var skillListResultSchema = external_exports.object({
26765
+ skills: external_exports.array(skillSchema),
26766
+ /** ISO 8601 time the source's skill list was last read from upstream. A
26767
+ * cache hit reports the original read, not the moment of the hit. */
26768
+ scannedAt: external_exports.string().datetime()
26769
+ });
26770
+ var scanFailureCodes = [
26771
+ "needs_github_connection",
26772
+ "needs_sandbox",
26773
+ "repo_unreachable",
26774
+ "agent_unreachable",
26775
+ "other"
26776
+ ];
26777
+ var scanFailureSchema = external_exports.object({
26778
+ code: external_exports.enum(scanFailureCodes),
26779
+ /** Single line naming the cause. */
26780
+ title: external_exports.string(),
26781
+ /** Single line naming the fix. */
26782
+ detail: external_exports.string()
26753
26783
  });
26754
26784
  var skillRefSchema = external_exports.object({
26755
26785
  source: external_exports.string(),
@@ -26771,7 +26801,11 @@ var localSkillSchema = external_exports.object({
26771
26801
  /** Provenance vs. the image's pristine copy: shipped untouched, shipped
26772
26802
  * but diverged, or created at runtime. Absent on pre-provenance pods —
26773
26803
  * treat as `user`. */
26774
- origin: external_exports.enum(["system", "system-modified", "user"]).optional()
26804
+ origin: external_exports.enum(["system", "system-modified", "user"]).optional(),
26805
+ /** Deterministic SHA-256 of the skill directory, comparable with a scanned
26806
+ * skill's `contentHash`. Present only for skills the server asked the pod to
26807
+ * hash, and absent on pods predating this field (#3019). */
26808
+ contentHash: external_exports.string().optional()
26775
26809
  });
26776
26810
  var skillPublishRecordSchema = external_exports.object({
26777
26811
  skillName: external_exports.string(),
@@ -26780,12 +26814,27 @@ var skillPublishRecordSchema = external_exports.object({
26780
26814
  sourceGitUrl: external_exports.string(),
26781
26815
  prUrl: external_exports.string(),
26782
26816
  /** ISO 8601 timestamp. */
26783
- publishedAt: external_exports.string()
26817
+ publishedAt: external_exports.string(),
26818
+ /** Resolved outcome of `prUrl`, or null when it has never been
26819
+ * resolved — the source is private, the read was rate-limited, the
26820
+ * pull request is gone. `merged` and `closed` are terminal and are
26821
+ * never re-read (#3019). */
26822
+ prState: external_exports.enum(["draft", "open", "merged", "closed"]).nullable(),
26823
+ /** ISO 8601 timestamp of the last resolution *attempt*, which is not
26824
+ * the same as the last success: an attempt that resolved nothing
26825
+ * still stamps it, because it doubles as the backoff clock. Null
26826
+ * until the first attempt. */
26827
+ prStateCheckedAt: external_exports.string().nullable()
26784
26828
  });
26785
26829
  var skillStateOutputSchema = external_exports.object({
26786
26830
  installed: external_exports.array(skillRefSchema),
26787
26831
  standalone: external_exports.array(localSkillSchema),
26788
- instancePublishes: external_exports.array(skillPublishRecordSchema)
26832
+ instancePublishes: external_exports.array(skillPublishRecordSchema),
26833
+ /** Present only when `standalone` came from a recorded snapshot rather than a
26834
+ * live pod read — the sandbox is stopped. Absent while running, which is what
26835
+ * lets a reader tell live truth from a snapshot without a second field for
26836
+ * the running case. */
26837
+ standaloneSnapshot: external_exports.object({ capturedAt: external_exports.string().datetime() }).optional()
26789
26838
  });
26790
26839
  var skillListSourcesInputSchema = external_exports.object({ agentId: external_exports.string().min(1).optional() }).optional();
26791
26840
  var skillCreateSourceInputSchema = external_exports.object({
@@ -27036,9 +27085,28 @@ var skillPublishInputSchema2 = external_exports.object({
27036
27085
  // subdir source's own scan finds what was published back to it.
27037
27086
  path: external_exports.string().optional()
27038
27087
  });
27088
+ var skillListLocalInputSchema2 = external_exports.object({
27089
+ /** Names to compute `contentHash` for. Hashing walks the whole skill dir on
27090
+ * an NFS-backed PVC and this runs on every state poll, so the caller asks
27091
+ * only for the few skills it needs it for (#3019). */
27092
+ hashNames: external_exports.array(external_exports.string()).optional()
27093
+ });
27039
27094
  var skillReadLocalInputSchema2 = external_exports.object({
27040
27095
  name: external_exports.string().min(1)
27041
27096
  });
27097
+ var skillReadPullRequestInputSchema = external_exports.object({
27098
+ owner: external_exports.string().min(1),
27099
+ repo: external_exports.string().min(1),
27100
+ number: external_exports.number().int().positive()
27101
+ });
27102
+ var skillReadSkillFileInputSchema = external_exports.object({
27103
+ source: external_exports.string().min(1),
27104
+ /** Commit SHA the scan pinned — the preview renders the revision the
27105
+ * catalog listed. */
27106
+ version: external_exports.string().min(1),
27107
+ /** Repo-relative skill directory from the scan; `SKILL.md` is read inside it. */
27108
+ dir: external_exports.string().min(1)
27109
+ });
27042
27110
  var skillDeleteLocalInputSchema2 = external_exports.object({
27043
27111
  name: external_exports.string().min(1)
27044
27112
  });
@@ -27058,6 +27126,21 @@ var sshAuthorizeKeyInputSchema = external_exports.object({
27058
27126
  publicKey: external_exports.string().min(1).max(8192).refine((s) => !/[\r\n]/.test(s), "must be a single line")
27059
27127
  });
27060
27128
 
27129
+ // ../agent-runtime-api/src/modules/background-work/schemas.ts
27130
+ var advisory = (max) => external_exports.string().transform((text) => text.slice(0, max)).optional();
27131
+ var backgroundWorkItemSchema = external_exports.object({
27132
+ id: external_exports.string().min(1).transform((id) => id.slice(0, 128)),
27133
+ description: advisory(200),
27134
+ command: advisory(500)
27135
+ });
27136
+ var backgroundWorkReportSchema = external_exports.object({
27137
+ // Also truncated rather than capped, for the same reason: a hold is per
27138
+ // session, so one surviving item holds it, whereas rejecting an over-long list
27139
+ // would hold nothing at all. Excess entries cost only detail in the status
27140
+ // payload.
27141
+ items: external_exports.array(backgroundWorkItemSchema).transform((items) => items.slice(0, 64))
27142
+ });
27143
+
27061
27144
  // ../agent-runtime-api/src/modules/import/types.ts
27062
27145
  var importBundleResultSchema = external_exports.object({
27063
27146
  filesWritten: external_exports.number().int().nonnegative(),
@@ -27246,6 +27329,12 @@ var harnessConfigCatalog = external_exports.object({
27246
27329
  // all allowed; empty array = group hidden for that model (e.g. Haiku effort).
27247
27330
  modelConstraints: external_exports.record(external_exports.string().min(1), external_exports.record(external_exports.string().min(1), external_exports.array(external_exports.string()))).optional()
27248
27331
  });
27332
+ var harnessConfigCurrent = external_exports.object({
27333
+ model: external_exports.string().nullable(),
27334
+ mode: external_exports.string().nullable(),
27335
+ configOptions: external_exports.record(external_exports.string().min(1), external_exports.string()),
27336
+ availableModels: external_exports.array(harnessConfigChoice).nullable().optional()
27337
+ });
27249
27338
  var capabilities = external_exports.object({
27250
27339
  contributions: external_exports.array(contributionKind),
27251
27340
  events: external_exports.array(eventKind),
@@ -27276,13 +27365,17 @@ var applyStateResult = external_exports.discriminatedUnion("status", [
27276
27365
  appliedHash: external_exports.string().min(1).nullable(),
27277
27366
  // null until the first clean settle
27278
27367
  failures: external_exports.array(driverFailure).default([]),
27279
- settledEvents: external_exports.array(external_exports.string()).default([])
27368
+ settledEvents: external_exports.array(external_exports.string()).default([]),
27369
+ // Absent from a pod predating this, or one whose manifest declares no
27370
+ // harness-config driver — the server then keeps whatever it holds.
27371
+ harnessConfigCurrent: harnessConfigCurrent.optional()
27280
27372
  }),
27281
27373
  // Contributions already at ≥ the requested version; worker reconciles. Events still apply (own version) — settledEvents reports which.
27282
27374
  external_exports.object({
27283
27375
  status: external_exports.literal("stale"),
27284
27376
  appliedVersion: external_exports.number().int().nonnegative(),
27285
- settledEvents: external_exports.array(external_exports.string()).default([])
27377
+ settledEvents: external_exports.array(external_exports.string()).default([]),
27378
+ harnessConfigCurrent: harnessConfigCurrent.optional()
27286
27379
  })
27287
27380
  ]);
27288
27381
  var helloInput = external_exports.object({
@@ -27290,7 +27383,12 @@ var helloInput = external_exports.object({
27290
27383
  lastAppliedHash: external_exports.string().optional(),
27291
27384
  protocolVersion: external_exports.literal("v1"),
27292
27385
  agentRuntimeVersion: external_exports.string(),
27293
- capabilities
27386
+ capabilities,
27387
+ // The config file as it stands at boot, with no discovered model list: `hello`
27388
+ // is what delivers capabilities, and the worker won't dispatch an apply until
27389
+ // they land, so waiting on the provider here delays the first apply after
27390
+ // every boot and wake. The apply reply carries the list instead.
27391
+ harnessConfigCurrent: harnessConfigCurrent.optional()
27294
27392
  });
27295
27393
  var helloResult = external_exports.object({
27296
27394
  version: external_exports.number().int().positive().optional(),
@@ -27317,6 +27415,29 @@ var harnessConfigStatusSchema = external_exports.object({
27317
27415
  var harnessConfigSettledSchema = external_exports.object({
27318
27416
  settled: external_exports.boolean()
27319
27417
  });
27418
+ var harnessConfigSnapshotSchema = external_exports.object({
27419
+ model: external_exports.string().nullable(),
27420
+ mode: external_exports.string().nullable(),
27421
+ configOptions: agentConfigOptionsSchema,
27422
+ /** Models the provider offered when it was last successfully asked; null when
27423
+ * the harness declares no discovery source. A failed attempt leaves this
27424
+ * alone, so it can be older than the rest of the snapshot. */
27425
+ availableModels: external_exports.array(harnessConfigChoice).nullable(),
27426
+ capturedAt: external_exports.string().datetime(),
27427
+ /** The model that was in effect when `availableModels` was observed. Comparing
27428
+ * the two is only meaningful while this still equals `model`: a model changed
27429
+ * since the list was read proves nothing about whether the provider offers it.
27430
+ * Absent on rows written before this field existed — treat as unpaired. */
27431
+ modelAtDiscovery: external_exports.string().nullable().optional(),
27432
+ /** False while the only source is an apply the pod has not reported back. */
27433
+ confirmed: external_exports.boolean()
27434
+ });
27435
+ var harnessConfigSnapshotResultSchema = external_exports.object({
27436
+ /** The agent has sent `hello` at least once, so a snapshot is possible.
27437
+ * False means "never run" — genuinely nothing to show, not a miss. */
27438
+ hasRun: external_exports.boolean(),
27439
+ snapshot: harnessConfigSnapshotSchema.nullable()
27440
+ });
27320
27441
 
27321
27442
  // ../api-server-api/src/modules/egress-rules/schemas.ts
27322
27443
  var ruleVerdictSchema = external_exports.enum(["allow", "deny"]);
@@ -27359,8 +27480,8 @@ var idSchema = external_exports.object({ id: external_exports.string().min(1) })
27359
27480
  var cpuQuantitySchema = external_exports.string().regex(/^\d+(\.\d+)?m?$/, "CPU must look like '2', '0.5' or '500m'").refine((v2) => toCpuMilli(v2) >= 100, {
27360
27481
  message: "CPU must be at least 100m"
27361
27482
  });
27362
- var memoryQuantitySchema = external_exports.string().regex(/^\d+(Mi|Gi)$/, "memory must look like '512Mi' or '2Gi'").refine((v2) => toMemoryMi(v2) >= 128, {
27363
- message: "memory must be at least 128Mi"
27483
+ var memoryQuantitySchema = external_exports.string().regex(/^\d+(Mi|Gi)$/, "memory must look like '512Mi' or '2Gi'").refine((v2) => toMemoryMi(v2) >= 384, {
27484
+ message: "memory must be at least 384Mi"
27364
27485
  });
27365
27486
  function toCpuMilli(v2) {
27366
27487
  return v2.endsWith("m") ? Number(v2.slice(0, -1)) : Number(v2) * 1e3;
@@ -27375,6 +27496,9 @@ var agentSizeSchema = external_exports.object({
27375
27496
  var agentUpgradeInputSchema = idSchema.extend({
27376
27497
  expectedToImage: external_exports.string().min(1).optional()
27377
27498
  });
27499
+ var agentDisconnectSlackInputSchema = idSchema.extend({
27500
+ slackChannelId: external_exports.string().min(1).optional()
27501
+ });
27378
27502
  var agentKindSchema = external_exports.enum(["knowledge-base", "experiment"]);
27379
27503
  var agentCreateInputSchema = external_exports.object({
27380
27504
  name: external_exports.string().min(1).refine((n) => !n.startsWith("agent-"), {
@@ -27727,7 +27851,6 @@ var artifactUpdateInputSchema = external_exports.object({
27727
27851
  folderId: external_exports.string().min(1).nullish(),
27728
27852
  ...contentOrUploadRef,
27729
27853
  fileName: fileNameSchema.optional(),
27730
- kind: artifactKindSchema.optional(),
27731
27854
  contentType: external_exports.string().trim().min(1).max(200).optional()
27732
27855
  }).refine((v2) => !(v2.content != null && v2.uploadRef != null), {
27733
27856
  message: "provide at most one of content or uploadRef",
@@ -27751,7 +27874,11 @@ var folderUpdateInputSchema = external_exports.object({
27751
27874
  var folderIdInputSchema = external_exports.object({ id: external_exports.string().min(1) });
27752
27875
 
27753
27876
  // ../api-server-api/src/modules/features/schemas.ts
27754
- var featureIdSchema = external_exports.enum(["advanced-connections", "vm-sandboxes"]);
27877
+ var featureIdSchema = external_exports.enum([
27878
+ "advanced-connections",
27879
+ "vm-sandboxes",
27880
+ "session-costs"
27881
+ ]);
27755
27882
  var featureSetFlagInputSchema = external_exports.object({
27756
27883
  feature: featureIdSchema,
27757
27884
  enabled: external_exports.boolean()
@@ -30958,6 +31085,11 @@ var secretRef = external_exports.object({
30958
31085
 
30959
31086
  // ../api-server-api/src/modules/connections/types.ts
30960
31087
  var connectionCategory = external_exports.enum(["app", "mcp", "other"]);
31088
+ var refreshBackoff = external_exports.object({
31089
+ failures: external_exports.number().int(),
31090
+ /** Epoch seconds; ticks before this skip the connection. */
31091
+ nextAttempt: external_exports.number().int()
31092
+ });
30961
31093
  var oauthAuth = external_exports.object({
30962
31094
  kind: external_exports.literal("oauth"),
30963
31095
  clientId: external_exports.string(),
@@ -30969,6 +31101,10 @@ var oauthAuth = external_exports.object({
30969
31101
  clientSecretRef: secretRef.optional(),
30970
31102
  expiresAt: external_exports.number().int().optional(),
30971
31103
  connectedAt: external_exports.number().int().optional(),
31104
+ // Epoch seconds, set only on a *permanent* token rejection: derives
31105
+ // `expired` and parks the connection. Any successful token write clears it.
31106
+ refreshFailedAt: external_exports.number().int().optional(),
31107
+ refreshBackoff: refreshBackoff.optional(),
30972
31108
  tokenEndpointAcceptJson: external_exports.boolean().optional(),
30973
31109
  extraAuthParams: external_exports.record(external_exports.string(), external_exports.string()).optional(),
30974
31110
  host: external_exports.string().min(1).optional(),
@@ -30985,6 +31121,8 @@ var clientCredentialsAuth = external_exports.object({
30985
31121
  audience: external_exports.string().min(1).optional(),
30986
31122
  expiresAt: external_exports.number().int().optional(),
30987
31123
  connectedAt: external_exports.number().int().optional(),
31124
+ refreshFailedAt: external_exports.number().int().optional(),
31125
+ refreshBackoff: refreshBackoff.optional(),
30988
31126
  tokenEndpointAcceptJson: external_exports.boolean().optional(),
30989
31127
  host: external_exports.string().min(1).optional()
30990
31128
  });
@@ -30997,7 +31135,21 @@ var githubAppAuth = external_exports.object({
30997
31135
  apiBaseUrl: external_exports.string().url(),
30998
31136
  expiresAt: external_exports.number().int().optional(),
30999
31137
  connectedAt: external_exports.number().int().optional(),
31000
- host: external_exports.string().min(1).optional()
31138
+ refreshFailedAt: external_exports.number().int().optional(),
31139
+ refreshBackoff: refreshBackoff.optional(),
31140
+ host: external_exports.string().min(1).optional(),
31141
+ // Optional narrowing of the minted token, stored because every re-mint must
31142
+ // ask for the same subset — a scope kept only on the create input would widen
31143
+ // back to the whole installation at the first renewal. Absent means the
31144
+ // installation's full authority, which is what every connection made before
31145
+ // this field existed carries.
31146
+ repositories: external_exports.array(external_exports.string().min(1)).nonempty().optional(),
31147
+ permissions: external_exports.record(external_exports.string(), external_exports.string()).optional(),
31148
+ // Repositories named by GitHub's numeric id rather than by name — what the
31149
+ // picker records, since an id survives a rename where a name would start
31150
+ // failing at the next renewal. Only one of the two reaches GitHub; ids win
31151
+ // when both are set, and connections predating the picker carry names only.
31152
+ repositoryIds: external_exports.array(external_exports.number().int()).nonempty().optional()
31001
31153
  });
31002
31154
  var headerAuth = external_exports.object({
31003
31155
  kind: external_exports.literal("header"),
@@ -31049,7 +31201,19 @@ var connectionView = external_exports.object({
31049
31201
  connectedAt: external_exports.string().optional(),
31050
31202
  hosts: external_exports.array(external_exports.string()),
31051
31203
  host: external_exports.string().min(1).optional(),
31052
- appSlug: external_exports.string().min(1).optional()
31204
+ appSlug: external_exports.string().min(1).optional(),
31205
+ // Only for an OAuth connection storing its own client secret — an
31206
+ // operator-supplied one is deploy config, not replaceable per connection.
31207
+ hasClientSecret: external_exports.boolean().optional(),
31208
+ // The narrowing a github-app connection currently mints against, so it can
31209
+ // be shown and edited rather than only set once at create. Absent means the
31210
+ // installation's full authority. Carries no secret — names, ids, and levels
31211
+ // are all things the user chose.
31212
+ githubAppScope: external_exports.object({
31213
+ repositories: external_exports.array(external_exports.string()).optional(),
31214
+ repositoryIds: external_exports.array(external_exports.number().int()).optional(),
31215
+ permissions: external_exports.record(external_exports.string(), external_exports.string()).optional()
31216
+ }).optional()
31053
31217
  });
31054
31218
  var templateInputState = external_exports.enum([
31055
31219
  "required",
@@ -31184,7 +31348,32 @@ var githubAppCreateInput = external_exports.object({
31184
31348
  host: external_exports.string().min(1).optional(),
31185
31349
  appId: external_exports.string().min(1),
31186
31350
  installationId: external_exports.string().min(1),
31187
- privateKey: external_exports.string().min(1)
31351
+ privateKey: external_exports.string().min(1),
31352
+ // Optional narrowing of the minted token. Space- or comma-separated; the
31353
+ // server parses both. Single strings keep the schema-driven forms all-string,
31354
+ // as client-credentials `scopes` does. Blank leaves the token with the
31355
+ // installation's full authority.
31356
+ repositories: external_exports.string().optional(),
31357
+ permissions: external_exports.string().optional(),
31358
+ // Repository ids, as picked from the installation. Same all-string shape as
31359
+ // the sibling fields; ids take precedence over names when both arrive.
31360
+ repositoryIds: external_exports.string().optional()
31361
+ });
31362
+ var connectionProbeGitHubAppInputSchema = external_exports.object({
31363
+ templateId: external_exports.string().min(1),
31364
+ appId: external_exports.string().min(1),
31365
+ installationId: external_exports.string().min(1),
31366
+ privateKey: external_exports.string().min(1),
31367
+ host: external_exports.string().min(1).optional()
31368
+ });
31369
+ var connectionProbeGitHubAppForConnectionInputSchema = external_exports.object({
31370
+ connectionId: external_exports.string().min(1)
31371
+ });
31372
+ var connectionUpdateGitHubAppScopeInputSchema = external_exports.object({
31373
+ id: external_exports.string().min(1),
31374
+ repositories: external_exports.string().optional(),
31375
+ repositoryIds: external_exports.string().optional(),
31376
+ permissions: external_exports.string().optional()
31188
31377
  });
31189
31378
  var noneCreateInput = external_exports.object({
31190
31379
  ...commonFields,
@@ -31348,6 +31537,26 @@ var platformTurnEndedNotificationSchema = external_exports.object({
31348
31537
  method: external_exports.literal("platform/turnEnded"),
31349
31538
  params: platformTurnEndedParamsSchema
31350
31539
  });
31540
+ var platformPromptAcceptedParamsSchema = external_exports.object({
31541
+ sessionId: external_exports.string().min(1),
31542
+ promptId: external_exports.string().min(1),
31543
+ /** True when the prompt was parked behind an in-flight turn. */
31544
+ queued: external_exports.boolean()
31545
+ });
31546
+ var platformPromptAcceptedNotificationSchema = external_exports.object({
31547
+ jsonrpc: external_exports.literal("2.0"),
31548
+ method: external_exports.literal("platform/promptAccepted"),
31549
+ params: platformPromptAcceptedParamsSchema
31550
+ });
31551
+ var platformPromptStartedParamsSchema = external_exports.object({
31552
+ sessionId: external_exports.string().min(1),
31553
+ promptId: external_exports.string().min(1)
31554
+ });
31555
+ var platformPromptStartedNotificationSchema = external_exports.object({
31556
+ jsonrpc: external_exports.literal("2.0"),
31557
+ method: external_exports.literal("platform/promptStarted"),
31558
+ params: platformPromptStartedParamsSchema
31559
+ });
31351
31560
 
31352
31561
  // ../api-server-api/src/modules/brand/types.ts
31353
31562
  var brandSchema = external_exports.object({
@@ -37573,7 +37782,9 @@ function buildSlackConnectCommand(deps) {
37573
37782
  process.exit(EXIT_RUNTIME_FAILURE);
37574
37783
  }
37575
37784
  if (opts.ambient) {
37576
- const slackCh = res.value.find((c2) => c2.type === "slack" /* Slack */);
37785
+ const slackCh = res.value.find(
37786
+ (c2) => c2.type === "slack" /* Slack */ && c2.slackChannelId === channelId
37787
+ );
37577
37788
  if (!slackCh?.ambient) {
37578
37789
  process.stderr.write(
37579
37790
  "error: this server does not support ambient mode \u2014 the channel is connected without it\n"
@@ -37606,46 +37817,67 @@ function buildSlackConnectCommand(deps) {
37606
37817
  // src/modules/channel/commands/slack-disconnect.ts
37607
37818
  function buildSlackDisconnectCommand(deps) {
37608
37819
  return new Command("disconnect").description(
37609
- "Unbind an Agent's Slack channel. Idempotent \u2014 a not-connected agent exits 0."
37820
+ "Unbind a Slack channel from an Agent. Idempotent \u2014 a not-connected agent exits 0."
37610
37821
  ).argument("<agent>", "Agent Ref \u2014 name or 'agent-\u2026' ID").option(
37822
+ "--channel-id <id>",
37823
+ "Slack channel id to disconnect; required when the Agent has more than one connected"
37824
+ ).option(
37611
37825
  "--server <url>",
37612
37826
  "override the configured server URL for this call"
37613
37827
  ).option("--json", "emit the updated ChannelConfig[] as JSON").addHelpText(
37614
37828
  "after",
37615
- "\nExamples:\n dam channel slack disconnect my-agent\n"
37616
- ).action(async (ref, opts) => {
37617
- const host = await resolveActiveHost(deps, {
37618
- flag: opts.server ? { server: opts.server } : void 0,
37619
- exitCodes: {
37620
- runtimeFailure: EXIT_RUNTIME_FAILURE,
37621
- belowFloor: EXIT_BELOW_FLOOR
37829
+ "\nExamples:\n dam channel slack disconnect my-agent\n dam channel slack disconnect my-agent --channel-id C0123ABCD\n"
37830
+ ).action(
37831
+ async (ref, opts) => {
37832
+ const channelId = opts.channelId?.trim();
37833
+ if (opts.channelId !== void 0 && !channelId) {
37834
+ process.stderr.write("error: --channel-id must not be empty\n");
37835
+ process.exit(EXIT_INVALID_INPUT);
37622
37836
  }
37623
- });
37624
- const resolver = createAgentResolver({
37625
- agentService: deps.createAgentService(host)
37626
- });
37627
- const resolved = await resolver.resolve(ref);
37628
- if (!resolved.ok) {
37629
- printResolveError(resolved.error, host);
37630
- process.exit(exitCodeForResolveError(resolved.error));
37631
- }
37632
- const svc = deps.createChannelService(host);
37633
- const res = await svc.disconnectSlack(resolved.value.id);
37634
- if (!res.ok) {
37635
- printServiceError(res.error, host);
37636
- process.exit(EXIT_RUNTIME_FAILURE);
37637
- }
37638
- if (opts.json) {
37639
- process.stdout.write(`${JSON.stringify(res.value)}
37837
+ const host = await resolveActiveHost(deps, {
37838
+ flag: opts.server ? { server: opts.server } : void 0,
37839
+ exitCodes: {
37840
+ runtimeFailure: EXIT_RUNTIME_FAILURE,
37841
+ belowFloor: EXIT_BELOW_FLOOR
37842
+ }
37843
+ });
37844
+ const resolver = createAgentResolver({
37845
+ agentService: deps.createAgentService(host)
37846
+ });
37847
+ const resolved = await resolver.resolve(ref);
37848
+ if (!resolved.ok) {
37849
+ printResolveError(resolved.error, host);
37850
+ process.exit(exitCodeForResolveError(resolved.error));
37851
+ }
37852
+ const bound = resolved.value.channels.filter(
37853
+ (c2) => c2.type === "slack" /* Slack */
37854
+ );
37855
+ if (!channelId && bound.length > 1) {
37856
+ process.stderr.write(
37857
+ `error: ${resolved.value.name} has ${bound.length} Slack channels connected (${bound.map((c2) => c2.slackChannelId).join(", ")}) \u2014 pass --channel-id to say which one
37858
+ `
37859
+ );
37860
+ process.exit(EXIT_INVALID_INPUT);
37861
+ }
37862
+ const svc = deps.createChannelService(host);
37863
+ const res = await svc.disconnectSlack(resolved.value.id, channelId);
37864
+ if (!res.ok) {
37865
+ printServiceError(res.error, host);
37866
+ process.exit(EXIT_RUNTIME_FAILURE);
37867
+ }
37868
+ if (opts.json) {
37869
+ process.stdout.write(`${JSON.stringify(res.value)}
37640
37870
  `);
37641
- } else {
37642
- process.stdout.write(
37643
- `\u2713 Slack disconnected from ${resolved.value.name}.
37871
+ } else {
37872
+ process.stdout.write(
37873
+ channelId ? `\u2713 Slack channel ${channelId} disconnected from ${resolved.value.name}.
37874
+ ` : `\u2713 Slack disconnected from ${resolved.value.name}.
37644
37875
  `
37645
- );
37876
+ );
37877
+ }
37878
+ process.exit(EXIT_SUCCESS);
37646
37879
  }
37647
- process.exit(EXIT_SUCCESS);
37648
- });
37880
+ );
37649
37881
  }
37650
37882
 
37651
37883
  // src/modules/channel/services/channel-service.ts
@@ -37674,9 +37906,12 @@ function createChannelService(deps) {
37674
37906
  return classifyTrpcError(e2);
37675
37907
  }
37676
37908
  },
37677
- async disconnectSlack(id) {
37909
+ async disconnectSlack(id, slackChannelId) {
37678
37910
  return trpcCall(async () => {
37679
- const agent = await deps.trpc.agents.disconnectSlack.mutate({ id });
37911
+ const agent = await deps.trpc.agents.disconnectSlack.mutate({
37912
+ id,
37913
+ ...slackChannelId ? { slackChannelId } : {}
37914
+ });
37680
37915
  return agent.channels;
37681
37916
  });
37682
37917
  }
@@ -40245,7 +40480,7 @@ function createProcessEnvReader() {
40245
40480
 
40246
40481
  // src/modules/cli/infrastructure/package-version.ts
40247
40482
  function readPackageVersion() {
40248
- return true ? "0.2.12" : DEV_VERSION;
40483
+ return true ? "0.2.13-rc1" : DEV_VERSION;
40249
40484
  }
40250
40485
 
40251
40486
  // src/modules/cli/infrastructure/version-probe.ts
@@ -40487,6 +40722,15 @@ function buildConnectCommand(deps) {
40487
40722
  ).option(
40488
40723
  "--private-key <pem>",
40489
40724
  'input: GitHub App private key \u2014 PEM or base64; use --private-key "$(cat app.pem)" (GitHub App installation)'
40725
+ ).option(
40726
+ "--repositories <names>",
40727
+ "input: limit the minted token to these repository names, space- or comma-separated (GitHub App installation)"
40728
+ ).option(
40729
+ "--repository-ids <ids>",
40730
+ "input: limit the minted token to these numeric repository ids; takes precedence over --repositories (GitHub App installation)"
40731
+ ).option(
40732
+ "--permissions <pairs>",
40733
+ "input: limit the minted token to these name:level permissions, e.g. contents:read (GitHub App installation)"
40490
40734
  ).option("--header-name <name>", "input: header name").option("--value-format <format>", "input: header value format").option(
40491
40735
  "--env-name <name>",
40492
40736
  "input: expose the credential to the agent as this env var (custom header credentials)"
@@ -40649,6 +40893,19 @@ async function resolveSlugTemplate(args) {
40649
40893
  );
40650
40894
  process.exit(EXIT_INVALID_INPUT);
40651
40895
  }
40896
+ for (const flag of [
40897
+ "repositories",
40898
+ "repositoryIds",
40899
+ "permissions"
40900
+ ]) {
40901
+ if (opts[flag] && !template.inputs.some((i) => i.name === flag)) {
40902
+ process.stderr.write(
40903
+ `error: this server does not support --${camelToKebab(flag)} for '${template.id}' \u2014 the token would carry the installation's full authority
40904
+ `
40905
+ );
40906
+ process.exit(EXIT_INVALID_INPUT);
40907
+ }
40908
+ }
40652
40909
  const name = (opts.name ?? slugifyTemplateName(template.name)).trim();
40653
40910
  validateName(name);
40654
40911
  const { values, presetsApplied } = await collectInputs(template, opts, json2);
@@ -40790,7 +41047,10 @@ function buildPayload(template, name, values) {
40790
41047
  ...v2("host") ? { host: v2("host") } : {},
40791
41048
  appId,
40792
41049
  installationId,
40793
- privateKey
41050
+ privateKey,
41051
+ ...v2("repositories") ? { repositories: v2("repositories") } : {},
41052
+ ...v2("repositoryIds") ? { repositoryIds: v2("repositoryIds") } : {},
41053
+ ...v2("permissions") ? { permissions: v2("permissions") } : {}
40794
41054
  };
40795
41055
  }
40796
41056
  case "header": {
@@ -41204,6 +41464,137 @@ function buildListCommand4(deps) {
41204
41464
  );
41205
41465
  }
41206
41466
 
41467
+ // src/modules/connection/commands/reauth.ts
41468
+ var POLL_INTERVAL_MS3 = 2e3;
41469
+ var DEFAULT_TIMEOUT_SECONDS4 = 300;
41470
+ function buildReauthCommand(deps) {
41471
+ return new Command("reauth").description("Re-run login and consent for an existing OAuth connection").argument(
41472
+ "<id-or-name>",
41473
+ "Connection id ('conn-\u2026') or unique name (from `dam connection list`)"
41474
+ ).option(
41475
+ "--server <url>",
41476
+ "override the configured server URL for this call"
41477
+ ).option("--json", "emit { ok, id, name } as JSON").option("--no-browser", "print the authorize URL instead of opening it").option(
41478
+ "--timeout <seconds>",
41479
+ "how long to wait for authorization",
41480
+ String(DEFAULT_TIMEOUT_SECONDS4)
41481
+ ).addHelpText(
41482
+ "after",
41483
+ "\nRe-authentication keeps the connection's identity and every sandbox\ngrant; only its tokens are replaced. Use it when a connection shows\nexpired, or to re-consent after its template gained scopes.\n\nExamples:\n dam connection reauth github\n dam connection reauth conn-61cc7b9137b0 --no-browser\n\nConnections that store their own secret take a new one instead:\n dam connection update <id-or-name>\n"
41484
+ ).action(
41485
+ async (ref, opts) => {
41486
+ const json2 = opts.json ?? false;
41487
+ const timeoutSeconds = parseTimeout3(opts.timeout);
41488
+ if (timeoutSeconds === null) {
41489
+ process.stderr.write("error: --timeout must be a positive integer\n");
41490
+ process.exit(EXIT_INVALID_INPUT);
41491
+ }
41492
+ const host = await resolveActiveHost(deps, {
41493
+ flag: opts.server ? { server: opts.server } : void 0,
41494
+ exitCodes: {
41495
+ runtimeFailure: EXIT_RUNTIME_FAILURE,
41496
+ belowFloor: EXIT_BELOW_FLOOR
41497
+ }
41498
+ });
41499
+ const svc = deps.createConnectionService(host);
41500
+ const listed = await svc.list();
41501
+ if (!listed.ok) {
41502
+ printServiceError(listed.error, host);
41503
+ process.exit(EXIT_RUNTIME_FAILURE);
41504
+ }
41505
+ const match = resolveConnectionRef(listed.value, ref);
41506
+ if (!match) {
41507
+ process.stderr.write(
41508
+ `error: no connection with id or name '${ref}'
41509
+ `
41510
+ );
41511
+ process.stderr.write(
41512
+ "hint: run `dam connection list` to see ids and names\n"
41513
+ );
41514
+ process.exit(EXIT_INVALID_INPUT);
41515
+ }
41516
+ if (match.authKind !== "oauth") {
41517
+ process.stderr.write(
41518
+ `error: '${match.name}' uses ${match.authKind} auth, which has no login flow
41519
+ `
41520
+ );
41521
+ process.stderr.write(
41522
+ `hint: replace its stored credential with \`dam connection update ${match.name}\`
41523
+ `
41524
+ );
41525
+ process.exit(EXIT_INVALID_INPUT);
41526
+ }
41527
+ const connectedAtBefore = match.connectedAt;
41528
+ const started = await svc.startOAuth(match.id);
41529
+ if (!started.ok) {
41530
+ printServiceError(started.error, host);
41531
+ process.exit(EXIT_RUNTIME_FAILURE);
41532
+ }
41533
+ const { authUrl } = started.value;
41534
+ const noBrowser = opts.browser === false;
41535
+ if (noBrowser) {
41536
+ process.stderr.write(`Open this URL to authorize:
41537
+ ${authUrl}
41538
+ `);
41539
+ } else {
41540
+ const opened = await deps.browserOpener.open(authUrl);
41541
+ if (!opened.ok) {
41542
+ process.stderr.write(
41543
+ `Couldn't open a browser. Open this URL to authorize:
41544
+ ${authUrl}
41545
+ `
41546
+ );
41547
+ }
41548
+ }
41549
+ process.stderr.write("Waiting for authorization\u2026\n");
41550
+ const landed = await pollUntilReconnected(
41551
+ svc,
41552
+ match.id,
41553
+ connectedAtBefore,
41554
+ timeoutSeconds
41555
+ );
41556
+ if (!landed) {
41557
+ process.stderr.write(
41558
+ `error: couldn't confirm the re-authentication finished within ${timeoutSeconds}s; it may still complete \u2014 check \`dam connection list\`
41559
+ `
41560
+ );
41561
+ process.exit(EXIT_RUNTIME_FAILURE);
41562
+ }
41563
+ if (json2) {
41564
+ process.stdout.write(
41565
+ `${JSON.stringify({ ok: true, id: match.id, name: match.name })}
41566
+ `
41567
+ );
41568
+ } else {
41569
+ process.stdout.write(
41570
+ `\u2713 Re-authenticated ${match.name} (${match.id}).
41571
+ `
41572
+ );
41573
+ }
41574
+ process.exit(EXIT_SUCCESS);
41575
+ }
41576
+ );
41577
+ }
41578
+ async function pollUntilReconnected(svc, id, connectedAtBefore, timeoutSeconds) {
41579
+ const deadline = Date.now() + timeoutSeconds * 1e3;
41580
+ while (true) {
41581
+ const res = await svc.getConnection(id);
41582
+ if (res.ok && res.value && res.value.connectedAt !== connectedAtBefore) {
41583
+ return true;
41584
+ }
41585
+ if (Date.now() + POLL_INTERVAL_MS3 >= deadline) return false;
41586
+ await sleep5(POLL_INTERVAL_MS3);
41587
+ }
41588
+ }
41589
+ function parseTimeout3(raw) {
41590
+ if (raw === void 0) return DEFAULT_TIMEOUT_SECONDS4;
41591
+ const n = Number(raw);
41592
+ return Number.isInteger(n) && n > 0 ? n : null;
41593
+ }
41594
+ function sleep5(ms) {
41595
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
41596
+ }
41597
+
41207
41598
  // src/modules/connection/commands/revoke.ts
41208
41599
  var collect2 = (v2, acc) => [...acc, v2];
41209
41600
  function buildRevokeCommand(deps) {
@@ -41351,19 +41742,39 @@ function buildTemplatesCommand(deps) {
41351
41742
  }
41352
41743
 
41353
41744
  // src/modules/connection/commands/update.ts
41745
+ var SECRET_LABELS = {
41746
+ header: "New credential value",
41747
+ "client-credentials": "New client secret",
41748
+ "github-app": "New private key (PEM)",
41749
+ // Its own client secret, not its tokens — those come from `reauth`. Only
41750
+ // connections carrying their own qualify; the server rejects the rest.
41751
+ oauth: "New OAuth client secret"
41752
+ };
41354
41753
  function buildUpdateCommand(deps) {
41355
- return new Command("update").description("Replace a connection's stored credential value").argument(
41754
+ return new Command("update").description("Replace a connection's stored credential").argument(
41356
41755
  "<id-or-name>",
41357
41756
  "Connection id ('conn-\u2026') or unique name (from `dam connection list`)"
41358
41757
  ).option(
41359
41758
  "--value <value>",
41360
- "the new credential value (prompts securely if omitted)"
41759
+ "the new secret \u2014 the injected value, client secret, or private key, depending on the connection's auth kind (prompts securely if omitted)"
41361
41760
  ).option(
41362
41761
  "--server <url>",
41363
41762
  "override the configured server URL for this call"
41364
41763
  ).option("--json", "emit { ok, id, name } as JSON").addHelpText(
41365
41764
  "after",
41366
- "\nExamples:\n dam connection update conn-61cc7b9137b0 --value sk-ant-...\n dam connection update anthropic # prompts for the value\n"
41765
+ `
41766
+ Examples:
41767
+ dam connection update conn-61cc7b9137b0 --value sk-ant-...
41768
+ dam connection update anthropic # prompts for the value
41769
+ dam connection update my-github-app --value "$(cat app.pem)"
41770
+
41771
+ A multi-line secret (a PEM private key) can't be typed at the
41772
+ prompt \u2014 pass it with --value, as in the last example.
41773
+
41774
+ On an OAuth connection this rotates its *client secret* (only when the
41775
+ connection carries its own). To replace expired tokens, re-consent:
41776
+ dam connection reauth <id-or-name>
41777
+ `
41367
41778
  ).action(
41368
41779
  async (ref, opts) => {
41369
41780
  const host = await resolveActiveHost(deps, {
@@ -41390,9 +41801,9 @@ function buildUpdateCommand(deps) {
41390
41801
  );
41391
41802
  process.exit(EXIT_INVALID_INPUT);
41392
41803
  }
41393
- if (match.authKind !== "header") {
41804
+ if (match.authKind === "none") {
41394
41805
  process.stderr.write(
41395
- `error: only header-credential connections can be updated; '${match.name}' uses ${match.authKind} auth
41806
+ `error: '${match.name}' stores no credential to update
41396
41807
  `
41397
41808
  );
41398
41809
  process.exit(EXIT_INVALID_INPUT);
@@ -41405,9 +41816,14 @@ function buildUpdateCommand(deps) {
41405
41816
  );
41406
41817
  process.exit(EXIT_INVALID_INPUT);
41407
41818
  }
41408
- const entered = await promptSecret(
41409
- `New credential value for ${match.name}`
41410
- );
41819
+ if (match.authKind === "github-app") {
41820
+ process.stderr.write(
41821
+ `note: a PEM key can't be typed at the prompt \u2014 pass --value "$(cat app.pem)" instead
41822
+ `
41823
+ );
41824
+ }
41825
+ const label = SECRET_LABELS[match.authKind];
41826
+ const entered = await promptSecret(`${label} for ${match.name}`);
41411
41827
  if (q(entered)) {
41412
41828
  me("Cancelled");
41413
41829
  process.exit(EXIT_SUCCESS);
@@ -41476,6 +41892,14 @@ function composeConnectionModule(opts) {
41476
41892
  createConnectionService: createService
41477
41893
  })
41478
41894
  );
41895
+ parent.addCommand(
41896
+ buildReauthCommand({
41897
+ compatService: opts.compatService,
41898
+ configService: opts.configService,
41899
+ createConnectionService: createService,
41900
+ browserOpener: opts.browserOpener
41901
+ })
41902
+ );
41479
41903
  parent.addCommand(buildGrantCommand(agentScoped));
41480
41904
  parent.addCommand(buildRevokeCommand(agentScoped));
41481
41905
  return { commands: [parent], exports: { createService } };
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.12",
4
+ "version": "0.2.13-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",
@@ -43,8 +43,8 @@
43
43
  "vitest": "^4.1.3",
44
44
  "ws": "^8.20.0",
45
45
  "zod": "^4.4.3",
46
+ "api-server-api": "0.0.1",
46
47
  "agent-runtime-api": "0.0.1",
47
- "dev-config": "0.0.1",
48
- "api-server-api": "0.0.1"
48
+ "dev-config": "0.0.1"
49
49
  }
50
50
  }