@staix/agent-hub 0.25.0 → 0.27.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 (87) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +12 -6
  3. package/docs/agent-notes/README.md +12 -0
  4. package/docs/agent-notes/adapters.md +1 -1
  5. package/docs/agent-notes/daemon.md +7 -5
  6. package/docs/agent-notes/tasks.md +7 -6
  7. package/docs/agent-notes/tests.md +1 -0
  8. package/docs/dogfood.md +7 -1
  9. package/docs/operations.md +160 -17
  10. package/docs/profiles.md +1 -0
  11. package/docs/quickstart.md +18 -4
  12. package/docs/sdlc.md +3 -3
  13. package/docs/security.md +52 -9
  14. package/docs/specs/2026-09-19-agent-hub-design.md +1 -1
  15. package/docs/specs/2026-11-01-research-campaigns-design.md +21 -7
  16. package/docs/verification/2026-11-01-0.26.0.md +54 -0
  17. package/docs/verification/2026-11-01-0.27.0.md +49 -0
  18. package/docs/verified.json +28 -16
  19. package/package.json +1 -1
  20. package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
  21. package/plugins/agent-hub/server.js +190 -101
  22. package/src/adapters/channel-peer.ts +4 -2
  23. package/src/adapters/definitions/builtin-metadata.ts +6 -6
  24. package/src/adapters/definitions/qwen.ts +2 -0
  25. package/src/adapters/registry-types.ts +2 -0
  26. package/src/adapters/registry.ts +1 -0
  27. package/src/cli/conductor-recovery.ts +3 -2
  28. package/src/cli/help.ts +9 -8
  29. package/src/cli/identity.ts +5 -5
  30. package/src/cli/main.ts +68 -24
  31. package/src/cli/recovery-package.ts +94 -4
  32. package/src/cli/reset.ts +14 -4
  33. package/src/cli/runtime-version-warning.ts +28 -0
  34. package/src/cli/start-agents-run.ts +125 -0
  35. package/src/cli/study-output.ts +56 -0
  36. package/src/cli/study.ts +26 -3
  37. package/src/cli/task-output.ts +5 -0
  38. package/src/cli/upgrade-interactive.ts +4 -4
  39. package/src/cli/upgrade-runtime.ts +105 -57
  40. package/src/cli/upgrade.ts +90 -28
  41. package/src/hub/action-policy.ts +5 -3
  42. package/src/hub/autonomy-defaults.ts +32 -7
  43. package/src/hub/board.ts +129 -13
  44. package/src/hub/budget.ts +3 -4
  45. package/src/hub/child-process.ts +4 -3
  46. package/src/hub/conductor.ts +3 -4
  47. package/src/hub/config-apply.ts +13 -2
  48. package/src/hub/config-edit-host.ts +1 -0
  49. package/src/hub/config-tier.ts +3 -0
  50. package/src/hub/config-trust.ts +10 -2
  51. package/src/hub/control-client.ts +30 -10
  52. package/src/hub/daemon.ts +103 -26
  53. package/src/hub/db-schema.ts +143 -0
  54. package/src/hub/delivery-journal.ts +3 -4
  55. package/src/hub/events.ts +2 -1
  56. package/src/hub/execution-budget.ts +3 -4
  57. package/src/hub/folder-trigger.ts +3 -4
  58. package/src/hub/hub-tools.ts +7 -5
  59. package/src/hub/invocations.ts +3 -4
  60. package/src/hub/lifecycle.ts +87 -29
  61. package/src/hub/manager.ts +49 -33
  62. package/src/hub/no-writes.ts +1 -1
  63. package/src/hub/orca-env.ts +19 -0
  64. package/src/hub/project-runtime-state.ts +164 -0
  65. package/src/hub/project-runtime.ts +62 -0
  66. package/src/hub/protocol-window.ts +19 -0
  67. package/src/hub/recovery-store.ts +102 -12
  68. package/src/hub/registry.ts +5 -0
  69. package/src/hub/research-experiments.ts +33 -4
  70. package/src/hub/research-runner.ts +172 -0
  71. package/src/hub/restart.ts +9 -0
  72. package/src/hub/runtime-capture-prune.ts +415 -0
  73. package/src/hub/runtime-prune-health.ts +112 -0
  74. package/src/hub/schedules.ts +3 -4
  75. package/src/hub/sdlc-merge.ts +7 -0
  76. package/src/hub/sdlc-queue.ts +13 -1
  77. package/src/hub/sdlc-release-authorization.ts +11 -5
  78. package/src/hub/session-identity.ts +1 -1
  79. package/src/hub/settings.ts +4 -0
  80. package/src/hub/snapshots.ts +3 -4
  81. package/src/hub/start-agents.ts +44 -0
  82. package/src/hub/task-approval.ts +23 -0
  83. package/src/hub/tasks.ts +133 -34
  84. package/src/hub/usage-rollup.ts +3 -4
  85. package/src/pi/tool-receipts.ts +3 -4
  86. package/templates/presets/confirmation-matrix.json +5 -5
  87. package/templates/release-guard.block.md +2 -1
@@ -806,6 +806,12 @@ var init_agy_mcp = __esm(() => {
806
806
  MAX_CONFIG_BYTES = 256 * 1024;
807
807
  });
808
808
 
809
+ // src/hub/orca-env.ts
810
+ var ORCA_LAUNCHER_ENV;
811
+ var init_orca_env = __esm(() => {
812
+ ORCA_LAUNCHER_ENV = Object.freeze(["ORCA_CLI_COMMAND", "ORCA_DEV_REPO_ROOT", "ORCA_TERMINAL_HANDLE", "ORCA_WORKTREE_ID"]);
813
+ });
814
+
809
815
  // src/hub/child-process.ts
