@lambdacurry/arbor 0.14.0 → 0.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/arbor.js +330 -14
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -42,7 +42,7 @@ This prints a URL + short code to relay to the human, who approves it in their l
42
42
 
43
43
  ## Output contract (agent-friendly)
44
44
 
45
- Every command takes `--json` to emit a stable `{ ok, data | error, meta }` envelope on stdout (with structured error codes and agent-mode exit codes); advisory/human text goes to stderr. A failure envelope adds the server's granular `reason` — `validation.missing_field`, `limit.exceeded`, `conflict.state`, … — beside the coarse `code`, optionally with `field`, `limit`, `retryable`, and `phase` (AD-237). `--quiet` (auto under `--json` or a pipe) silences the advisory stream. `--fields a,b,list:N` projects a result; `--limit`/`--cursor` paginate list commands.
45
+ Every command takes `--json` to emit a stable `{ ok, data | error, meta }` envelope on stdout (with structured error codes and agent-mode exit codes); advisory/human text goes to stderr. A failure envelope adds the server's granular `reason` — `validation.missing_field`, `limit.exceeded`, `conflict.state`, … — beside the coarse `code`, optionally with `field`, `limit`, `retryable`, `phase`, and bounded sanitized `provider` lifecycle diagnostics (AD-237/261). `--quiet` (auto under `--json` or a pipe) silences the advisory stream. `--fields a,b,list:N` projects a result; `--limit`/`--cursor` paginate list commands.
46
46
 
