atomix-cli 1.0.0 → 1.1.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/dist/tui.mjs CHANGED
@@ -27277,6 +27277,20 @@ var require_stack_utils = __commonJS({
27277
27277
  }
27278
27278
  });
27279
27279
 
27280
+ // src/paths.ts
27281
+ import * as os3 from "os";
27282
+ import * as path from "path";
27283
+ function getAtomixRoot() {
27284
+ const custom = process.env.ATOMIX_ROOT;
27285
+ if (custom) return path.resolve(custom);
27286
+ return path.join(os3.homedir(), ".atomix");
27287
+ }
27288
+ var init_paths = __esm({
27289
+ "src/paths.ts"() {
27290
+ "use strict";
27291
+ }
27292
+ });
27293
+
27280
27294
  // ../atomix-core/dist/util/adapter.js
27281
27295
  var require_adapter = __commonJS({
27282
27296
  "../atomix-core/dist/util/adapter.js"(exports2) {
@@ -34969,7 +34983,7 @@ var require_combineLatest = __commonJS({
34969
34983
  maybeSchedule(scheduler, function() {
34970
34984
  var length = observables.length;
34971
34985
  var values2 = new Array(length);
34972
- var active2 = length;
34986
+ var active = length;
34973
34987
  var remainingFirstValues = length;
34974
34988
  var _loop_1 = function(i2) {
34975
34989
  maybeSchedule(scheduler, function() {
@@ -34985,7 +34999,7 @@ var require_combineLatest = __commonJS({
34985
34999
  subscriber.next(valueTransform(values2.slice()));
34986
35000
  }
34987
35001
  }, function() {
34988
- if (!--active2) {
35002
+ if (!--active) {
34989
35003
  subscriber.complete();
34990
35004
  }
34991
35005
  }));
@@ -35019,20 +35033,20 @@ var require_mergeInternals = __commonJS({
35019
35033
  var OperatorSubscriber_1 = require_OperatorSubscriber();
35020
35034
  function mergeInternals(source, subscriber, project, concurrent, onBeforeNext, expand, innerSubScheduler, additionalFinalizer) {
35021
35035
  var buffer = [];
35022
- var active2 = 0;
35036
+ var active = 0;
35023
35037
  var index = 0;
35024
35038
  var isComplete = false;
35025
35039
  var checkComplete = function() {
35026
- if (isComplete && !buffer.length && !active2) {
35040
+ if (isComplete && !buffer.length && !active) {
35027
35041
  subscriber.complete();
35028
35042
  }
35029
35043
  };
35030
35044
  var outerNext = function(value) {
35031
- return active2 < concurrent ? doInnerSub(value) : buffer.push(value);
35045
+ return active < concurrent ? doInnerSub(value) : buffer.push(value);
35032
35046
  };
35033
35047
  var doInnerSub = function(value) {
35034
35048
  expand && subscriber.next(value);
35035
- active2++;
35049
+ active++;
35036
35050
  var innerComplete = false;
35037
35051
  innerFrom_1.innerFrom(project(value, index++)).subscribe(OperatorSubscriber_1.createOperatorSubscriber(subscriber, function(innerValue) {
35038
35052
  onBeforeNext === null || onBeforeNext === void 0 ? void 0 : onBeforeNext(innerValue);
@@ -35046,7 +35060,7 @@ var require_mergeInternals = __commonJS({
35046
35060
  }, void 0, function() {
35047
35061
  if (innerComplete) {
35048
35062
  try {
35049
- active2--;
35063
+ active--;
35050
35064
  var _loop_1 = function() {
35051
35065
  var bufferedValue = buffer.shift();
35052
35066
  if (innerSubScheduler) {
@@ -35057,7 +35071,7 @@ var require_mergeInternals = __commonJS({
35057
35071
  doInnerSub(bufferedValue);
35058
35072
  }
35059
35073
  };
35060
- while (buffer.length && active2 < concurrent) {
35074
+ while (buffer.length && active < concurrent) {
35061
35075
  _loop_1();
35062
35076
  }
35063
35077
  checkComplete();
@@ -42241,7 +42255,7 @@ var require_shell = __commonJS({
42241
42255
  var os9 = __importStar(__require("os"));
42242
42256
  var crypto3 = __importStar(__require("crypto"));
42243
42257
  var log_1 = require_log();
42244
- var TEMPFILE_PREFIX = os9.tmpdir() + `sema-`;
42258
+ var TEMPFILE_PREFIX = (0, path_1.join)(os9.tmpdir(), "sema-");
42245
42259
  var DEFAULT_TIMEOUT = 30 * 60 * 1e3;
42246
42260
  var SIGTERM_CODE = 143;
42247
42261
  var FILE_SUFFIXES = {
@@ -51127,9 +51141,9 @@ var require_agentsManager = __commonJS({
51127
51141
  }
51128
51142
  const userNext = /* @__PURE__ */ new Map();
51129
51143
  await this.loadAgentsFromDir(userNext, this.userAgentsDir, "user");
51130
- const projectDir2 = opts?.projectAgentsDir !== void 0 ? path15.resolve(opts.projectAgentsDir) : this.resolveProjectAgentsDir();
51144
+ const projectDir = opts?.projectAgentsDir !== void 0 ? path15.resolve(opts.projectAgentsDir) : this.resolveProjectAgentsDir();
51131
51145
  const projectNext = /* @__PURE__ */ new Map();
51132
- await this.loadAgentsFromDir(projectNext, projectDir2, "project");
51146
+ await this.loadAgentsFromDir(projectNext, projectDir, "project");
51133
51147
  for (const name of userNext.keys()) {
51134
51148
  if (managedNext.has(name) || builtinNext.has(name))
51135
51149
  (0, log_1.logWarn)(`Agent [${name}] \u88AB user \u7EA7\u914D\u7F6E\u8986\u76D6`);
@@ -51142,11 +51156,11 @@ var require_agentsManager = __commonJS({
51142
51156
  this.builtinLayer = builtinNext;
51143
51157
  this.managedLayers.set(key, managedNext);
51144
51158
  this.userLayer = userNext;
51145
- this.projectLayers.set(projectDir2, projectNext);
51159
+ this.projectLayers.set(projectDir, projectNext);
51146
51160
  this.lastInitKey = key;
51147
- this.lastInitProjectKey = projectDir2;
51161
+ this.lastInitProjectKey = projectDir;
51148
51162
  this.invalidateCache();
51149
- const agentNames = Array.from(this.mergedFor(key, projectDir2).keys()).join(", ");
51163
+ const agentNames = Array.from(this.mergedFor(key, projectDir).keys()).join(", ");
51150
51164
  (0, log_1.logInfo)(`\u52A0\u8F7D Agents \u914D\u7F6E: ${agentNames}`);
51151
51165
  }
51152
51166
  /** 按 managed 键 + project 键合并四层(带缓存);spread 顺序即覆盖顺序 */
@@ -51385,20 +51399,20 @@ var require_agentsManager = __commonJS({
51385
51399
  if (this.currentMerged(view).has(agentConf.name)) {
51386
51400
  (0, log_1.logWarn)(`Agent [${agentConf.name}] \u88AB\u8986\u76D6`);
51387
51401
  }
51388
- const projectDir2 = view?.projectAgentsDir !== void 0 ? path15.resolve(view.projectAgentsDir) : this.resolveProjectAgentsDir();
51402
+ const projectDir = view?.projectAgentsDir !== void 0 ? path15.resolve(view.projectAgentsDir) : this.resolveProjectAgentsDir();
51389
51403
  if (agentConf.locate === "user") {
51390
51404
  this.userLayer.set(agentConf.name, { ...agentConf });
51391
51405
  } else {
51392
- let layer = this.projectLayers.get(projectDir2);
51406
+ let layer = this.projectLayers.get(projectDir);
51393
51407
  if (!layer) {
51394
51408
  layer = /* @__PURE__ */ new Map();
51395
- this.projectLayers.set(projectDir2, layer);
51409
+ this.projectLayers.set(projectDir, layer);
51396
51410
  }
51397
51411
  layer.set(agentConf.name, { ...agentConf });
51398
51412
  }
51399
51413
  this.invalidateCache();
51400
51414
  (0, log_1.logInfo)(`\u6DFB\u52A0 Agent \u914D\u7F6E: ${agentConf.name}`);
51401
- const saved = await this.saveAgentToFile(agentConf, projectDir2);
51415
+ const saved = await this.saveAgentToFile(agentConf, projectDir);
51402
51416
  if (!saved) {
51403
51417
  (0, log_1.logWarn)(`Agent \u914D\u7F6E\u5DF2\u6DFB\u52A0\u5230\u5185\u5B58\uFF0C\u4F46\u4FDD\u5B58\u5230\u6587\u4EF6\u5931\u8D25: ${agentConf.name}`);
51404
51418
  }
@@ -51870,9 +51884,15 @@ var require_Bash = __commonJS({
51870
51884
  "--eof",
51871
51885
  "-a",
51872
51886
  "--arg-file"
51873
- ])
51874
- };
51875
- var STATEMENT_KEYWORDS = /* @__PURE__ */ new Set([
51887
+ ]),
51888
+ // zsh precommand modifier(macOS 默认 $SHELL 是 zsh,PersistentShell 直接用它):
51889
+ // `repeat N cmd`、`noglob cmd`、`nocorrect cmd`、`- cmd`(argv[0] 加 `-`)都会执行后面的命令
51890
+ repeat: W([], [], 1),
51891
+ noglob: W([], []),
51892
+ nocorrect: W([], []),
51893
+ "-": W([], [])
51894
+ };
51895
+ var CMD_KEYWORDS = /* @__PURE__ */ new Set([
51876
51896
  "!",
51877
51897
  "{",
51878
51898
  "}",
@@ -51885,13 +51905,9 @@ var require_Bash = __commonJS({
51885
51905
  "until",
51886
51906
  "do",
51887
51907
  "done",
51888
- "case",
51889
51908
  "esac",
51890
- "in",
51891
- "for",
51892
- "select",
51893
- "function",
51894
- "coproc"
51909
+ "always",
51910
+ "end"
51895
51911
  ]);
51896
51912
  var REDIRECT_OPS = /* @__PURE__ */ new Set([">", ">>", "<", ">&", "<&", "<<<", ">|"]);
51897
51913
  var LIST_SEPARATORS = /* @__PURE__ */ new Set(["&&", "||", ";", ";;", "|", "|&", "&"]);
@@ -51901,6 +51917,8 @@ var require_Bash = __commonJS({
51901
51917
  var isClobberPipe = (entries, k) => isOp(entries[k], "|") && isOp(entries[k - 1], ">");
51902
51918
  function analyzeCommandSegments(command) {
51903
51919
  const out = [];
51920
+ let state = "cmd";
51921
+ let caseDepth = 0;
51904
51922
  for (const line of command.split(/\r\n|\n|\r/)) {
51905
51923
  if (!line.trim())
51906
51924
  continue;
@@ -51911,32 +51929,226 @@ var require_Bash = __commonJS({
51911
51929
  out.push({ error: `command could not be parsed: ${line}` });
51912
51930
  continue;
51913
51931
  }
51914
- const segments = [];
51932
+ if (state !== "patterns")
51933
+ state = "cmd";
51934
+ let pending = null;
51935
+ let parenList = false;
51936
+ let patternWord = false;
51915
51937
  let cur = [];
51916
- for (let k = 0; k < entries.length; k++) {
51938
+ let failed = false;
51939
+ const flush = () => {
51940
+ if (cur.length) {
51941
+ const r = unwrapEntries(cur, line);
51942
+ if (r !== null)
51943
+ out.push(r);
51944
+ }
51945
+ cur = [];
51946
+ };
51947
+ const fail = (msg) => {
51948
+ out.push({ error: msg });
51949
+ failed = true;
51950
+ };
51951
+ for (let k = 0; k < entries.length && !failed; k++) {
51917
51952
  const e = entries[k];
51918
- let boundary;
51919
- if (typeof e === "string")
51920
- boundary = STATEMENT_KEYWORDS.has(e);
51921
- else if ("op" in e)
51922
- boundary = e.op === "(" || e.op === ")" || LIST_SEPARATORS.has(e.op) && !isAmpRedirect(entries, k) && !isClobberPipe(entries, k);
51923
- else
51924
- boundary = false;
51925
- if (boundary) {
51926
- if (cur.length)
51927
- segments.push(cur);
51928
- cur = [];
51953
+ if (typeof e === "object" && "comment" in e)
51954
+ break;
51955
+ const kw = typeof e === "string" ? e : null;
51956
+ const isWord = kw !== null || isOp(e, "glob");
51957
+ if (isWord) {
51958
+ switch (state) {
51959
+ case "cmd":
51960
+ if (kw !== null && CMD_KEYWORDS.has(kw)) {
51961
+ flush();
51962
+ if (kw === "esac")
51963
+ caseDepth = Math.max(0, caseDepth - 1);
51964
+ continue;
51965
+ }
51966
+ if (kw === "for" || kw === "select" || kw === "foreach") {
51967
+ flush();
51968
+ pending = "for";
51969
+ state = "name";
51970
+ continue;
51971
+ }
51972
+ if (kw === "case") {
51973
+ flush();
51974
+ pending = "case";
51975
+ state = "name";
51976
+ continue;
51977
+ }
51978
+ if (kw === "function") {
51979
+ flush();
51980
+ pending = "function";
51981
+ state = "name";
51982
+ continue;
51983
+ }
51984
+ if (kw === "coproc") {
51985
+ flush();
51986
+ if (typeof entries[k + 1] === "string" && (entries[k + 2] === "{" || isOp(entries[k + 2], "(")))
51987
+ k++;
51988
+ continue;
51989
+ }
51990
+ if (kw === "[[") {
51991
+ flush();
51992
+ state = "cond";
51993
+ continue;
51994
+ }
51995
+ cur.push(e);
51996
+ if (kw !== null && (ENV_ASSIGN_RE.test(kw) || kw.startsWith("-") || /^\d+$/.test(kw) && isRedirectOp(entries[k + 1])))
51997
+ continue;
51998
+ if (kw !== null && WRAPPERS[kw]) {
51999
+ const words2 = [kw];
52000
+ for (let j = k + 1; j < entries.length; j++) {
52001
+ const w = entries[j];
52002
+ if (typeof w === "string")
52003
+ words2.push(w);
52004
+ else if (isOp(w, "glob"))
52005
+ words2.push(w.pattern);
52006
+ else
52007
+ break;
52008
+ }
52009
+ const r = consumeWrapper(words2, 0);
52010
+ if ("error" in r) {
52011
+ fail(r.error);
52012
+ continue;
52013
+ }
52014
+ const n = Math.min(r.next, words2.length);
52015
+ for (let m = 1; m < n; m++)
52016
+ cur.push(entries[k + m]);
52017
+ k += n - 1;
52018
+ if (r.query)
52019
+ state = "args";
52020
+ continue;
52021
+ }
52022
+ state = "args";
52023
+ continue;
52024
+ case "args":
52025
+ if (kw === "}") {
52026
+ flush();
52027
+ state = "cmd";
52028
+ continue;
52029
+ }
52030
+ cur.push(e);
52031
+ continue;
52032
+ case "name":
52033
+ state = pending === "function" ? "cmd" : "afterName";
52034
+ continue;
52035
+ case "afterName":
52036
+ if (kw === "in") {
52037
+ if (pending === "case") {
52038
+ caseDepth++;
52039
+ state = "patterns";
52040
+ patternWord = false;
52041
+ } else
52042
+ state = "wordList";
52043
+ continue;
52044
+ }
52045
+ if (kw === "do" && pending === "for") {
52046
+ state = "cmd";
52047
+ continue;
52048
+ }
52049
+ state = "cmd";
52050
+ k--;
52051
+ continue;
52052
+ case "wordList":
52053
+ continue;
52054
+ // 字面量列表,不是命令
52055
+ case "patterns":
52056
+ if (kw === "esac") {
52057
+ caseDepth = Math.max(0, caseDepth - 1);
52058
+ state = "cmd";
52059
+ continue;
52060
+ }
52061
+ if (patternWord) {
52062
+ fail(`case pattern cannot be analyzed statically in: ${line}`);
52063
+ continue;
52064
+ }
52065
+ patternWord = true;
52066
+ continue;
52067
+ case "cond":
52068
+ if (kw === "]]")
52069
+ state = "cmd";
52070
+ continue;
52071
+ }
52072
+ }
52073
+ const op = e.op;
52074
+ if (state === "cond") {
52075
+ if (LIST_SEPARATORS.has(op) && op !== "&&" && op !== "||")
52076
+ state = "cmd";
52077
+ continue;
52078
+ }
52079
+ if ((state === "name" || state === "afterName") && !(state === "afterName" && op === "(")) {
52080
+ state = "cmd";
52081
+ k--;
52082
+ continue;
52083
+ }
52084
+ if (REDIRECT_OPS.has(op) || isAmpRedirect(entries, k)) {
52085
+ const skip = state === "wordList" || state === "patterns";
52086
+ const take2 = (idx) => {
52087
+ if (!skip)
52088
+ cur.push(entries[idx]);
52089
+ };
52090
+ take2(k);
52091
+ if (op === "&")
52092
+ take2(++k);
52093
+ while (k + 1 < entries.length && (isRedirectOp(entries[k + 1]) || isClobberPipe(entries, k + 1)))
52094
+ take2(++k);
52095
+ if (k + 1 < entries.length && typeof entries[k + 1] === "string")
52096
+ take2(++k);
52097
+ continue;
52098
+ }
52099
+ if (op === "(") {
52100
+ if (state === "afterName") {
52101
+ state = "wordList";
52102
+ parenList = true;
52103
+ continue;
52104
+ }
52105
+ if (state === "patterns") {
52106
+ patternWord = false;
52107
+ continue;
52108
+ }
52109
+ flush();
52110
+ state = "cmd";
51929
52111
  continue;
51930
52112
  }
52113
+ if (op === ")") {
52114
+ if (state === "wordList" && parenList) {
52115
+ parenList = false;
52116
+ state = "cmd";
52117
+ continue;
52118
+ }
52119
+ if (state === "patterns") {
52120
+ state = "cmd";
52121
+ continue;
52122
+ }
52123
+ flush();
52124
+ state = "cmd";
52125
+ continue;
52126
+ }
52127
+ if (op === "|" && state === "patterns") {
52128
+ patternWord = false;
52129
+ continue;
52130
+ }
52131
+ if (LIST_SEPARATORS.has(op) && !isClobberPipe(entries, k)) {
52132
+ flush();
52133
+ if (op === ";;" && caseDepth > 0) {
52134
+ state = "patterns";
52135
+ patternWord = false;
52136
+ } else
52137
+ state = "cmd";
52138
+ parenList = false;
52139
+ continue;
52140
+ }
52141
+ if (state === "wordList" || state === "patterns")
52142
+ continue;
51931
52143
  cur.push(e);
51932
52144
  }
51933
- if (cur.length)
51934
- segments.push(cur);
51935
- for (const seg of segments) {
51936
- const r = unwrapEntries(seg, line);
51937
- if (r !== null)
51938
- out.push(r);
52145
+ if (failed)
52146
+ continue;
52147
+ if (state === "cond") {
52148
+ fail(`unterminated [[ in: ${line}`);
52149
+ continue;
51939
52150
  }
52151
+ flush();
51940
52152
  }
51941
52153
  return out;
51942
52154
  }
@@ -51977,53 +52189,62 @@ var require_Bash = __commonJS({
51977
52189
  i++;
51978
52190
  continue;
51979
52191
  }
51980
- const spec = WRAPPERS[t];
51981
- if (!spec)
52192
+ if (!WRAPPERS[t])
51982
52193
  break;
51983
- if (t === "command") {
51984
- const rest2 = tokens.slice(i + 1);
51985
- const optEnd = rest2.findIndex((x) => !x.startsWith("-") || x === "--");
51986
- const opts = optEnd < 0 ? rest2 : rest2.slice(0, optEnd);
51987
- if (opts.some((o) => /^-[pvV]*[vV][pvV]*$/.test(o)))
51988
- return { baseCmd: "command", args: rest2 };
51989
- }
51990
- i++;
51991
- while (i < tokens.length && tokens[i].startsWith("-")) {
51992
- const opt = tokens[i];
51993
- if (opt === "--") {
51994
- i++;
51995
- break;
51996
- }
51997
- const eq2 = opt.startsWith("--") ? opt.indexOf("=") : -1;
51998
- const name = eq2 > 0 ? opt.slice(0, eq2) : opt;
51999
- if (eq2 > 0 && (spec.flags.has(name) || spec.valueFlags.has(name))) {
52000
- i++;
52001
- continue;
52002
- }
52003
- if (spec.flags.has(opt)) {
52004
- i++;
52005
- continue;
52006
- }
52007
- if (spec.valueFlags.has(opt)) {
52008
- i += 2;
52009
- continue;
52010
- }
52011
- if (/^-[A-Za-z]/.test(opt) && opt.length > 2 && spec.valueFlags.has(opt.slice(0, 2))) {
52012
- i++;
52013
- continue;
52014
- }
52015
- if (t === "nice" && /^-\d+$/.test(opt)) {
52016
- i++;
52017
- continue;
52018
- }
52019
- return { error: `option '${opt}' of wrapper '${t}' cannot be analyzed statically` };
52020
- }
52021
- i += spec.positional ?? 0;
52194
+ const r = consumeWrapper(tokens, i);
52195
+ if ("error" in r)
52196
+ return r;
52197
+ if (r.query)
52198
+ return { baseCmd: "command", args: tokens.slice(i + 1) };
52199
+ i = r.next;
52022
52200
  }
52023
52201
  if (i >= tokens.length)
52024
52202
  return { baseCmd: tokens[tokens.length - 1], args: [] };
52025
52203
  return { baseCmd: tokens[i], args: tokens.slice(i + 1) };
52026
52204
  }
52205
+ function consumeWrapper(tokens, i) {
52206
+ const t = tokens[i];
52207
+ const spec = WRAPPERS[t];
52208
+ if (t === "command") {
52209
+ const rest2 = tokens.slice(i + 1);
52210
+ const optEnd = rest2.findIndex((x) => !x.startsWith("-") || x === "--");
52211
+ const opts = optEnd < 0 ? rest2 : rest2.slice(0, optEnd);
52212
+ if (opts.some((o) => /^-[pvV]*[vV][pvV]*$/.test(o)))
52213
+ return { next: tokens.length, query: true };
52214
+ }
52215
+ i++;
52216
+ while (i < tokens.length && tokens[i].startsWith("-")) {
52217
+ const opt = tokens[i];
52218
+ if (opt === "--") {
52219
+ i++;
52220
+ break;
52221
+ }
52222
+ const eq2 = opt.startsWith("--") ? opt.indexOf("=") : -1;
52223
+ const name = eq2 > 0 ? opt.slice(0, eq2) : opt;
52224
+ if (eq2 > 0 && (spec.flags.has(name) || spec.valueFlags.has(name))) {
52225
+ i++;
52226
+ continue;
52227
+ }
52228
+ if (spec.flags.has(opt)) {
52229
+ i++;
52230
+ continue;
52231
+ }
52232
+ if (spec.valueFlags.has(opt)) {
52233
+ i += 2;
52234
+ continue;
52235
+ }
52236
+ if (/^-[A-Za-z]/.test(opt) && opt.length > 2 && spec.valueFlags.has(opt.slice(0, 2))) {
52237
+ i++;
52238
+ continue;
52239
+ }
52240
+ if (t === "nice" && /^-\d+$/.test(opt)) {
52241
+ i++;
52242
+ continue;
52243
+ }
52244
+ return { error: `option '${opt}' of wrapper '${t}' cannot be analyzed statically` };
52245
+ }
52246
+ return { next: i + (spec.positional ?? 0) };
52247
+ }
52027
52248
  function resolveCdTarget(args) {
52028
52249
  const positional = [];
52029
52250
  let optionsDone = false;
@@ -64769,7 +64990,7 @@ var init_iteratee = __esm({
64769
64990
  });
64770
64991
 
64771
64992
  // ../atomix-core/node_modules/lodash-es/join.js
64772
- function join(array, separator) {
64993
+ function join2(array, separator) {
64773
64994
  return array == null ? "" : nativeJoin.call(array, separator);
64774
64995
  }
64775
64996
  var arrayProto2, nativeJoin, join_default;
@@ -64777,7 +64998,7 @@ var init_join = __esm({
64777
64998
  "../atomix-core/node_modules/lodash-es/join.js"() {
64778
64999
  arrayProto2 = Array.prototype;
64779
65000
  nativeJoin = arrayProto2.join;
64780
- join_default = join;
65001
+ join_default = join2;
64781
65002
  }
64782
65003
  });
64783
65004
 
@@ -74274,15 +74495,30 @@ var require_skillRegistry = __commonJS({
74274
74495
  "../atomix-core/dist/services/skill/skillRegistry.js"(exports2) {
74275
74496
  "use strict";
74276
74497
  Object.defineProperty(exports2, "__esModule", { value: true });
74498
+ exports2.skillRegistryKey = skillRegistryKey;
74277
74499
  exports2.initializeSkillRegistry = initializeSkillRegistry;
74278
74500
  exports2.getSkillRegistry = getSkillRegistry;
74279
74501
  exports2.findSkill = findSkill;
74280
74502
  exports2.getSkillsInfo = getSkillsInfo;
74281
74503
  exports2.getSkillsSummary = getSkillsSummary;
74504
+ exports2.invalidateSkillCache = invalidateSkillCache;
74282
74505
  exports2.clearSkillRegistry = clearSkillRegistry;
74283
74506
  var skillLoader_1 = require_skillLoader();
74284
74507
  var log_1 = require_log();
74285
- var globalRegistry = null;
74508
+ var EngineContext_1 = require_EngineContext();
74509
+ var registries = /* @__PURE__ */ new Map();
74510
+ var lastKey = null;
74511
+ function skillRegistryKey(workingDir, extraDirs) {
74512
+ return workingDir + "\0" + (extraDirs ?? []).map((e) => `${e.locate}:${e.dir}`).join("\0");
74513
+ }
74514
+ function viewFromContext() {
74515
+ const store = (0, EngineContext_1.getEngineStore)();
74516
+ const cfg = store?.coreConfig;
74517
+ if (!store || !cfg)
74518
+ return null;
74519
+ const workingDir = cfg.agentDataDir || cfg.workingDir || store.agentDataDir || store.workingDir || process.cwd();
74520
+ return { workingDir, extraDirs: cfg.skillsExtraDirs, disabledNames: cfg.skillsDisabledNames };
74521
+ }
74286
74522
  function initializeSkillRegistry(workingDir, extraDirs) {
74287
74523
  const registry = /* @__PURE__ */ new Map();
74288
74524
  const skills = (0, skillLoader_1.loadAllSkills)(workingDir, extraDirs);
@@ -74294,21 +74530,44 @@ var require_skillRegistry = __commonJS({
74294
74530
  }
74295
74531
  registry.set(name, skill);
74296
74532
  }
74297
- globalRegistry = registry;
74533
+ const key = skillRegistryKey(workingDir, extraDirs);
74534
+ registries.set(key, registry);
74535
+ lastKey = key;
74298
74536
  return registry;
74299
74537
  }
74300
- function getSkillRegistry() {
74301
- if (!globalRegistry) {
74538
+ function resolve9(view) {
74539
+ const v = view ?? viewFromContext();
74540
+ if (v) {
74541
+ const key = skillRegistryKey(v.workingDir, v.extraDirs);
74542
+ let registry = registries.get(key);
74543
+ if (!registry) {
74544
+ registry = initializeSkillRegistry(v.workingDir, v.extraDirs);
74545
+ }
74546
+ return { registry, disabled: new Set(v.disabledNames ?? []) };
74547
+ }
74548
+ if (!lastKey) {
74302
74549
  throw new Error("Skill registry not initialized. Call initializeSkillRegistry() first.");
74303
74550
  }
74304
- return globalRegistry;
74305
- }
74306
- function findSkill(name) {
74307
- const registry = getSkillRegistry();
74551
+ return { registry: registries.get(lastKey), disabled: /* @__PURE__ */ new Set() };
74552
+ }
74553
+ function getSkillRegistry(view) {
74554
+ const { registry, disabled } = resolve9(view);
74555
+ if (disabled.size === 0)
74556
+ return registry;
74557
+ const filtered = /* @__PURE__ */ new Map();
74558
+ for (const [name, skill] of registry)
74559
+ if (!disabled.has(name))
74560
+ filtered.set(name, skill);
74561
+ return filtered;
74562
+ }
74563
+ function findSkill(name, view) {
74564
+ const { registry, disabled } = resolve9(view);
74565
+ if (disabled.has(name))
74566
+ return void 0;
74308
74567
  return registry.get(name);
74309
74568
  }
74310
- function getSkillsInfo() {
74311
- const registry = getSkillRegistry();
74569
+ function getSkillsInfo(view, opts) {
74570
+ const registry = opts?.includeDisabled ? resolve9(view).registry : getSkillRegistry(view);
74312
74571
  const skillsInfo = [];
74313
74572
  for (const [name, skill] of registry.entries()) {
74314
74573
  skillsInfo.push({
@@ -74320,8 +74579,8 @@ var require_skillRegistry = __commonJS({
74320
74579
  }
74321
74580
  return skillsInfo;
74322
74581
  }
74323
- function getSkillsSummary() {
74324
- const registry = getSkillRegistry();
74582
+ function getSkillsSummary(view) {
74583
+ const registry = getSkillRegistry(view);
74325
74584
  if (registry.size === 0) {
74326
74585
  return "";
74327
74586
  }
@@ -74335,10 +74594,14 @@ var require_skillRegistry = __commonJS({
74335
74594
  lines.push("When a task requires specific domain knowledge or workflow, use the Skill tool to activate the relevant skill.");
74336
74595
  return lines.join("\n");
74337
74596
  }
74338
- function clearSkillRegistry() {
74339
- globalRegistry = null;
74597
+ function invalidateSkillCache() {
74340
74598
  skillLoader_1.loadAllSkills.cache.clear?.();
74341
74599
  }
74600
+ function clearSkillRegistry() {
74601
+ registries.clear();
74602
+ lastKey = null;
74603
+ invalidateSkillCache();
74604
+ }
74342
74605
  }
74343
74606
  });
74344
74607
 
@@ -135411,7 +135674,7 @@ var require_session = __commonJS({
135411
135674
  exports2.parseSessionIdFromHistoryPath = parseSessionIdFromHistoryPath;
135412
135675
  exports2.generateSessionId = generateSessionId;
135413
135676
  exports2.initializeSessionId = initializeSessionId;
135414
- exports2.validateSessionId = validateSessionId;
135677
+ exports2.validateSessionId = validateSessionId2;
135415
135678
  exports2.generateHistoryPath = generateHistoryPath;
135416
135679
  var crypto3 = __importStar(__require("crypto"));
135417
135680
  var path15 = __importStar(__require("path"));
@@ -135446,7 +135709,7 @@ var require_session = __commonJS({
135446
135709
  }
135447
135710
  return generateSessionId();
135448
135711
  }
135449
- function validateSessionId(sessionId) {
135712
+ function validateSessionId2(sessionId) {
135450
135713
  const shortIdRegex = /^[0-9a-f]{8}$/i;
135451
135714
  return shortIdRegex.test(sessionId);
135452
135715
  }
@@ -136429,7 +136692,7 @@ var require_SemaEngine = __commonJS({
136429
136692
  */
136430
136693
  async initializePlugins(workingDir, extraDirs) {
136431
136694
  try {
136432
- (0, skillRegistry_1.clearSkillRegistry)();
136695
+ (0, skillRegistry_1.invalidateSkillCache)();
136433
136696
  (0, skillRegistry_1.initializeSkillRegistry)(workingDir || process.cwd(), extraDirs);
136434
136697
  (0, log_1.logDebug)("Skill registry initialized successfully");
136435
136698
  } catch (error) {
@@ -136609,6 +136872,11 @@ var require_SemaSession = __commonJS({
136609
136872
  this.engine = new SemaEngine_1.SemaEngine(instanceId, resolvedConfig, this.instanceMCPManager, kernel);
136610
136873
  if (resolvedConfig.skipMCPInit) {
136611
136874
  this.configPromise = (0, ConfManager_1.getConfManager)().registerProjectConfig(resolvedConfig);
136875
+ } else if (resolvedConfig.multiSession) {
136876
+ (0, log_1.setLogLevel)(resolvedConfig.logLevel || "info");
136877
+ this.configPromise = (0, ConfManager_1.getConfManager)().registerProjectConfig(resolvedConfig).then(async () => {
136878
+ await this.instanceMCPManager.init();
136879
+ });
136612
136880
  } else {
136613
136881
  this.configPromise = (0, ConfManager_1.getConfManager)().setCoreConfig(resolvedConfig);
136614
136882
  this.configPromise = this.configPromise.then(async () => {
@@ -136675,26 +136943,34 @@ var require_SemaSession = __commonJS({
136675
136943
  return this.engine.coreConfig;
136676
136944
  }
136677
136945
  // ==================== Skill 热重载(session 触发)====================
136946
+ /** 本 session 的 skill 视图(同 agentsView:显式上下文,ALS 外可读)。 */
136947
+ skillsView() {
136948
+ const config = this.engine["initialConfig"];
136949
+ return {
136950
+ workingDir: config.agentDataDir || config.workingDir || (0, cwd_1.getCwd)(),
136951
+ extraDirs: config.skillsExtraDirs,
136952
+ disabledNames: config.skillsDisabledNames ?? []
136953
+ };
136954
+ }
136678
136955
  /**
136679
136956
  * 热重载 Skill 注册表(不重建 session/历史)。
136680
136957
  *
136681
- * Stage A wrinkle:方法依赖本 session 的 workingDir / skillsExtraDirs,但内部
136682
- * clearSkillRegistry + initializeSkillRegistry mutate 的是【全局】registry,会影响所有
136683
- * session。这是 D6「project 层 vs 全局 registry」矛盾的具象,Stage A 保持现状行为
136684
- * (全局重扫),Stage D 做 global/project 分层 + mtime 缓存时彻底解决。
136958
+ * 注册表按供给键(workingDir + skillsExtraDirs)隔离,只重建本 session 键;屏蔽名单写入
136959
+ * initialConfig.skillsDisabledNames 由读取端过滤(session-api-v1 §3.1,语义同 reloadAgents)。
136685
136960
  *
136686
- * @param disabledNames 需要从注册表中移除的 skill 名称集合。
136961
+ * @param disabledNames 按名屏蔽的 skill 集合;undefined = 只重扫,屏蔽名单不变。
136687
136962
  */
136688
136963
  reloadSkills(disabledNames) {
136689
136964
  const config = this.engine["initialConfig"];
136690
- const workingDir = config.agentDataDir || config.workingDir || (0, cwd_1.getCwd)();
136691
- (0, skillRegistry_1.clearSkillRegistry)();
136692
- const registry = (0, skillRegistry_1.initializeSkillRegistry)(workingDir, config.skillsExtraDirs);
136693
- if (disabledNames?.size) {
136694
- for (const name of disabledNames) {
136695
- registry.delete(name);
136696
- }
136697
- }
136965
+ if (disabledNames !== void 0)
136966
+ config.skillsDisabledNames = [...disabledNames];
136967
+ const view = this.skillsView();
136968
+ (0, skillRegistry_1.invalidateSkillCache)();
136969
+ (0, skillRegistry_1.initializeSkillRegistry)(view.workingDir, view.extraDirs);
136970
+ }
136971
+ /** 本 session 视角的 skills 列表;includeDisabled 取供给全集(harness whitelist 求补用)。 */
136972
+ getSkillsInfo(opts) {
136973
+ return (0, skillRegistry_1.getSkillsInfo)(this.skillsView(), opts);
136698
136974
  }
136699
136975
  // ==================== Agents(session 视角,显式上下文)====================
136700
136976
  /**
@@ -137287,7 +137563,7 @@ var require_AtomixCore = __commonJS({
137287
137563
  this.getMCPServerConfigs = () => this.session.getMCPServerConfigs();
137288
137564
  this.connectMCPServer = (name) => this.session.connectMCPServer(name);
137289
137565
  this.updateMCPUseTools = (name, toolNames) => this.session.updateMCPUseTools(name, toolNames);
137290
- this.getSkillsInfo = () => this.kernel.skills.getInfo();
137566
+ this.getSkillsInfo = (opts) => this.session.getSkillsInfo(opts);
137291
137567
  this.getAgentsInfo = () => this.session.getAgentsInfo();
137292
137568
  this.addAgentConf = (agentConf) => this.session.addAgentConf(agentConf);
137293
137569
  this.getCustomCommands = () => this.session.getCustomCommands();
@@ -144002,20 +144278,6 @@ var require_dist4 = __commonJS({
144002
144278
  }
144003
144279
  });
144004
144280
 
144005
- // src/paths.ts
144006
- import * as os3 from "os";
144007
- import * as path from "path";
144008
- function getAtomixRoot() {
144009
- const custom = process.env.ATOMIX_ROOT;
144010
- if (custom) return path.resolve(custom);
144011
- return path.join(os3.homedir(), ".atomix");
144012
- }
144013
- var init_paths = __esm({
144014
- "src/paths.ts"() {
144015
- "use strict";
144016
- }
144017
- });
144018
-
144019
144281
  // src/theme.ts
144020
144282
  function getThemeName() {
144021
144283
  return activeThemeName;
@@ -151485,8 +151747,8 @@ function enableAgent(name) {
151485
151747
  async function applyDisabledAgents(core) {
151486
151748
  await core.reloadAgents(/* @__PURE__ */ new Set());
151487
151749
  const allNames = core.getAgentsInfo().map((a) => a.name);
151488
- recordAgentUniverse(allNames);
151489
- const disabled = /* @__PURE__ */ new Set([...readDisabledAgents(), ...harnessDisabledAgents(allNames)]);
151750
+ recordAgentUniverse(core, allNames);
151751
+ const disabled = /* @__PURE__ */ new Set([...readDisabledAgents(), ...harnessDisabledAgents(core, allNames)]);
151490
151752
  await core.reloadAgents(disabled);
151491
151753
  }
151492
151754
  async function agentsCommand(core, args) {
@@ -151535,6 +151797,14 @@ var init_agents = __esm({
151535
151797
  // src/harness.ts
151536
151798
  import * as fs3 from "fs";
151537
151799
  import * as path3 from "path";
151800
+ function runtimeOf(core) {
151801
+ return runtimes.get(core) ?? null;
151802
+ }
151803
+ function requireRuntime(core) {
151804
+ const rt = runtimeOf(core);
151805
+ if (!rt) throw new Error("harness \u672A\u521D\u59CB\u5316(initHarness \u672A\u8C03\u7528)");
151806
+ return rt;
151807
+ }
151538
151808
  function overrideOf(activeValue, baseValue) {
151539
151809
  if (baseValue === void 0 || activeValue === void 0) return null;
151540
151810
  const baseOn = baseValue !== null;
@@ -151547,33 +151817,40 @@ function personaOverrideOf(activeValue, baseValue) {
151547
151817
  if (activeValue && baseValue && activeValue !== baseValue) return "swap";
151548
151818
  return null;
151549
151819
  }
151550
- function harnessMemoryOverride() {
151551
- return overrideOf(activeMemoryFiles, baseline.memoryFiles);
151820
+ function harnessMemoryOverride(core) {
151821
+ const rt = runtimeOf(core);
151822
+ return rt ? overrideOf(rt.activeMemoryFiles, rt.baseline.memoryFiles) : null;
151552
151823
  }
151553
- function harnessPersonaOverride() {
151554
- return personaOverrideOf(activePersonaFile, baseline.personaFile);
151824
+ function harnessPersonaOverride(core) {
151825
+ const rt = runtimeOf(core);
151826
+ return rt ? personaOverrideOf(rt.activePersonaFile, rt.baseline.personaFile) : null;
151555
151827
  }
151556
- function getActivePersonaFile() {
151557
- return activePersonaFile;
151828
+ function getActivePersonaFile(core) {
151829
+ return runtimeOf(core)?.activePersonaFile;
151558
151830
  }
151559
- function getActiveHarnessName() {
151560
- return active?.name ?? BASE_HARNESS;
151831
+ function getActiveHarnessName(core) {
151832
+ return runtimeOf(core)?.active?.name ?? BASE_HARNESS;
151561
151833
  }
151562
- function recordSkillUniverse(names) {
151563
- fullSkillNames = names.slice();
151834
+ function isHarnessOverridden(core) {
151835
+ return runtimeOf(core)?.overridden ?? false;
151564
151836
  }
151565
- function recordAgentUniverse(names) {
151566
- fullAgentNames = names.slice();
151837
+ function recordSkillUniverse(core, names) {
151838
+ const rt = runtimeOf(core);
151839
+ if (rt) rt.fullSkillNames = names.slice();
151840
+ }
151841
+ function recordAgentUniverse(core, names) {
151842
+ const rt = runtimeOf(core);
151843
+ if (rt) rt.fullAgentNames = names.slice();
151567
151844
  }
151568
151845
  function computeDisabledFrom(spec, allNames) {
151569
151846
  if (!spec) return /* @__PURE__ */ new Set();
151570
151847
  return spec.mode === "whitelist" ? new Set(allNames.filter((n) => !spec.enable.includes(n))) : new Set(spec.disable);
151571
151848
  }
151572
- function harnessDisabledSkills(allNames) {
151573
- return computeDisabledFrom(active?.skillsSpec ?? null, allNames);
151849
+ function harnessDisabledSkills(core, allNames) {
151850
+ return computeDisabledFrom(runtimeOf(core)?.active?.skillsSpec ?? null, allNames);
151574
151851
  }
151575
- function harnessDisabledAgents(allNames) {
151576
- return computeDisabledFrom(active?.agentsSpec ?? null, allNames);
151852
+ function harnessDisabledAgents(core, allNames) {
151853
+ return computeDisabledFrom(runtimeOf(core)?.active?.agentsSpec ?? null, allNames);
151577
151854
  }
151578
151855
  function libraryDir() {
151579
151856
  return path3.join(getAtomixRoot(), "harness");
@@ -151841,17 +152118,19 @@ function resolveHarness(doc, ctx) {
151841
152118
  };
151842
152119
  }
151843
152120
  function buildContext(core) {
152121
+ const rt = requireRuntime(core);
151844
152122
  return {
151845
- baseline,
152123
+ baseline: rt.baseline,
151846
152124
  // 工具:getToolInfos 恒返回内置全集(禁用项带 status),可直读;
151847
- // skill/agent:注册表是已过滤视图,优先用 applyDisabled* 回写的全集缓存,
151848
- // 缓存为空只在启动初始化时(此刻注册表尚未过滤,直读即全集)
152125
+ // skill:core session 读取时过滤,includeDisabled 直接取供给全集;
152126
+ // agent:注册表是已过滤视图,优先用 applyDisabledAgents 回写的全集缓存,
152127
+ // 缓存为空只在启动初始化时(此刻尚未过滤,直读即全集)
151849
152128
  allToolNames: core.getToolInfos().map((t) => t.name),
151850
- allSkillNames: fullSkillNames ?? core.getSkillsInfo().map((s) => s.name),
151851
- allAgentNames: fullAgentNames ?? core.getAgentsInfo().map((a) => a.name)
152129
+ allSkillNames: rt.fullSkillNames ?? core.getSkillsInfo({ includeDisabled: true }).map((s) => s.name),
152130
+ allAgentNames: rt.fullAgentNames ?? core.getAgentsInfo().map((a) => a.name)
151852
152131
  };
151853
152132
  }
151854
- function applyAssembly(core, r) {
152133
+ function applyAssembly(core, rt, r) {
151855
152134
  core.updateAssemblyConfig({
151856
152135
  useTools: r.useTools,
151857
152136
  deferBuiltinTools: r.deferBuiltinTools,
@@ -151863,44 +152142,54 @@ function applyAssembly(core, r) {
151863
152142
  ...r.memoryFiles !== void 0 ? { memoryFiles: r.memoryFiles } : {},
151864
152143
  ...r.personaFile !== void 0 ? { personaFile: r.personaFile } : {}
151865
152144
  });
151866
- activeMemoryFiles = r.memoryFiles;
151867
- activePersonaFile = r.personaFile;
151868
- active = r.name === BASE_HARNESS ? null : r;
151869
- }
151870
- function initHarness(core, cwd2, base) {
151871
- baseline = {
151872
- useTools: base.useTools ? [...base.useTools] : null,
151873
- deferBuiltinTools: base.deferBuiltinTools?.slice(),
151874
- memoryFiles: base.memoryFiles,
151875
- personaFile: base.personaFile,
151876
- potentialMemoryFiles: base.potentialMemoryFiles
152145
+ rt.activeMemoryFiles = r.memoryFiles;
152146
+ rt.activePersonaFile = r.personaFile;
152147
+ rt.active = r.name === BASE_HARNESS ? null : r;
152148
+ }
152149
+ function initHarness(core, cwd2, base, opts = {}) {
152150
+ const rt = {
152151
+ baseline: {
152152
+ useTools: base.useTools ? [...base.useTools] : null,
152153
+ deferBuiltinTools: base.deferBuiltinTools?.slice(),
152154
+ memoryFiles: base.memoryFiles,
152155
+ personaFile: base.personaFile,
152156
+ potentialMemoryFiles: base.potentialMemoryFiles
152157
+ },
152158
+ activeMemoryFiles: base.memoryFiles,
152159
+ activePersonaFile: base.personaFile,
152160
+ projectDir: cwd2,
152161
+ active: null,
152162
+ overridden: opts.harness !== void 0,
152163
+ fullSkillNames: null,
152164
+ fullAgentNames: null
151877
152165
  };
151878
- activeMemoryFiles = base.memoryFiles;
151879
- activePersonaFile = base.personaFile;
151880
- projectDir = cwd2;
151881
- const name = readState(cwd2);
152166
+ runtimes.set(core, rt);
152167
+ const name = opts.harness ?? readState(cwd2);
152168
+ const source = rt.overridden ? "\u4F1A\u8BDD\u7EA7\u6307\u5B9A" : "\u6765\u81EA .atomix/harness-state.json";
151882
152169
  if (name === BASE_HARNESS) return null;
151883
152170
  try {
151884
152171
  const doc = loadHarnessDoc(name);
151885
152172
  const r = resolveHarness(doc, buildContext(core));
151886
- applyAssembly(core, r);
151887
- return r.warnings.length ? `harness "${r.name}"(\u6765\u81EA .atomix/harness-state.json)\u5DF2\u52A0\u8F7D:
152173
+ applyAssembly(core, rt, r);
152174
+ return r.warnings.length ? `harness "${r.name}"(${source})\u5DF2\u52A0\u8F7D:
151888
152175
  \u26A0 ${r.warnings.join("\n \u26A0 ")}` : null;
151889
152176
  } catch (e) {
151890
- return `harness "${name}"(\u6765\u81EA .atomix/harness-state.json)\u52A0\u8F7D\u5931\u8D25,\u5DF2\u56DE\u843D base:${e instanceof Error ? e.message : e}`;
152177
+ if (rt.overridden) throw new Error(`harness "${name}" \u52A0\u8F7D\u5931\u8D25:${e instanceof Error ? e.message : e}`);
152178
+ return `harness "${name}"(${source})\u52A0\u8F7D\u5931\u8D25,\u5DF2\u56DE\u843D base:${e instanceof Error ? e.message : e}`;
151891
152179
  }
151892
152180
  }
151893
152181
  async function switchTo(core, name) {
151894
- if (!projectDir) throw new Error("harness \u672A\u521D\u59CB\u5316(initHarness \u672A\u8C03\u7528)");
152182
+ const rt = requireRuntime(core);
151895
152183
  const ctx = buildContext(core);
151896
152184
  const r = name === BASE_HARNESS ? resolveBase(ctx) : resolveHarness(loadHarnessDoc(name), ctx);
151897
152185
  const wasOn = (v) => v !== null && v !== void 0;
151898
- const memWasOn = wasOn(activeMemoryFiles);
151899
- const personaWas = activePersonaFile;
151900
- applyAssembly(core, r);
151901
- const memNowOn = wasOn(activeMemoryFiles);
151902
- const personaNow = activePersonaFile;
151903
- writeState(projectDir, name);
152186
+ const memWasOn = wasOn(rt.activeMemoryFiles);
152187
+ const personaWas = rt.activePersonaFile;
152188
+ applyAssembly(core, rt, r);
152189
+ const memNowOn = wasOn(rt.activeMemoryFiles);
152190
+ const personaNow = rt.activePersonaFile;
152191
+ writeState(rt.projectDir, name);
152192
+ rt.overridden = false;
151904
152193
  const { applyDisabledSkills: applyDisabledSkills2 } = await Promise.resolve().then(() => (init_skills(), skills_exports));
151905
152194
  const { applyDisabledAgents: applyDisabledAgents2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
151906
152195
  applyDisabledSkills2(core);
@@ -151955,13 +152244,15 @@ async function harnessCommand(core, args) {
151955
152244
  switch (sub) {
151956
152245
  case void 0:
151957
152246
  case "list": {
151958
- const cur = getActiveHarnessName();
152247
+ const cur = getActiveHarnessName(core);
152248
+ const rt = runtimeOf(core);
151959
152249
  const lines = names.map((n) => `${n === cur ? "\u25CF" : "\u25CB"} ${n}${n === BASE_HARNESS ? "(\u9ED8\u8BA4\u88C5\u914D)" : ""}`);
151960
- if (sub === void 0 && active) {
152250
+ if (sub === void 0 && rt?.active) {
151961
152251
  const ctx = buildContext(core);
151962
- lines.unshift(`\u5F53\u524D:${cur}(\u9879\u76EE\u7EA7,${path3.join(".atomix", "harness-state.json")})`, " " + summarize(active, ctx), "");
152252
+ const where = rt.overridden ? "\u4F1A\u8BDD\u7EA7\u6307\u5B9A,\u672A\u5199\u5165\u9879\u76EE\u6001" : `\u9879\u76EE\u7EA7,${path3.join(".atomix", "harness-state.json")}`;
152253
+ lines.unshift(`\u5F53\u524D:${cur}(${where})`, " " + summarize(rt.active, ctx), "");
151963
152254
  } else if (sub === void 0) {
151964
- lines.unshift(`\u5F53\u524D:base(\u9ED8\u8BA4\u88C5\u914D,\u672A\u9009\u62E9 harness)`, "");
152255
+ lines.unshift(rt?.overridden ? "\u5F53\u524D:base(\u4F1A\u8BDD\u7EA7\u6307\u5B9A\u9ED8\u8BA4\u88C5\u914D)" : "\u5F53\u524D:base(\u9ED8\u8BA4\u88C5\u914D,\u672A\u9009\u62E9 harness)", "");
151965
152256
  }
151966
152257
  lines.push("", "\u7528\u6CD5:/harness list | use <\u540D\u79F0> | show <\u540D\u79F0> | diff <\u540D\u79F0> | reset");
151967
152258
  lines.push(`\u5E93\u76EE\u5F55:${libraryDir()}(\u6BCF\u4E2A harness \u4E00\u4E2A\u5B50\u76EE\u5F55,\u542B harness.yaml + rules.md)`);
@@ -151985,7 +152276,7 @@ async function harnessCommand(core, args) {
151985
152276
  try {
151986
152277
  const ctx = buildContext(core);
151987
152278
  const r = resolveHarness(loadHarnessDoc(arg), ctx);
151988
- return `${r.name}${arg === getActiveHarnessName() ? "(\u5F53\u524D)" : ""}
152279
+ return `${r.name}${arg === getActiveHarnessName(core) ? "(\u5F53\u524D)" : ""}
151989
152280
  ${summarize(r, ctx)}`;
151990
152281
  } catch (e) {
151991
152282
  return `\u8BFB\u53D6\u5931\u8D25:${e instanceof Error ? e.message : e}`;
@@ -151995,7 +152286,7 @@ async function harnessCommand(core, args) {
151995
152286
  return `\u672A\u77E5\u5B50\u547D\u4EE4:${sub}(\u53EF\u7528:list / use / show / diff / reset)`;
151996
152287
  }
151997
152288
  }
151998
- var import_yaml, import_atomix_core2, BASE_HARNESS, baseline, activeMemoryFiles, activePersonaFile, projectDir, active, fullSkillNames, fullAgentNames;
152289
+ var import_yaml, import_atomix_core2, BASE_HARNESS, runtimes;
151999
152290
  var init_harness = __esm({
152000
152291
  "src/harness.ts"() {
152001
152292
  "use strict";
@@ -152003,11 +152294,7 @@ var init_harness = __esm({
152003
152294
  import_atomix_core2 = __toESM(require_dist4());
152004
152295
  init_paths();
152005
152296
  BASE_HARNESS = "base";
152006
- baseline = { useTools: null };
152007
- projectDir = null;
152008
- active = null;
152009
- fullSkillNames = null;
152010
- fullAgentNames = null;
152297
+ runtimes = /* @__PURE__ */ new WeakMap();
152011
152298
  }
152012
152299
  });
152013
152300
 
@@ -152017,14 +152304,14 @@ import * as path4 from "path";
152017
152304
  function getMemoryPaths(cwd2) {
152018
152305
  const root2 = realpathOrSelf(getAtomixRoot());
152019
152306
  const slug = (0, import_atomix_core3.projectPathToDirName)(cwd2);
152020
- const projectDir2 = path4.join(root2, "projects", slug);
152307
+ const projectDir = path4.join(root2, "projects", slug);
152021
152308
  return {
152022
152309
  root: root2,
152023
152310
  slug,
152024
152311
  soul: path4.join(root2, "SOUL.md"),
152025
152312
  globalMemory: path4.join(root2, "MEMORY.md"),
152026
- projectDir: projectDir2,
152027
- projectMemory: path4.join(projectDir2, "MEMORY.md")
152313
+ projectDir,
152314
+ projectMemory: path4.join(projectDir, "MEMORY.md")
152028
152315
  };
152029
152316
  }
152030
152317
  function realpathOrSelf(p) {
@@ -152190,19 +152477,28 @@ function getMarketplace() {
152190
152477
  if (!_instance) _instance = new Marketplace();
152191
152478
  return _instance;
152192
152479
  }
152480
+ function registerSessionDirs(core, dirs) {
152481
+ sessionRegistry.set(core, dirs);
152482
+ }
152483
+ function unregisterSessionDirs(core) {
152484
+ sessionRegistry.delete(core);
152485
+ }
152486
+ function listSessionDirs() {
152487
+ return [...sessionRegistry.entries()];
152488
+ }
152193
152489
  function buildAgentsExtraDirs() {
152194
- activeAgentsDirs = getMarketplace().getSubagentDirs();
152195
- return activeAgentsDirs;
152490
+ return getMarketplace().getSubagentDirs();
152196
152491
  }
152197
152492
  function refreshAgentsExtraDirs() {
152198
- if (activeAgentsDirs) activeAgentsDirs.splice(0, activeAgentsDirs.length, ...getMarketplace().getSubagentDirs());
152493
+ const fresh = getMarketplace().getSubagentDirs();
152494
+ for (const [, d] of sessionRegistry) d.agents.splice(0, d.agents.length, ...fresh);
152199
152495
  }
152200
152496
  function buildCommandsExtraDirs() {
152201
- activeCommandDirs = getMarketplace().getCommandDirs();
152202
- return activeCommandDirs;
152497
+ return getMarketplace().getCommandDirs();
152203
152498
  }
152204
152499
  function refreshCommandsExtraDirs() {
152205
- if (activeCommandDirs) activeCommandDirs.splice(0, activeCommandDirs.length, ...getMarketplace().getCommandDirs());
152500
+ const fresh = getMarketplace().getCommandDirs();
152501
+ for (const [, d] of sessionRegistry) d.commands.splice(0, d.commands.length, ...fresh);
152206
152502
  }
152207
152503
  function syncMarketplaceMcp() {
152208
152504
  const mcpPath = path6.join(getAtomixRoot(), "mcp.json");
@@ -152316,7 +152612,7 @@ function countPluginContents(dir) {
152316
152612
  hasHooks: fs6.existsSync(path6.join(dir, "hooks", "hooks.json"))
152317
152613
  };
152318
152614
  }
152319
- var execFileP, MKT_PREFIX, activeProjectDir, Marketplace, _instance, activeAgentsDirs, activeCommandDirs;
152615
+ var execFileP, MKT_PREFIX, activeProjectDir, Marketplace, _instance, sessionRegistry;
152320
152616
  var init_marketplace = __esm({
152321
152617
  "src/marketplace.ts"() {
152322
152618
  "use strict";
@@ -152608,8 +152904,7 @@ var init_marketplace = __esm({
152608
152904
  }
152609
152905
  };
152610
152906
  _instance = null;
152611
- activeAgentsDirs = null;
152612
- activeCommandDirs = null;
152907
+ sessionRegistry = /* @__PURE__ */ new Map();
152613
152908
  }
152614
152909
  });
152615
152910
 
@@ -152676,17 +152971,17 @@ function computeSkillsExtraDirs() {
152676
152971
  return dirs;
152677
152972
  }
152678
152973
  function buildSkillsExtraDirs() {
152679
- activeExtraDirs = computeSkillsExtraDirs();
152680
- return activeExtraDirs;
152974
+ return computeSkillsExtraDirs();
152681
152975
  }
152682
152976
  function refreshSkillsExtraDirs() {
152683
- if (activeExtraDirs) activeExtraDirs.splice(0, activeExtraDirs.length, ...computeSkillsExtraDirs());
152977
+ const fresh = computeSkillsExtraDirs();
152978
+ for (const [, d] of listSessionDirs()) d.skills.splice(0, d.skills.length, ...fresh);
152684
152979
  }
152685
152980
  function applyDisabledSkills(core) {
152686
152981
  core.reloadSkills();
152687
- const allNames = core.getSkillsInfo().map((s) => s.name);
152688
- recordSkillUniverse(allNames);
152689
- const disabled = /* @__PURE__ */ new Set([...readDisabledSkills(), ...harnessDisabledSkills(allNames)]);
152982
+ const allNames = core.getSkillsInfo({ includeDisabled: true }).map((s) => s.name);
152983
+ recordSkillUniverse(core, allNames);
152984
+ const disabled = /* @__PURE__ */ new Set([...readDisabledSkills(), ...harnessDisabledSkills(core, allNames)]);
152690
152985
  core.reloadSkills(disabled);
152691
152986
  }
152692
152987
  function sourceLabel(s) {
@@ -152755,7 +153050,7 @@ async function skillsCommand(core, args) {
152755
153050
  return `\u672A\u77E5\u5B50\u547D\u4EE4\uFF1A${sub}\uFF08\u7528\u6CD5\uFF1A/skills list | enable <\u540D\u79F0> | disable <\u540D\u79F0> | import-disabled\uFF09`;
152756
153051
  }
152757
153052
  }
152758
- var activeExtraDirs, LOCATE_LABEL;
153053
+ var LOCATE_LABEL;
152759
153054
  var init_skills = __esm({
152760
153055
  "src/skills.ts"() {
152761
153056
  "use strict";
@@ -152763,7 +153058,6 @@ var init_skills = __esm({
152763
153058
  init_harness();
152764
153059
  init_appConfig();
152765
153060
  init_marketplace();
152766
- activeExtraDirs = null;
152767
153061
  LOCATE_LABEL = {
152768
153062
  user: "user",
152769
153063
  project: "project",
@@ -159339,26 +159633,6 @@ var import_react20 = __toESM(require_react(), 1);
159339
159633
  // node_modules/ink/build/hooks/use-focus-manager.js
159340
159634
  var import_react21 = __toESM(require_react(), 1);
159341
159635
 
159342
- // src/tui/index.tsx
159343
- var import_atomix_core8 = __toESM(require_dist4());
159344
-
159345
- // src/tools.ts
159346
- var ATOMIX_TOOLS = [
159347
- "Bash",
159348
- "Glob",
159349
- "Grep",
159350
- "Read",
159351
- "Write",
159352
- "Edit",
159353
- "TodoWrite",
159354
- "Skill",
159355
- "AgentTeam",
159356
- "NotebookEdit",
159357
- "AskUser",
159358
- "ToolSearch"
159359
- ];
159360
- var ATOMIX_DEFER_TOOLS = ["NotebookEdit"];
159361
-
159362
159636
  // src/tui/index.tsx
159363
159637
  init_paths();
159364
159638
 
@@ -159745,7 +160019,30 @@ async function modelCommand(core, args, ask) {
159745
160019
  }
159746
160020
  }
159747
160021
 
159748
- // src/tui/index.tsx
160022
+ // src/session.ts
160023
+ var import_atomix_core5 = __toESM(require_dist4());
160024
+
160025
+ // src/sessionTypes.ts
160026
+ var SESSION_HANDLE_BRAND = /* @__PURE__ */ Symbol.for("atomix-cli.sessionHandle");
160027
+
160028
+ // src/tools.ts
160029
+ var ATOMIX_TOOLS = [
160030
+ "Bash",
160031
+ "Glob",
160032
+ "Grep",
160033
+ "Read",
160034
+ "Write",
160035
+ "Edit",
160036
+ "TodoWrite",
160037
+ "Skill",
160038
+ "AgentTeam",
160039
+ "NotebookEdit",
160040
+ "AskUser",
160041
+ "ToolSearch"
160042
+ ];
160043
+ var ATOMIX_DEFER_TOOLS = ["NotebookEdit"];
160044
+
160045
+ // src/session.ts
159749
160046
  init_skills();
159750
160047
  init_agents();
159751
160048
  init_harness();
@@ -159820,7 +160117,7 @@ async function mcpCommand(core, args) {
159820
160117
  return lines.join("\n ");
159821
160118
  }
159822
160119
 
159823
- // src/tui/index.tsx
160120
+ // src/session.ts
159824
160121
  init_marketplace();
159825
160122
 
159826
160123
  // src/marketplaceCommand.ts
@@ -159878,6 +160175,19 @@ async function applyMcpHotUpdates(core) {
159878
160175
  }
159879
160176
  return notes;
159880
160177
  }
160178
+ async function refreshRegisteredSessions(invoker) {
160179
+ refreshSkillsExtraDirs();
160180
+ refreshAgentsExtraDirs();
160181
+ refreshCommandsExtraDirs();
160182
+ const cores = new Set(listSessionDirs().map(([c]) => c));
160183
+ if (invoker) cores.add(invoker);
160184
+ for (const c of cores) {
160185
+ applyDisabledSkills(c);
160186
+ await applyDisabledAgents(c).catch(() => {
160187
+ });
160188
+ c.reloadCustomCommands();
160189
+ }
160190
+ }
159881
160191
  async function applyChanges(core, opts) {
159882
160192
  const notes = [];
159883
160193
  const { synced, removed } = syncMarketplaceMcp();
@@ -159885,13 +160195,7 @@ async function applyChanges(core, opts) {
159885
160195
  if (synced.length || removed.length) notes.push(`MCP \u5168\u5C40\u540C\u6B65\uFF1A+${synced.length} \u2212${removed.length}\uFF08\u4E0B\u6B21\u542F\u52A8\u8FDE\u63A5\uFF09`);
159886
160196
  return notes;
159887
160197
  }
159888
- refreshSkillsExtraDirs();
159889
- applyDisabledSkills(core);
159890
- refreshAgentsExtraDirs();
159891
- await applyDisabledAgents(core).catch(() => {
159892
- });
159893
- refreshCommandsExtraDirs();
159894
- core.reloadCustomCommands();
160198
+ await refreshRegisteredSessions(core);
159895
160199
  notes.push(...await applyMcpHotUpdates(core));
159896
160200
  const hooksNow = getMarketplace().getHookEntries().map((h) => h.file).sort();
159897
160201
  const hooksBefore = [...opts?.hooksBefore ?? hooksNow].sort();
@@ -160104,8 +160408,246 @@ function loadHooks(cwd2) {
160104
160408
  };
160105
160409
  }
160106
160410
 
160411
+ // src/session.ts
160412
+ init_appConfig();
160413
+ function internalHandle(handle) {
160414
+ if (!handle || handle[SESSION_HANDLE_BRAND] !== true) {
160415
+ throw new Error("\u975E\u6CD5\u4F1A\u8BDD\u53E5\u67C4:\u5FC5\u987B\u6765\u81EA createSessionCore()");
160416
+ }
160417
+ return handle;
160418
+ }
160419
+ var MAIN = "main";
160420
+ var DEFAULT_SYSTEM_PROMPT = "You are Atomix, a CLI coding agent bound to the current working directory.";
160421
+ var DEFAULT_SEND_TIMEOUT_MS = 10 * 60 * 1e3;
160422
+ var SESSION_ID_PATTERN = /^[A-Za-z0-9._-]{1,128}$/;
160423
+ function validateSessionId(id) {
160424
+ if (!SESSION_ID_PATTERN.test(id) || id === "." || id === "..") {
160425
+ throw new Error(`\u975E\u6CD5 session id:${JSON.stringify(id)}(\u53EA\u5141\u8BB8 1\u2013128 \u4E2A\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u70B9\u3001\u4E0B\u5212\u7EBF\u3001\u8FDE\u5B57\u7B26)`);
160426
+ }
160427
+ }
160428
+ var preparedCwd = null;
160429
+ function prepareProcess(cwd2) {
160430
+ if (preparedCwd === null) {
160431
+ initMarketplaceProject(cwd2);
160432
+ syncInheritedMcp();
160433
+ syncMarketplaceMcp();
160434
+ preparedCwd = cwd2;
160435
+ return null;
160436
+ }
160437
+ if (preparedCwd !== cwd2) {
160438
+ return `marketplace \u9879\u76EE\u7EA7 override \u4ECD\u7ED1\u5B9A\u9996\u4E2A\u4F1A\u8BDD\u76EE\u5F55 ${preparedCwd}(\u672C\u8FDB\u7A0B\u5185\u591A\u4F1A\u8BDD\u5171\u7528\u4E00\u4E2A\u9879\u76EE\u57DF)`;
160439
+ }
160440
+ return null;
160441
+ }
160442
+ function createSessionCore(opts) {
160443
+ const interactive = opts.interactive ?? false;
160444
+ const permissionMode = opts.permissionMode ?? (interactive ? import_atomix_core5.DEFAULT_PERMISSION_MODE : "free-style");
160445
+ const notes = [];
160446
+ const prepNote = prepareProcess(opts.cwd);
160447
+ if (prepNote) notes.push(prepNote);
160448
+ const appConfig = readConfig();
160449
+ const contextFiles = buildContextFilesConfig(opts.cwd, appConfig);
160450
+ const hookCfg = opts.hooks ?? interactive ? loadHooks(opts.cwd) : {};
160451
+ const dirs = { skills: buildSkillsExtraDirs(), agents: buildAgentsExtraDirs(), commands: buildCommandsExtraDirs() };
160452
+ const core = new import_atomix_core5.AtomixCore({
160453
+ workingDir: opts.cwd,
160454
+ logLevel: opts.logLevel ?? atomixLogLevel(),
160455
+ stream: opts.stream ?? interactive,
160456
+ useTools: ATOMIX_TOOLS,
160457
+ deferBuiltinTools: ATOMIX_DEFER_TOOLS,
160458
+ skillsExtraDirs: dirs.skills,
160459
+ agentsExtraDirs: dirs.agents,
160460
+ commandsExtraDirs: dirs.commands,
160461
+ ...hookCfg,
160462
+ ...contextFiles,
160463
+ permissionMode,
160464
+ // 交互模式下文件编辑必须过权限卡;无人值守靠 permissionMode(free-style 全放行,其余由自动应答器 fail-closed)
160465
+ skipFileEditPermission: false,
160466
+ multiSession: opts.multiSession ?? false,
160467
+ systemPrompt: opts.systemPrompt ?? DEFAULT_SYSTEM_PROMPT
160468
+ });
160469
+ registerSessionDirs(core, dirs);
160470
+ const potential = buildPotentialContextFiles(opts.cwd, appConfig);
160471
+ const baseline = {
160472
+ useTools: ATOMIX_TOOLS,
160473
+ deferBuiltinTools: ATOMIX_DEFER_TOOLS,
160474
+ memoryFiles: contextFiles.memoryFiles,
160475
+ personaFile: contextFiles.personaFile,
160476
+ potentialMemoryFiles: potential.memoryFiles
160477
+ };
160478
+ return { [SESSION_HANDLE_BRAND]: true, core, cwd: opts.cwd, interactive, permissionMode, appConfig, contextFiles, baseline, notes };
160479
+ }
160480
+ async function discardSessionCore(handle) {
160481
+ const h = internalHandle(handle);
160482
+ unregisterSessionDirs(h.core);
160483
+ await h.core.dispose().catch(() => {
160484
+ });
160485
+ }
160486
+ async function startSession(handle, opts = {}) {
160487
+ const h = internalHandle(handle);
160488
+ const { core, cwd: cwd2 } = h;
160489
+ if (opts.sessionId !== void 0) validateSessionId(opts.sessionId);
160490
+ const notes = [...h.notes];
160491
+ const warn = initHarness(core, cwd2, h.baseline, opts.harness !== void 0 ? { harness: opts.harness } : {});
160492
+ if (warn) notes.push(warn);
160493
+ let ready;
160494
+ const onReady = (d) => {
160495
+ ready = d;
160496
+ };
160497
+ core.once("session:ready", onReady);
160498
+ try {
160499
+ await core.createSession(opts.sessionId);
160500
+ } finally {
160501
+ core.off("session:ready", onReady);
160502
+ }
160503
+ if (!ready) throw new Error("createSession \u5DF2\u8FD4\u56DE\u4F46\u672A\u6536\u5230 session:ready");
160504
+ applyDisabledSkills(core);
160505
+ await applyDisabledAgents(core).catch((e) => {
160506
+ notes.push(`subagent \u542F\u505C\u540D\u5355\u5E94\u7528\u5931\u8D25(harness agent \u53D6\u820D\u53EF\u80FD\u672A\u751F\u6548):${e instanceof Error ? e.message : String(e)}`);
160507
+ });
160508
+ const mcpNotes = await applyMcpHotUpdates(core).catch(() => []);
160509
+ notes.push(...mcpNotes.map((n) => `${n}\uFF08\u9879\u76EE\u7EA7 override\uFF09`));
160510
+ const responder = h.interactive ? null : attachHeadlessResponder(core);
160511
+ return new SessionImpl(h, ready, notes, responder);
160512
+ }
160513
+ function attachHeadlessResponder(core) {
160514
+ const blocked = [];
160515
+ const onPermission = (d) => {
160516
+ blocked.push({ kind: "permission", name: d.toolName, title: d.title, agentId: d.agentId });
160517
+ setImmediate(() => core.respondToToolPermission({ toolName: d.toolName, selected: "refuse", agentId: d.agentId }));
160518
+ };
160519
+ const onQuestion = (d) => {
160520
+ blocked.push({ kind: "question", name: "AskUserQuestion", title: d.questions.map((q) => q.question).join(" / "), agentId: d.agentId });
160521
+ setImmediate(() => core.respondToAskQuestion({ agentId: d.agentId, answers: {} }));
160522
+ };
160523
+ const onForm = (d) => {
160524
+ blocked.push({ kind: "form", name: "FormUI", title: d.title, agentId: d.agentId });
160525
+ setImmediate(() => core.respondToForm({ agentId: d.agentId, values: {}, submitted: false }));
160526
+ };
160527
+ core.on("tool:permission:request", onPermission);
160528
+ core.on("ask:question:request", onQuestion);
160529
+ core.on("form:request", onForm);
160530
+ return {
160531
+ blocked,
160532
+ detach() {
160533
+ core.off("tool:permission:request", onPermission);
160534
+ core.off("ask:question:request", onQuestion);
160535
+ core.off("form:request", onForm);
160536
+ }
160537
+ };
160538
+ }
160539
+ var DISPOSED_ERROR = "session \u5DF2\u91CA\u653E";
160540
+ var SessionImpl = class {
160541
+ constructor(handle, ready, notes, responder) {
160542
+ this.responder = responder;
160543
+ this.core = handle.core;
160544
+ this.cwd = handle.cwd;
160545
+ this.permissionMode = handle.permissionMode;
160546
+ this.ready = ready;
160547
+ this.notes = notes;
160548
+ }
160549
+ responder;
160550
+ core;
160551
+ cwd;
160552
+ permissionMode;
160553
+ ready;
160554
+ notes;
160555
+ queue = Promise.resolve();
160556
+ disposed = false;
160557
+ /** 进行中一轮的强制收尾(dispose 用):以给定错误结束 send 并中断 core */
160558
+ abortCurrent = null;
160559
+ get sessionId() {
160560
+ return this.core.getCurrentSessionId() ?? this.ready.sessionId;
160561
+ }
160562
+ get harness() {
160563
+ return getActiveHarnessName(this.core);
160564
+ }
160565
+ on(event, listener) {
160566
+ this.core.on(event, listener);
160567
+ }
160568
+ off(event, listener) {
160569
+ this.core.off(event, listener);
160570
+ }
160571
+ send(input, opts = {}) {
160572
+ if (this.disposed) return Promise.reject(new Error(DISPOSED_ERROR));
160573
+ const run = this.queue.then(() => this.sendNow(input, opts));
160574
+ this.queue = run.catch(() => void 0);
160575
+ return run;
160576
+ }
160577
+ sendNow(input, opts) {
160578
+ if (this.disposed) return Promise.reject(new Error(DISPOSED_ERROR));
160579
+ const core = this.core;
160580
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_SEND_TIMEOUT_MS;
160581
+ const blockedStart = this.responder?.blocked.length ?? 0;
160582
+ return new Promise((resolve9) => {
160583
+ const texts = [];
160584
+ let usage2;
160585
+ let sawProcessing = false;
160586
+ let done = false;
160587
+ const onMessage = (d) => {
160588
+ if (d.agentId === MAIN && d.content.trim()) texts.push(d.content);
160589
+ };
160590
+ const onState = (d) => {
160591
+ if (d.state === "processing") sawProcessing = true;
160592
+ else if (d.state === "idle" && sawProcessing) finish();
160593
+ };
160594
+ const onError = (d) => {
160595
+ finish({ type: d.type, message: d.error?.message ?? d.error?.code ?? "" });
160596
+ };
160597
+ const onUsage = (d) => {
160598
+ if (d.agentId === void 0 || d.agentId === MAIN) usage2 = d.usage;
160599
+ };
160600
+ const interruptWith = (error) => {
160601
+ if (done) return;
160602
+ finish(error);
160603
+ core.interruptSession();
160604
+ };
160605
+ const onAbort = () => interruptWith({ type: "aborted", message: "\u8C03\u7528\u65B9\u4E2D\u6B62" });
160606
+ const timer = setTimeout(() => interruptWith({ type: "timeout", message: `\u8D85\u65F6\uFF08${timeoutMs / 1e3}s\uFF09` }), timeoutMs);
160607
+ const finish = (error) => {
160608
+ if (done) return;
160609
+ done = true;
160610
+ clearTimeout(timer);
160611
+ this.abortCurrent = null;
160612
+ core.off("message:complete", onMessage);
160613
+ core.off("state:update", onState);
160614
+ core.off("session:error", onError);
160615
+ core.off("conversation:usage", onUsage);
160616
+ opts.signal?.removeEventListener("abort", onAbort);
160617
+ resolve9({
160618
+ text: texts[texts.length - 1] ?? "",
160619
+ texts,
160620
+ blocked: this.responder ? this.responder.blocked.slice(blockedStart) : [],
160621
+ usage: usage2,
160622
+ ...error ? { error } : {}
160623
+ });
160624
+ };
160625
+ this.abortCurrent = interruptWith;
160626
+ core.on("message:complete", onMessage);
160627
+ core.on("state:update", onState);
160628
+ core.on("session:error", onError);
160629
+ core.on("conversation:usage", onUsage);
160630
+ if (opts.signal) {
160631
+ if (opts.signal.aborted) return onAbort();
160632
+ opts.signal.addEventListener("abort", onAbort, { once: true });
160633
+ }
160634
+ core.processUserInput(input);
160635
+ });
160636
+ }
160637
+ async dispose() {
160638
+ if (this.disposed) return;
160639
+ this.disposed = true;
160640
+ this.abortCurrent?.({ type: "disposed", message: DISPOSED_ERROR });
160641
+ await this.queue.catch(() => void 0);
160642
+ this.responder?.detach();
160643
+ unregisterSessionDirs(this.core);
160644
+ await this.core.dispose().catch(() => {
160645
+ });
160646
+ }
160647
+ };
160648
+
160107
160649
  // src/resume.ts
160108
- var import_atomix_core5 = __toESM(require_dist4());
160650
+ var import_atomix_core6 = __toESM(require_dist4());
160109
160651
  import * as fs10 from "fs";
160110
160652
  import * as path10 from "path";
160111
160653
  function extractText(content) {
@@ -160124,7 +160666,7 @@ function readMessages(file) {
160124
160666
  }
160125
160667
  }
160126
160668
  function listSessions(cwd2) {
160127
- const dir = (0, import_atomix_core5.getProjectHistoryDir)(cwd2);
160669
+ const dir = (0, import_atomix_core6.getProjectHistoryDir)(cwd2);
160128
160670
  if (!fs10.existsSync(dir)) return [];
160129
160671
  const entries = [];
160130
160672
  for (const f of fs10.readdirSync(dir)) {
@@ -160264,15 +160806,15 @@ function setGlyphMode(mode) {
160264
160806
  }
160265
160807
 
160266
160808
  // src/permissionMode.ts
160267
- var import_atomix_core6 = __toESM(require_dist4());
160809
+ var import_atomix_core7 = __toESM(require_dist4());
160268
160810
  var META = {
160269
160811
  "step-by-step": { label: "step by step", hint: "\u6BCF\u4E2A\u654F\u611F\u64CD\u4F5C\u9010\u9879\u786E\u8BA4", tone: "muted" },
160270
160812
  "action-check": { label: "action check", hint: "\u53EA\u8BFB\u64CD\u4F5C\u514D\u786E\u8BA4\uFF0C\u5176\u4F59\u9010\u9879\u786E\u8BA4", tone: "accent" },
160271
160813
  "free-style": { label: "free style", hint: "\u5168\u90E8\u514D\u786E\u8BA4\uFF08\u5B89\u5168\u6821\u9A8C\u4ECD\u751F\u6548\uFF09", tone: "warning" }
160272
160814
  };
160273
- var PERMISSION_MODE_ORDER = import_atomix_core6.PERMISSION_MODES;
160815
+ var PERMISSION_MODE_ORDER = import_atomix_core7.PERMISSION_MODES;
160274
160816
  function permissionModeMeta(mode) {
160275
- return META[mode] ?? META[import_atomix_core6.DEFAULT_PERMISSION_MODE];
160817
+ return META[mode] ?? META[import_atomix_core7.DEFAULT_PERMISSION_MODE];
160276
160818
  }
160277
160819
  function nextPermissionMode(mode) {
160278
160820
  const i = PERMISSION_MODE_ORDER.indexOf(mode);
@@ -160490,7 +161032,7 @@ function windowAroundCursor(chars, cursor, budget, newlineGlyph) {
160490
161032
  }
160491
161033
 
160492
161034
  // src/tui/bridge.ts
160493
- var MAIN = "main";
161035
+ var MAIN2 = "main";
160494
161036
  function estimateItemRows(item, columns) {
160495
161037
  const text = item.kind === "thinking" ? "" : item.kind === "tool" ? `${item.title} ${item.summary ?? ""}` : item.kind === "shell" ? `${item.cmd}
160496
161038
  ${item.body}
@@ -160533,7 +161075,7 @@ var Bridge = class {
160533
161075
  interactions: [],
160534
161076
  sessionId: "",
160535
161077
  thinkingEnabled: false,
160536
- permissionMode: import_atomix_core6.DEFAULT_PERMISSION_MODE,
161078
+ permissionMode: import_atomix_core7.DEFAULT_PERMISSION_MODE,
160537
161079
  modelName: "",
160538
161080
  redrawNonce: 0,
160539
161081
  staticEpoch: 0,
@@ -160710,7 +161252,7 @@ var Bridge = class {
160710
161252
  this.set({ streamText: content ?? "" });
160711
161253
  });
160712
161254
  core.on("message:complete", (d) => {
160713
- if (d.agentId !== MAIN) return;
161255
+ if (d.agentId !== MAIN2) return;
160714
161256
  const items = [...this.state.items];
160715
161257
  if (d.reasoning) items.push({ kind: "thinking", chars: d.reasoning.length });
160716
161258
  if (d.content.trim()) items.push({ kind: "assistant", text: d.content });
@@ -160759,7 +161301,7 @@ var Bridge = class {
160759
161301
  core.on("todos:update", (todos) => {
160760
161302
  this.set({ todos: todos ?? [] });
160761
161303
  });
160762
- const isMainEvent = (agentId) => !agentId || agentId === MAIN;
161304
+ const isMainEvent = (agentId) => !agentId || agentId === MAIN2;
160763
161305
  core.on("conversation:usage", (d) => {
160764
161306
  if (isMainEvent(d.agentId)) this.set({ usage: d.usage });
160765
161307
  });
@@ -160790,7 +161332,7 @@ var Bridge = class {
160790
161332
  });
160791
161333
  });
160792
161334
  core.on("session:interrupted", (d) => {
160793
- if (d.agentId === MAIN) this.notice("\u23F9 \u5DF2\u4E2D\u65AD", "warn");
161335
+ if (d.agentId === MAIN2) this.notice("\u23F9 \u5DF2\u4E2D\u65AD", "warn");
160794
161336
  });
160795
161337
  core.on("session:error", (d) => {
160796
161338
  this.notice(`\u4F1A\u8BDD\u9519\u8BEF [${d.type}] ${d.error?.message ?? d.error?.code ?? ""}`, "error");
@@ -161484,9 +162026,9 @@ function SelectList({ options: options2, multi = false, color = theme.accent, on
161484
162026
  winStart > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { dimColor: true, children: ` \u2026 \u4E0A\u65B9\u8FD8\u6709 ${winStart} \u9879` }) : null,
161485
162027
  visible.map((o, vi) => {
161486
162028
  const i = winStart + vi;
161487
- const active2 = i === index;
161488
- const mark = multi ? checked.has(i) ? G.radioOn : G.radioOff : active2 ? G.pointer : " ";
161489
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Text, { color: active2 ? color : void 0, dimColor: !active2, children: [
162029
+ const active = i === index;
162030
+ const mark = multi ? checked.has(i) ? G.radioOn : G.radioOff : active ? G.pointer : " ";
162031
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Text, { color: active ? color : void 0, dimColor: !active, children: [
161490
162032
  ` ${mark} ${i + 1}. ${o.label}`,
161491
162033
  o.hint ? ` ${o.hint}` : ""
161492
162034
  ] }, i);
@@ -161695,7 +162237,7 @@ function PromptCard({
161695
162237
  }
161696
162238
 
161697
162239
  // src/tui/images.ts
161698
- var import_atomix_core7 = __toESM(require_dist4());
162240
+ var import_atomix_core8 = __toESM(require_dist4());
161699
162241
  import { execFile as execFile2 } from "child_process";
161700
162242
  import * as fs13 from "fs";
161701
162243
  import * as os8 from "os";
@@ -161812,7 +162354,7 @@ async function buildUserInput(text, cwd2) {
161812
162354
  if (sources.length === 0) return { input: text, display: text };
161813
162355
  const blocks = [
161814
162356
  { type: "text", text: rewritten },
161815
- ...await Promise.all(sources.map((src) => (0, import_atomix_core7.loadImageAsBlock)(src)))
162357
+ ...await Promise.all(sources.map((src) => (0, import_atomix_core8.loadImageAsBlock)(src)))
161816
162358
  ];
161817
162359
  for (const placeholder of usedPlaceholders) {
161818
162360
  const file = pastedImages.get(placeholder);
@@ -162042,7 +162584,7 @@ function App2({ bridge, cwd: cwd2, initialHistory, appConfig }) {
162042
162584
  }, [bridge]);
162043
162585
  const submittingRef = (0, import_react25.useRef)(false);
162044
162586
  const [submitting, setSubmitting] = (0, import_react25.useState)(false);
162045
- const active2 = s.interactions[0];
162587
+ const active = s.interactions[0];
162046
162588
  const shellKillRef = (0, import_react25.useRef)(null);
162047
162589
  const [shellCmd, setShellCmd] = (0, import_react25.useState)(null);
162048
162590
  use_input_default((input, key) => {
@@ -162181,7 +162723,7 @@ function App2({ bridge, cwd: cwd2, initialHistory, appConfig }) {
162181
162723
  bridge.notice(await harnessCommand(bridge.core, rest2));
162182
162724
  return;
162183
162725
  case "/memory":
162184
- bridge.notice(await memoryCommand(cwd2, appConfig, rest2, { harnessMemory: harnessMemoryOverride(), harnessPersona: harnessPersonaOverride(), personaPath: getActivePersonaFile() }));
162726
+ bridge.notice(await memoryCommand(cwd2, appConfig, rest2, { harnessMemory: harnessMemoryOverride(bridge.core), harnessPersona: harnessPersonaOverride(bridge.core), personaPath: getActivePersonaFile(bridge.core) }));
162185
162727
  return;
162186
162728
  case "/mcp":
162187
162729
  bridge.notice(await mcpCommand(bridge.core, rest2));
@@ -162196,8 +162738,8 @@ function App2({ bridge, cwd: cwd2, initialHistory, appConfig }) {
162196
162738
  [
162197
162739
  `session ${s.sessionId}`,
162198
162740
  `cwd ${cwd2}`,
162199
- `harness ${getActiveHarnessName()}`,
162200
- `memory ${memoryStatusLine(appConfig, { harnessMemory: harnessMemoryOverride(), harnessPersona: harnessPersonaOverride() })}`,
162741
+ `harness ${getActiveHarnessName(bridge.core)}${isHarnessOverridden(bridge.core) ? "\uFF08\u4F1A\u8BDD\u7EA7\u6307\u5B9A\uFF09" : ""}`,
162742
+ `memory ${memoryStatusLine(appConfig, { harnessMemory: harnessMemoryOverride(bridge.core), harnessPersona: harnessPersonaOverride(bridge.core) })}`,
162201
162743
  `model main=${md?.taskConfig.main ?? "-"} quick=${md?.taskConfig.quick ?? "-"}`,
162202
162744
  `context ${s.usage ? `${s.usage.useTokens} / ${s.usage.maxTokens} tokens` : "-"}`,
162203
162745
  `thinking ${s.thinkingEnabled ? "on" : "off"}`,
@@ -162324,11 +162866,11 @@ function App2({ bridge, cwd: cwd2, initialHistory, appConfig }) {
162324
162866
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Box_default, { flexDirection: "column", width: previewWidth, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: streamPreview.text }) })
162325
162867
  ] })
162326
162868
  ] }) : null,
162327
- active2?.kind === "permission" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PermissionCard, { data: active2.data, respond: active2.respond }) : null,
162328
- active2?.kind === "question" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(QuestionCard, { data: active2.data, respond: active2.respond }) : null,
162329
- active2?.kind === "form" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FormCard, { data: active2.data, respond: active2.respond }) : null,
162330
- active2?.kind === "prompt" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PromptCard, { question: active2.question, respond: active2.respond, cancel: active2.cancel }) : null,
162331
- active2?.kind === "select" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SelectCard, { question: active2.question, options: active2.options, respond: active2.respond }) : null,
162869
+ active?.kind === "permission" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PermissionCard, { data: active.data, respond: active.respond }) : null,
162870
+ active?.kind === "question" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(QuestionCard, { data: active.data, respond: active.respond }) : null,
162871
+ active?.kind === "form" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FormCard, { data: active.data, respond: active.respond }) : null,
162872
+ active?.kind === "prompt" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PromptCard, { question: active.question, respond: active.respond, cancel: active.cancel }) : null,
162873
+ active?.kind === "select" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SelectCard, { question: active.question, options: active.options, respond: active.respond }) : null,
162332
162874
  showTodos ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Box_default, { flexDirection: "column", marginTop: 1, children: [
162333
162875
  s.todos.slice(0, 6).map((t, i) => {
162334
162876
  const mark = t.status === "completed" ? G.todoDone : t.status === "in_progress" ? G.todoDoing : G.todoPending;
@@ -162349,9 +162891,9 @@ function App2({ bridge, cwd: cwd2, initialHistory, appConfig }) {
162349
162891
  }
162350
162892
  ),
162351
162893
  redrawPulse ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: " " }) : null,
162352
- s.processing && !active2 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProcessingLine, {}) : null,
162353
- shellCmd && !active2 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ShellRunningLine, { cmd: shellCmd }) : null,
162354
- !s.processing && !active2 && !submitting ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Box_default, { flexDirection: "column", children: [
162894
+ s.processing && !active ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProcessingLine, {}) : null,
162895
+ shellCmd && !active ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ShellRunningLine, { cmd: shellCmd }) : null,
162896
+ !s.processing && !active && !submitting ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Box_default, { flexDirection: "column", children: [
162355
162897
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Box_default, { borderStyle: G.border, borderColor: theme.muted, paddingX: 1, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Box_default, { flexGrow: 1, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
162356
162898
  LineInput,
162357
162899
  {
@@ -162375,32 +162917,15 @@ function App2({ bridge, cwd: cwd2, initialHistory, appConfig }) {
162375
162917
  // src/tui/index.tsx
162376
162918
  var import_jsx_runtime7 = __toESM(require_jsx_runtime());
162377
162919
  var VERSION2 = "0.1.0";
162378
- async function startTui(cwd2, resumeSessionId) {
162920
+ async function startTui(cwd2, options2 = {}) {
162921
+ const { resumeSessionId } = options2;
162379
162922
  applyConfiguredTheme();
162380
162923
  if (!process.env.ATOMIX_GLYPHS) {
162381
162924
  const mode = configuredGlyphMode();
162382
162925
  if (mode) setGlyphMode(mode);
162383
162926
  }
162384
- initMarketplaceProject(cwd2);
162385
- syncInheritedMcp();
162386
- syncMarketplaceMcp();
162387
- const hookCfg = loadHooks(cwd2);
162388
- const appConfig = readConfig();
162389
- const contextFiles = buildContextFilesConfig(cwd2, appConfig);
162390
- const core = new import_atomix_core8.AtomixCore({
162391
- workingDir: cwd2,
162392
- logLevel: atomixLogLevel(),
162393
- stream: true,
162394
- useTools: ATOMIX_TOOLS,
162395
- deferBuiltinTools: ATOMIX_DEFER_TOOLS,
162396
- skillsExtraDirs: buildSkillsExtraDirs(),
162397
- agentsExtraDirs: buildAgentsExtraDirs(),
162398
- commandsExtraDirs: buildCommandsExtraDirs(),
162399
- ...hookCfg,
162400
- ...contextFiles,
162401
- skipFileEditPermission: false,
162402
- systemPrompt: "You are Atomix, a CLI coding agent bound to the current working directory."
162403
- });
162927
+ const handle = createSessionCore({ cwd: cwd2, interactive: true, permissionMode: options2.permissionMode });
162928
+ const { core, appConfig } = handle;
162404
162929
  {
162405
162930
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
162406
162931
  const { ask, dispose } = makeCancellableAsk(rl);
@@ -162413,8 +162938,7 @@ async function startTui(cwd2, resumeSessionId) {
162413
162938
  }
162414
162939
  if (!ok) {
162415
162940
  console.log(gray("\u672A\u5B8C\u6210\u6A21\u578B\u914D\u7F6E\uFF0C\u9000\u51FA\u3002"));
162416
- await core.dispose().catch(() => {
162417
- });
162941
+ await discardSessionCore(handle);
162418
162942
  process.exit(1);
162419
162943
  }
162420
162944
  }
@@ -162432,37 +162956,16 @@ async function startTui(cwd2, resumeSessionId) {
162432
162956
  accent("\u2570\u2500 ") + muted("/help \u67E5\u770B\u547D\u4EE4")
162433
162957
  ].join("\n")
162434
162958
  );
162435
- let initialHistory = [];
162436
- await new Promise((resolve9, reject2) => {
162437
- core.once("session:ready", (d) => {
162438
- bridge.setSessionId(d.sessionId);
162439
- bridge.setUsage(d.usage);
162440
- initialHistory = [...d.projectInputHistory ?? []];
162441
- resolve9();
162442
- });
162443
- core.createSession(resumeSessionId).catch(reject2);
162444
- }).catch(async (e) => {
162959
+ const session = await startSession(handle, { sessionId: resumeSessionId, harness: options2.harness }).catch(async (e) => {
162445
162960
  console.error(`\u4F1A\u8BDD\u521D\u59CB\u5316\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
162446
- await core.dispose().catch(() => {
162447
- });
162961
+ await discardSessionCore(handle);
162448
162962
  process.exit(1);
162449
162963
  });
162450
- {
162451
- const potential = buildPotentialContextFiles(cwd2, appConfig);
162452
- const warn = initHarness(core, cwd2, {
162453
- useTools: ATOMIX_TOOLS,
162454
- deferBuiltinTools: ATOMIX_DEFER_TOOLS,
162455
- memoryFiles: contextFiles.memoryFiles,
162456
- personaFile: contextFiles.personaFile,
162457
- potentialMemoryFiles: potential.memoryFiles
162458
- });
162459
- if (warn) console.error(warn);
162460
- }
162461
- applyDisabledSkills(core);
162462
- await applyDisabledAgents(core).catch(() => {
162463
- });
162464
- const mcpNotes = await applyMcpHotUpdates(core).catch(() => []);
162465
- for (const n of mcpNotes) bridge.notice(`${n}\uFF08\u9879\u76EE\u7EA7 override\uFF09`);
162964
+ bridge.setPermissionMode(handle.permissionMode, { silent: true });
162965
+ bridge.setSessionId(session.ready.sessionId);
162966
+ bridge.setUsage(session.ready.usage);
162967
+ const initialHistory = [...session.ready.projectInputHistory ?? []];
162968
+ for (const n of session.notes) bridge.notice(n, n.startsWith("harness") ? "warn" : "info");
162466
162969
  if (resumeSessionId) {
162467
162970
  bridge.seedReplay(loadReplay(cwd2, resumeSessionId));
162468
162971
  }