810
816
  function childEnv(source = process.env) {
811
817
  const env = { ...source };
@@ -1066,6 +1072,7 @@ var PS, PS_OPTIONS, own = (text) => {
1066
1072
  proc.stderr?.destroy();
1067
1073
  }, emptied;
1068
1074
  var init_child_process = __esm(() => {
1075
+ init_orca_env();
1069
1076
  PS = ["ps", "-axo", "pid=,ppid=,pgid=,stat=,lstart=,command="];
1070
1077
  PS_OPTIONS = { env: { ...process.env, LC_ALL: "C", TZ: "UTC" }, detached: true };
1071
1078
  emptied = new WeakSet;
@@ -5896,8 +5903,13 @@ var init_launch = __esm(() => {
5896
5903
  init_child_process();
5897
5904
  });
5898
5905
 
5906
+ // src/hub/recovery-error.ts
5907
+ var init_recovery_error = __esm(() => {
5908
+ init_envelope();
5909
+ });
5910
+
5899
5911
  // src/hub/recovery-store.ts
5900
- import { chmodSync, existsSync as existsSync5, mkdirSync as mkdirSync6, readFileSync as readFileSync5, renameSync as renameSync4, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "fs";
5912
+ import { chmodSync, existsSync as existsSync5, linkSync, lstatSync as lstatSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync5, renameSync as renameSync4, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "fs";
5901
5913
  import { randomUUID as randomUUID4 } from "crypto";
5902
5914
  function atomicPrivateJSON(file, value) {
5903
5915
  const temporary = `${file}.${randomUUID4()}.tmp`;
@@ -5912,6 +5924,7 @@ function atomicPrivateJSON(file, value) {
5912
5924
  }
5913
5925
  var init_recovery_store = __esm(() => {
5914
5926
  init_project();
5927
+ init_recovery_error();
5915
5928
  init_process_signature();
5916
5929
  });
5917
5930
 
@@ -5985,11 +5998,11 @@ var init_permission_mode = __esm(() => {
5985
5998
  });
5986
5999
 
5987
6000
  // src/hub/path-policy.ts
5988
- import { accessSync, constants as constants4, lstatSync as lstatSync8, opendirSync, readlinkSync, statSync as statSync2 } from "fs";
6001
+ import { accessSync, constants as constants4, lstatSync as lstatSync9, opendirSync, readlinkSync, statSync as statSync2 } from "fs";
5989
6002
  import { dirname as dirname7, isAbsolute as isAbsolute5, join as join11, relative as relative3, resolve as resolve8, sep as sep2 } from "path";
5990
6003
  function existing(path) {
5991
6004
  try {
5992
- lstatSync8(path);
6005
+ lstatSync9(path);
5993
6006
  return true;
5994
6007
  } catch (error) {
5995
6008
  if (error.code === "ENOENT")
@@ -6038,7 +6051,7 @@ function directAliasTarget(path) {
6038
6051
  return;
6039
6052
  ancestor = parent;
6040
6053
  }
6041
- if (!lstatSync8(ancestor).isSymbolicLink())
6054
+ if (!lstatSync9(ancestor).isSymbolicLink())
6042
6055
  return;
6043
6056
  target = resolve8(dirname7(ancestor), readlinkSync(ancestor), relative3(ancestor, target));
6044
6057
  }
@@ -6515,7 +6528,7 @@ var init_text_projection = __esm(() => {
6515
6528
  });
6516
6529
 
6517
6530
  // src/local/doc-read.ts
6518
- import { lstatSync as lstatSync9 } from "fs";
6531
+ import { lstatSync as lstatSync10 } from "fs";
6519
6532
  import { extname } from "path";
6520
6533
  function docRead(file, shown, args, port, cwd) {
6521
6534
  const projections = port.projections();
@@ -6525,7 +6538,7 @@ function docRead(file, shown, args, port, cwd) {
6525
6538
  }
6526
6539
  let st;
6527
6540
  try {
6528
- st = lstatSync9(file);
6541
+ st = lstatSync10(file);
6529
6542
  } catch {
6530
6543
  return `error: ${shown} cannot be read`;
6531
6544
  }
@@ -6848,7 +6861,7 @@ var init_web_fetch = __esm(() => {
6848
6861
  });
6849
6862
 
6850
6863
  // src/local/tools.ts
6851
- import { lstatSync as lstatSync10, mkdirSync as mkdirSync8, readFileSync as readFileSync7, statSync as statSync3, writeFileSync as writeFileSync7 } from "fs";
6864
+ import { lstatSync as lstatSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync7, statSync as statSync3, writeFileSync as writeFileSync7 } from "fs";
6852
6865
  import { dirname as dirname10, join as join13, relative as relative4, resolve as resolve10 } from "path";
6853
6866
  function guardPath(ctx, path, mode) {
6854
6867
  const root = realPath(ctx.cwd);
@@ -6871,7 +6884,7 @@ function guardPath(ctx, path, mode) {
6871
6884
  throw new Error(`${path} is on the secrets denylist`);
6872
6885
  if (mode === "write" && (isHubWritePath(rel) || inside && isHubWritePath(typed)))
6873
6886
  throw new Error(`${path} is not writable by the local worker`);
6874
- if (mode === "write" && ctx.readOnly?.length && (lstatSync10(real, { throwIfNoEntry: false })?.nlink ?? 1) > 1)
6887
+ if (mode === "write" && ctx.readOnly?.length && (lstatSync11(real, { throwIfNoEntry: false })?.nlink ?? 1) > 1)
6875
6888
  throw new Error("hardlinked write target cannot be verified with data.readonly");
6876
6889
  if (mode === "write" && matchesPolicy(root, path, ctx.readOnly ?? []))
6877
6890
  throw new Error("target is protected by data.readonly");
@@ -7045,7 +7058,7 @@ ${preview(content)}`, "write", ctx.signal, file, undefined, String(a.path), a),
7045
7058
  }
7046
7059
  var APPROVAL_EXPIRED_TEXT = "error: approval expired: no person answered; do not retry this call; hand the task off or stop", ApprovalWaitStop, approvalError = (picked, denied) => picked === true ? undefined : picked === "expired" ? APPROVAL_EXPIRED_TEXT : picked === "aborted" ? "error: approval withdrawn because the turn ended; no operation was executed" : denied, lexists = (p) => {
7047
7060
  try {
7048
- lstatSync10(p);
7061
+ lstatSync11(p);
7049
7062
  return true;
7050
7063
  } catch {
7051
7064
  return false;
@@ -10695,7 +10708,7 @@ var init_shipped_roles = __esm(() => {
10695
10708
 
10696
10709
  // src/hub/roles.ts
10697
10710
  import { createHash as createHash6 } from "crypto";
10698
- import { constants as constants5, closeSync as closeSync6, fstatSync as fstatSync5, lstatSync as lstatSync11, openSync as openSync6, readSync as readSync4, readdirSync as readdirSync2 } from "fs";
10711
+ import { constants as constants5, closeSync as closeSync6, fstatSync as fstatSync5, lstatSync as lstatSync12, openSync as openSync6, readSync as readSync4, readdirSync as readdirSync2 } from "fs";
10699
10712
  import { join as join15 } from "path";
10700
10713
  function parseRole(text, stem, layer) {
10701
10714
  if (Buffer.byteLength(text) > 8192 || text.includes("\r") || !ID.test(stem))
@@ -10777,7 +10790,7 @@ function loadRoleCatalog(cwd) {
10777
10790
  try {
10778
10791
  const config = join15(cwd, ".agenthub"), dir = join15(config, "roles");
10779
10792
  for (const path of [config, dir]) {
10780
- const stat = lstatSync11(path);
10793
+ const stat = lstatSync12(path);
10781
10794
  if (!stat.isDirectory() || stat.isSymbolicLink())
10782
10795
  throw new Error("unsafe role directory");
10783
10796
  }
@@ -10871,6 +10884,14 @@ var init_packs = __esm(() => {
10871
10884
  init_workflow();
10872
10885
  });
10873
10886
 
10887
+ // src/hub/research-runner.ts
10888
+ var BODY, RUNNER_RECEIPT_DOMAIN;
10889
+ var init_research_runner = __esm(() => {
10890
+ init_packs();
10891
+ BODY = 64 * 1024;
10892
+ RUNNER_RECEIPT_DOMAIN = "agent-hub.runner-receipt/v1" + String.fromCharCode(0);
10893
+ });
10894
+
10874
10895
  // node_modules/@staix/agent-mem/src/memory/mutation.ts
10875
10896
  var mutations;
10876
10897
  var init_mutation = __esm(() => {
@@ -11890,12 +11911,13 @@ var init_deliverables = __esm(() => {
11890
11911
  });
11891
11912
 
11892
11913
  // src/hub/research-experiments.ts
11893
- var BODY;
11914
+ var BODY2;
11894
11915
  var init_research_experiments = __esm(() => {
11895
11916
  init_src();
11896
11917
  init_packs();
11918
+ init_research_runner();
11897
11919
  init_deliverables();
11898
- BODY = 64 * 1024;
11920
+ BODY2 = 64 * 1024;
11899
11921
  });
11900
11922
 
11901
11923
  // src/hub/task-code-symbols.ts
@@ -11904,24 +11926,98 @@ var init_task_code_symbols = __esm(() => {
11904
11926
  HOST_CODE_SYMBOLS = Symbol("host task code symbols");
11905
11927
  });
11906
11928
 
11929
+ // package.json
11930
+ var package_default;
11931
+ var init_package = __esm(() => {
11932
+ package_default = {
11933
+ name: "@staix/agent-hub",
11934
+ version: "0.27.0",
11935
+ description: "Native multi-agent hub: Claude Code, Codex, Kimi Code, Pi and local inference as peers in one project",
11936
+ license: "MIT",
11937
+ type: "module",
11938
+ bin: {
11939
+ ahub: "src/cli/main.js",
11940
+ "agent-hub": "src/cli/main.js"
11941
+ },
11942
+ scripts: {
11943
+ check: "scripts/check.sh",
11944
+ build: "bun scripts/build.mjs",
11945
+ test: "bun test"
11946
+ },
11947
+ engines: {
11948
+ bun: ">=1.4.2"
11949
+ },
11950
+ dependencies: {
11951
+ "@staix/agent-mem": "0.18.0"
11952
+ },
11953
+ devDependencies: {
11954
+ "@modelcontextprotocol/sdk": "^1.27.1",
11955
+ "@types/bun": "^1.3.0",
11956
+ typescript: "^5.8.0"
11957
+ },
11958
+ files: [
11959
+ ".claude-plugin",
11960
+ "src",
11961
+ "src/pet/window.jxa.js",
11962
+ "src/pet/window.html",
11963
+ "plugins",
11964
+ "templates",
11965
+ "scripts/check-docs.mjs",
11966
+ "docs",
11967
+ "README.md",
11968
+ "LICENSE",
11969
+ "CHANGELOG.md",
11970
+ "THIRD_PARTY_NOTICES.md",
11971
+ "LICENSES"
11972
+ ],
11973
+ repository: {
11974
+ type: "git",
11975
+ url: "git+https://github.com/STAIxBWLB/agent-hub.git"
11976
+ },
11977
+ homepage: "https://github.com/STAIxBWLB/agent-hub",
11978
+ publishConfig: {
11979
+ access: "public"
11980
+ },
11981
+ exports: {
11982
+ "./adapter": "./src/adapters/public.ts",
11983
+ "./conformance": "./src/adapters/conformance/index.ts",
11984
+ "./ui-plugin": "./src/ui/plugin.ts"
11985
+ }
11986
+ };
11987
+ });
11988
+
11989
+ // src/version.ts
11990
+ var VERSION;
11991
+ var init_version = __esm(() => {
11992
+ init_package();
11993
+ VERSION = package_default.version;
11994
+ });
11995
+ // src/hub/db-schema.ts
11996
+ var init_db_schema = __esm(() => {
11997
+ init_version();
11998
+ });
11999
+
11907
12000
  // src/hub/planning.ts
11908
12001
  var init_planning = __esm(() => {
11909
12002
  init_sdlc();
11910
12003
  });
12004
+
11911
12005
  // src/hub/research-campaign.ts
11912
- var BODY2;
12006
+ var BODY3;
11913
12007
  var init_research_campaign = __esm(() => {
11914
12008
  init_packs();
11915
- BODY2 = 64 * 1024;
12009
+ BODY3 = 64 * 1024;
11916
12010
  });
11917
12011
 
11918
12012
  // src/hub/board.ts
11919
12013
  var CLASSES2, PLAN_KEYS, ALL_PLAN_KEYS, OUTCOMES_KEPT_MS;
11920
12014
  var init_board = __esm(() => {
12015
+ init_research_runner();
11921
12016
  init_packs();
11922
12017
  init_research_experiments();
11923
12018
  init_task_code_symbols();
11924
12019
  init_plan_conformance();
12020
+ init_db_schema();
11925
12021
  init_planning();
11926
12022
  init_envelope();
11927
12023
  init_review_findings();
@@ -12077,7 +12173,7 @@ function profileTaskTools(profile = "dev", stages, criteria = false) {
12077
12173
  }
12078
12174
  if (customProfile && tool.name === "hub_task_propose")
12079
12175
  properties.class = { type: "string", enum: [...new Set([...Object.keys(data.classes), ...PROFILE_CLASS_NAMES.filter((v) => projectProfile("dev").classes[v])])] };
12080
- if (customProfile && properties.plan && tool.name !== "hub_task_accept")
12176
+ if (customProfile && properties.plan && tool.name !== "hub_task_accept" && tool.name !== "hub_experiment_record")
12081
12177
  properties.plan = { ...plan, properties: { ...Object.fromEntries(data.plan_keys.map((key) => [key, plan.properties[key] ?? list(key === "sections" ? "document heading anchors, such as report.md#methods" : key === "sources" ? "citation ids, DOI or source URL ids" : "short claim ids to verify")])) } };
12082
12178
  if (customProfile && tool.name === "hub_task_done" && data.name !== "dev") {
12083
12179
  const summaryProp = properties.summary;
@@ -12091,7 +12187,7 @@ function profileTaskTools(profile = "dev", stages, criteria = false) {
12091
12187
  const selectedPlan = { ...plan, properties: { ...Object.fromEntries(data.plan_keys.map((key) => [key, plan.properties[key] ?? list(key === "sections" ? "document heading anchors, such as report.md#methods" : key === "sources" ? "citation ids, DOI or source URL ids" : "short claim ids to verify")])) } };
12092
12188
  properties.parts = { ...parts, items: { ...parts.items, properties: { ...parts.items.properties, plan: selectedPlan } } };
12093
12189
  }
12094
- if (criteria && properties.plan) {
12190
+ if (criteria && properties.plan && tool.name !== "hub_experiment_record") {
12095
12191
  const current = properties.plan;
12096
12192
  properties.plan = { ...current, properties: { ...current.properties, ...costPlanProperties, ...evidencePlanProperties } };
12097
12193
  }
@@ -12124,7 +12220,7 @@ var init_hub_tools = __esm(() => {
12124
12220
  init_roles();
12125
12221
  init_registry();
12126
12222
  init_envelope();
12127
- IMPLEMENTER_HUB_TOOL_NAMES = Object.freeze(["hub_task_accept", "hub_task_decline", "hub_task_done", "hub_checkpoint", "hub_send", "hub_task_show", "hub_task_propose", "hub_remember", "hub_inbox", "hub_permission_request", "hub_study_show", "hub_study_handoff"]);
12223
+ IMPLEMENTER_HUB_TOOL_NAMES = Object.freeze(["hub_task_accept", "hub_task_decline", "hub_task_done", "hub_checkpoint", "hub_send", "hub_task_show", "hub_task_propose", "hub_remember", "hub_inbox", "hub_permission_request", "hub_study_show", "hub_experiment_show", "hub_experiment_record", "hub_study_handoff"]);
12128
12224
  IMPLEMENTER_PERMISSION_TOOL = {
12129
12225
  name: "hub_permission_request",
12130
12226
  description: "Native permission prompt for this current owned child. The person allows once or denies; failure is deny.",
@@ -12178,7 +12274,7 @@ var init_hub_tools = __esm(() => {
12178
12274
  additionalProperties: false
12179
12275
  };
12180
12276
  acceptPlan = { ...plan, properties: { ...plan.properties, sections: list("document heading anchors, such as report.md#methods"), sources: list("citation ids, DOI or source URL ids"), claims: list("short claim ids to verify") } };
12181
- STUDY_TOOLS = new Set(["hub_study_draft", "hub_study_revise", "hub_study_show", "hub_study_handoff"]);
12277
+ STUDY_TOOLS = new Set(["hub_study_draft", "hub_study_revise", "hub_study_show", "hub_experiment_show", "hub_experiment_record", "hub_study_handoff"]);
12182
12278
  HANDOFF_TOOLS = new Set(["hub_task_handoff", "hub_task_handoffs"]);
12183
12279
  BOUNDED_TASK_TOOLS = new Set(["hub_task_spec", "hub_check_start", "hub_check_result", "hub_check_cancel"]);
12184
12280
  CAPABILITY_TOOLS = new Set(["hub_capabilities", "hub_capabilities_publish", "hub_invoke"]);
@@ -12196,6 +12292,8 @@ var init_hub_tools = __esm(() => {
12196
12292
  tool2("hub_study_draft", "Store a research campaign contract as a DRAFT revision 1 on an approved parent task. Configured planners only; it creates no task, dispatches nothing and never approves (only the person approves, with ahub study approve). The contract is data: question, scope, exclusions, sourceIds, units, deliverableSections, stopPolicy and an optional budget.", { parentTaskId: id2, contract: { type: "object" } }, ["parentTaskId", "contract"]),
12197
12293
  tool2("hub_study_revise", "Store the next DRAFT revision of a research campaign with the revision you read. Configured planners only; a stale revision refuses, and a draft holds older bound work until the person approves it. Never approves.", { id: str2, revision: { type: "integer", minimum: 1 }, contract: { type: "object" } }, ["id", "revision", "contract"]),
12198
12294
  tool2("hub_study_show", "Read a research campaign's coverage and stop projection: per unit round, state, handoff completeness and budget support, and why dispatch is held. Read-only. A private campaign, task or source shows ids, counts and states only, never its question, scope, path or excerpt. Give no id to list this project's campaigns, at most 50 per call: when the reply carries `next`, pass it as `after` for the following page.", { id: str2, after: str2 }),
12295
+ tool2("hub_experiment_record", "Record experiment metadata for your current in-progress campaign unit: protocol, attempt, event or comparison plan, or relay a signed runner receipt. The hub validates ownership, sources, campaign and signatures. It runs no command, starts no experiment and contacts no runner. Refused during a PII turn.", { kind: { type: "string", enum: ["protocol", "attempt", "event", "plan", "receipt"] }, taskId: id2, protocol: { type: "object" }, attempt: { type: "object" }, attemptId: str2, idempotencyKey: str2, event: { type: "object" }, plan: { type: "object" }, receipt: { type: "object" }, signature: str2 }, ["kind"]),
12296
+ tool2("hub_experiment_show", "Read the experiment attempts of a research campaign, one attempt, or one baseline/variant comparison under a recorded plan. Read-only: it runs no command and reads no file. Every metric, hash and setting says where it came from (declared by an agent, host-observed, runner-attested or person-attested); a declared value is never shown as observed, failed, cancelled and unknown attempts stay in the counts, and a repeat is never an independent reproduction. A private campaign, task or source shows ids, counts and states only. Give campaignId (with after to page, at most 50 rows), or attemptId, or planHash with baselineAttemptId and variantAttemptId.", { campaignId: str2, attemptId: str2, after: { type: "integer", minimum: 0 }, eventAfter: { type: "integer", minimum: 0 }, limit: { type: "integer", minimum: 1, maximum: 50 }, planHash: str2, baselineAttemptId: str2, variantAttemptId: str2 }),
12199
12297
  tool2("hub_task_handoff", "Hand work that belongs to ANOTHER project that runs agent-hub to that project's board. Use it instead of implementing it from this session: a feature or behavior change first needs a spec issue in that project (pass its number as issue); a mechanical chore (an exact version pin, a regenerated file) goes straight to a task. The target is a registered project (its root or id) whose hub is running; it is not queued. Planner, conductor or person only. Never for a [pii] task or during a private turn. You learn the task's state changes as kind task messages.", { project: str2, title: str2, class: { type: "string", description: "task class, default implement" }, detail: str2, paths: { type: "array", items: str2, description: "repository-relative paths in the TARGET project" }, issue: { type: "integer", minimum: 1, description: "the target repository's issue number" }, task: { type: "integer", minimum: 1, description: "your own task in THIS project that this work comes from; a [pii] task is refused" } }, ["project", "title"]),
12200
12298
  tool2("hub_task_handoffs", "List what this project handed to other projects, with the last state each target reported. Read-only.", {}),
12201
12299
  tool2("hub_study_handoff", "Record the handoff for the research unit you currently own and have in progress: evidence per source, unresolved questions, contradictions and limitations, or insufficientEvidence. Only the bound owner; every required field must be present. Not a task completion.", { handoff: { type: "object" } }, ["handoff"]),
@@ -12256,7 +12354,7 @@ var init_hub_tools = __esm(() => {
12256
12354
  tool2("hub_peer_release", "Release only the conductor hold you placed. Never lifts a person's hold or a budget pause.", { peer: str2 }, ["peer"])
12257
12355
  ];
12258
12356
  CONDUCTOR_TOOL_NAMES = new Set(CONDUCTOR_TOOLS.map((t) => t.name));
12259
- READ_ONLY_PROJECT_TOOLS = Object.freeze(["hub_capabilities", "hub_send", "hub_inbox", "hub_delivery_done", "hub_review", "hub_task_show", "hub_task_list", "hub_study_show", "hub_memory_search", "hub_memory_show", "hub_memory_graph", "hub_source_read", "hub_status"]);
12357
+ READ_ONLY_PROJECT_TOOLS = Object.freeze(["hub_capabilities", "hub_send", "hub_inbox", "hub_delivery_done", "hub_review", "hub_task_show", "hub_task_list", "hub_study_show", "hub_experiment_show", "hub_memory_search", "hub_memory_show", "hub_memory_graph", "hub_source_read", "hub_status"]);
12260
12358
  ROLE_TEXT = {
12261
12359
  conductor: "conductor: plan and split work into tasks with owners, watch the team with hub_status, move stalled work, and ensure every task is reviewed (review it yourself only if you also hold reviewer). Report results and open decisions to the person. Do not implement tasks you handed out. Never ask a peer to answer an approval; ask the person for human-only actions. You may release only holds you placed, never human holds or budget pauses.",
12262
12360
  planner: "planner: break work into tasks with hub_task_propose (one outcome each, the right class, paths in refs, and after: [ids] for work that must wait for other tasks) instead of doing everything yourself.",
@@ -13012,7 +13110,7 @@ var WITHHELD = "Claude implementer turn failed (details withheld)";
13012
13110
 
13013
13111
  // src/adapters/claude-implementer.ts
13014
13112
  import { randomUUID as randomUUID9 } from "crypto";
13015
- import { lstatSync as lstatSync12, mkdtempSync as mkdtempSync5, rmSync as rmSync6, writeFileSync as writeFileSync8 } from "fs";
13113
+ import { lstatSync as lstatSync13, mkdtempSync as mkdtempSync5, rmSync as rmSync6, writeFileSync as writeFileSync8 } from "fs";
13016
13114
  import { tmpdir as tmpdir5 } from "os";
13017
13115
  import { join as join17 } from "path";
13018
13116
  function provenVersion(binding) {
@@ -13070,7 +13168,7 @@ function claudeImplementerArgs(turn, mcp, settings, prompt, model) {
13070
13168
  async function proveClaudeImplementer(peer, command) {
13071
13169
  const binary = Bun.which(command[0], { PATH: process.env.PATH }) ?? command[0];
13072
13170
  const fingerprint = () => {
13073
- const file = realPath(binary), stat = lstatSync12(file);
13171
+ const file = realPath(binary), stat = lstatSync13(file);
13074
13172
  return [file, stat.dev, stat.ino, stat.size, stat.mtimeMs, stat.ctimeMs].join(":");
13075
13173
  };
13076
13174
  const binding = fingerprint(), home = mkdtempSync5(join17(tmpdir5(), "ahub-claude-proof-"));
@@ -13625,7 +13723,7 @@ var init_reviewer_variants = __esm(() => {
13625
13723
  });
13626
13724
 
13627
13725
  // src/adapters/agy/hooks.ts
13628
- import { closeSync as closeSync7, constants as constants6, fstatSync as fstatSync6, lstatSync as lstatSync13, openSync as openSync7, readSync as readSync5 } from "fs";
13726
+ import { closeSync as closeSync7, constants as constants6, fstatSync as fstatSync6, lstatSync as lstatSync14, openSync as openSync7, readSync as readSync5 } from "fs";
13629
13727
  import { homedir as homedir5 } from "os";
13630
13728
  import { isAbsolute as isAbsolute6, join as join18, relative as relative5 } from "path";
13631
13729
  import { createHash as createHash7 } from "crypto";
@@ -13673,7 +13771,7 @@ function readAgyTranscript(session, transcript) {
13673
13771
  let cursor = home;
13674
13772
  for (const name of relative5(home, transcript).split("/")) {
13675
13773
  cursor = join18(cursor, name);
13676
- if (lstatSync13(cursor).isSymbolicLink())
13774
+ if (lstatSync14(cursor).isSymbolicLink())
13677
13775
  return empty;
13678
13776
  }
13679
13777
  fd = openSync7(transcript, constants6.O_RDONLY | constants6.O_NOFOLLOW);
@@ -15107,6 +15205,7 @@ var init_builtin_metadata = __esm(() => {
15107
15205
  version: claudeObservedVersion,
15108
15206
  ...CLAUDE_LAUNCH_POLICY,
15109
15207
  conductorStartable: true,
15208
+ upStart: { allowed: true, default: true },
15110
15209
  unattended: true,
15111
15210
  hubSwitches: switches,
15112
15211
  ownedFlags: Object.freeze(["--dangerously-load-development-channels", "--dangerously-skip-permissions"])
@@ -15148,6 +15247,7 @@ var init_builtin_metadata = __esm(() => {
15148
15247
  version: codexObservedVersion,
15149
15248
  ...CODEX_LAUNCH_POLICY,
15150
15249
  conductorStartable: true,
15250
+ upStart: { allowed: true, default: true },
15151
15251
  unattended: true,
15152
15252
  hubSwitches: switches,
15153
15253
  ownedFlags: Object.freeze(["--remote", "--remote-auth-token-env", "--yolo", "--dangerously-bypass-approvals-and-sandbox"])
@@ -15173,7 +15273,7 @@ var init_builtin_metadata = __esm(() => {
15173
15273
  roles: implementerRoles,
15174
15274
  defaultOnRoster: true,
15175
15275
  trust: { onPrem: false, hubSandboxed: false },
15176
- start: { create: createKimi, acpCommand: kimiAcpCommand, explicitHeadlessMode: true, planCommand: () => "ahub kimi", daemonPort: "acp", forms: dualForms, defaultForm: "tui", conductorStartable: true, hubSwitches: [], ownedFlags: [] },
15276
+ start: { create: createKimi, acpCommand: kimiAcpCommand, explicitHeadlessMode: true, planCommand: () => "ahub kimi", daemonPort: "acp", forms: dualForms, defaultForm: "tui", conductorStartable: true, upStart: { allowed: true }, hubSwitches: [], ownedFlags: [] },
15177
15277
  identity: { mcp: "acp-session" },
15178
15278
  instances: { mode: "headless" },
15179
15279
  attach: {
@@ -15207,7 +15307,7 @@ var init_builtin_metadata = __esm(() => {
15207
15307
  roles: implementerRoles,
15208
15308
  defaultOnRoster: false,
15209
15309
  trust: { onPrem: false, hubSandboxed: true },
15210
- start: { create: createPi, exclusiveStartRefusal: "Pi start is in progress; inspect status before retrying", refreshTools: true, explicitHeadlessMode: true, daemonPort: "pi-rpc", forms: dualForms, defaultForm: "tui", conductorStartable: true, autoStart: "pi.auto_start", conductorStartArgs: piConductorStartArgs, hubSwitches: [], ownedFlags: [] },
15310
+ start: { create: createPi, exclusiveStartRefusal: "Pi start is in progress; inspect status before retrying", refreshTools: true, explicitHeadlessMode: true, daemonPort: "pi-rpc", forms: dualForms, defaultForm: "tui", conductorStartable: true, upStart: { allowed: true }, autoStart: "pi.auto_start", conductorStartArgs: piConductorStartArgs, hubSwitches: [], ownedFlags: [] },
15211
15311
  identity: { mcp: "env" },
15212
15312
  instances: { mode: "headless" },
15213
15313
  permission: { grants: { ...hubGrants } },
@@ -15230,7 +15330,7 @@ var init_builtin_metadata = __esm(() => {
15230
15330
  roles: implementerRoles,
15231
15331
  defaultOnRoster: true,
15232
15332
  trust: { onPrem: true, hubSandboxed: true },
15233
- start: { create: createLocal, reconfigureWhileAttached: true, refreshTools: true, daemonPort: "local-worker", forms: headlessForms, defaultForm: "headless", conductorStartable: true, hubSwitches: [], ownedFlags: [] },
15333
+ start: { create: createLocal, reconfigureWhileAttached: true, refreshTools: true, daemonPort: "local-worker", forms: headlessForms, defaultForm: "headless", conductorStartable: true, upStart: { allowed: true }, hubSwitches: [], ownedFlags: [] },
15234
15334
  identity: { mcp: "env" },
15235
15335
  instances: { mode: "headless" },
15236
15336
  permission: { grants: { ...hubGrants } },
@@ -15253,7 +15353,7 @@ var init_builtin_metadata = __esm(() => {
15253
15353
  optional: true,
15254
15354
  defaultOnRoster: false,
15255
15355
  trust: { onPrem: false, hubSandboxed: false },
15256
- start: { create: createJcode, preflight: jcodeStartPreflight, daemonPort: "owned-acp", forms: dualForms, defaultForm: "tui", explicitHeadlessMode: true, conductorStartable: true, hubSwitches: [], ownedFlags: [] },
15356
+ start: { create: createJcode, preflight: jcodeStartPreflight, daemonPort: "owned-acp", forms: dualForms, defaultForm: "tui", explicitHeadlessMode: true, conductorStartable: true, upStart: { allowed: true }, hubSwitches: [], ownedFlags: [] },
15257
15357
  identity: { mcp: "project-file" },
15258
15358
  instances: { mode: "headless", nativeHome: true },
15259
15359
  permission: { unmanaged: "Jcode native policy is unmanaged; no hub mode mapping", grants: {
@@ -15411,6 +15511,7 @@ var init_qwen = __esm(() => {
15411
15511
  forms: ["headless"],
15412
15512
  defaultForm: "headless",
15413
15513
  conductorStartable: true,
15514
+ upStart: { allowed: false, refusal: "the hub never opens its TUI, and a Qwen is started only by ahub qwen" },
15414
15515
  hubSwitches: [],
15415
15516
  ownedFlags: [],
15416
15517
  preflight: (request) => request.form !== undefined && request.form !== "headless" && request.form !== "tui" ? "unknown Qwen mode; usage: ahub qwen [--mode headless|tui]" : undefined,
@@ -15838,6 +15939,7 @@ function assertNativeCapabilityScope(definition) {
15838
15939
  ["start.daemonPort pi-rpc", definition.start.daemonPort === "pi-rpc"],
15839
15940
  ["start.daemonPort qwen-dual", definition.start.daemonPort === "qwen-dual"],
15840
15941
  ["start.createTui", declared(definition.start, "createTui")],
15942
+ ["start.upStart", declared(definition.start, "upStart")],
15841
15943
  ["routing", definition.routing !== undefined],
15842
15944
  ["projection", definition.projection !== undefined],
15843
15945
  ["instances.nativeHome", declared(definition.instances, "nativeHome")],
@@ -22924,7 +23026,7 @@ init_registry();
22924
23026
  // src/hub/config-trust.ts
22925
23027
  init_child_process();
22926
23028
  init_git();
22927
- import { lstatSync as lstatSync14, statSync as statSync5 } from "fs";
23029
+ import { lstatSync as lstatSync15, statSync as statSync5 } from "fs";
22928
23030
  import { dirname as dirname12, join as join28 } from "path";
22929
23031
  var MACHINE_LOCAL = [
22930
23032
  "kimi_cmd",
@@ -22953,7 +23055,7 @@ var MACHINE_LOCAL = [
22953
23055
  "corpus.paths",
22954
23056
  "invocation"
22955
23057
  ];
22956
- var ALL_MACHINE_LOCAL = [...MACHINE_LOCAL, "rooms", "tasks.queue_backpressure", "context.max_assignment_used", "action_policy", "protect_instruction_files", "qwen_cmd", "jcode_cmd", "jcode_home", "jcode_provider_profile", "adapters", "adapter_modules", "text_projection", "instances"];
23058
+ var ALL_MACHINE_LOCAL = [...MACHINE_LOCAL, "research.runners", "rooms", "tasks.queue_backpressure", "context.max_assignment_used", "action_policy", "protect_instruction_files", "qwen_cmd", "jcode_cmd", "jcode_home", "jcode_provider_profile", "start.agents", "adapters", "adapter_modules", "text_projection", "instances"];
22957
23059
  function configRefusal(cwd, name) {
22958
23060
  const tracked = configTracked(cwd, name);
22959
23061
  return tracked === undefined ? `git could not confirm that .agenthub/${name} is untracked` : tracked ? `.agenthub/${name} is committed to git` : undefined;
@@ -23032,11 +23134,40 @@ function readAdapterModuleDeclarations(cwd, layers) {
23032
23134
  init_project();
23033
23135
  import { readFileSync as readFileSync14 } from "fs";
23034
23136
  import { join as join29, resolve as resolve17 } from "path";
23137
+
23138
+ // src/hub/protocol-window.ts
23139
+ function protocolWindow(v, vMin) {
23140
+ if (typeof v !== "number" || !Number.isSafeInteger(v) || v <= 0)
23141
+ return;
23142
+ const minimum = vMin === undefined ? v : vMin;
23143
+ if (typeof minimum !== "number" || !Number.isSafeInteger(minimum) || minimum <= 0 || minimum > v)
23144
+ return;
23145
+ return { v, vMin: minimum };
23146
+ }
23147
+ function negotiateProtocol(local, remote) {
23148
+ if (!local || typeof local !== "object" || Array.isArray(local) || !remote || typeof remote !== "object" || Array.isArray(remote))
23149
+ return;
23150
+ const a = protocolWindow(local.v, local.vMin), b = protocolWindow(remote.v, remote.vMin);
23151
+ if (!a || !b)
23152
+ return;
23153
+ const highest = Math.min(a.v, b.v);
23154
+ return highest >= Math.max(a.vMin, b.vMin) ? highest : undefined;
23155
+ }
23156
+
23157
+ // src/hub/control-client.ts
23035
23158
  function stateDirFor(cwd) {
23036
23159
  return projectContext(cwd).stateDir;
23037
23160
  }
23038
- var PROTOCOL = 16;
23039
- var RECOVERY_SOURCE_PROTOCOLS = [9, 10, 11, 12, 13, 14, 15, PROTOCOL];
23161
+ var PROTOCOL = 17;
23162
+ var PROTOCOL_MIN = 16;
23163
+ var RECOVERY_SOURCE_PROTOCOLS = [9, 10, 11, 12, 13, 14, 15, 16, PROTOCOL];
23164
+ function controlProtocolWindow(descriptor) {
23165
+ const legacy = protocolWindow(descriptor.protocol);
23166
+ const window = protocolWindow(descriptor.protocolMax ?? descriptor.protocol, descriptor.protocolMin ?? descriptor.protocol);
23167
+ if (!legacy || !window || legacy.v < window.vMin || legacy.v > window.v)
23168
+ return;
23169
+ return window;
23170
+ }
23040
23171
  function readControl(stateDir) {
23041
23172
  try {
23042
23173
  const status = JSON.parse(readFileSync14(join29(stateDir, "status.json"), "utf8"));
@@ -23051,6 +23182,8 @@ function readControl(stateDir) {
23051
23182
  instanceId: status.instanceId,
23052
23183
  cwd: status.cwd,
23053
23184
  protocol: status.protocol,
23185
+ protocolMin: status.protocolMin,
23186
+ protocolMax: status.protocolMax,
23054
23187
  pid: status.pid,
23055
23188
  features: Array.isArray(status.features) ? status.features.filter((feature) => typeof feature === "string") : [],
23056
23189
  ...startModes ? { startModes } : {},
@@ -23071,6 +23204,7 @@ class ControlClient {
23071
23204
  ws;
23072
23205
  features = [];
23073
23206
  sessionId;
23207
+ protocol;
23074
23208
  welcomeInstanceId;
23075
23209
  get instanceId() {
23076
23210
  return this.welcomeInstanceId;
@@ -23097,8 +23231,8 @@ class ControlClient {
23097
23231
  instancePins.delete(key);
23098
23232
  };
23099
23233
  }
23100
- static connect(stateDir, hello, timeoutMs = 3000, protocol = PROTOCOL) {
23101
- if (!RECOVERY_SOURCE_PROTOCOLS.includes(protocol))
23234
+ static connect(stateDir, hello, timeoutMs = 3000, protocol) {
23235
+ if (protocol !== undefined && !RECOVERY_SOURCE_PROTOCOLS.includes(protocol))
23102
23236
  return Promise.reject(new Error(`unsupported recovery source protocol ${protocol}`));
23103
23237
  const control = readControl(stateDir);
23104
23238
  if (!control)
@@ -23107,9 +23241,13 @@ class ControlClient {
23107
23241
  if (pin && (control.instanceId !== pin.instanceId || hello.instanceId !== undefined && hello.instanceId !== pin.instanceId)) {
23108
23242
  return Promise.reject(new Error("delegated audit consumer changed; refusing a connection to its replacement"));
23109
23243
  }
23110
- if (control.protocol !== undefined && control.protocol !== protocol) {
23111
- return Promise.reject(Object.assign(new Error(`wire version mismatch: hub speaks ${control.protocol}, CLI speaks ${protocol}; stop it with its matching CLI, then upgrade and restart`), { code: 4426 }));
23112
- }
23244
+ const local = protocolWindow(protocol ?? PROTOCOL, protocol ?? PROTOCOL_MIN);
23245
+ const versioned = control.protocol !== undefined || control.protocolMin !== undefined || control.protocolMax !== undefined;
23246
+ const remote = versioned ? controlProtocolWindow(control) : undefined;
23247
+ const selected = versioned ? remote && negotiateProtocol(local, remote) : protocol ?? PROTOCOL_MIN;
23248
+ const mismatch = () => Object.assign(new Error(`wire version mismatch: hub speaks ${control.protocolMax ?? control.protocol}, CLI speaks ${protocol ?? PROTOCOL}; stop it with its matching CLI, then upgrade and restart`), { code: 4426 });
23249
+ if (selected === undefined)
23250
+ return Promise.reject(mismatch());
23113
23251
  if (hello.projectId && hello.projectId !== control.projectId || hello.instanceId && hello.instanceId !== control.instanceId || hello.projectRoot && hello.projectRoot !== control.cwd) {
23114
23252
  return Promise.reject(Object.assign(new Error("hub project or instance does not match the selected project"), { code: 4404 }));
23115
23253
  }
@@ -23151,12 +23289,15 @@ class ControlClient {
23151
23289
  client.pending.delete(msg.rid);
23152
23290
  done(msg);
23153
23291
  };
23154
- ws.onopen = () => void client.request({ t: "hello", v: protocol, token: control.token, ...hello, ...expected }, timeoutMs).then((reply) => {
23292
+ ws.onopen = () => void client.request({ t: "hello", token: control.token, ...hello, ...expected, v: selected, vMin: remote?.vMin === undefined ? selected : Math.max(local.vMin, remote.vMin) }, timeoutMs).then((reply) => {
23155
23293
  if (reply.t !== "welcome" || reply.ok === false)
23156
23294
  return refuse(new Error(reply.error ?? "hub refused handshake"));
23157
23295
  if (expected.projectId && reply.projectId !== expected.projectId || expected.instanceId && reply.instanceId !== expected.instanceId || expected.projectRoot && reply.cwd !== expected.projectRoot) {
23158
23296
  return refuse(Object.assign(new Error("connected hub has a different project or instance"), { code: 4404 }));
23159
23297
  }
23298
+ if (reply.protocol !== undefined && reply.protocol !== selected)
23299
+ return refuse(mismatch());
23300
+ client.protocol = selected;
23160
23301
  client.features = Object.freeze(Array.isArray(reply.features) ? reply.features.filter((feature) => typeof feature === "string") : []);
23161
23302
  client.welcomeInstanceId = typeof reply.instanceId === "string" && reply.instanceId ? reply.instanceId : undefined;
23162
23303
  client.sessionId = typeof reply.session === "string" && reply.session.length <= 64 ? reply.session : undefined;
@@ -23239,10 +23380,12 @@ class ControlClient {
23239
23380
 
23240
23381
  // src/hub/conductor.ts
23241
23382
  init_registry();
23383
+ init_db_schema();
23242
23384
  init_hub_tools();
23243
23385
  init_envelope();
23244
23386
 
23245
23387
  // src/hub/tasks.ts
23388
+ init_research_runner();
23246
23389
  init_queue_backpressure();
23247
23390
 
23248
23391
  // src/hub/memory-symbols.ts
@@ -23275,7 +23418,9 @@ init_git();
23275
23418
 
23276
23419
  // src/hub/tasks.ts
23277
23420
  init_spec_read();
23421
+
23278
23422
  // src/hub/schedules.ts
23423
+ init_db_schema();
23279
23424
  var MIN_EVERY_MS = 15 * 60000;
23280
23425
  var MAX_EVERY_MS = 365 * 86400000;
23281
23426
  var KEYS = new Set(["id", "every", "cron", "tz", "class", "title", "detail", "sources", "owner", "queue"]);
@@ -23289,68 +23434,10 @@ var INTAKE_MAX_ANSWER = 64 * 1024;
23289
23434
  // src/hub/tasks.ts
23290
23435
  init_sdlc_metrics();
23291
23436
  init_security_baseline();
23292
- // package.json
23293
- var package_default = {
23294
- name: "@staix/agent-hub",
23295
- version: "0.25.0",
23296
- description: "Native multi-agent hub: Claude Code, Codex, Kimi Code, Pi and local inference as peers in one project",
23297
- license: "MIT",
23298
- type: "module",
23299
- bin: {
23300
- ahub: "src/cli/main.js",
23301
- "agent-hub": "src/cli/main.js"
23302
- },
23303
- scripts: {
23304
- check: "scripts/check.sh",
23305
- build: "bun scripts/build.mjs",
23306
- test: "bun test"
23307
- },
23308
- engines: {
23309
- bun: ">=1.4.2"
23310
- },
23311
- dependencies: {
23312
- "@staix/agent-mem": "0.18.0"
23313
- },
23314
- devDependencies: {
23315
- "@modelcontextprotocol/sdk": "^1.27.1",
23316
- "@types/bun": "^1.3.0",
23317
- typescript: "^5.8.0"
23318
- },
23319
- files: [
23320
- ".claude-plugin",
23321
- "src",
23322
- "src/pet/window.jxa.js",
23323
- "src/pet/window.html",
23324
- "plugins",
23325
- "templates",
23326
- "scripts/check-docs.mjs",
23327
- "docs",
23328
- "README.md",
23329
- "LICENSE",
23330
- "CHANGELOG.md",
23331
- "THIRD_PARTY_NOTICES.md",
23332
- "LICENSES"
23333
- ],
23334
- repository: {
23335
- type: "git",
23336
- url: "git+https://github.com/STAIxBWLB/agent-hub.git"
23337
- },
23338
- homepage: "https://github.com/STAIxBWLB/agent-hub",
23339
- publishConfig: {
23340
- access: "public"
23341
- },
23342
- exports: {
23343
- "./adapter": "./src/adapters/public.ts",
23344
- "./conformance": "./src/adapters/conformance/index.ts",
23345
- "./ui-plugin": "./src/ui/plugin.ts"
23346
- }
23347
- };
23348
-
23349
- // src/version.ts
23350
- var VERSION = package_default.version;
23437
+ init_version();
23351
23438
 
23352
23439
  // src/hub/no-writes.ts
23353
- var OWNER_TOOL_EFFECTS = new Set(["hub_task_propose", "hub_task_decline", "hub_task_done", "hub_task_cancel", "hub_task_assign", "hub_task_escalate", "hub_review", "hub_checkpoint", "hub_remember", "hub_memory_correct", "hub_check_start", "hub_check_cancel", "hub_sdlc_record", "hub_plan_review", "hub_backlog_plan", "hub_backlog_pull", "hub_backlog_undo", "hub_backlog_split", "hub_backlog_return_untouched", "hub_release_new", "hub_release_configure", "hub_release_assign", "hub_release_cut", "hub_study_handoff"]);
23440
+ var OWNER_TOOL_EFFECTS = new Set(["hub_task_propose", "hub_task_decline", "hub_task_done", "hub_task_cancel", "hub_task_assign", "hub_task_escalate", "hub_review", "hub_checkpoint", "hub_remember", "hub_memory_correct", "hub_check_start", "hub_check_cancel", "hub_sdlc_record", "hub_plan_review", "hub_backlog_plan", "hub_backlog_pull", "hub_backlog_undo", "hub_backlog_split", "hub_backlog_return_untouched", "hub_release_new", "hub_release_configure", "hub_release_assign", "hub_release_cut", "hub_study_handoff", "hub_experiment_record"]);
23354
23441
 
23355
23442
  // src/hub/github-import.ts
23356
23443
  init_sdlc();
@@ -23405,7 +23492,7 @@ var LEARNING_DEFAULTS = { windowMs: 30 * 24 * 3600000, threshold: 3, maxGroups:
23405
23492
  init_deliverables();
23406
23493
 
23407
23494
  // src/hub/deliverable-files.ts
23408
- import { constants as constants8, lstatSync as lstatSync15 } from "fs";
23495
+ import { constants as constants8, lstatSync as lstatSync16 } from "fs";
23409
23496
  init_tools();
23410
23497
  init_deny();
23411
23498
  init_permission_mode();
@@ -23466,6 +23553,7 @@ init_tool_refusal();
23466
23553
  // src/hub/peer-doing.ts
23467
23554
  var TITLE_READ_MAX = 1024 * 1024;
23468
23555
  var TITLE_LINE_MAX = 64 * 1024;
23556
+
23469
23557
  // src/hub/instances.ts
23470
23558
  import { types as types4 } from "util";
23471
23559
  init_project();
@@ -32106,7 +32194,7 @@ init_registry();
32106
32194
  // src/hub/instance-execution.ts
32107
32195
  init_git();
32108
32196
  init_project();
32109
- import { lstatSync as lstatSync16 } from "fs";
32197
+ import { lstatSync as lstatSync17 } from "fs";
32110
32198
  import { join as join31, resolve as resolve19 } from "path";
32111
32199
  var refuse = (reason) => {
32112
32200
  throw new Error(`instance execution workspace refused: ${reason}`);
@@ -32149,7 +32237,7 @@ function resolveInstanceExecutionCwd(projectRoot, id, declarations, roles, adapt
32149
32237
  try {
32150
32238
  root = realPath(projectRoot);
32151
32239
  cwd = realPath(resolve19(root, declaration.worktree));
32152
- if (!lstatSync16(root).isDirectory() || !lstatSync16(cwd).isDirectory())
32240
+ if (!lstatSync17(root).isDirectory() || !lstatSync17(cwd).isDirectory())
32153
32241
  return refuse("workspace is not a directory");
32154
32242
  } catch {
32155
32243
  return refuse("workspace paths are unavailable");
@@ -32220,6 +32308,7 @@ function channelProject(cwd, env, policyRoles) {
32220
32308
  }
32221
32309
 
32222
32310
  // src/adapters/claude-channel.ts
32311
+ init_version();
32223
32312
  init_hub_tools();
32224
32313
  init_envelope();
32225
32314