47
47
  ```bash
48
48
  arbor inbox --json --limit 20
package/dist/arbor.js CHANGED
@@ -1801,6 +1801,52 @@ var artifactVersions = sqliteTable("artifact_versions", {
1801
1801
  }, (t) => ({
1802
1802
  artifactVersionUq: uniqueIndex("artifact_versions_artifact_version_uq").on(t.artifactId, t.version)
1803
1803
  }));
1804
+ var secrets = sqliteTable("secrets", {
1805
+ id: text("id").primaryKey(),
1806
+ orgId: text("org_id").notNull().references(() => orgs.id),
1807
+ name: text("name").notNull(),
1808
+ description: text("description").notNull().default(""),
1809
+ lifecycle: text("lifecycle").$type().notNull().default("active"),
1810
+ currentVersionId: text("current_version_id"),
1811
+ currentVersion: integer("current_version").notNull().default(0),
1812
+ metadataRevision: integer("metadata_revision").notNull().default(0),
1813
+ createdByProfileId: text("created_by_profile_id").notNull().references(() => profiles.id),
1814
+ createdExecutionContextId: text("created_execution_context_id").notNull().references(() => executionContexts.id),
1815
+ createdAt: ts("created_at").notNull(),
1816
+ revokedAt: ts("revoked_at")
1817
+ }, (t) => ({
1818
+ orgNameUq: uniqueIndex("secrets_org_name_uq").on(t.orgId, t.name),
1819
+ orgLifecycleIdx: index("secrets_org_lifecycle_idx").on(t.orgId, t.lifecycle, t.createdAt)
1820
+ }));
1821
+ var secretVersions = sqliteTable("secret_versions", {
1822
+ id: text("id").primaryKey(),
1823
+ secretId: text("secret_id").notNull().references(() => secrets.id),
1824
+ version: integer("version").notNull(),
1825
+ ciphertext: text("ciphertext").notNull(),
1826
+ iv: text("iv").notNull(),
1827
+ keyId: text("key_id").notNull(),
1828
+ algorithm: text("algorithm").notNull().default("AES-GCM-256"),
1829
+ createdByProfileId: text("created_by_profile_id").notNull().references(() => profiles.id),
1830
+ createdExecutionContextId: text("created_execution_context_id").notNull().references(() => executionContexts.id),
1831
+ createdAt: ts("created_at").notNull()
1832
+ }, (t) => ({
1833
+ secretVersionUq: uniqueIndex("secret_versions_secret_version_uq").on(t.secretId, t.version)
1834
+ }));
1835
+ var secretGrants = sqliteTable("secret_grants", {
1836
+ id: text("id").primaryKey(),
1837
+ orgId: text("org_id").notNull().references(() => orgs.id),
1838
+ secretId: text("secret_id").references(() => secrets.id),
1839
+ scopeKey: text("scope_key").notNull(),
1840
+ profileId: text("profile_id").notNull().references(() => profiles.id),
1841
+ permissions: text("permissions", { mode: "json" }).$type().notNull(),
1842
+ grantedByProfileId: text("granted_by_profile_id").notNull().references(() => profiles.id),
1843
+ grantedExecutionContextId: text("granted_execution_context_id").notNull().references(() => executionContexts.id),
1844
+ createdAt: ts("created_at").notNull(),
1845
+ updatedAt: ts("updated_at").notNull()
1846
+ }, (t) => ({
1847
+ scopeProfileUq: uniqueIndex("secret_grants_scope_profile_uq").on(t.orgId, t.scopeKey, t.profileId),
1848
+ profileIdx: index("secret_grants_profile_idx").on(t.profileId, t.orgId)
1849
+ }));
1804
1850
  var appBundles = sqliteTable("app_bundles", {
1805
1851
  id: text("id").primaryKey(),
1806
1852
  artifactVersionId: text("artifact_version_id").notNull().references(() => artifactVersions.id),
@@ -1864,6 +1910,23 @@ var apps = sqliteTable("apps", {
1864
1910
  spaceIdx: index("apps_space_idx").on(t.spaceId, t.lifecycle, t.createdAt),
1865
1911
  orgIdx: index("apps_org_idx").on(t.orgId, t.access, t.discovery)
1866
1912
  }));
1913
+ var secretBindings = sqliteTable("secret_bindings", {
1914
+ id: text("id").primaryKey(),
1915
+ secretId: text("secret_id").notNull().references(() => secrets.id),
1916
+ targetType: text("target_type").notNull().default("app"),
1917
+ appId: text("app_id").notNull().references(() => apps.id),
1918
+ bindingName: text("binding_name").notNull(),
1919
+ status: text("status").$type().notNull().default("active"),
1920
+ createdByProfileId: text("created_by_profile_id").notNull().references(() => profiles.id),
1921
+ createdExecutionContextId: text("created_execution_context_id").notNull().references(() => executionContexts.id),
1922
+ createdAt: ts("created_at").notNull(),
1923
+ updatedByProfileId: text("updated_by_profile_id").notNull().references(() => profiles.id),
1924
+ updatedExecutionContextId: text("updated_execution_context_id").notNull().references(() => executionContexts.id),
1925
+ updatedAt: ts("updated_at").notNull()
1926
+ }, (t) => ({
1927
+ appNameUq: uniqueIndex("secret_bindings_app_name_uq").on(t.appId, t.bindingName),
1928
+ secretIdx: index("secret_bindings_secret_idx").on(t.secretId, t.status)
1929
+ }));
1867
1930
  var appDeployments = sqliteTable("app_deployments", {
1868
1931
  id: text("id").primaryKey(),
1869
1932
  appId: text("app_id").notNull().references(() => apps.id),
@@ -2015,6 +2078,9 @@ var watches = sqliteTable("watches", {
2015
2078
  watchUq: uniqueIndex("watches_watcher_target_uniq").on(t.watcherProfileId, t.targetType, t.targetId),
2016
2079
  watchTargetIdx: index("watches_target_idx").on(t.targetType, t.targetId)
2017
2080
  }));
2081
+ // ../core/src/ops/computer.ts
2082
+ var MAX_COMPUTER_REPOSITORIES = 10;
2083
+
2018
2084
  // ../core/src/ops/request.ts
2019
2085
  var REQUEST_TTL_MS = 14 * 24 * 60 * 60 * 1000;
2020
2086
 
@@ -2049,6 +2115,19 @@ var PREVIEW_MIME_TYPES = new Set([
2049
2115
  // ../core/src/ops/app.ts
2050
2116
  var APP_MAX_MODULE_BYTES = 10 * 1024 * 1024;
2051
2117
  var APP_MAX_ASSET_BYTES = 25 * 1024 * 1024;
2118
+ // ../core/src/ops/secret.ts
2119
+ var SECRET_PERMISSIONS = [
2120
+ "create",
2121
+ "metadata:read",
2122
+ "value:write",
2123
+ "rotate",
2124
+ "bind",
2125
+ "unbind",
2126
+ "revoke",
2127
+ "delete",
2128
+ "plaintext:read"
2129
+ ];
2130
+ var SECRET_ADMIN_PERMISSIONS = SECRET_PERMISSIONS.filter((permission) => permission !== "create" && permission !== "plaintext:read");
2052
2131
  // ../core/src/queries/lane-match.ts
2053
2132
  var STOP_WORDS = new Set("a an and are as at be by for from has have here how i in is it me of on or our the their they this to was what when where which who will with you your".split(" "));
2054
2133
  // ../core/src/queries/activity.ts
@@ -16542,7 +16621,8 @@ var computerProfile = exports_external.looseObject({
16542
16621
  id: exports_external.string(),
16543
16622
  version: exports_external.number(),
16544
16623
  shell: exports_external.string(),
16545
- runtimes: exports_external.looseObject({ bun: exports_external.string() }),
16624
+ runtimes: exports_external.looseObject({ bun: exports_external.string(), node: exports_external.string() }),
16625
+ packageManagers: exports_external.looseObject({ pnpm: exports_external.string() }),
16546
16626
  tools: exports_external.array(exports_external.string()),
16547
16627
  recommendedEditingPrimitive: exports_external.string()
16548
16628
  });
@@ -16714,6 +16794,31 @@ var app2 = exports_external.looseObject({
16714
16794
  url: exports_external.string().optional()
16715
16795
  });
16716
16796
  var deployment = exports_external.looseObject({ id, appId: id, bundleId: id, status: exports_external.string() });
16797
+ var secretMetadata = exports_external.looseObject({
16798
+ id,
16799
+ orgId: id,
16800
+ name: exports_external.string(),
16801
+ description: exports_external.string(),
16802
+ lifecycle: exports_external.enum(["active", "revoked"]),
16803
+ currentVersionId: nullableString,
16804
+ currentVersion: exports_external.number().int().min(0),
16805
+ metadataRevision: exports_external.number().int().min(0),
16806
+ createdByProfileId: id,
16807
+ createdExecutionContextId: id,
16808
+ createdAt: timestamp,
16809
+ revokedAt: nullableString
16810
+ });
16811
+ var secretPermission = exports_external.enum([
16812
+ "create",
16813
+ "metadata:read",
16814
+ "value:write",
16815
+ "rotate",
16816
+ "bind",
16817
+ "unbind",
16818
+ "revoke",
16819
+ "delete",
16820
+ "plaintext:read"
16821
+ ]);
16717
16822
  var treeThread = exports_external.looseObject({
16718
16823
  id,
16719
16824
  title: exports_external.string(),
@@ -16995,6 +17100,30 @@ var MCP_OUTPUT_SCHEMAS = {
16995
17100
  status: exports_external.literal("deleted"),
16996
17101
  retrievalTier: exports_external.string()
16997
17102
  }),
17103
+ secrets: exports_external.looseObject({
17104
+ result: exports_external.array(secretMetadata).optional(),
17105
+ secret: secretMetadata.optional(),
17106
+ bindings: exports_external.array(exports_external.looseObject({
17107
+ id,
17108
+ targetType: exports_external.literal("app"),
17109
+ appId: id,
17110
+ bindingName: exports_external.string(),
17111
+ status: exports_external.enum(["active", "unbound"]),
17112
+ updatedAt: timestamp
17113
+ })).optional(),
17114
+ grants: exports_external.array(exports_external.looseObject({ profileId: id, permissions: exports_external.array(secretPermission) })).optional(),
17115
+ id: id.optional(),
17116
+ secretId: id.nullable().optional(),
17117
+ version: exports_external.number().int().min(1).optional(),
17118
+ rotated: exports_external.boolean().optional(),
17119
+ profileId: id.optional(),
17120
+ permissions: exports_external.array(secretPermission).optional(),
17121
+ revoked: exports_external.boolean().optional(),
17122
+ targetType: exports_external.literal("app").optional(),
17123
+ appId: id.optional(),
17124
+ bindingName: exports_external.string().optional(),
17125
+ unbound: exports_external.boolean().optional()
17126
+ }),
16998
17127
  app_list: exports_external.object({ result: exports_external.array(app2) }),
16999
17128
  app_get: exports_external.looseObject({
17000
17129
  app: app2,
@@ -17271,6 +17400,7 @@ var MCP_TOOL_ANNOTATIONS = {
17271
17400
  artifact_get: readOnly,
17272
17401
  artifact_transition: additive,
17273
17402
  artifact_delete: destructive,
17403
+ secrets: destructive,
17274
17404
  app_get: readOnly,
17275
17405
  app_list: readOnly,
17276
17406
  app_deployment_get: readOnly,
@@ -17567,9 +17697,9 @@ var ACTION_DEFINITIONS = [
17567
17697
  description: "Replace your organization's sparse computer-default layer without allocating runtime state. Omitted/null values fall back to provider defaults; Space, Topic, and Thread layers may override individual fields.",
17568
17698
  inputSchema: {
17569
17699
  backend: exports_external.enum(["worker-shell", "container"]).nullable().optional().describe("default execution tier, or null to use worker-shell"),
17570
- containerProfile: exports_external.string().nullable().optional().describe("logical container profile; use bun-typescript-v1 for the pinned Bun monorepo toolchain, or null to clear"),
17571
- setupScript: exports_external.string().nullable().optional().describe("optional setup run when materializing a reusable base, or null to clear"),
17572
- repositories: exports_external.array(exports_external.string()).nullable().optional().describe("default repositories, repeated --repositories; [] clears and null inherits provider default")
17700
+ containerProfile: exports_external.string().nullable().optional().describe("logical container profile; bun-typescript-v1 guarantees Bash, Git, Bun 1.3.3, Node 26.5.1, and pnpm 10.33.0, or null to clear"),
17701
+ setupScript: exports_external.string().nullable().optional().describe("optional strict Bash setup run after connected repositories materialize, or null to clear"),
17702
+ repositories: exports_external.array(exports_external.string()).max(MAX_COMPUTER_REPOSITORIES).nullable().optional().describe("connected GitHub repositories to materialize into a fresh reusable base and allow for later Git calls; [] clears and null inherits")
17573
17703
  },
17574
17704
  surfaces: ["mcp", "cli"],
17575
17705
  toolset: "structure",
@@ -17582,9 +17712,9 @@ var ACTION_DEFINITIONS = [
17582
17712
  inputSchema: {
17583
17713
  spaceId: exports_external.string().describe("the Space, spc_…"),
17584
17714
  backend: exports_external.enum(["worker-shell", "container"]).nullable().optional().describe("override execution tier, or null to inherit"),
17585
- containerProfile: exports_external.string().nullable().optional().describe("logical container profile; use bun-typescript-v1 for the pinned Bun monorepo toolchain, or null to clear inherited profile"),
17586
- setupScript: exports_external.string().nullable().optional().describe("optional setup run when materializing a reusable base, or null to clear"),
17587
- repositories: exports_external.array(exports_external.string()).nullable().optional().describe("repository allowlist/default clones; [] clears and null inherits")
17715
+ containerProfile: exports_external.string().nullable().optional().describe("logical container profile; bun-typescript-v1 guarantees Bash, Git, Bun 1.3.3, Node 26.5.1, and pnpm 10.33.0, or null to clear inherited profile"),
17716
+ setupScript: exports_external.string().nullable().optional().describe("optional strict Bash setup run after connected repositories materialize, or null to clear"),
17717
+ repositories: exports_external.array(exports_external.string()).max(MAX_COMPUTER_REPOSITORIES).nullable().optional().describe("connected GitHub repositories to materialize into a fresh reusable base and allow for later Git calls; [] clears and null inherits")
17588
17718
  },
17589
17719
  surfaces: ["mcp", "cli"],
17590
17720
  toolset: "structure",
@@ -17597,9 +17727,9 @@ var ACTION_DEFINITIONS = [
17597
17727
  inputSchema: {
17598
17728
  topicId: exports_external.string().describe("the Topic, top_…"),
17599
17729
  backend: exports_external.enum(["worker-shell", "container"]).nullable().optional().describe("override execution tier, or null to inherit"),
17600
- containerProfile: exports_external.string().nullable().optional().describe("logical container profile; use bun-typescript-v1 for the pinned Bun monorepo toolchain, or null to clear inherited profile"),
17601
- setupScript: exports_external.string().nullable().optional().describe("optional setup run, or null to clear"),
17602
- repositories: exports_external.array(exports_external.string()).nullable().optional().describe("repository allowlist/default clones; [] clears and null inherits")
17730
+ containerProfile: exports_external.string().nullable().optional().describe("logical container profile; bun-typescript-v1 guarantees Bash, Git, Bun 1.3.3, Node 26.5.1, and pnpm 10.33.0, or null to clear inherited profile"),
17731
+ setupScript: exports_external.string().nullable().optional().describe("optional strict Bash setup run after connected repositories materialize"),
17732
+ repositories: exports_external.array(exports_external.string()).max(MAX_COMPUTER_REPOSITORIES).nullable().optional().describe("connected GitHub repositories to materialize into a fresh reusable base and allow for later Git calls; [] clears and null inherits")
17603
17733
  },
17604
17734
  surfaces: ["mcp", "cli"],
17605
17735
  toolset: "structure",
@@ -17612,9 +17742,9 @@ var ACTION_DEFINITIONS = [
17612
17742
  inputSchema: {
17613
17743
  threadId: exports_external.string().describe("the Thread, thr_…"),
17614
17744
  backend: exports_external.enum(["worker-shell", "container"]).nullable().optional().describe("override execution tier, or null to inherit"),
17615
- containerProfile: exports_external.string().nullable().optional().describe("logical container profile; use bun-typescript-v1 for the pinned Bun monorepo toolchain, or null to clear inherited profile"),
17616
- setupScript: exports_external.string().nullable().optional().describe("optional setup run, or null to clear"),
17617
- repositories: exports_external.array(exports_external.string()).nullable().optional().describe("repository allowlist/default clones; [] clears and null inherits")
17745
+ containerProfile: exports_external.string().nullable().optional().describe("logical container profile; bun-typescript-v1 guarantees Bash, Git, Bun 1.3.3, Node 26.5.1, and pnpm 10.33.0, or null to clear inherited profile"),
17746
+ setupScript: exports_external.string().nullable().optional().describe("optional strict Bash setup run after connected repositories materialize"),
17747
+ repositories: exports_external.array(exports_external.string()).max(MAX_COMPUTER_REPOSITORIES).nullable().optional().describe("connected GitHub repositories to materialize into a fresh reusable base and allow for later Git calls; [] clears and null inherits")
17618
17748
  },
17619
17749
  surfaces: ["mcp", "cli"],
17620
17750
  toolset: "structure",
@@ -17634,7 +17764,7 @@ var ACTION_DEFINITIONS = [
17634
17764
  {
17635
17765
  name: "computer_open",
17636
17766
  title: "Open a Thread computer",
17637
- description: "Open or resume this Thread's project environment for filesystem or command work. Returns computerSessionId and, when a declared container profile is selected, its guaranteed shell/runtimes/tools/editing primitive; pass the session id unchanged to later Computer tools and to Contributions or responses produced from the work.",
17767
+ description: "Open or resume this Thread's project environment for filesystem or command work. Every configured repository is re-authorized through its explicit GitHub connection; a fresh reusable base clones it with a request-scoped contents:read credential before strict setup runs, while a restore receives no credential. Returns computerSessionId and the selected profile contract; pass the session id unchanged to later Computer tools and cited work.",
17638
17768
  inputSchema: {
17639
17769
  threadId: exports_external.string().describe("the Arbor Thread whose stable computer to open, thr_…"),
17640
17770
  vcpus: exports_external.number().int().min(1).max(4).optional().describe("optional container vCPU request"),
@@ -18843,6 +18973,178 @@ var ACTION_DEFINITIONS = [
18843
18973
  toolset: "artifacts",
18844
18974
  run: (ex, input) => ex.call("artifact.transition", { ...input, to: "deleted" })
18845
18975
  },
18976
+ {
18977
+ name: "secrets",
18978
+ title: "Manage encrypted Secrets",
18979
+ description: "Create, authorize, version, rotate, bind, and revoke first-class Arbor Secrets without revealing plaintext. set and rotate never echo submitted values; bind exposes the current version only to the named App runtime binding, while identity administration and runtime consumption remain separate. Plaintext reveal is not shipped in v1.",
18980
+ inputSchema: {
18981
+ verb: exports_external.enum([
18982
+ "list",
18983
+ "get",
18984
+ "create",
18985
+ "set",
18986
+ "rotate",
18987
+ "grant",
18988
+ "revoke_grant",
18989
+ "bind",
18990
+ "unbind",
18991
+ "revoke"
18992
+ ]).describe("which Secret operation to perform"),
18993
+ secretId: exports_external.string().optional().describe("Secret id; omit only when granting/revoking org-scoped create permission"),
18994
+ name: exports_external.string().optional().describe("create: lowercase Secret name"),
18995
+ description: exports_external.string().max(500).optional().describe("create: non-sensitive purpose"),
18996
+ value: exports_external.string().min(1).optional().describe("set/rotate: plaintext submitted once and never returned or recorded"),
18997
+ profileId: exports_external.string().optional().describe("grant/revoke_grant: authorized human or agent"),
18998
+ permissions: exports_external.array(exports_external.enum([
18999
+ "create",
19000
+ "metadata:read",
19001
+ "value:write",
19002
+ "rotate",
19003
+ "bind",
19004
+ "unbind",
19005
+ "revoke",
19006
+ "delete",
19007
+ "plaintext:read"
19008
+ ])).optional().describe("grant: explicit permissions; plaintext:read is reserved for a future dedicated reveal path and normal grants reject it"),
19009
+ appId: exports_external.string().optional().describe("bind: target App, app_…"),
19010
+ bindingName: exports_external.string().optional().describe("bind: uppercase Dynamic Worker env binding, e.g. API_TOKEN"),
19011
+ bindingId: exports_external.string().optional().describe("unbind: binding id, sbd_…")
19012
+ },
19013
+ surfaces: ["mcp"],
19014
+ toolset: "apps",
19015
+ run: dispatch({
19016
+ list: "secret.list",
19017
+ get: "secret.get",
19018
+ create: "secret.create",
19019
+ set: "secret.set",
19020
+ rotate: "secret.rotate",
19021
+ grant: "secret.grant",
19022
+ revoke_grant: "secret.revoke_grant",
19023
+ bind: "secret.bind",
19024
+ unbind: "secret.unbind",
19025
+ revoke: "secret.revoke"
19026
+ })
19027
+ },
19028
+ {
19029
+ name: "secret_list",
19030
+ title: "List authorized Secrets",
19031
+ description: "List only Secret metadata the current identity may read. Values, ciphertext, and encryption metadata are never projected.",
19032
+ inputSchema: {},
19033
+ surfaces: ["cli"],
19034
+ toolset: "apps",
19035
+ run: forward("secret.list")
19036
+ },
19037
+ {
19038
+ name: "secret_get",
19039
+ title: "Read Secret metadata",
19040
+ description: "Read one Secret's lifecycle, current version number, identity grants, and App bindings. This never returns plaintext, ciphertext, IVs, or key identifiers.",
19041
+ inputSchema: { secretId: exports_external.string().describe("the Secret, sec_…") },
19042
+ surfaces: ["cli"],
19043
+ toolset: "apps",
19044
+ run: forward("secret.get")
19045
+ },
19046
+ {
19047
+ name: "secret_create",
19048
+ title: "Create a Secret",
19049
+ description: "Create first-class Secret metadata without material; an Org owner/admin or identity with org-scoped create permission may do this. Follow with secret_set to write its first encrypted version.",
19050
+ inputSchema: {
19051
+ name: exports_external.string().min(1).max(63).describe("lowercase stable name"),
19052
+ description: exports_external.string().max(500).optional().describe("non-sensitive purpose")
19053
+ },
19054
+ surfaces: ["cli"],
19055
+ toolset: "apps",
19056
+ run: forward("secret.create")
19057
+ },
19058
+ {
19059
+ name: "secret_set",
19060
+ title: "Set a Secret value",
19061
+ description: "Write the first encrypted SecretVersion. The submitted value is never echoed, logged, audited, or placed in provenance; use secret_rotate after the first version.",
19062
+ inputSchema: {
19063
+ secretId: exports_external.string().describe("the empty Secret, sec_…"),
19064
+ value: exports_external.string().min(1).describe("plaintext submitted once and never returned")
19065
+ },
19066
+ surfaces: ["cli"],
19067
+ toolset: "apps",
19068
+ run: forward("secret.set")
19069
+ },
19070
+ {
19071
+ name: "secret_rotate",
19072
+ title: "Rotate a Secret value",
19073
+ description: "Append a new encrypted SecretVersion and make every active App binding consume it. Rotation permission is independent of value-write, bind, and plaintext-read permission; the submitted value is never returned.",
19074
+ inputSchema: {
19075
+ secretId: exports_external.string().describe("the active Secret, sec_…"),
19076
+ value: exports_external.string().min(1).describe("new plaintext submitted once and never returned")
19077
+ },
19078
+ surfaces: ["cli"],
19079
+ toolset: "apps",
19080
+ run: forward("secret.rotate")
19081
+ },
19082
+ {
19083
+ name: "secret_grant",
19084
+ title: "Grant Secret access",
19085
+ description: "Replace one human or agent's explicit Secret permissions; omit secretId only to grant org-scoped create. Plaintext-read is reserved for a future dedicated reveal path and this command rejects it; runtime App consumption is controlled by bindings, not this identity grant.",
19086
+ inputSchema: {
19087
+ secretId: exports_external.string().optional().describe("Secret scope; omit only for org-scoped create permission"),
19088
+ profileId: exports_external.string().describe("authorized human or agent profile"),
19089
+ permissions: exports_external.array(exports_external.enum([
19090
+ "create",
19091
+ "metadata:read",
19092
+ "value:write",
19093
+ "rotate",
19094
+ "bind",
19095
+ "unbind",
19096
+ "revoke",
19097
+ "delete",
19098
+ "plaintext:read"
19099
+ ]))
19100
+ },
19101
+ surfaces: ["cli"],
19102
+ toolset: "apps",
19103
+ run: forward("secret.grant")
19104
+ },
19105
+ {
19106
+ name: "secret_revoke_grant",
19107
+ title: "Revoke Secret access",
19108
+ description: "Remove one human or agent's explicit Secret grant. This changes administration authority only; an App binding remains a separate runtime-consumption grant.",
19109
+ inputSchema: {
19110
+ secretId: exports_external.string().optional().describe("Secret scope; omit for org create permission"),
19111
+ profileId: exports_external.string().describe("human or agent profile")
19112
+ },
19113
+ surfaces: ["cli"],
19114
+ toolset: "apps",
19115
+ run: forward("secret.revoke_grant")
19116
+ },
19117
+ {
19118
+ name: "secret_bind",
19119
+ title: "Bind a Secret to an App",
19120
+ description: "Authorize one App workload to consume the active Secret version through a provider-native Dynamic Worker env binding. The actor needs Secret bind authority and access to the App's Space. Binding permission never grants plaintext read to the acting identity, and no material enters bundles, deployments, receipts, or Events.",
19121
+ inputSchema: {
19122
+ secretId: exports_external.string().describe("active Secret with a value, sec_…"),
19123
+ appId: exports_external.string().describe("target App, app_…"),
19124
+ bindingName: exports_external.string().describe("uppercase runtime name, e.g. API_TOKEN")
19125
+ },
19126
+ surfaces: ["cli"],
19127
+ toolset: "apps",
19128
+ run: forward("secret.bind")
19129
+ },
19130
+ {
19131
+ name: "secret_unbind",
19132
+ title: "Unbind an App Secret",
19133
+ description: "Remove one App workload's runtime consumption binding without revoking the Secret or changing identity administration grants. Read secret_get for the binding id.",
19134
+ inputSchema: { bindingId: exports_external.string().describe("the App binding, sbd_…") },
19135
+ surfaces: ["cli"],
19136
+ toolset: "apps",
19137
+ run: forward("secret.unbind")
19138
+ },
19139
+ {
19140
+ name: "secret_revoke",
19141
+ title: "Revoke a Secret",
19142
+ description: "Move a Secret to revoked so every active workload binding fails closed while durable metadata, encrypted versions, attribution, and audit history remain. Permanent deletion and plaintext reveal are not shipped in v1.",
19143
+ inputSchema: { secretId: exports_external.string().describe("the Secret, sec_…") },
19144
+ surfaces: ["cli"],
19145
+ toolset: "apps",
19146
+ run: forward("secret.revoke")
19147
+ },
18846
19148
  {
18847
19149
  name: "apps",
18848
19150
  title: "List visible Apps",
@@ -19185,6 +19487,20 @@ function parseErrorDetails(value) {
19185
19487
  details.retryable = raw.retryable;
19186
19488
  if (typeof raw.phase === "string")
19187
19489
  details.phase = raw.phase;
19490
+ if (raw.provider && typeof raw.provider === "object" && !Array.isArray(raw.provider)) {
19491
+ const provider = raw.provider;
19492
+ if (typeof provider.stage === "string" && provider.stage !== "") {
19493
+ details.provider = {
19494
+ stage: provider.stage,
19495
+ ...typeof provider.command === "string" ? { command: provider.command } : {},
19496
+ ...typeof provider.exitCode === "number" ? { exitCode: provider.exitCode } : {},
19497
+ ...typeof provider.stdout === "string" ? { stdout: provider.stdout } : {},
19498
+ ...typeof provider.stderr === "string" ? { stderr: provider.stderr } : {},
19499
+ ...typeof provider.containerStarted === "boolean" ? { containerStarted: provider.containerStarted } : {},
19500
+ ...typeof provider.repositoryMaterialized === "boolean" ? { repositoryMaterialized: provider.repositoryMaterialized } : {}
19501
+ };
19502
+ }
19503
+ }
19188
19504
  return details;
19189
19505
  }
19190
19506
  function detailsForError(err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lambdacurry/arbor",
3
- "version": "0.14.0",
3
+ "version": "0.14.2",
4
4
  "description": "The Arbor CLI — a shared workspace for people and agents. The human + headless-agent write path over Arbor's guarded operation surface.",
5
5
  "keywords": [
6
6
  "agents",
@@ -36,7 +36,7 @@
36
36
  "devDependencies": {
37
37
  "@arbor/actions": "workspace:*",
38
38
  "@arbor/core": "workspace:*",
39
- "@types/node": "^22.19.19",
39
+ "@types/node": "^26.2.0",
40
40
  "tsx": "^4.20.6",
41
41
  "typescript": "^5.8.0",
42
42
  "vitest": "^4.1.4",