@lambdacurry/arbor 0.14.5 → 0.15.0

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/arbor.js +73 -12
  2. package/package.json +1 -1
package/dist/arbor.js CHANGED
@@ -1625,6 +1625,7 @@ var computerReprovisions = sqliteTable("computer_reprovisions", {
1625
1625
  restorationOutcome: text("restoration_outcome").$type().notNull().default("not_needed"),
1626
1626
  restoredSnapshotId: text("restored_snapshot_id"),
1627
1627
  failureCode: text("failure_code"),
1628
+ failureDetail: text("failure_detail"),
1628
1629
  createdAt: ts("created_at").notNull(),
1629
1630
  completedAt: ts("completed_at")
1630
1631
  }, (t) => ({
@@ -1908,6 +1909,7 @@ var appBundles = sqliteTable("app_bundles", {
1908
1909
  }).$type(),
1909
1910
  runtimeEntrypoint: text("runtime_entrypoint").$type().notNull(),
1910
1911
  capabilityRequirements: text("capability_requirements", { mode: "json" }).$type().notNull().default([]),
1912
+ runtimeConfigRequirements: text("runtime_config_requirements", { mode: "json" }).$type().notNull().default([]),
1911
1913
  stateSchemaVersion: integer("state_schema_version").notNull().default(0),
1912
1914
  stateCompatibleFrom: integer("state_compatible_from").notNull().default(0),
1913
1915
  stateCompatibleThrough: integer("state_compatible_through").notNull().default(0),
@@ -1974,6 +1976,22 @@ var secretBindings = sqliteTable("secret_bindings", {
1974
1976
  appNameUq: uniqueIndex("secret_bindings_app_name_uq").on(t.appId, t.bindingName),
1975
1977
  secretIdx: index("secret_bindings_secret_idx").on(t.secretId, t.status)
1976
1978
  }));
1979
+ var appRuntimeVars = sqliteTable("app_runtime_vars", {
1980
+ id: text("id").primaryKey(),
1981
+ appId: text("app_id").notNull().references(() => apps.id),
1982
+ name: text("name").notNull(),
1983
+ value: text("value").notNull(),
1984
+ revision: integer("revision").notNull().default(1),
1985
+ createdByProfileId: text("created_by_profile_id").notNull().references(() => profiles.id),
1986
+ createdExecutionContextId: text("created_execution_context_id").notNull().references(() => executionContexts.id),
1987
+ createdAt: ts("created_at").notNull(),
1988
+ updatedByProfileId: text("updated_by_profile_id").notNull().references(() => profiles.id),
1989
+ updatedExecutionContextId: text("updated_execution_context_id").notNull().references(() => executionContexts.id),
1990
+ updatedAt: ts("updated_at").notNull()
1991
+ }, (t) => ({
1992
+ appNameUq: uniqueIndex("app_runtime_vars_app_name_uq").on(t.appId, t.name),
1993
+ appIdx: index("app_runtime_vars_app_idx").on(t.appId)
1994
+ }));
1977
1995
  var appDeployments = sqliteTable("app_deployments", {
1978
1996
  id: text("id").primaryKey(),
1979
1997
  appId: text("app_id").notNull().references(() => apps.id),
@@ -17203,6 +17221,7 @@ var MCP_OUTPUT_SCHEMAS = {
17203
17221
  app_fetch: appInvocationResponse,
17204
17222
  app_request: appInvocationResponse,
17205
17223
  app_create: app2,
17224
+ app_config_apply: exports_external.object({ appId: id, dryRun: exports_external.boolean(), changes: exports_external.array(jsonObject) }),
17206
17225
  app_deploy: exports_external.looseObject({
17207
17226
  deployment,
17208
17227
  activated: exports_external.boolean(),
@@ -17310,6 +17329,7 @@ var MCP_OUTPUT_SCHEMAS = {
17310
17329
  operation: exports_external.literal("clone"),
17311
17330
  repository: exports_external.string(),
17312
17331
  dir: exports_external.string(),
17332
+ credential: exports_external.enum(["caller", "arbor-managed"]),
17313
17333
  branch: exports_external.string().optional(),
17314
17334
  head: exports_external.string().optional(),
17315
17335
  refs: exports_external.array(exports_external.string()).optional()
@@ -17319,6 +17339,7 @@ var MCP_OUTPUT_SCHEMAS = {
17319
17339
  operation: exports_external.literal("fetch"),
17320
17340
  repository: exports_external.string(),
17321
17341
  dir: exports_external.string(),
17342
+ credential: exports_external.enum(["caller", "arbor-managed"]),
17322
17343
  branch: exports_external.string().optional(),
17323
17344
  head: exports_external.string().optional(),
17324
17345
  fetchHead: exports_external.string().optional(),
@@ -17329,6 +17350,7 @@ var MCP_OUTPUT_SCHEMAS = {
17329
17350
  operation: exports_external.literal("pull"),
17330
17351
  repository: exports_external.string(),
17331
17352
  dir: exports_external.string(),
17353
+ credential: exports_external.enum(["caller", "arbor-managed"]),
17332
17354
  branch: exports_external.string().optional(),
17333
17355
  head: exports_external.string().optional(),
17334
17356
  before: exports_external.string().optional(),
@@ -17341,6 +17363,7 @@ var MCP_OUTPUT_SCHEMAS = {
17341
17363
  operation: exports_external.literal("push"),
17342
17364
  repository: exports_external.string(),
17343
17365
  dir: exports_external.string(),
17366
+ credential: exports_external.enum(["caller", "arbor-managed"]),
17344
17367
  branch: exports_external.string().optional(),
17345
17368
  head: exports_external.string().optional(),
17346
17369
  before: exports_external.string().optional(),
@@ -17487,6 +17510,7 @@ var MCP_TOOL_ANNOTATIONS = {
17487
17510
  app_fetch: readOnly,
17488
17511
  app_request: destructive,
17489
17512
  app_create: additive,
17513
+ app_config_apply: idempotent,
17490
17514
  app_deploy: idempotent,
17491
17515
  app_activate: additive,
17492
17516
  app_rollback: additive,
@@ -17964,13 +17988,13 @@ var ACTION_DEFINITIONS = [
17964
17988
  {
17965
17989
  name: "computer_sync",
17966
17990
  title: "Sync an allowed repository",
17967
- description: "Fetch, fast-forward pull, or push the checked-out branch of a cloned recipe repository using the working collaborator's GitHub token just in time. The lightweight Computer fixes the allowlisted GitHub URL, never force-pushes or deletes refs, and neither stores nor returns the token.",
17991
+ description: "Fetch, fast-forward pull, or push the checked-out branch of a cloned recipe repository. OMIT githubToken to refresh a repository named in this computer's effective recipe with Arbor's own managed credential — Arbor rechecks the repository connection and mints a request-scoped one-repository read credential server-side, so a restored computer can reach current history with no token of yours. Managed refresh covers fetch and pull; push writes to GitHub and still takes your just-in-time collaborator token. The lightweight Computer fixes the allowlisted GitHub URL, never force-pushes or deletes refs, and neither stores nor returns either credential.",
17968
17992
  inputSchema: {
17969
17993
  computerSessionId: exports_external.string().describe("the computerSessionId returned by computer_open, cms_…"),
17970
17994
  repository: exports_external.string().describe("allowed owner/repository slug already cloned by computer_clone"),
17971
17995
  operation: exports_external.enum(["fetch", "pull", "push"]).describe("network operation to perform"),
17972
- githubToken: exports_external.string().min(1).describe("short-lived GitHub token supplied by the caller"),
17973
- githubUsername: exports_external.string().optional().describe("GitHub username; defaults to x-access-token")
17996
+ githubToken: exports_external.string().min(1).optional().describe("short-lived collaborator GitHub token; omit for fetch/pull to use Arbor's managed recipe credential, required for push"),
17997
+ githubUsername: exports_external.string().optional().describe("GitHub username for a supplied githubToken; defaults to x-access-token")
17974
17998
  },
17975
17999
  surfaces: ["computer-cli"],
17976
18000
  toolset: "loop",
@@ -17979,12 +18003,12 @@ var ACTION_DEFINITIONS = [
17979
18003
  {
17980
18004
  name: "computer_fetch",
17981
18005
  title: "Fetch an allowed repository",
17982
- description: "Fetch remote refs for a cloned recipe repository without changing its checked-out branch or any remote ref. The collaborator's GitHub token is spent only on this call and is neither stored nor returned.",
18006
+ description: `Fetch remote refs for a cloned recipe repository without changing its checked-out branch or any remote ref. OMIT githubToken and Arbor refreshes it for you: it rechecks that the repository is in this computer's effective recipe and still connected, mints a request-scoped one-repository read credential server-side, spends it on this fetch alone, and returns credential: "arbor-managed" — this is the way a RESTORED computer, which deliberately holds no credential, catches up with the remote. Supply githubToken instead to fetch as the collaborator. Neither credential is stored or returned.`,
17983
18007
  inputSchema: {
17984
18008
  computerSessionId: exports_external.string().describe("the computerSessionId returned by computer_open, cms_…"),
17985
18009
  repository: exports_external.string().describe("allowed owner/repository slug already cloned"),
17986
- githubToken: exports_external.string().min(1).describe("short-lived GitHub token supplied by the caller"),
17987
- githubUsername: exports_external.string().optional().describe("GitHub username; defaults to x-access-token")
18010
+ githubToken: exports_external.string().min(1).optional().describe("short-lived collaborator GitHub token; omit to use Arbor's managed recipe credential"),
18011
+ githubUsername: exports_external.string().optional().describe("GitHub username for a supplied githubToken; defaults to x-access-token")
17988
18012
  },
17989
18013
  surfaces: ["computer-mcp"],
17990
18014
  toolset: "loop",
@@ -17993,12 +18017,12 @@ var ACTION_DEFINITIONS = [
17993
18017
  {
17994
18018
  name: "computer_pull",
17995
18019
  title: "Fast-forward an allowed repository",
17996
- description: "Fetch and fast-forward the checked-out branch of a cloned recipe repository; divergent history is rejected. The collaborator's GitHub token is spent only on this call and is neither stored nor returned.",
18020
+ description: "Fetch and fast-forward the checked-out branch of a cloned recipe repository; divergent history, a dirty working tree, and anything needing a merge are rejected rather than forced. OMIT githubToken and Arbor pulls with its own managed recipe credential after rechecking the repository connection — the way a restored computer reaches current history. Supply githubToken instead to pull as the collaborator. Neither credential is stored or returned.",
17997
18021
  inputSchema: {
17998
18022
  computerSessionId: exports_external.string().describe("the computerSessionId returned by computer_open, cms_…"),
17999
18023
  repository: exports_external.string().describe("allowed owner/repository slug already cloned"),
18000
- githubToken: exports_external.string().min(1).describe("short-lived GitHub token supplied by the caller"),
18001
- githubUsername: exports_external.string().optional().describe("GitHub username; defaults to x-access-token")
18024
+ githubToken: exports_external.string().min(1).optional().describe("short-lived collaborator GitHub token; omit to use Arbor's managed recipe credential"),
18025
+ githubUsername: exports_external.string().optional().describe("GitHub username for a supplied githubToken; defaults to x-access-token")
18002
18026
  },
18003
18027
  surfaces: ["computer-mcp"],
18004
18028
  toolset: "loop",
@@ -18057,6 +18081,7 @@ var ACTION_DEFINITIONS = [
18057
18081
  stateSchemaVersion: exports_external.number().int().min(0).optional().describe("durable schema this release writes; default 0"),
18058
18082
  stateCompatibleFrom: exports_external.number().int().min(0).optional().describe("oldest durable schema this code can open"),
18059
18083
  stateCompatibleThrough: exports_external.number().int().min(0).optional().describe("newest durable schema this code can open"),
18084
+ runtimeConfigRequirements: exports_external.array(exports_external.object({ name: exports_external.string().min(1).max(64), kind: exports_external.enum(["var", "secret"]) })).optional().describe("required runtime config keys and kinds; values are never part of the AppBundle"),
18060
18085
  idempotencyKey: exports_external.string().min(1).max(200).describe("stable key for this one logical bundle publication")
18061
18086
  },
18062
18087
  surfaces: ["computer-mcp", "computer-cli"],
@@ -19287,6 +19312,22 @@ var ACTION_DEFINITIONS = [
19287
19312
  toolset: "apps",
19288
19313
  run: forward("app.create")
19289
19314
  },
19315
+ {
19316
+ name: "app_config_apply",
19317
+ title: "Apply App runtime config",
19318
+ description: "Declaratively apply the complete typed runtime config for one App. var stores an ordinary runtime value; secret references an existing Arbor Secret without accepting or returning secret material. Dry-run performs the same validation and returns create/update/delete/no-op actions without mutating.",
19319
+ inputSchema: {
19320
+ appId: exports_external.string().describe("target App, app_…"),
19321
+ config: exports_external.record(exports_external.string(), exports_external.discriminatedUnion("kind", [
19322
+ exports_external.object({ kind: exports_external.literal("var"), value: exports_external.string().max(16384) }),
19323
+ exports_external.object({ kind: exports_external.literal("secret"), secretId: exports_external.string() })
19324
+ ])).describe("complete desired runtime config object keyed by environment variable name"),
19325
+ dryRun: exports_external.boolean().optional().describe("validate and plan without mutating")
19326
+ },
19327
+ surfaces: ["mcp", "cli"],
19328
+ toolset: "apps",
19329
+ run: forward("app.config_apply")
19330
+ },
19290
19331
  {
19291
19332
  name: "app_deploy",
19292
19333
  title: "Prepare an App deployment",
@@ -19842,6 +19883,9 @@ function kindOf(node) {
19842
19883
  return "array";
19843
19884
  case "boolean":
19844
19885
  return "boolean";
19886
+ case "object":
19887
+ case "record":
19888
+ return "json";
19845
19889
  default:
19846
19890
  return "string";
19847
19891
  }
@@ -19850,7 +19894,7 @@ function acceptedFlags(inputSchema) {
19850
19894
  const out = new Set;
19851
19895
  for (const spec of flagsForSchema(inputSchema)) {
19852
19896
  out.add(spec.flag);
19853
- if (spec.kind === "string")
19897
+ if (spec.kind === "string" || spec.kind === "json")
19854
19898
  out.add(`${spec.flag}-file`);
19855
19899
  }
19856
19900
  return out;
@@ -19886,7 +19930,7 @@ function buildInput(inputSchema, flags, command) {
19886
19930
  const primary = primaryPositionalField(inputSchema);
19887
19931
  const input = {};
19888
19932
  for (const spec of flagsForSchema(inputSchema)) {
19889
- if (spec.kind === "string") {
19933
+ if (spec.kind === "string" || spec.kind === "json") {
19890
19934
  const fileSrc = lastValue(flags[`${spec.flag}-file`]);
19891
19935
  if (fileSrc !== undefined) {
19892
19936
  if (flags[spec.flag] !== undefined) {
@@ -19894,7 +19938,16 @@ function buildInput(inputSchema, flags, command) {
19894
19938
  }
19895
19939
  if (fileSrc === true)
19896
19940
  throw new UsageError(`--${spec.flag}-file expects a path (or - for stdin)`);
19897
- input[spec.field] = readTextSource(String(fileSrc));
19941
+ const sourced = readTextSource(String(fileSrc));
19942
+ if (spec.kind === "json") {
19943
+ try {
19944
+ input[spec.field] = JSON.parse(sourced);
19945
+ } catch {
19946
+ throw new UsageError(`--${spec.flag}-file must contain valid JSON`);
19947
+ }
19948
+ } else {
19949
+ input[spec.field] = sourced;
19950
+ }
19898
19951
  continue;
19899
19952
  }
19900
19953
  }
@@ -19958,6 +20011,14 @@ function buildInput(inputSchema, flags, command) {
19958
20011
  input[spec.field] = out;
19959
20012
  break;
19960
20013
  }
20014
+ case "json": {
20015
+ try {
20016
+ input[spec.field] = JSON.parse(String(lastValue(raw)));
20017
+ } catch {
20018
+ throw new UsageError(`--${spec.flag} must be valid JSON`);
20019
+ }
20020
+ break;
20021
+ }
19961
20022
  case "boolean": {
19962
20023
  const v = lastValue(raw);
19963
20024
  input[spec.field] = v === true ? true : v !== "false";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lambdacurry/arbor",
3
- "version": "0.14.5",
3
+ "version": "0.15.0",
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",