@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.
- package/CHANGELOG.md +17 -0
- package/README.md +12 -6
- package/docs/agent-notes/README.md +12 -0
- package/docs/agent-notes/adapters.md +1 -1
- package/docs/agent-notes/daemon.md +7 -5
- package/docs/agent-notes/tasks.md +7 -6
- package/docs/agent-notes/tests.md +1 -0
- package/docs/dogfood.md +7 -1
- package/docs/operations.md +160 -17
- package/docs/profiles.md +1 -0
- package/docs/quickstart.md +18 -4
- package/docs/sdlc.md +3 -3
- package/docs/security.md +52 -9
- package/docs/specs/2026-09-19-agent-hub-design.md +1 -1
- package/docs/specs/2026-11-01-research-campaigns-design.md +21 -7
- package/docs/verification/2026-11-01-0.26.0.md +54 -0
- package/docs/verification/2026-11-01-0.27.0.md +49 -0
- package/docs/verified.json +28 -16
- package/package.json +1 -1
- package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
- package/plugins/agent-hub/server.js +190 -101
- package/src/adapters/channel-peer.ts +4 -2
- package/src/adapters/definitions/builtin-metadata.ts +6 -6
- package/src/adapters/definitions/qwen.ts +2 -0
- package/src/adapters/registry-types.ts +2 -0
- package/src/adapters/registry.ts +1 -0
- package/src/cli/conductor-recovery.ts +3 -2
- package/src/cli/help.ts +9 -8
- package/src/cli/identity.ts +5 -5
- package/src/cli/main.ts +68 -24
- package/src/cli/recovery-package.ts +94 -4
- package/src/cli/reset.ts +14 -4
- package/src/cli/runtime-version-warning.ts +28 -0
- package/src/cli/start-agents-run.ts +125 -0
- package/src/cli/study-output.ts +56 -0
- package/src/cli/study.ts +26 -3
- package/src/cli/task-output.ts +5 -0
- package/src/cli/upgrade-interactive.ts +4 -4
- package/src/cli/upgrade-runtime.ts +105 -57
- package/src/cli/upgrade.ts +90 -28
- package/src/hub/action-policy.ts +5 -3
- package/src/hub/autonomy-defaults.ts +32 -7
- package/src/hub/board.ts +129 -13
- package/src/hub/budget.ts +3 -4
- package/src/hub/child-process.ts +4 -3
- package/src/hub/conductor.ts +3 -4
- package/src/hub/config-apply.ts +13 -2
- package/src/hub/config-edit-host.ts +1 -0
- package/src/hub/config-tier.ts +3 -0
- package/src/hub/config-trust.ts +10 -2
- package/src/hub/control-client.ts +30 -10
- package/src/hub/daemon.ts +103 -26
- package/src/hub/db-schema.ts +143 -0
- package/src/hub/delivery-journal.ts +3 -4
- package/src/hub/events.ts +2 -1
- package/src/hub/execution-budget.ts +3 -4
- package/src/hub/folder-trigger.ts +3 -4
- package/src/hub/hub-tools.ts +7 -5
- package/src/hub/invocations.ts +3 -4
- package/src/hub/lifecycle.ts +87 -29
- package/src/hub/manager.ts +49 -33
- package/src/hub/no-writes.ts +1 -1
- package/src/hub/orca-env.ts +19 -0
- package/src/hub/project-runtime-state.ts +164 -0
- package/src/hub/project-runtime.ts +62 -0
- package/src/hub/protocol-window.ts +19 -0
- package/src/hub/recovery-store.ts +102 -12
- package/src/hub/registry.ts +5 -0
- package/src/hub/research-experiments.ts +33 -4
- package/src/hub/research-runner.ts +172 -0
- package/src/hub/restart.ts +9 -0
- package/src/hub/runtime-capture-prune.ts +415 -0
- package/src/hub/runtime-prune-health.ts +112 -0
- package/src/hub/schedules.ts +3 -4
- package/src/hub/sdlc-merge.ts +7 -0
- package/src/hub/sdlc-queue.ts +13 -1
- package/src/hub/sdlc-release-authorization.ts +11 -5
- package/src/hub/session-identity.ts +1 -1
- package/src/hub/settings.ts +4 -0
- package/src/hub/snapshots.ts +3 -4
- package/src/hub/start-agents.ts +44 -0
- package/src/hub/task-approval.ts +23 -0
- package/src/hub/tasks.ts +133 -34
- package/src/hub/usage-rollup.ts +3 -4
- package/src/pi/tool-receipts.ts +3 -4
- package/templates/presets/confirmation-matrix.json +5 -5
- 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
|
|
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
|
-
|
|
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 (!
|
|
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
|
|
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 =
|
|
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
|
|
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 && (
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
|
12006
|
+
var BODY3;
|
|
11913
12007
|
var init_research_campaign = __esm(() => {
|
|
11914
12008
|
init_packs();
|
|
11915
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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 (
|
|
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
|
|
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 =
|
|
23039
|
-
var
|
|
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
|
|
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
|
-
|
|
23111
|
-
|
|
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",
|
|
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
|
-
|
|
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
|
|
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
|
|
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 (!
|
|
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
|
|