harness-wingman 0.8.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7757,11 +7757,11 @@ function isPatchState(value) {
7757
7757
  const patch = value;
7758
7758
  return typeof patch.patchFile === "string" && typeof patch.original === "object" && patch.original !== null && typeof patch.original.existed === "boolean" && (patch.original.bytesBase64 === void 0 || typeof patch.original.bytesBase64 === "string");
7759
7759
  }
7760
- async function readState(paths) {
7761
- const buffer = await readIfExists(paths.stateFile);
7760
+ async function readState(paths3) {
7761
+ const buffer = await readIfExists(paths3.stateFile);
7762
7762
  if (buffer === void 0)
7763
7763
  return void 0;
7764
- const state = JSON.parse(decodeUtf8Strict(buffer, paths.stateFile));
7764
+ const state = JSON.parse(decodeUtf8Strict(buffer, paths3.stateFile));
7765
7765
  if (typeof state !== "object" || state === null || state.version !== 1 && state.version !== 2) {
7766
7766
  throw new Error("\u672A\u77E5\u7684\u63A5\u7EBF\u72B6\u6001\u7248\u672C,\u4E0D\u731C");
7767
7767
  }
@@ -7770,18 +7770,18 @@ async function readState(paths) {
7770
7770
  }
7771
7771
  return state;
7772
7772
  }
7773
- async function writeState(paths, state) {
7774
- await mkdir(dirname(paths.stateFile), { recursive: true });
7775
- await writeFile(paths.stateFile, `${JSON.stringify(state, void 0, 2)}
7773
+ async function writeState(paths3, state) {
7774
+ await mkdir(dirname(paths3.stateFile), { recursive: true });
7775
+ await writeFile(paths3.stateFile, `${JSON.stringify(state, void 0, 2)}
7776
7776
  `, "utf8");
7777
7777
  }
7778
- function backupDirectory(paths) {
7779
- return join(paths.backupsRoot, (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-"));
7778
+ function backupDirectory(paths3) {
7779
+ return join(paths3.backupsRoot, (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-"));
7780
7780
  }
7781
- async function backupPatchFile(paths, backupDir, file, bytes) {
7782
- const fromProfiles = relative(paths.profilesDir, file);
7781
+ async function backupPatchFile(paths3, backupDir, file, bytes) {
7782
+ const fromProfiles = relative(paths3.profilesDir, file);
7783
7783
  let safeRelative;
7784
- if (file === paths.patchFile) {
7784
+ if (file === paths3.patchFile) {
7785
7785
  safeRelative = join("home", "cordis.patch.yml");
7786
7786
  } else if (!fromProfiles.startsWith("..") && !isAbsolute(fromProfiles)) {
7787
7787
  safeRelative = join("profiles", fromProfiles);
@@ -7793,15 +7793,15 @@ async function backupPatchFile(paths, backupDir, file, bytes) {
7793
7793
  await mkdir(dirname(target), { recursive: true });
7794
7794
  await writeFile(target, bytes);
7795
7795
  }
7796
- async function writeOwnedFiles(paths, url) {
7797
- await mkdir(dirname(paths.hooksConfigFile), { recursive: true });
7798
- await writeFile(paths.forwarderFile, FORWARDER_SOURCE, "utf8");
7799
- await writeFile(paths.hooksConfigFile, buildHooksConfig(paths.forwarderFile, url), "utf8");
7796
+ async function writeOwnedFiles(paths3, url) {
7797
+ await mkdir(dirname(paths3.hooksConfigFile), { recursive: true });
7798
+ await writeFile(paths3.forwarderFile, FORWARDER_SOURCE, "utf8");
7799
+ await writeFile(paths3.hooksConfigFile, buildHooksConfig(paths3.forwarderFile, url), "utf8");
7800
7800
  }
7801
- async function listProfiles(paths, environment) {
7801
+ async function listProfiles(paths3, environment) {
7802
7802
  let entries;
7803
7803
  try {
7804
- entries = await readdir(paths.profilesDir, { withFileTypes: true });
7804
+ entries = await readdir(paths3.profilesDir, { withFileTypes: true });
7805
7805
  } catch (error) {
7806
7806
  if (error.code === "ENOENT")
7807
7807
  entries = [];
@@ -7813,12 +7813,12 @@ async function listProfiles(paths, environment) {
7813
7813
  if (entry.name === "node_modules")
7814
7814
  continue;
7815
7815
  try {
7816
- if (!(await stat(join(paths.profilesDir, entry.name))).isDirectory())
7816
+ if (!(await stat(join(paths3.profilesDir, entry.name))).isDirectory())
7817
7817
  continue;
7818
7818
  } catch {
7819
7819
  continue;
7820
7820
  }
7821
- const manifest = join(paths.profilesDir, entry.name, "package.json");
7821
+ const manifest = join(paths3.profilesDir, entry.name, "package.json");
7822
7822
  if (await readIfExists(manifest) !== void 0)
7823
7823
  names.push(entry.name);
7824
7824
  }
@@ -7830,12 +7830,12 @@ async function listProfiles(paths, environment) {
7830
7830
  const selectedNames = selected === void 0 || selected === "" ? names : [selected];
7831
7831
  const inspected = [];
7832
7832
  for (const name of selectedNames) {
7833
- const dir = join(paths.profilesDir, name);
7833
+ const dir = join(paths3.profilesDir, name);
7834
7834
  const missingPackages = [];
7835
7835
  for (const packageName of REQUIRED_PACKAGES) {
7836
7836
  const parts = packageName.split("/");
7837
7837
  const localManifest = join(dir, "node_modules", ...parts, "package.json");
7838
- const parentManifest = join(paths.profilesDir, "node_modules", ...parts, "package.json");
7838
+ const parentManifest = join(paths3.profilesDir, "node_modules", ...parts, "package.json");
7839
7839
  if (await readIfExists(localManifest) === void 0 && await readIfExists(parentManifest) === void 0) {
7840
7840
  missingPackages.push(packageName);
7841
7841
  }
@@ -7852,7 +7852,7 @@ async function listProfiles(paths, environment) {
7852
7852
  function installCommand(profile) {
7853
7853
  return `dsh plugin --profile ${profile} add ${DSH_HOOKS_PACKAGE}@${DSH_PINNED_VERSION} ${DSH_HOOK_PROTOCOL_PACKAGE}@${DSH_PINNED_VERSION}`;
7854
7854
  }
7855
- async function profileIsWired(profile, paths) {
7855
+ async function profileIsWired(profile, paths3) {
7856
7856
  if (profile.missingPackages.length > 0)
7857
7857
  return false;
7858
7858
  const buffer = await readIfExists(profile.patchFile);
@@ -7869,18 +7869,18 @@ async function profileIsWired(profile, paths) {
7869
7869
  const entries = tryParsePatchEntries(text, profile.patchFile);
7870
7870
  if (entries === void 0 || !hasWingmanRow(entries))
7871
7871
  return false;
7872
- return await readIfExists(paths.hooksConfigFile) !== void 0;
7872
+ return await readIfExists(paths3.hooksConfigFile) !== void 0;
7873
7873
  }
7874
7874
  async function dshHookInstallReport(options, environment = process.env) {
7875
- const paths = resolveDshHookPaths(options);
7876
- const profiles = await listProfiles(paths, environment);
7875
+ const paths3 = resolveDshHookPaths(options);
7876
+ const profiles = await listProfiles(paths3, environment);
7877
7877
  const reports = [];
7878
7878
  for (const profile of profiles) {
7879
7879
  const missingPackages = [...profile.missingPackages];
7880
7880
  const blockPresent = hasLiveHooksBlock(await readIfExists(profile.patchFile));
7881
7881
  const report = {
7882
7882
  profile: profile.name,
7883
- wired: await profileIsWired(profile, paths),
7883
+ wired: await profileIsWired(profile, paths3),
7884
7884
  blockPresent,
7885
7885
  missingPackages
7886
7886
  };
@@ -7890,16 +7890,16 @@ async function dshHookInstallReport(options, environment = process.env) {
7890
7890
  }
7891
7891
  return { profiles: reports };
7892
7892
  }
7893
- function prepareInstalledProfile(profile, paths, before, previous) {
7893
+ function prepareInstalledProfile(profile, paths3, before, previous) {
7894
7894
  const currentText = before === void 0 ? void 0 : decodeUtf8Strict(before, profile.patchFile);
7895
7895
  const surgicalText = currentText === void 0 ? void 0 : stripLiveHooksBlocks(currentText, profile.patchFile);
7896
7896
  const entriesBefore = surgicalText === void 0 ? [] : parsePatchEntries(surgicalText, profile.patchFile);
7897
7897
  if (hasWingmanRow(entriesBefore)) {
7898
7898
  throw new Error(`\u62D2\u5199:${profile.patchFile} \u5DF2\u6709\u672A\u5E26 wingman \u6807\u8BB0\u7684 ${DSH_HOOK_ROW_ID} \u6761\u76EE(\u7591\u624B\u5DE5\u6284\u5165),\u8BF7\u5148\u624B\u5DE5\u79FB\u9664`);
7899
7899
  }
7900
- const composed = composeInstalledText(surgicalText, entriesBefore.length, buildPatchBlock(paths.hooksConfigFile));
7900
+ const composed = composeInstalledText(surgicalText, entriesBefore.length, buildPatchBlock(paths3.hooksConfigFile));
7901
7901
  const composedEntries = parsePatchEntries(composed, profile.patchFile);
7902
- const expected = [...entriesBefore, expectedEntry(paths.hooksConfigFile)];
7902
+ const expected = [...entriesBefore, expectedEntry(paths3.hooksConfigFile)];
7903
7903
  if (JSON.stringify(composedEntries) !== JSON.stringify(expected)) {
7904
7904
  throw new Error(`\u62D2\u5199:${profile.patchFile} \u8FFD\u52A0\u540E\u5F62\u72B6\u6821\u9A8C\u5931\u8D25(\u539F\u6587\u4EF6\u5F62\u6001\u65E0\u6CD5\u5B89\u5168\u8FFD\u52A0),\u4E0D\u731C`);
7905
7905
  }
@@ -7951,13 +7951,13 @@ function restoredFromSnapshot(after, state) {
7951
7951
  return false;
7952
7952
  return after.equals(Buffer2.from(state.original.bytesBase64, "base64"));
7953
7953
  }
7954
- async function applyMutations(paths, mutations) {
7954
+ async function applyMutations(paths3, mutations) {
7955
7955
  if (mutations.length === 0)
7956
7956
  return;
7957
- const backupDir = backupDirectory(paths);
7957
+ const backupDir = backupDirectory(paths3);
7958
7958
  for (const mutation of mutations) {
7959
7959
  if (mutation.before !== void 0) {
7960
- await backupPatchFile(paths, backupDir, mutation.file, mutation.before);
7960
+ await backupPatchFile(paths3, backupDir, mutation.file, mutation.before);
7961
7961
  }
7962
7962
  }
7963
7963
  for (const mutation of mutations) {
@@ -7970,22 +7970,22 @@ async function applyMutations(paths, mutations) {
7970
7970
  }
7971
7971
  }
7972
7972
  async function retireLegacyDshHomeHooks(options) {
7973
- const paths = resolveDshHookPaths(options);
7973
+ const paths3 = resolveDshHookPaths(options);
7974
7974
  try {
7975
- const before = await readIfExists(paths.patchFile);
7975
+ const before = await readIfExists(paths3.patchFile);
7976
7976
  if (!hasLiveHooksBlock(before))
7977
7977
  return { removed: false, restored: "none" };
7978
- const state = await readState(paths);
7978
+ const state = await readState(paths3);
7979
7979
  const candidate = state?.version === 1 ? { patchFile: state.patchFile, original: state.original } : state?.legacyHome;
7980
- const legacyState = candidate?.patchFile === paths.patchFile ? candidate : void 0;
7981
- const mutation = prepareRemoval(paths.patchFile, before, legacyState);
7980
+ const legacyState = candidate?.patchFile === paths3.patchFile ? candidate : void 0;
7981
+ const mutation = prepareRemoval(paths3.patchFile, before, legacyState);
7982
7982
  if (mutation === void 0)
7983
7983
  return { removed: false, restored: "none" };
7984
- await applyMutations(paths, [mutation]);
7984
+ await applyMutations(paths3, [mutation]);
7985
7985
  return {
7986
7986
  removed: true,
7987
7987
  restored: restoredFromSnapshot(mutation.after, legacyState) ? "byte-identical" : "surgical",
7988
- path: paths.patchFile
7988
+ path: paths3.patchFile
7989
7989
  };
7990
7990
  } catch {
7991
7991
  return {
@@ -7997,9 +7997,9 @@ async function installDshHooks(port, options, environment = process.env) {
7997
7997
  if (!Number.isInteger(port) || port < 1 || port > 65535) {
7998
7998
  throw new Error(`\u975E\u6CD5\u7AEF\u53E3:${String(port)}`);
7999
7999
  }
8000
- const paths = resolveDshHookPaths(options);
8001
- const profiles = await listProfiles(paths, environment);
8002
- const previousState = await readState(paths);
8000
+ const paths3 = resolveDshHookPaths(options);
8001
+ const profiles = await listProfiles(paths3, environment);
8002
+ const previousState = await readState(paths3);
8003
8003
  const previousProfiles = previousState?.version === 2 ? previousState.profiles : {};
8004
8004
  const nextProfiles = { ...previousProfiles };
8005
8005
  const mutations = [];
@@ -8007,7 +8007,7 @@ async function installDshHooks(port, options, environment = process.env) {
8007
8007
  for (const profile of profiles) {
8008
8008
  const before = await readIfExists(profile.patchFile);
8009
8009
  if (profile.missingPackages.length === 0) {
8010
- const prepared = prepareInstalledProfile(profile, paths, before, previousProfiles[profile.name]);
8010
+ const prepared = prepareInstalledProfile(profile, paths3, before, previousProfiles[profile.name]);
8011
8011
  nextProfiles[profile.name] = prepared.state;
8012
8012
  if (prepared.mutation !== void 0)
8013
8013
  mutations.push(prepared.mutation);
@@ -8021,19 +8021,19 @@ async function installDshHooks(port, options, environment = process.env) {
8021
8021
  }
8022
8022
  }
8023
8023
  let legacyHome = previousState?.version === 2 ? previousState.legacyHome : previousState?.version === 1 ? { patchFile: previousState.patchFile, original: previousState.original } : void 0;
8024
- const legacyBefore = await readIfExists(paths.patchFile);
8024
+ const legacyBefore = await readIfExists(paths3.patchFile);
8025
8025
  let migratedThisRun = false;
8026
8026
  if (hasLiveHooksBlock(legacyBefore)) {
8027
- const legacyText = decodeUtf8Strict(legacyBefore, paths.patchFile);
8028
- parsePatchEntries(legacyText, paths.patchFile);
8029
- const surgical = stripLiveHooksBlocks(legacyText, paths.patchFile);
8030
- const surgicalEntries = parsePatchEntries(surgical, paths.patchFile);
8027
+ const legacyText = decodeUtf8Strict(legacyBefore, paths3.patchFile);
8028
+ parsePatchEntries(legacyText, paths3.patchFile);
8029
+ const surgical = stripLiveHooksBlocks(legacyText, paths3.patchFile);
8030
+ const surgicalEntries = parsePatchEntries(surgical, paths3.patchFile);
8031
8031
  legacyHome ??= {
8032
- patchFile: paths.patchFile,
8032
+ patchFile: paths3.patchFile,
8033
8033
  original: { existed: true }
8034
8034
  };
8035
- const after = resolveRestoredBytes(surgical, surgicalEntries, legacyHome, paths.patchFile);
8036
- mutations.push({ file: paths.patchFile, before: legacyBefore, after });
8035
+ const after = resolveRestoredBytes(surgical, surgicalEntries, legacyHome, paths3.patchFile);
8036
+ mutations.push({ file: paths3.patchFile, before: legacyBefore, after });
8037
8037
  migratedThisRun = true;
8038
8038
  }
8039
8039
  const nextState = {
@@ -8046,38 +8046,38 @@ async function installDshHooks(port, options, environment = process.env) {
8046
8046
  const hasState = hasManagedProfiles || legacyHome !== void 0;
8047
8047
  const url = `http://127.0.0.1:${port}/hook?harness=dsh`;
8048
8048
  if (hasManagedProfiles) {
8049
- await writeOwnedFiles(paths, url);
8049
+ await writeOwnedFiles(paths3, url);
8050
8050
  if (hasState)
8051
- await writeState(paths, nextState);
8051
+ await writeState(paths3, nextState);
8052
8052
  else
8053
- await rm(paths.stateFile, { force: true });
8054
- await applyMutations(paths, mutations);
8053
+ await rm(paths3.stateFile, { force: true });
8054
+ await applyMutations(paths3, mutations);
8055
8055
  } else {
8056
- await applyMutations(paths, mutations);
8057
- await rm(paths.hooksConfigFile, { force: true });
8058
- await rm(paths.forwarderFile, { force: true });
8056
+ await applyMutations(paths3, mutations);
8057
+ await rm(paths3.hooksConfigFile, { force: true });
8058
+ await rm(paths3.forwarderFile, { force: true });
8059
8059
  if (hasState)
8060
- await writeState(paths, nextState);
8060
+ await writeState(paths3, nextState);
8061
8061
  else
8062
- await rm(paths.stateFile, { force: true });
8062
+ await rm(paths3.stateFile, { force: true });
8063
8063
  }
8064
8064
  return { migratedThisRun, removedProfiles };
8065
8065
  }
8066
8066
  async function uninstallDshHooks(options, environment = process.env) {
8067
- const paths = resolveDshHookPaths(options);
8068
- const state = await readState(paths);
8067
+ const paths3 = resolveDshHookPaths(options);
8068
+ const state = await readState(paths3);
8069
8069
  const stateProfiles = state?.version === 2 ? state.profiles : {};
8070
8070
  const selected = environment.WINGMAN_DSH_PROFILE;
8071
8071
  const inspectionEnvironment = { ...environment };
8072
8072
  delete inspectionEnvironment.WINGMAN_DSH_PROFILE;
8073
- const inspected = await listProfiles(paths, inspectionEnvironment);
8073
+ const inspected = await listProfiles(paths3, inspectionEnvironment);
8074
8074
  if (selected !== void 0 && selected !== "" && !inspected.some((profile) => profile.name === selected) && stateProfiles[selected] === void 0) {
8075
8075
  throw new Error(`dsh profile \u4E0D\u5B58\u5728\u6216\u7F3A package.json:${selected}`);
8076
8076
  }
8077
8077
  const targetNames = selected === void 0 || selected === "" ? [.../* @__PURE__ */ new Set([...inspected.map((profile) => profile.name), ...Object.keys(stateProfiles)])] : [selected];
8078
8078
  const remainingProfiles = { ...stateProfiles };
8079
8079
  for (const profile of inspected) {
8080
- if (!targetNames.includes(profile.name) && await profileIsWired(profile, paths)) {
8080
+ if (!targetNames.includes(profile.name) && await profileIsWired(profile, paths3)) {
8081
8081
  remainingProfiles[profile.name] ??= {
8082
8082
  patchFile: profile.patchFile,
8083
8083
  original: { existed: true }
@@ -8088,10 +8088,10 @@ async function uninstallDshHooks(options, environment = process.env) {
8088
8088
  const results = [];
8089
8089
  for (const name of targetNames) {
8090
8090
  const profileState = stateProfiles[name];
8091
- const file = profileState?.patchFile ?? join(paths.profilesDir, name, "cordis.patch.yml");
8091
+ const file = profileState?.patchFile ?? join(paths3.profilesDir, name, "cordis.patch.yml");
8092
8092
  const before = await readIfExists(file);
8093
8093
  const inspectedProfile = inspected.find((profile) => profile.name === name);
8094
- const wired = inspectedProfile === void 0 ? false : await profileIsWired(inspectedProfile, paths);
8094
+ const wired = inspectedProfile === void 0 ? false : await profileIsWired(inspectedProfile, paths3);
8095
8095
  const removal = prepareRemoval(file, before, profileState);
8096
8096
  if (removal !== void 0) {
8097
8097
  mutations.push(removal);
@@ -8105,31 +8105,31 @@ async function uninstallDshHooks(options, environment = process.env) {
8105
8105
  delete remainingProfiles[name];
8106
8106
  }
8107
8107
  const legacyState = state?.version === 1 ? { patchFile: state.patchFile, original: state.original } : state?.legacyHome;
8108
- const legacyFile = legacyState?.patchFile ?? paths.patchFile;
8108
+ const legacyFile = legacyState?.patchFile ?? paths3.patchFile;
8109
8109
  const legacyRemoval = prepareRemoval(legacyFile, await readIfExists(legacyFile), legacyState);
8110
8110
  if (legacyRemoval !== void 0)
8111
8111
  mutations.push(legacyRemoval);
8112
- await applyMutations(paths, mutations);
8112
+ await applyMutations(paths3, mutations);
8113
8113
  if (Object.keys(remainingProfiles).length > 0) {
8114
- await writeState(paths, {
8114
+ await writeState(paths3, {
8115
8115
  version: 2,
8116
8116
  port: state?.port ?? 7333,
8117
8117
  profiles: remainingProfiles
8118
8118
  });
8119
8119
  } else {
8120
- await rm(paths.hooksConfigFile, { force: true });
8121
- await rm(paths.forwarderFile, { force: true });
8122
- await rm(paths.stateFile, { force: true });
8120
+ await rm(paths3.hooksConfigFile, { force: true });
8121
+ await rm(paths3.forwarderFile, { force: true });
8122
+ await rm(paths3.stateFile, { force: true });
8123
8123
  }
8124
8124
  return { profiles: results };
8125
8125
  }
8126
8126
  async function detectDshLiveWiring(options, environment = process.env) {
8127
- const paths = resolveDshHookPaths(options);
8127
+ const paths3 = resolveDshHookPaths(options);
8128
8128
  const inspectionEnvironment = { ...environment };
8129
8129
  delete inspectionEnvironment.WINGMAN_DSH_PROFILE;
8130
- const profiles = await listProfiles(paths, inspectionEnvironment);
8130
+ const profiles = await listProfiles(paths3, inspectionEnvironment);
8131
8131
  for (const profile of profiles) {
8132
- if (await profileIsWired(profile, paths))
8132
+ if (await profileIsWired(profile, paths3))
8133
8133
  return true;
8134
8134
  }
8135
8135
  return false;
@@ -8193,17 +8193,19 @@ var init_feedback_url = __esm({
8193
8193
 
8194
8194
  // packages/core/dist/plan-protocol.js
8195
8195
  import { createHash as createHash2 } from "node:crypto";
8196
- function planProtocolBlockStart(version = PLAN_PROTOCOL_VERSION) {
8197
- return `<!-- >>> wingman plan protocol v${version} >>> -->`;
8196
+ function planProtocolBlockStart(version = PLAN_PROTOCOL_VERSION, scope = "project") {
8197
+ return `<!-- >>> wingman plan protocol ${scope === "user" ? "user " : ""}v${version} >>> -->`;
8198
8198
  }
8199
- function buildPlanProtocolBlock(version = PLAN_PROTOCOL_VERSION, text) {
8200
- let body = normalizeMarkdownLineEndings(text ?? KNOWN_PROTOCOL_TEXT.get(version) ?? "");
8199
+ function buildPlanProtocolBlock(version = PLAN_PROTOCOL_VERSION, text, scope = "project") {
8200
+ const known = scope === "user" ? KNOWN_USER_PROTOCOL_TEXT : KNOWN_PROTOCOL_TEXT;
8201
+ let body = normalizeMarkdownLineEndings(text ?? known.get(version) ?? "");
8201
8202
  if (body === "")
8202
8203
  throw new Error(`\u672A\u77E5 Plan Protocol \u7248\u672C v${version}\uFF0C\u4E14\u672A\u63D0\u4F9B\u6B63\u6587`);
8203
8204
  if (!body.endsWith("\n"))
8204
8205
  body += "\n";
8205
- return `${planProtocolBlockStart(version)}
8206
- ${body}${PLAN_PROTOCOL_BLOCK_END}
8206
+ const end = scope === "user" ? PLAN_PROTOCOL_USER_BLOCK_END : PLAN_PROTOCOL_BLOCK_END;
8207
+ return `${planProtocolBlockStart(version, scope)}
8208
+ ${body}${end}
8207
8209
  `;
8208
8210
  }
8209
8211
  function decodeUtf8Strict2(bytes, sourcePath = "<memory>") {
@@ -8224,9 +8226,17 @@ function preferredMarkdownLineEnding(text) {
8224
8226
  const hasBareLf = text.replaceAll("\r\n", "").includes("\n");
8225
8227
  return hasCrlf && !hasBareLf ? "\r\n" : "\n";
8226
8228
  }
8227
- function splitPlanProtocolBlock(text, sourcePath = "<memory>") {
8228
- const starts = [...text.matchAll(BLOCK_START)];
8229
- const ends = allIndexesOf(text, PLAN_PROTOCOL_BLOCK_END);
8229
+ function splitPlanProtocolBlock(text, sourcePath = "<memory>", scope = "project") {
8230
+ const startPattern = scope === "user" ? USER_BLOCK_START : BLOCK_START;
8231
+ const endMarker = scope === "user" ? PLAN_PROTOCOL_USER_BLOCK_END : PLAN_PROTOCOL_BLOCK_END;
8232
+ const starts = [...text.matchAll(startPattern)];
8233
+ const ends = allIndexesOf(text, endMarker);
8234
+ if (scope === "user") {
8235
+ const unrecognized = text.replace(startPattern, "").replaceAll(endMarker, "");
8236
+ if (/<!--\s*(?:>>>|<<<)\s*wingman plan protocol user\b/u.test(unrecognized)) {
8237
+ throw new Error(`wingman plan protocol user \u672A\u77E5\u6807\u8BB0\u683C\u5F0F(${sourcePath})`);
8238
+ }
8239
+ }
8230
8240
  if (starts.length === 0 && ends.length === 0) {
8231
8241
  return { before: text, after: "", remainder: text };
8232
8242
  }
@@ -8238,7 +8248,7 @@ function splitPlanProtocolBlock(text, sourcePath = "<memory>") {
8238
8248
  if (start === void 0 || endMark === void 0 || endMark < start.index) {
8239
8249
  throw new Error(`wingman plan protocol \u6807\u8BB0\u5757\u6B8B\u7F3A(${sourcePath})`);
8240
8250
  }
8241
- let end = endMark + PLAN_PROTOCOL_BLOCK_END.length;
8251
+ let end = endMark + endMarker.length;
8242
8252
  if (text.startsWith("\r\n", end))
8243
8253
  end += 2;
8244
8254
  else if (text[end] === "\n")
@@ -8253,15 +8263,17 @@ function splitPlanProtocolBlock(text, sourcePath = "<memory>") {
8253
8263
  version: Number(start[1])
8254
8264
  };
8255
8265
  }
8256
- function inspectPlanProtocolBlock(block) {
8266
+ function inspectPlanProtocolBlock(block, scope = "project") {
8257
8267
  const normalized = normalizeMarkdownLineEndings(block);
8258
- const split = splitPlanProtocolBlock(normalized);
8268
+ const split = splitPlanProtocolBlock(normalized, "<memory>", scope);
8259
8269
  const version = split.version;
8260
- const knownText = version === void 0 ? void 0 : KNOWN_PROTOCOL_TEXT.get(version);
8261
- const knownBlock = version === void 0 || knownText === void 0 ? void 0 : buildPlanProtocolBlock(version, knownText);
8270
+ const currentVersion = scope === "user" ? PLAN_PROTOCOL_USER_VERSION : PLAN_PROTOCOL_VERSION;
8271
+ const knownTexts = scope === "user" ? KNOWN_USER_PROTOCOL_TEXT : KNOWN_PROTOCOL_TEXT;
8272
+ const knownText = version === void 0 ? void 0 : knownTexts.get(version);
8273
+ const knownBlock = version === void 0 || knownText === void 0 ? void 0 : buildPlanProtocolBlock(version, knownText, scope);
8262
8274
  const known = split.before === "" && split.after === "" && normalized === knownBlock;
8263
8275
  return {
8264
- kind: known && version === PLAN_PROTOCOL_VERSION ? "current" : known ? "legacy" : "modified",
8276
+ kind: known && version === currentVersion ? "current" : known ? "outdated" : "modified",
8265
8277
  ...version !== void 0 ? { version } : {},
8266
8278
  sha256: sha256Hex(normalized)
8267
8279
  };
@@ -8272,7 +8284,7 @@ function inspectPlanProtocolFile(bytes, sourcePath = "<memory>") {
8272
8284
  for (const [version, text] of KNOWN_PROTOCOL_TEXT) {
8273
8285
  if (sha256 === sha256Hex(text)) {
8274
8286
  return {
8275
- kind: version === PLAN_PROTOCOL_VERSION ? "current" : "legacy",
8287
+ kind: version === PLAN_PROTOCOL_VERSION ? "current" : "outdated",
8276
8288
  version,
8277
8289
  sha256
8278
8290
  };
@@ -8287,12 +8299,37 @@ function allIndexesOf(text, needle) {
8287
8299
  }
8288
8300
  return indexes;
8289
8301
  }
8290
- var PLAN_PROTOCOL_VERSION, PLAN_PROTOCOL_TEXT, PLAN_PROTOCOL_BLOCK_END, LEGACY_PLAN_PROTOCOL_TEXT, KNOWN_PROTOCOL_TEXT, BLOCK_START;
8302
+ function mergePlanProtocolBlock(text, block, sourcePath = "<memory>", scope = "project") {
8303
+ const split = splitPlanProtocolBlock(text, sourcePath, scope);
8304
+ const lineEnding = preferredMarkdownLineEnding(text);
8305
+ const normalizedBlock = normalizeMarkdownLineEndings(block).replaceAll("\n", lineEnding);
8306
+ if (split.block !== void 0)
8307
+ return split.before + normalizedBlock + split.after;
8308
+ if (text === "")
8309
+ return normalizedBlock;
8310
+ let before = text;
8311
+ if (!before.endsWith("\n"))
8312
+ before += lineEnding;
8313
+ if (!before.endsWith(`${lineEnding}${lineEnding}`))
8314
+ before += lineEnding;
8315
+ return before + normalizedBlock;
8316
+ }
8317
+ var PLAN_PROTOCOL_VERSION, PLAN_PROTOCOL_USER_VERSION, PLAN_PROTOCOL_TEXT, PLAN_PROTOCOL_TEXT_USER, PLAN_PROTOCOL_TEXT_V1, PLAN_PROTOCOL_TEXT_USER_V1, PLAN_PROTOCOL_USER_BLOCK_END, PLAN_PROTOCOL_BLOCK_END, LEGACY_PLAN_PROTOCOL_TEXT, KNOWN_PROTOCOL_TEXT, KNOWN_USER_PROTOCOL_TEXT, BLOCK_START, USER_BLOCK_START;
8291
8318
  var init_plan_protocol = __esm({
8292
8319
  "packages/core/dist/plan-protocol.js"() {
8293
8320
  "use strict";
8294
- PLAN_PROTOCOL_VERSION = 1;
8295
- PLAN_PROTOCOL_TEXT = `Wingman plan protocol v1 \u2014 a behavioral convention, not a gate. Wingman only reads; it never replies to you.
8321
+ PLAN_PROTOCOL_VERSION = 2;
8322
+ PLAN_PROTOCOL_USER_VERSION = 2;
8323
+ PLAN_PROTOCOL_TEXT = `Wingman plan protocol v2 \u2014 a behavioral convention, not a gate. Wingman only reads; it never replies to you.
8324
+ - The project root is the directory that contains this instruction file (for Claude Code: the parent of \`.claude/\`).
8325
+ - Before starting work, read \`<project root>/.wingman/plan.md\`. If it does not exist, create it: a \`# Title\` line, immediately followed by \`\u76EE\u6807: <one sentence, what done looks like>\` (or \`Goal:\`), then a nested checkbox tree of steps; add an indented \`Verify:\` line to the steps whose completion a person would want to check; not every step needs one.
8326
+ - As soon as the scope is clear (after any clarifying questions), create the plan file before doing the first step. Mark a step \`[/]\` right before you start it and \`[x]\` right after it is done; do not write the whole plan as finished afterwards. Add sub-steps under your current step as you learn more. Mark abandoned steps \`[-]\` and steps that need the user's decision \`[?]\`.
8327
+ - Re-read the file before every write; change only your own lines; never reorder or rewrite other entries. Use your file-editing tool, not shell redirection.
8328
+ - Keep your in-session todo list as sub-steps of the \`[/]\` step; do not copy the whole file into it.
8329
+ - Never put secrets, credentials, or personal data in the plan.
8330
+ `;
8331
+ PLAN_PROTOCOL_TEXT_USER = PLAN_PROTOCOL_TEXT.replace(/^- The project root .*$/mu, "- The project root is the nearest git root containing the current working directory, or the current working directory when there is no git root. If the current working directory is the user\u2019s home directory, you MUST NOT create a plan file. Only multi-step tasks use the plan workflow below; single-turn questions do not create or update a plan file.");
8332
+ PLAN_PROTOCOL_TEXT_V1 = `Wingman plan protocol v1 \u2014 a behavioral convention, not a gate. Wingman only reads; it never replies to you.
8296
8333
  - The project root is the directory that contains this instruction file (for Claude Code: the parent of \`.claude/\`).
8297
8334
  - Before starting work, read \`<project root>/.wingman/plan.md\`. If it does not exist, create it: a \`# Title\` line, then a nested checkbox tree of steps, each step with an indented \`Verify:\` line describing how it will be checked.
8298
8335
  - Mark the step you are working on \`[/]\` and add sub-steps under it as you learn more. Mark finished steps \`[x]\`, abandoned steps \`[-]\`, and steps that need the user's decision \`[?]\`.
@@ -8300,13 +8337,169 @@ var init_plan_protocol = __esm({
8300
8337
  - Keep your in-session todo list as sub-steps of the \`[/]\` step; do not copy the whole file into it.
8301
8338
  - Never put secrets, credentials, or personal data in the plan.
8302
8339
  `;
8340
+ PLAN_PROTOCOL_TEXT_USER_V1 = PLAN_PROTOCOL_TEXT_V1.replace(/^- The project root .*$/mu, "- The project root is the nearest git root containing the current working directory, or the current working directory when there is no git root. If the current working directory is the user\u2019s home directory, you MUST NOT create a plan file. Only multi-step tasks use the plan workflow below; single-turn questions do not create or update a plan file.");
8341
+ PLAN_PROTOCOL_USER_BLOCK_END = "<!-- <<< wingman plan protocol user <<< -->";
8303
8342
  PLAN_PROTOCOL_BLOCK_END = "<!-- <<< wingman plan protocol <<< -->";
8304
8343
  LEGACY_PLAN_PROTOCOL_TEXT = "Wingman plan protocol v0 \u2014 legacy fixture text.\n";
8305
8344
  KNOWN_PROTOCOL_TEXT = /* @__PURE__ */ new Map([
8306
8345
  [0, LEGACY_PLAN_PROTOCOL_TEXT],
8346
+ [1, PLAN_PROTOCOL_TEXT_V1],
8307
8347
  [PLAN_PROTOCOL_VERSION, PLAN_PROTOCOL_TEXT]
8308
8348
  ]);
8349
+ KNOWN_USER_PROTOCOL_TEXT = /* @__PURE__ */ new Map([
8350
+ [1, PLAN_PROTOCOL_TEXT_USER_V1],
8351
+ [PLAN_PROTOCOL_USER_VERSION, PLAN_PROTOCOL_TEXT_USER]
8352
+ ]);
8309
8353
  BLOCK_START = /<!-- >>> wingman plan protocol v(\d+) >>> -->/gu;
8354
+ USER_BLOCK_START = /<!-- >>> wingman plan protocol user v(\d+) >>> -->/gu;
8355
+ }
8356
+ });
8357
+
8358
+ // packages/core/dist/plan-protocol-user.js
8359
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
8360
+ import { basename as basename2, dirname as dirname2, join as join2 } from "node:path";
8361
+ function readTarget(targetPath2) {
8362
+ if (!existsSync(targetPath2))
8363
+ return void 0;
8364
+ const bytes = readFileSync(targetPath2);
8365
+ decodeUtf8Strict2(bytes, targetPath2);
8366
+ const text = bytes.toString("utf8");
8367
+ const split = splitPlanProtocolBlock(text, targetPath2, "user");
8368
+ const identity = split.block === void 0 ? void 0 : inspectPlanProtocolBlock(split.block, "user");
8369
+ return { bytes, text, split, identity };
8370
+ }
8371
+ function statusPlanProtocolUser(targetPath2) {
8372
+ try {
8373
+ const identity = readTarget(targetPath2)?.identity;
8374
+ return {
8375
+ targetPath: targetPath2,
8376
+ state: identity === void 0 ? "missing" : identity.kind === "current" ? "installed" : identity.kind,
8377
+ ...identity?.version !== void 0 ? { version: identity.version } : {},
8378
+ ...identity?.kind === "modified" ? { reason: "\u7528\u6237\u7EA7\u53D7\u7BA1\u5757\u5DF2\u88AB\u4FEE\u6539" } : {}
8379
+ };
8380
+ } catch (error) {
8381
+ return { targetPath: targetPath2, state: "modified", reason: error.message };
8382
+ }
8383
+ }
8384
+ function installPlanProtocolUser(paths3) {
8385
+ const existing = readTarget(paths3.targetPath);
8386
+ assertKnown(existing, paths3.targetPath);
8387
+ const before = existing?.text ?? "";
8388
+ if (existing?.identity?.kind === "current") {
8389
+ return result(paths3.targetPath, "install", "installed", before, before, true, false);
8390
+ }
8391
+ const statePath2 = snapshotPath(paths3);
8392
+ const prior = readSnapshot(statePath2, paths3.targetPath);
8393
+ const outdated = existing?.identity?.kind === "outdated";
8394
+ const block = buildPlanProtocolBlock(PLAN_PROTOCOL_USER_VERSION, void 0, "user");
8395
+ const after = mergePlanProtocolBlock(before, block, paths3.targetPath, "user");
8396
+ const backupDir = nextBackupDir(paths3.homeDir);
8397
+ if (!paths3.dryRun) {
8398
+ backupTarget(backupDir, paths3.targetPath, existing?.bytes);
8399
+ const snapshot = {
8400
+ version: 1,
8401
+ targetPath: paths3.targetPath,
8402
+ installedRemainderSha256: sha256Hex(splitPlanProtocolBlock(after, paths3.targetPath, "user").remainder),
8403
+ original: existing === void 0 || outdated && existing.split.remainder === "" ? { existed: false } : {
8404
+ existed: true,
8405
+ base64: (outdated ? Buffer.from(existing.split.remainder) : existing.bytes).toString("base64")
8406
+ }
8407
+ };
8408
+ if (!outdated || prior === void 0) {
8409
+ mkdirSync(dirname2(statePath2), { recursive: true });
8410
+ writeFileSync(statePath2, `${JSON.stringify(snapshot, null, 2)}
8411
+ `);
8412
+ }
8413
+ mkdirSync(dirname2(paths3.targetPath), { recursive: true });
8414
+ writeFileSync(paths3.targetPath, after);
8415
+ }
8416
+ return {
8417
+ ...result(paths3.targetPath, "install", outdated ? "outdated" : "missing", before, after, true, true),
8418
+ state: "installed",
8419
+ version: PLAN_PROTOCOL_USER_VERSION,
8420
+ backupDir
8421
+ };
8422
+ }
8423
+ function uninstallPlanProtocolUser(paths3) {
8424
+ const existing = readTarget(paths3.targetPath);
8425
+ assertKnown(existing, paths3.targetPath);
8426
+ const before = existing?.text ?? "";
8427
+ if (existing?.identity === void 0) {
8428
+ return result(paths3.targetPath, "uninstall", "missing", before, before, existing !== void 0, false);
8429
+ }
8430
+ const statePath2 = snapshotPath(paths3);
8431
+ const snapshot = readSnapshot(statePath2, paths3.targetPath);
8432
+ const canRestore = snapshot !== void 0 && sha256Hex(existing.split.remainder) === snapshot.installedRemainderSha256;
8433
+ const restored = canRestore && snapshot.original.existed ? Buffer.from(snapshot.original.base64 ?? "", "base64") : void 0;
8434
+ const afterExists = canRestore ? snapshot.original.existed : existing.split.remainder !== "";
8435
+ const after = afterExists ? restored?.toString("utf8") ?? existing.split.remainder : "";
8436
+ const backupDir = nextBackupDir(paths3.homeDir);
8437
+ if (!paths3.dryRun) {
8438
+ backupTarget(backupDir, paths3.targetPath, existing.bytes);
8439
+ if (afterExists)
8440
+ writeFileSync(paths3.targetPath, restored ?? after);
8441
+ else
8442
+ rmSync(paths3.targetPath);
8443
+ rmSync(statePath2, { force: true });
8444
+ }
8445
+ return {
8446
+ ...result(paths3.targetPath, "uninstall", existing.identity.kind === "outdated" ? "outdated" : "installed", before, after, afterExists, true),
8447
+ state: "missing",
8448
+ backupDir,
8449
+ restoredOriginal: canRestore
8450
+ };
8451
+ }
8452
+ function assertKnown(existing, targetPath2) {
8453
+ if (existing?.identity?.kind === "modified") {
8454
+ throw new Error(`${targetPath2}: \u7528\u6237\u7EA7\u53D7\u7BA1\u5757\u5DF2\u88AB\u4FEE\u6539\u6216\u7248\u672C\u672A\u77E5\uFF0C\u62D2\u5199\u5E76\u4FDD\u7559\u7528\u6237\u5185\u5BB9`);
8455
+ }
8456
+ }
8457
+ function result(targetPath2, operation, previousState, before, after, afterExists, changed) {
8458
+ return {
8459
+ targetPath: targetPath2,
8460
+ operation,
8461
+ previousState,
8462
+ state: previousState,
8463
+ before,
8464
+ after,
8465
+ afterExists,
8466
+ changed,
8467
+ effectiveAt: "next_session",
8468
+ totalBytes: Buffer.byteLength(after)
8469
+ };
8470
+ }
8471
+ function snapshotPath(paths3) {
8472
+ return join2(paths3.homeDir, ".wingman", "state", `plan-protocol-user-${sha256Hex(paths3.targetPath)}.json`);
8473
+ }
8474
+ function readSnapshot(statePath2, targetPath2) {
8475
+ if (!existsSync(statePath2))
8476
+ return void 0;
8477
+ try {
8478
+ const value = JSON.parse(readFileSync(statePath2, "utf8"));
8479
+ if (value.version === 1 && value.targetPath === targetPath2 && typeof value.installedRemainderSha256 === "string" && /^[a-f0-9]{64}$/u.test(value.installedRemainderSha256) && typeof value.original?.existed === "boolean" && (value.original.existed ? typeof value.original.base64 === "string" && Buffer.from(value.original.base64, "base64").toString("base64") === value.original.base64 : value.original.base64 === void 0)) {
8480
+ return value;
8481
+ }
8482
+ } catch {
8483
+ }
8484
+ throw new Error(`\u7528\u6237\u7EA7\u534F\u8BAE\u5FEB\u7167\u683C\u5F0F\u672A\u77E5(${statePath2})\uFF0C\u62D2\u5199\u5E76\u4FDD\u7559\u7528\u6237\u5185\u5BB9`);
8485
+ }
8486
+ function nextBackupDir(homeDir) {
8487
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replaceAll(":", "-");
8488
+ const root = join2(homeDir, ".wingman", "backups");
8489
+ let dir = join2(root, stamp);
8490
+ for (let n = 2; existsSync(dir); n += 1)
8491
+ dir = join2(root, `${stamp}-${n}`);
8492
+ return dir;
8493
+ }
8494
+ function backupTarget(backupDir, targetPath2, bytes) {
8495
+ mkdirSync(backupDir, { recursive: true });
8496
+ if (bytes !== void 0)
8497
+ writeFileSync(join2(backupDir, basename2(targetPath2)), bytes);
8498
+ }
8499
+ var init_plan_protocol_user = __esm({
8500
+ "packages/core/dist/plan-protocol-user.js"() {
8501
+ "use strict";
8502
+ init_plan_protocol();
8310
8503
  }
8311
8504
  });
8312
8505
 
@@ -8492,6 +8685,7 @@ var init_dist = __esm({
8492
8685
  "use strict";
8493
8686
  init_feedback_url();
8494
8687
  init_plan_protocol();
8688
+ init_plan_protocol_user();
8495
8689
  init_refscan();
8496
8690
  SLOT_IDS = ["base", "rules", "skills", "tools", "gates", "history"];
8497
8691
  HARNESS_IDS = ["cc", "codex", "dsh"];
@@ -8521,7 +8715,7 @@ var init_dist = __esm({
8521
8715
  import { Buffer as Buffer3 } from "node:buffer";
8522
8716
  import { randomBytes } from "node:crypto";
8523
8717
  import { mkdir as mkdir2, rm as rm2, writeFile as writeFile2 } from "node:fs/promises";
8524
- import { dirname as dirname2, isAbsolute as isAbsolute2, join as join2, relative as relative2 } from "node:path";
8718
+ import { dirname as dirname3, isAbsolute as isAbsolute2, join as join3, relative as relative2 } from "node:path";
8525
8719
  function buildToggleBlock(instanceId, flags) {
8526
8720
  const lines2 = [`${TOGGLE_BEGIN_PREFIX}${instanceId}${TOGGLE_BEGIN_SUFFIX}`];
8527
8721
  if (flags.fileCreated)
@@ -8782,15 +8976,15 @@ async function planDshToggle(action, dump, options) {
8782
8976
  if (row.id === DSH_HOOK_ROW_ID && row.name === DSH_HOOKS_PACKAGE) {
8783
8977
  throw new Error(`\u300C${row.name}\u300D(${row.id})\u7531 Wingman \u5B9E\u51B5\u63A5\u7EBF(live hooks \u5757)\u5F15\u5165,\u8BF7\u7528 \`wingman hook uninstall dsh\` \u7BA1\u7406,\u4E0D\u8D70\u5F00\u5173`);
8784
8978
  }
8785
- const paths = resolveDshHookPaths(options);
8786
- const buffer = await readIfExists(paths.patchFile);
8787
- const text = buffer === void 0 ? void 0 : decodeUtf8Strict(buffer, paths.patchFile);
8788
- const blocks = text === void 0 ? [] : findToggleBlocks(text, paths.patchFile);
8979
+ const paths3 = resolveDshHookPaths(options);
8980
+ const buffer = await readIfExists(paths3.patchFile);
8981
+ const text = buffer === void 0 ? void 0 : decodeUtf8Strict(buffer, paths3.patchFile);
8982
+ const blocks = text === void 0 ? [] : findToggleBlocks(text, paths3.patchFile);
8789
8983
  const myBlock = blocks.find((b) => b.instanceId === row.id);
8790
- const entriesAll = text === void 0 ? [] : parsePatchEntries(text, paths.patchFile);
8984
+ const entriesAll = text === void 0 ? [] : parsePatchEntries(text, paths3.patchFile);
8791
8985
  const outsideToggle = text === void 0 ? "" : stripAllToggleBlocks(text, blocks);
8792
- const entriesOutsideToggle = text === void 0 ? [] : parsePatchEntries(outsideToggle, paths.patchFile);
8793
- const entriesUser = text === void 0 ? [] : parsePatchEntries(stripHooksBlocks(outsideToggle), paths.patchFile);
8986
+ const entriesOutsideToggle = text === void 0 ? [] : parsePatchEntries(outsideToggle, paths3.patchFile);
8987
+ const entriesUser = text === void 0 ? [] : parsePatchEntries(stripHooksBlocks(outsideToggle), paths3.patchFile);
8794
8988
  const refInUser = referencesInstanceId(entriesUser, row.id);
8795
8989
  const refInHooks = !refInUser && referencesInstanceId(entriesOutsideToggle, row.id);
8796
8990
  if (refInHooks) {
@@ -8802,36 +8996,36 @@ async function planDshToggle(action, dump, options) {
8802
8996
  throw new Error(`\u300C${row.name}\u300D(${row.id})\u5DF2\u7531 Wingman \u5173\u95ED(dsh \u4E0B\u6B21\u542F\u52A8\u751F\u6548);\u5982\u9700\u6062\u590D\u8BF7 toggle on`);
8803
8997
  }
8804
8998
  if (refInUser) {
8805
- throw new Error(`${paths.patchFile} \u5DF2\u6709\u7528\u6237\u81EA\u5DF1\u7684 ${row.id} \u6761\u76EE,\u4E0D\u731C\u5408\u5E76:\u8BF7\u624B\u5DE5\u5904\u7406\u8BE5\u6761\u76EE\u540E\u518D\u8BD5`);
8999
+ throw new Error(`${paths3.patchFile} \u5DF2\u6709\u7528\u6237\u81EA\u5DF1\u7684 ${row.id} \u6761\u76EE,\u4E0D\u731C\u5408\u5E76:\u8BF7\u624B\u5DE5\u5904\u7406\u8BE5\u6761\u76EE\u540E\u518D\u8BD5`);
8806
9000
  }
8807
9001
  if (row.disabled === true) {
8808
9002
  throw new Error(`\u300C${row.name}\u300D(${row.id})\u5DF2\u5728 ${item.source} \u5C42\u88AB\u7981\u7528(\u539F\u751F\u7981\u7528\u975E Wingman \u6240\u8F96),\u65E0\u9700\u518D\u5173`);
8809
9003
  }
8810
9004
  const composed = composeToggleOff(text, row.id, entriesAll.length);
8811
9005
  const expected = JSON.stringify([...entriesAll, { id: row.id, disabled: true }]);
8812
- if (JSON.stringify(parsePatchEntries(composed.after, paths.patchFile)) !== expected) {
8813
- throw new Error(`\u62D2\u5199:${paths.patchFile} \u8FFD\u52A0\u540E\u5F62\u72B6\u6821\u9A8C\u5931\u8D25(\u539F\u6587\u4EF6\u5F62\u6001\u65E0\u6CD5\u5B89\u5168\u8FFD\u52A0),\u4E0D\u731C`);
9006
+ if (JSON.stringify(parsePatchEntries(composed.after, paths3.patchFile)) !== expected) {
9007
+ throw new Error(`\u62D2\u5199:${paths3.patchFile} \u8FFD\u52A0\u540E\u5F62\u72B6\u6821\u9A8C\u5931\u8D25(\u539F\u6587\u4EF6\u5F62\u6001\u65E0\u6CD5\u5B89\u5168\u8FFD\u52A0),\u4E0D\u731C`);
8814
9008
  }
8815
- change = composed.kind === "create" || text === void 0 ? { file: paths.patchFile, kind: "create", after: composed.after } : { file: paths.patchFile, kind: "modify", before: text, after: composed.after };
9009
+ change = composed.kind === "create" || text === void 0 ? { file: paths3.patchFile, kind: "create", after: composed.after } : { file: paths3.patchFile, kind: "modify", before: text, after: composed.after };
8816
9010
  } else {
8817
9011
  if (myBlock === void 0 || text === void 0) {
8818
9012
  if (refInUser) {
8819
- throw new Error(`${paths.patchFile} \u5DF2\u6709\u7528\u6237\u81EA\u5DF1\u7684 ${row.id} \u6761\u76EE,\u4E0D\u731C\u5408\u5E76:\u8BF7\u624B\u5DE5\u5904\u7406\u8BE5\u6761\u76EE\u540E\u518D\u8BD5`);
9013
+ throw new Error(`${paths3.patchFile} \u5DF2\u6709\u7528\u6237\u81EA\u5DF1\u7684 ${row.id} \u6761\u76EE,\u4E0D\u731C\u5408\u5E76:\u8BF7\u624B\u5DE5\u5904\u7406\u8BE5\u6761\u76EE\u540E\u518D\u8BD5`);
8820
9014
  }
8821
9015
  if (row.disabled === true) {
8822
9016
  throw new Error(`\u300C${row.name}\u300D(${row.id})\u5728 ${item.source} \u5C42\u88AB\u539F\u751F\u7981\u7528,\u975E Wingman \u6240\u8F96:\u8BF7\u5230\u8BE5\u5C42(bundle/profile \u914D\u7F6E)\u4FEE\u6539`);
8823
9017
  }
8824
9018
  throw new Error(`\u300C${row.name}\u300D(${row.id})\u5DF2\u662F\u542F\u7528\u72B6\u6001,\u65E0\u9700 toggle on`);
8825
9019
  }
8826
- const composed = composeToggleOn(text, myBlock, paths.patchFile);
8827
- change = composed.kind === "delete" || composed.after === void 0 ? { file: paths.patchFile, kind: "delete", before: text } : { file: paths.patchFile, kind: "modify", before: text, after: composed.after };
9020
+ const composed = composeToggleOn(text, myBlock, paths3.patchFile);
9021
+ change = composed.kind === "delete" || composed.after === void 0 ? { file: paths3.patchFile, kind: "delete", before: text } : { file: paths3.patchFile, kind: "modify", before: text, after: composed.after };
8828
9022
  }
8829
9023
  return {
8830
9024
  harness: "dsh",
8831
9025
  action: toggle,
8832
9026
  writes: [change],
8833
- backupDir: join2(paths.backupsRoot, backupDirName()),
8834
- references: scanDshReferences(paths.patchFile, text, dump, row),
9027
+ backupDir: join3(paths3.backupsRoot, backupDirName()),
9028
+ references: scanDshReferences(paths3.patchFile, text, dump, row),
8835
9029
  // 生效时机:patch 层在 boot 时组装(composeProfile),保证下次启动生效;钉定版本
8836
9030
  // 还会 watchUserPatches 热重载家目录层,但该监听失败被静默吞掉(suppressShutdownError)
8837
9031
  // 且热拔插行为无兼容承诺 → 按宪法取保守值 next_session,如实不夸大。
@@ -8864,39 +9058,39 @@ function validatePlanShape(plan, patchFile, backupsRoot) {
8864
9058
  }
8865
9059
  async function applyDshToggle(plan, options) {
8866
9060
  try {
8867
- const paths = resolveDshHookPaths(options);
8868
- const { change } = validatePlanShape(plan, paths.patchFile, paths.backupsRoot);
8869
- const buffer = await readIfExists(paths.patchFile);
9061
+ const paths3 = resolveDshHookPaths(options);
9062
+ const { change } = validatePlanShape(plan, paths3.patchFile, paths3.backupsRoot);
9063
+ const buffer = await readIfExists(paths3.patchFile);
8870
9064
  if (change.kind === "create") {
8871
9065
  if (buffer !== void 0) {
8872
9066
  return {
8873
9067
  ok: false,
8874
- error: `${paths.patchFile} \u5728 plan \u4E4B\u540E\u88AB\u521B\u5EFA,\u4E0E plan \u524D\u63D0\u4E0D\u7B26:\u8BF7\u91CD\u65B0 plan`
9068
+ error: `${paths3.patchFile} \u5728 plan \u4E4B\u540E\u88AB\u521B\u5EFA,\u4E0E plan \u524D\u63D0\u4E0D\u7B26:\u8BF7\u91CD\u65B0 plan`
8875
9069
  };
8876
9070
  }
8877
9071
  } else {
8878
9072
  if (buffer === void 0) {
8879
9073
  return {
8880
9074
  ok: false,
8881
- error: `${paths.patchFile} \u5728 plan \u4E4B\u540E\u88AB\u5220\u9664,\u4E0E plan \u524D\u63D0\u4E0D\u7B26:\u8BF7\u91CD\u65B0 plan`
9075
+ error: `${paths3.patchFile} \u5728 plan \u4E4B\u540E\u88AB\u5220\u9664,\u4E0E plan \u524D\u63D0\u4E0D\u7B26:\u8BF7\u91CD\u65B0 plan`
8882
9076
  };
8883
9077
  }
8884
9078
  if (!buffer.equals(Buffer3.from(change.before ?? "", "utf8"))) {
8885
9079
  return {
8886
9080
  ok: false,
8887
- error: `${paths.patchFile} \u5728 plan \u4E4B\u540E\u88AB\u6539\u52A8,\u4E0E plan \u5FEB\u7167\u4E0D\u4E00\u81F4:\u8BF7\u91CD\u65B0 plan`
9081
+ error: `${paths3.patchFile} \u5728 plan \u4E4B\u540E\u88AB\u6539\u52A8,\u4E0E plan \u5FEB\u7167\u4E0D\u4E00\u81F4:\u8BF7\u91CD\u65B0 plan`
8888
9082
  };
8889
9083
  }
8890
9084
  }
8891
9085
  await mkdir2(plan.backupDir, { recursive: true });
8892
9086
  if (buffer !== void 0) {
8893
- await writeFile2(join2(plan.backupDir, "cordis.patch.yml"), buffer);
9087
+ await writeFile2(join3(plan.backupDir, "cordis.patch.yml"), buffer);
8894
9088
  }
8895
9089
  if (change.kind === "delete") {
8896
- await rm2(paths.patchFile);
9090
+ await rm2(paths3.patchFile);
8897
9091
  } else {
8898
- await mkdir2(dirname2(paths.patchFile), { recursive: true });
8899
- await writeFile2(paths.patchFile, change.after ?? "", "utf8");
9092
+ await mkdir2(dirname3(paths3.patchFile), { recursive: true });
9093
+ await writeFile2(paths3.patchFile, change.after ?? "", "utf8");
8900
9094
  }
8901
9095
  return { ok: true, backupDir: plan.backupDir };
8902
9096
  } catch (error) {
@@ -8925,55 +9119,55 @@ var init_toggle = __esm({
8925
9119
 
8926
9120
  // packages/adapter-dsh/dist/protocol.js
8927
9121
  import { execFileSync } from "node:child_process";
8928
- import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
9122
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
8929
9123
  import { homedir as homedir2 } from "node:os";
8930
- import { basename as basename2, dirname as dirname3, join as join3, resolve } from "node:path";
9124
+ import { basename as basename3, dirname as dirname4, join as join4, resolve } from "node:path";
8931
9125
  function protocolStatusDsh(options) {
8932
- const paths = resolveOptions(options);
8933
- if (!existsSync(paths.targetPath))
8934
- return status(paths.targetPath, "not_installed", options);
9126
+ const paths3 = resolveOptions(options);
9127
+ if (!existsSync2(paths3.targetPath))
9128
+ return status(paths3.targetPath, "not_installed", options);
8935
9129
  try {
8936
- const file = readAgents(paths.targetPath);
9130
+ const file = readAgents(paths3.targetPath);
8937
9131
  if (file.identity === void 0)
8938
- return status(paths.targetPath, "not_installed", options);
9132
+ return status(paths3.targetPath, "not_installed", options);
8939
9133
  const state = stateForIdentity(file.identity);
8940
- return status(paths.targetPath, state, options, file.identity);
9134
+ return status(paths3.targetPath, state, options, file.identity);
8941
9135
  } catch (error) {
8942
- return status(paths.targetPath, "invalid", options, void 0, error.message);
9136
+ return status(paths3.targetPath, "invalid", options, void 0, error.message);
8943
9137
  }
8944
9138
  }
8945
9139
  function installProtocolDsh(options) {
8946
- const paths = resolveOptions(options);
8947
- const existing = existsSync(paths.targetPath) ? readAgents(paths.targetPath) : void 0;
9140
+ const paths3 = resolveOptions(options);
9141
+ const existing = existsSync2(paths3.targetPath) ? readAgents(paths3.targetPath) : void 0;
8948
9142
  const previousState = stateForIdentity(existing?.identity);
8949
9143
  if (previousState === "installed") {
8950
- return overlayLoadState(result(paths.targetPath, "install", false, previousState, existing?.text ?? "", true), options);
9144
+ return overlayLoadState(result2(paths3.targetPath, "install", false, previousState, existing?.text ?? "", true), options);
8951
9145
  }
8952
9146
  if (previousState === "modified")
8953
- throw modifiedError(paths.targetPath, "\u5B89\u88C5");
9147
+ throw modifiedError(paths3.targetPath, "\u5B89\u88C5");
8954
9148
  const before = existing?.text ?? "";
8955
9149
  const lineEnding = preferredMarkdownLineEnding(before);
8956
9150
  const block = buildPlanProtocolBlock().replaceAll("\n", lineEnding);
8957
9151
  const after = existing?.split.block ? existing.split.before + block + existing.split.after : appendBlock(before, block, lineEnding);
8958
- const installedRemainder = splitPlanProtocolBlock(after, paths.targetPath).remainder;
8959
- const backupDir = nextBackupDir(paths.homeDir);
8960
- if (!paths.dryRun) {
8961
- const prior = readState2(paths.statePath, paths.targetPath);
8962
- backupTarget(backupDir, paths.targetPath, existing?.bytes);
8963
- writeState2(paths.statePath, {
9152
+ const installedRemainder = splitPlanProtocolBlock(after, paths3.targetPath).remainder;
9153
+ const backupDir = nextBackupDir2(paths3.homeDir);
9154
+ if (!paths3.dryRun) {
9155
+ const prior = readState2(paths3.statePath, paths3.targetPath);
9156
+ backupTarget2(backupDir, paths3.targetPath, existing?.bytes);
9157
+ writeState2(paths3.statePath, {
8964
9158
  version: 1,
8965
- projectDir: paths.projectDir,
8966
- targetPath: paths.targetPath,
9159
+ projectDir: paths3.projectDir,
9160
+ targetPath: paths3.targetPath,
8967
9161
  protocolVersion: PLAN_PROTOCOL_VERSION,
8968
9162
  installedAt: (/* @__PURE__ */ new Date()).toISOString(),
8969
9163
  backupDir,
8970
- installedRemainderSha256: sha256Hex(installedRemainder),
9164
+ installedRemainderSha256: previousState === "outdated" && prior !== void 0 ? prior.installedRemainderSha256 : sha256Hex(installedRemainder),
8971
9165
  original: prior?.original ?? (existing === void 0 ? { existed: false } : { existed: true, base64: existing.bytes.toString("base64") })
8972
9166
  });
8973
- writeFileSync(paths.targetPath, after);
9167
+ writeFileSync2(paths3.targetPath, after);
8974
9168
  }
8975
9169
  return overlayLoadState({
8976
- ...result(paths.targetPath, "install", true, previousState, before, true),
9170
+ ...result2(paths3.targetPath, "install", true, previousState, before, true),
8977
9171
  state: "installed",
8978
9172
  version: PLAN_PROTOCOL_VERSION,
8979
9173
  after,
@@ -8982,33 +9176,33 @@ function installProtocolDsh(options) {
8982
9176
  }, options);
8983
9177
  }
8984
9178
  function uninstallProtocolDsh(options) {
8985
- const paths = resolveOptions(options);
8986
- if (!existsSync(paths.targetPath)) {
8987
- return result(paths.targetPath, "uninstall", false, "not_installed", "", false);
9179
+ const paths3 = resolveOptions(options);
9180
+ if (!existsSync2(paths3.targetPath)) {
9181
+ return result2(paths3.targetPath, "uninstall", false, "not_installed", "", false);
8988
9182
  }
8989
- const existing = readAgents(paths.targetPath);
9183
+ const existing = readAgents(paths3.targetPath);
8990
9184
  if (existing.identity === void 0) {
8991
- return result(paths.targetPath, "uninstall", false, "not_installed", existing.text, true);
9185
+ return result2(paths3.targetPath, "uninstall", false, "not_installed", existing.text, true);
8992
9186
  }
8993
9187
  const previousState = stateForIdentity(existing.identity);
8994
9188
  if (previousState === "modified")
8995
- throw modifiedError(paths.targetPath, "\u5378\u8F7D");
8996
- const state = readState2(paths.statePath, paths.targetPath);
9189
+ throw modifiedError(paths3.targetPath, "\u5378\u8F7D");
9190
+ const state = readState2(paths3.statePath, paths3.targetPath);
8997
9191
  const canRestore = state !== void 0 && sha256Hex(existing.split.remainder) === state.installedRemainderSha256;
8998
9192
  const restored = canRestore ? originalBytes(state) : void 0;
8999
9193
  const deleteTarget = canRestore ? state?.original.existed === false : existing.split.remainder.trim() === "";
9000
9194
  const after = deleteTarget ? "" : restored?.toString("utf8") ?? existing.split.remainder;
9001
- const backupDir = nextBackupDir(paths.homeDir);
9002
- if (!paths.dryRun) {
9003
- backupTarget(backupDir, paths.targetPath, existing.bytes);
9195
+ const backupDir = nextBackupDir2(paths3.homeDir);
9196
+ if (!paths3.dryRun) {
9197
+ backupTarget2(backupDir, paths3.targetPath, existing.bytes);
9004
9198
  if (deleteTarget)
9005
- rmSync(paths.targetPath, { force: true });
9199
+ rmSync2(paths3.targetPath, { force: true });
9006
9200
  else
9007
- writeFileSync(paths.targetPath, restored ?? existing.split.remainder);
9008
- rmSync(paths.statePath, { force: true });
9201
+ writeFileSync2(paths3.targetPath, restored ?? existing.split.remainder);
9202
+ rmSync2(paths3.statePath, { force: true });
9009
9203
  }
9010
9204
  return {
9011
- ...result(paths.targetPath, "uninstall", true, previousState, existing.text, !deleteTarget),
9205
+ ...result2(paths3.targetPath, "uninstall", true, previousState, existing.text, !deleteTarget),
9012
9206
  state: "not_installed",
9013
9207
  message: canRestore ? `${SHARED_MESSAGE}\uFF1B\u5378\u8F7D\u540C\u65F6\u5F71\u54CD Codex \u4E0E dsh` : `${SHARED_MESSAGE}\uFF1B\u5378\u8F7D\u540C\u65F6\u5F71\u54CD Codex \u4E0E dsh\uFF1B\u5DF2\u4FDD\u7559\u7528\u6237\u6539\u52A8`,
9014
9208
  after,
@@ -9020,18 +9214,19 @@ function uninstallProtocolDsh(options) {
9020
9214
  function resolveOptions(options) {
9021
9215
  const homeDir = resolve(options?.homeDir ?? homedir2());
9022
9216
  const projectDir = resolve(options?.projectDir ?? process.cwd());
9023
- const targetPath2 = join3(projectDir, "AGENTS.md");
9217
+ const targetPath2 = join4(projectDir, "AGENTS.md");
9024
9218
  return {
9025
9219
  homeDir,
9026
9220
  projectDir,
9027
9221
  targetPath: targetPath2,
9028
- statePath: join3(homeDir, ".wingman", "state", `plan-protocol-agents-${sha256Hex(projectDir)}.json`),
9222
+ statePath: join4(homeDir, ".wingman", "state", `plan-protocol-agents-${sha256Hex(projectDir)}.json`),
9029
9223
  dryRun: options?.dryRun ?? false
9030
9224
  };
9031
9225
  }
9032
9226
  function readAgents(targetPath2) {
9033
- const bytes = readFileSync(targetPath2);
9034
- const text = decodeUtf8Strict2(bytes, targetPath2);
9227
+ const bytes = readFileSync2(targetPath2);
9228
+ decodeUtf8Strict2(bytes, targetPath2);
9229
+ const text = bytes.toString("utf8");
9035
9230
  let split;
9036
9231
  try {
9037
9232
  split = splitPlanProtocolBlock(text, targetPath2);
@@ -9060,7 +9255,7 @@ function stateForIdentity(identity) {
9060
9255
  return "not_installed";
9061
9256
  if (identity.kind === "current")
9062
9257
  return "installed";
9063
- if (identity.kind === "legacy")
9258
+ if (identity.kind === "outdated")
9064
9259
  return "outdated";
9065
9260
  return "modified";
9066
9261
  }
@@ -9078,7 +9273,7 @@ function status(targetPath2, state, options, identity, reason) {
9078
9273
  ...reason !== void 0 ? { reason } : {}
9079
9274
  };
9080
9275
  }
9081
- function result(targetPath2, operation, changed, previousState, before, afterExists) {
9276
+ function result2(targetPath2, operation, changed, previousState, before, afterExists) {
9082
9277
  return {
9083
9278
  harness: "dsh",
9084
9279
  state: previousState,
@@ -9112,7 +9307,7 @@ function agentInstructionsDisabled(options) {
9112
9307
  if (options?.dumpConfigText !== void 0)
9113
9308
  text = options.dumpConfigText;
9114
9309
  else if (options?.dumpConfigPath !== void 0)
9115
- text = readFileSync(options.dumpConfigPath, "utf8");
9310
+ text = readFileSync2(options.dumpConfigPath, "utf8");
9116
9311
  else {
9117
9312
  text = execFileSync("dsh", ["--profile", options?.profile ?? "web", "--dump-config"], {
9118
9313
  encoding: "utf8",
@@ -9129,38 +9324,41 @@ function agentInstructionsDisabled(options) {
9129
9324
  function modifiedError(targetPath2, operation) {
9130
9325
  return new Error(`${targetPath2}: \u53D7\u7BA1\u5757\u5DF2\u88AB\u4FEE\u6539\uFF0C\u62D2\u7EDD${operation}\u5E76\u4FDD\u7559\u7528\u6237\u5185\u5BB9`);
9131
9326
  }
9132
- function nextBackupDir(homeDir) {
9327
+ function nextBackupDir2(homeDir) {
9133
9328
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replaceAll(":", "-");
9134
- const root = join3(homeDir, ".wingman", "backups");
9135
- let dir = join3(root, stamp);
9136
- for (let n = 2; existsSync(dir); n += 1)
9137
- dir = join3(root, `${stamp}-${n}`);
9329
+ const root = join4(homeDir, ".wingman", "backups");
9330
+ let dir = join4(root, stamp);
9331
+ for (let n = 2; existsSync2(dir); n += 1)
9332
+ dir = join4(root, `${stamp}-${n}`);
9138
9333
  return dir;
9139
9334
  }
9140
- function backupTarget(backupDir, targetPath2, bytes) {
9141
- mkdirSync(backupDir, { recursive: true });
9335
+ function backupTarget2(backupDir, targetPath2, bytes) {
9336
+ mkdirSync2(backupDir, { recursive: true });
9142
9337
  if (bytes !== void 0)
9143
- writeFileSync(join3(backupDir, basename2(targetPath2)), bytes);
9338
+ writeFileSync2(join4(backupDir, basename3(targetPath2)), bytes);
9144
9339
  }
9145
9340
  function readState2(statePath2, targetPath2) {
9146
- if (!existsSync(statePath2))
9341
+ if (!existsSync2(statePath2))
9147
9342
  return void 0;
9148
9343
  try {
9149
- const value = JSON.parse(readFileSync(statePath2, "utf8"));
9344
+ const value = JSON.parse(readFileSync2(statePath2, "utf8"));
9150
9345
  return value.version === 1 && value.targetPath === targetPath2 ? value : void 0;
9151
9346
  } catch {
9152
9347
  return void 0;
9153
9348
  }
9154
9349
  }
9155
9350
  function writeState2(statePath2, state) {
9156
- mkdirSync(dirname3(statePath2), { recursive: true });
9157
- writeFileSync(statePath2, `${JSON.stringify(state, null, 2)}
9351
+ mkdirSync2(dirname4(statePath2), { recursive: true });
9352
+ writeFileSync2(statePath2, `${JSON.stringify(state, null, 2)}
9158
9353
  `);
9159
9354
  }
9160
9355
  function originalBytes(state) {
9161
9356
  return state.original.existed ? Buffer.from(state.original.base64 ?? "", "base64") : void 0;
9162
9357
  }
9163
- var SHARED_MESSAGE, DISABLED_MESSAGE;
9358
+ function protocolStatusDshUser(_options) {
9359
+ return { unsupported: "dsh \u6CA1\u6709\u7528\u6237\u7EA7\u6307\u4EE4\u6587\u4EF6,\u8BF7\u6309\u9879\u76EE\u5B89\u88C5" };
9360
+ }
9361
+ var SHARED_MESSAGE, DISABLED_MESSAGE, installProtocolDshUser, uninstallProtocolDshUser;
9164
9362
  var init_protocol = __esm({
9165
9363
  "packages/adapter-dsh/dist/protocol.js"() {
9166
9364
  "use strict";
@@ -9168,6 +9366,8 @@ var init_protocol = __esm({
9168
9366
  init_dump_config();
9169
9367
  SHARED_MESSAGE = "\u6B64 AGENTS.md \u534F\u8BAE\u5757\u7531 Codex \u4E0E dsh \u5171\u7528";
9170
9368
  DISABLED_MESSAGE = "dsh \u6307\u4EE4\u52A0\u8F7D\u63D2\u4EF6\u5DF2\u7981\u7528\uFF0C\u89C1\u63A7\u5236\u9875\u5F00\u5173";
9369
+ installProtocolDshUser = protocolStatusDshUser;
9370
+ uninstallProtocolDshUser = protocolStatusDshUser;
9171
9371
  }
9172
9372
  });
9173
9373
 
@@ -9183,18 +9383,21 @@ __export(dist_exports, {
9183
9383
  hasManagedHooks: () => hasManagedHooks,
9184
9384
  installDshHooks: () => installDshHooks,
9185
9385
  installProtocolDsh: () => installProtocolDsh,
9386
+ installProtocolDshUser: () => installProtocolDshUser,
9186
9387
  parseDumpConfig: () => parseDumpConfig,
9187
9388
  protocolStatusDsh: () => protocolStatusDsh,
9389
+ protocolStatusDshUser: () => protocolStatusDshUser,
9188
9390
  resolveDshHome: () => resolveDshHome,
9189
9391
  resolveDshHookPaths: () => resolveDshHookPaths,
9190
9392
  retireLegacyDshHomeHooks: () => retireLegacyDshHomeHooks,
9191
9393
  uninstallDshHooks: () => uninstallDshHooks,
9192
- uninstallProtocolDsh: () => uninstallProtocolDsh
9394
+ uninstallProtocolDsh: () => uninstallProtocolDsh,
9395
+ uninstallProtocolDshUser: () => uninstallProtocolDshUser
9193
9396
  });
9194
9397
  import { execFile } from "node:child_process";
9195
- import { existsSync as existsSync2 } from "node:fs";
9398
+ import { existsSync as existsSync3 } from "node:fs";
9196
9399
  import { readFile as readFile2 } from "node:fs/promises";
9197
- import { join as join4 } from "node:path";
9400
+ import { join as join5 } from "node:path";
9198
9401
  import { promisify } from "node:util";
9199
9402
  async function execVersionViaPath() {
9200
9403
  const { stdout } = await execFileAsync("dsh", ["-V"], {
@@ -9267,7 +9470,7 @@ function createAdapter(options = {}) {
9267
9470
  // 检测与 CC/Codex 同构:探用户 dsh 家目录(homeDir/.dsh → $DSH_HOME → ~/.dsh)是否存在。
9268
9471
  // 版本尽力:PATH 上 `dsh -V`,3 秒超时;失败不影响 installed 判定。
9269
9472
  async detect(options2) {
9270
- if (!existsSync2(resolveDshHome(options2)))
9473
+ if (!existsSync3(resolveDshHome(options2)))
9271
9474
  return { installed: false };
9272
9475
  const version = await loadVersion();
9273
9476
  return version !== void 0 ? { installed: true, version } : { installed: true };
@@ -9300,7 +9503,7 @@ function createAdapter(options = {}) {
9300
9503
  },
9301
9504
  async planAction(action, options2) {
9302
9505
  const text = await loadDumpText();
9303
- const file = dumpConfigPath ?? join4(resolveDshHookPaths(options2).dshHome, `dump-config(${profile})`);
9506
+ const file = dumpConfigPath ?? join5(resolveDshHookPaths(options2).dshHome, `dump-config(${profile})`);
9304
9507
  return await planDshToggle(action, { text, file }, options2);
9305
9508
  },
9306
9509
  async applyAction(plan, options2) {
@@ -9331,7 +9534,7 @@ var init_dist2 = __esm({
9331
9534
 
9332
9535
  // packages/adapter-cc/dist/walk.js
9333
9536
  import { readdirSync } from "node:fs";
9334
- import { join as join8, parse as parse2, resolve as resolve2 } from "node:path";
9537
+ import { join as join9, parse as parse2, resolve as resolve2 } from "node:path";
9335
9538
  function newWalkStats(entryBudget = MAX_WALK_ENTRIES) {
9336
9539
  return { unknownErrors: 0, truncated: false, entriesLeft: entryBudget };
9337
9540
  }
@@ -9358,7 +9561,7 @@ function walkFiles(dir, fileName, stats = newWalkStats()) {
9358
9561
  return;
9359
9562
  }
9360
9563
  stats.entriesLeft -= 1;
9361
- const p = join8(d, entry.name);
9564
+ const p = join9(d, entry.name);
9362
9565
  if (entry.isDirectory()) {
9363
9566
  if (entry.name.startsWith(".") || SKIP_DIR_NAMES.has(entry.name))
9364
9567
  continue;
@@ -9375,7 +9578,7 @@ function walkFiles(dir, fileName, stats = newWalkStats()) {
9375
9578
  return found;
9376
9579
  }
9377
9580
  function listMdFiles(dir, stats) {
9378
- return safeReaddir(dir, stats).map((e) => e.name).filter((n) => n.endsWith(".md")).sort().map((n) => join8(dir, n));
9581
+ return safeReaddir(dir, stats).map((e) => e.name).filter((n) => n.endsWith(".md")).sort().map((n) => join9(dir, n));
9379
9582
  }
9380
9583
  function isBareProjectDir(projectDir, homeDir) {
9381
9584
  const r = resolve2(projectDir);
@@ -9393,21 +9596,21 @@ var init_walk = __esm({
9393
9596
  });
9394
9597
 
9395
9598
  // packages/adapter-cc/dist/detect.js
9396
- import { existsSync as existsSync4, readFileSync as readFileSync4, statSync } from "node:fs";
9599
+ import { existsSync as existsSync5, readFileSync as readFileSync5, statSync } from "node:fs";
9397
9600
  import { homedir as homedir5 } from "node:os";
9398
- import { join as join9 } from "node:path";
9601
+ import { join as join10 } from "node:path";
9399
9602
  function probeVersion(homeDir, stats = newWalkStats()) {
9400
- const root = join9(homeDir, ".claude", "projects");
9603
+ const root = join10(homeDir, ".claude", "projects");
9401
9604
  let latest;
9402
9605
  for (const entry of safeReaddir(root, stats)) {
9403
9606
  if (!entry.isDirectory())
9404
9607
  continue;
9405
- const dir = join9(root, entry.name);
9608
+ const dir = join10(root, entry.name);
9406
9609
  for (const sub of safeReaddir(dir, stats)) {
9407
9610
  const name = sub.name;
9408
9611
  if (!name.endsWith(".jsonl"))
9409
9612
  continue;
9410
- const file = join9(dir, name);
9613
+ const file = join10(dir, name);
9411
9614
  let mtimeMs;
9412
9615
  try {
9413
9616
  mtimeMs = statSync(file).mtimeMs;
@@ -9423,7 +9626,7 @@ function probeVersion(homeDir, stats = newWalkStats()) {
9423
9626
  return void 0;
9424
9627
  let lines2;
9425
9628
  try {
9426
- lines2 = readFileSync4(latest.file, "utf8").split("\n");
9629
+ lines2 = readFileSync5(latest.file, "utf8").split("\n");
9427
9630
  } catch (error) {
9428
9631
  recordWalkError(error, stats);
9429
9632
  return void 0;
@@ -9443,7 +9646,7 @@ function probeVersion(homeDir, stats = newWalkStats()) {
9443
9646
  }
9444
9647
  async function detectCc(options) {
9445
9648
  const homeDir = options?.homeDir ?? homedir5();
9446
- const installed = existsSync4(join9(homeDir, ".claude")) || existsSync4(join9(homeDir, ".claude.json"));
9649
+ const installed = existsSync5(join10(homeDir, ".claude")) || existsSync5(join10(homeDir, ".claude.json"));
9447
9650
  if (!installed)
9448
9651
  return { installed: false };
9449
9652
  const version = probeVersion(homeDir);
@@ -9458,11 +9661,11 @@ var init_detect = __esm({
9458
9661
 
9459
9662
  // packages/adapter-cc/dist/scan.js
9460
9663
  import { Buffer as Buffer4 } from "node:buffer";
9461
- import { existsSync as existsSync5, readFileSync as readFileSync5, statSync as statSync2 } from "node:fs";
9664
+ import { existsSync as existsSync6, readFileSync as readFileSync6, statSync as statSync2 } from "node:fs";
9462
9665
  import { homedir as homedir6 } from "node:os";
9463
- import { basename as basename3, dirname as dirname6, join as join10, resolve as resolve3, sep } from "node:path";
9666
+ import { basename as basename4, dirname as dirname7, join as join11, resolve as resolve3, sep } from "node:path";
9464
9667
  function readJsonFile(file) {
9465
- const text = readFileSync5(file, "utf8");
9668
+ const text = readFileSync6(file, "utf8");
9466
9669
  try {
9467
9670
  return JSON.parse(text);
9468
9671
  } catch (e) {
@@ -9478,13 +9681,13 @@ function recordField(v, key) {
9478
9681
  }
9479
9682
  function readSettingsChain(homeDir, projectDir) {
9480
9683
  const chain = [
9481
- { file: join10(homeDir, ".claude", "settings.json"), source: "user" },
9482
- { file: join10(projectDir, ".claude", "settings.json"), source: "project" },
9483
- { file: join10(projectDir, ".claude", "settings.local.json"), source: "local" }
9684
+ { file: join11(homeDir, ".claude", "settings.json"), source: "user" },
9685
+ { file: join11(projectDir, ".claude", "settings.json"), source: "project" },
9686
+ { file: join11(projectDir, ".claude", "settings.local.json"), source: "local" }
9484
9687
  ];
9485
9688
  const out = [];
9486
9689
  for (const { file, source } of chain) {
9487
- if (!existsSync5(file))
9690
+ if (!existsSync6(file))
9488
9691
  continue;
9489
9692
  const data = asRecord(readJsonFile(file));
9490
9693
  if (!data)
@@ -9527,7 +9730,7 @@ function ruleItem(file, source, stats) {
9527
9730
  return {
9528
9731
  id: "",
9529
9732
  slot: "rules",
9530
- nativeName: basename3(file),
9733
+ nativeName: basename4(file),
9531
9734
  nativePath: file,
9532
9735
  tokens: estimateTokens(statSync2(file).size),
9533
9736
  residency: "resident",
@@ -9547,20 +9750,20 @@ function buildRules(homeDir, projectDir, stats) {
9547
9750
  if (item !== void 0)
9548
9751
  items.push(item);
9549
9752
  };
9550
- const userClaudeMd = join10(homeDir, ".claude", "CLAUDE.md");
9551
- if (existsSync5(userClaudeMd))
9753
+ const userClaudeMd = join11(homeDir, ".claude", "CLAUDE.md");
9754
+ if (existsSync6(userClaudeMd))
9552
9755
  append(userClaudeMd, "user");
9553
- for (const f of listMdFiles(join10(homeDir, ".claude", "rules"), stats))
9756
+ for (const f of listMdFiles(join11(homeDir, ".claude", "rules"), stats))
9554
9757
  append(f, "user");
9555
9758
  if (isBareProjectDir(projectDir, homeDir)) {
9556
- const direct = join10(projectDir, "CLAUDE.md");
9557
- if (existsSync5(direct))
9759
+ const direct = join11(projectDir, "CLAUDE.md");
9760
+ if (existsSync6(direct))
9558
9761
  append(direct, "project");
9559
9762
  } else {
9560
9763
  for (const f of walkFiles(projectDir, "CLAUDE.md", stats))
9561
9764
  append(f, "project");
9562
9765
  }
9563
- for (const f of listMdFiles(join10(projectDir, ".claude", "rules"), stats)) {
9766
+ for (const f of listMdFiles(join11(projectDir, ".claude", "rules"), stats)) {
9564
9767
  append(f, "project");
9565
9768
  }
9566
9769
  return items;
@@ -9583,14 +9786,14 @@ function parseSkillFrontmatter(content) {
9583
9786
  return out;
9584
9787
  }
9585
9788
  function buildSkills(homeDir, projectDir, overrides, stats) {
9586
- const userRoot = join10(homeDir, ".claude", "skills");
9587
- const syncedRoot = join10(userRoot, "synced");
9789
+ const userRoot = join11(homeDir, ".claude", "skills");
9790
+ const syncedRoot = join11(userRoot, "synced");
9588
9791
  const roots = [
9589
9792
  { root: userRoot, source: "user", exclude: syncedRoot },
9590
9793
  // projectDir 为家目录时,项目 skills 根与 user 根是同一目录,再走一遍会把每个
9591
9794
  // skill 重复列为 project 层;bare root 无项目上下文 → 不设项目 skills 根
9592
- ...isBareProjectDir(projectDir, homeDir) ? [] : [{ root: join10(projectDir, ".claude", "skills"), source: "project" }],
9593
- { root: join10(homeDir, ".claude", "plugins"), source: "plugin" },
9795
+ ...isBareProjectDir(projectDir, homeDir) ? [] : [{ root: join11(projectDir, ".claude", "skills"), source: "project" }],
9796
+ { root: join11(homeDir, ".claude", "plugins"), source: "plugin" },
9594
9797
  { root: syncedRoot, source: "synced" }
9595
9798
  ];
9596
9799
  const items = [];
@@ -9599,8 +9802,8 @@ function buildSkills(homeDir, projectDir, overrides, stats) {
9599
9802
  if (exclude && (skillFile === exclude || skillFile.startsWith(exclude + sep)))
9600
9803
  continue;
9601
9804
  try {
9602
- const fm = parseSkillFrontmatter(readFileSync5(skillFile, "utf8"));
9603
- const name = fm.name ?? basename3(dirname6(skillFile));
9805
+ const fm = parseSkillFrontmatter(readFileSync6(skillFile, "utf8"));
9806
+ const name = fm.name ?? basename4(dirname7(skillFile));
9604
9807
  const size = statSync2(skillFile).size;
9605
9808
  items.push({
9606
9809
  id: "",
@@ -9624,9 +9827,9 @@ function buildSkills(homeDir, projectDir, overrides, stats) {
9624
9827
  }
9625
9828
  function buildTools(homeDir, projectDir) {
9626
9829
  const items = [];
9627
- const claudeJsonPath = join10(homeDir, ".claude.json");
9830
+ const claudeJsonPath = join11(homeDir, ".claude.json");
9628
9831
  let claudeJson;
9629
- if (existsSync5(claudeJsonPath))
9832
+ if (existsSync6(claudeJsonPath))
9630
9833
  claudeJson = asRecord(readJsonFile(claudeJsonPath));
9631
9834
  const projectEntry = recordField(claudeJson?.projects, resolve3(projectDir));
9632
9835
  const disabledRaw = projectEntry?.disabledMcpServers;
@@ -9650,8 +9853,8 @@ function buildTools(homeDir, projectDir) {
9650
9853
  for (const name of Object.keys(localServers).sort()) {
9651
9854
  items.push(mcpItem(name, "local", claudeJsonPath));
9652
9855
  }
9653
- const mcpJsonPath = join10(projectDir, ".mcp.json");
9654
- if (existsSync5(mcpJsonPath)) {
9856
+ const mcpJsonPath = join11(projectDir, ".mcp.json");
9857
+ if (existsSync6(mcpJsonPath)) {
9655
9858
  const projectServers = recordField(readJsonFile(mcpJsonPath), "mcpServers") ?? {};
9656
9859
  for (const name of Object.keys(projectServers).sort()) {
9657
9860
  items.push(mcpItem(name, "project", mcpJsonPath));
@@ -9697,7 +9900,7 @@ function lastContextTotal(file, stats) {
9697
9900
  let total;
9698
9901
  let text;
9699
9902
  try {
9700
- text = readFileSync5(file, "utf8");
9903
+ text = readFileSync6(file, "utf8");
9701
9904
  } catch (error) {
9702
9905
  recordWalkError(error, stats);
9703
9906
  return void 0;
@@ -9725,10 +9928,10 @@ function lastContextTotal(file, stats) {
9725
9928
  return total;
9726
9929
  }
9727
9930
  function buildHistory(homeDir, projectDir, stats) {
9728
- const dir = join10(homeDir, ".claude", "projects", projectSlug(projectDir));
9931
+ const dir = join11(homeDir, ".claude", "projects", projectSlug(projectDir));
9729
9932
  const items = [];
9730
9933
  for (const name of safeReaddir(dir, stats).map((e) => e.name).filter((n) => n.endsWith(".jsonl")).sort()) {
9731
- const file = join10(dir, name);
9934
+ const file = join11(dir, name);
9732
9935
  const total = lastContextTotal(file, stats);
9733
9936
  if (total === void 0)
9734
9937
  continue;
@@ -9839,9 +10042,9 @@ var init_scan = __esm({
9839
10042
  });
9840
10043
 
9841
10044
  // packages/adapter-cc/dist/actions.js
9842
- import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync6, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "node:fs";
10045
+ import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync7, rmSync as rmSync3, writeFileSync as writeFileSync5 } from "node:fs";
9843
10046
  import { homedir as homedir7 } from "node:os";
9844
- import { basename as basename4, dirname as dirname7, join as join11, resolve as resolve4 } from "node:path";
10047
+ import { basename as basename5, dirname as dirname8, join as join12, resolve as resolve4 } from "node:path";
9845
10048
  function asRecord2(v) {
9846
10049
  return typeof v === "object" && v !== null && !Array.isArray(v) ? v : void 0;
9847
10050
  }
@@ -9865,10 +10068,10 @@ function deepEqual(a, b) {
9865
10068
  }
9866
10069
  function backupDirPath(homeDir) {
9867
10070
  const ts = (/* @__PURE__ */ new Date()).toISOString().replaceAll(":", "-");
9868
- const root = join11(homeDir, ".wingman", "backups");
9869
- let dir = join11(root, ts);
9870
- for (let n = 2; existsSync6(dir); n++)
9871
- dir = join11(root, `${ts}-${n}`);
10071
+ const root = join12(homeDir, ".wingman", "backups");
10072
+ let dir = join12(root, ts);
10073
+ for (let n = 2; existsSync7(dir); n++)
10074
+ dir = join12(root, `${ts}-${n}`);
9872
10075
  return dir;
9873
10076
  }
9874
10077
  function decodeUtf8Strict3(buffer, file) {
@@ -9880,15 +10083,15 @@ function decodeUtf8Strict3(buffer, file) {
9880
10083
  }
9881
10084
  function readSettingsSnapshots(homeDir, projectDir) {
9882
10085
  const files = [
9883
- join11(homeDir, ".claude", "settings.json"),
9884
- join11(projectDir, ".claude", "settings.json"),
9885
- join11(projectDir, ".claude", "settings.local.json")
10086
+ join12(homeDir, ".claude", "settings.json"),
10087
+ join12(projectDir, ".claude", "settings.json"),
10088
+ join12(projectDir, ".claude", "settings.local.json")
9886
10089
  ];
9887
10090
  const out = [];
9888
10091
  for (const file of files) {
9889
- if (!existsSync6(file))
10092
+ if (!existsSync7(file))
9890
10093
  continue;
9891
- const raw = decodeUtf8Strict3(readFileSync6(file), file);
10094
+ const raw = decodeUtf8Strict3(readFileSync7(file), file);
9892
10095
  let parsed;
9893
10096
  try {
9894
10097
  parsed = JSON.parse(raw);
@@ -9911,7 +10114,7 @@ function overridesRecord(s) {
9911
10114
  return rec;
9912
10115
  }
9913
10116
  function skillTargetFile(item, homeDir, projectDir) {
9914
- return item.source === "project" ? join11(projectDir, ".claude", "settings.json") : join11(homeDir, ".claude", "settings.json");
10117
+ return item.source === "project" ? join12(projectDir, ".claude", "settings.json") : join12(homeDir, ".claude", "settings.json");
9915
10118
  }
9916
10119
  function planSkillToggle(item, enable, homeDir, projectDir) {
9917
10120
  const name = item.nativeName;
@@ -9964,11 +10167,11 @@ function planSkillToggle(item, enable, homeDir, projectDir) {
9964
10167
  });
9965
10168
  }
9966
10169
  function planMcpToggle(name, enable, homeDir, projectDir) {
9967
- const file = join11(homeDir, ".claude.json");
9968
- if (!existsSync6(file)) {
10170
+ const file = join12(homeDir, ".claude.json");
10171
+ if (!existsSync7(file)) {
9969
10172
  throw new Error(`\u62D2\u7EDD:\u627E\u4E0D\u5230 ${file}(MCP \u8FDE\u63A5\u5F00\u5173\u6309\u9879\u76EE\u5B58\u653E\u4E8E\u8BE5\u6587\u4EF6)`);
9970
10173
  }
9971
- const raw = readFileSync6(file, "utf8");
10174
+ const raw = readFileSync7(file, "utf8");
9972
10175
  let parsed;
9973
10176
  try {
9974
10177
  parsed = JSON.parse(raw);
@@ -10042,24 +10245,24 @@ function collectRefSources(homeDir, projectDir, exclude) {
10042
10245
  sources.push({ file, text });
10043
10246
  };
10044
10247
  const pushFile = (file) => {
10045
- if (!seen.has(file) && existsSync6(file))
10046
- push(file, readFileSync6(file, "utf8"));
10248
+ if (!seen.has(file) && existsSync7(file))
10249
+ push(file, readFileSync7(file, "utf8"));
10047
10250
  };
10048
10251
  const bareRoot = isBareProjectDir(projectDir, homeDir);
10049
- pushFile(join11(homeDir, ".claude", "CLAUDE.md"));
10050
- for (const f of listMdFiles(join11(homeDir, ".claude", "rules")))
10252
+ pushFile(join12(homeDir, ".claude", "CLAUDE.md"));
10253
+ for (const f of listMdFiles(join12(homeDir, ".claude", "rules")))
10051
10254
  pushFile(f);
10052
10255
  if (bareRoot)
10053
- pushFile(join11(projectDir, "CLAUDE.md"));
10256
+ pushFile(join12(projectDir, "CLAUDE.md"));
10054
10257
  else
10055
10258
  for (const f of walkFiles(projectDir, "CLAUDE.md"))
10056
10259
  pushFile(f);
10057
- for (const f of listMdFiles(join11(projectDir, ".claude", "rules")))
10260
+ for (const f of listMdFiles(join12(projectDir, ".claude", "rules")))
10058
10261
  pushFile(f);
10059
10262
  const skillRoots = [
10060
- join11(homeDir, ".claude", "skills"),
10061
- ...bareRoot ? [] : [join11(projectDir, ".claude", "skills")],
10062
- join11(homeDir, ".claude", "plugins")
10263
+ join12(homeDir, ".claude", "skills"),
10264
+ ...bareRoot ? [] : [join12(projectDir, ".claude", "skills")],
10265
+ join12(homeDir, ".claude", "plugins")
10063
10266
  ];
10064
10267
  for (const root of skillRoots) {
10065
10268
  for (const f of walkFiles(root, "SKILL.md")) {
@@ -10068,20 +10271,20 @@ function collectRefSources(homeDir, projectDir, exclude) {
10068
10271
  }
10069
10272
  }
10070
10273
  for (const dir of [
10071
- join11(homeDir, ".claude", "agents"),
10072
- join11(projectDir, ".claude", "agents"),
10073
- join11(homeDir, ".claude", "commands"),
10074
- join11(projectDir, ".claude", "commands")
10274
+ join12(homeDir, ".claude", "agents"),
10275
+ join12(projectDir, ".claude", "agents"),
10276
+ join12(homeDir, ".claude", "commands"),
10277
+ join12(projectDir, ".claude", "commands")
10075
10278
  ]) {
10076
10279
  for (const f of listMdFiles(dir))
10077
10280
  pushFile(f);
10078
10281
  }
10079
10282
  for (const s of readSettingsSnapshots(homeDir, projectDir))
10080
10283
  push(s.file, s.raw);
10081
- for (const file of [join11(projectDir, ".mcp.json"), join11(homeDir, ".claude.json")]) {
10082
- if (seen.has(file) || !existsSync6(file))
10284
+ for (const file of [join12(projectDir, ".mcp.json"), join12(homeDir, ".claude.json")]) {
10285
+ if (seen.has(file) || !existsSync7(file))
10083
10286
  continue;
10084
- const raw = readFileSync6(file, "utf8");
10287
+ const raw = readFileSync7(file, "utf8");
10085
10288
  let parsed;
10086
10289
  try {
10087
10290
  parsed = JSON.parse(raw);
@@ -10188,14 +10391,14 @@ async function applyActionCc(plan, _options) {
10188
10391
  const currentByFile = /* @__PURE__ */ new Map();
10189
10392
  for (const w of plan.writes) {
10190
10393
  if (w.kind === "create") {
10191
- if (existsSync6(w.file)) {
10394
+ if (existsSync7(w.file)) {
10192
10395
  return { ok: false, error: `\u62D2\u7EDD\u6267\u884C:${w.file} \u5728 plan \u540E\u88AB\u521B\u5EFA,\u8BF7\u91CD\u65B0 plan` };
10193
10396
  }
10194
10397
  } else {
10195
- if (!existsSync6(w.file)) {
10398
+ if (!existsSync7(w.file)) {
10196
10399
  return { ok: false, error: `\u62D2\u7EDD\u6267\u884C:${w.file} \u5DF2\u4E0D\u5B58\u5728(plan \u540E\u88AB\u6539\u52A8),\u8BF7\u91CD\u65B0 plan` };
10197
10400
  }
10198
- const currentRaw = readFileSync6(w.file);
10401
+ const currentRaw = readFileSync7(w.file);
10199
10402
  if (!currentRaw.equals(Buffer.from(w.before, "utf8"))) {
10200
10403
  return { ok: false, error: `\u62D2\u7EDD\u6267\u884C:${w.file} \u5728 plan \u540E\u88AB\u6539\u8FC7,\u8BF7\u91CD\u65B0 plan` };
10201
10404
  }
@@ -10203,15 +10406,15 @@ async function applyActionCc(plan, _options) {
10203
10406
  }
10204
10407
  }
10205
10408
  const toBackup = plan.writes.filter((w) => w.kind !== "create");
10206
- mkdirSync3(plan.backupDir, { recursive: true });
10409
+ mkdirSync4(plan.backupDir, { recursive: true });
10207
10410
  const manifestFiles = toBackup.map((w, i) => ({
10208
- backup: `${i}-${basename4(w.file)}`,
10411
+ backup: `${i}-${basename5(w.file)}`,
10209
10412
  target: w.file
10210
10413
  }));
10211
10414
  toBackup.forEach((w, i) => {
10212
- writeFileSync4(join11(plan.backupDir, `${i}-${basename4(w.file)}`), currentByFile.get(w.file));
10415
+ writeFileSync5(join12(plan.backupDir, `${i}-${basename5(w.file)}`), currentByFile.get(w.file));
10213
10416
  });
10214
- writeFileSync4(join11(plan.backupDir, "manifest.json"), serialize({
10417
+ writeFileSync5(join12(plan.backupDir, "manifest.json"), serialize({
10215
10418
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
10216
10419
  harness: "cc",
10217
10420
  action: plan.action,
@@ -10221,10 +10424,10 @@ async function applyActionCc(plan, _options) {
10221
10424
  try {
10222
10425
  for (const w of plan.writes) {
10223
10426
  if (w.kind === "delete") {
10224
- rmSync2(w.file);
10427
+ rmSync3(w.file);
10225
10428
  } else {
10226
- mkdirSync3(dirname7(w.file), { recursive: true });
10227
- writeFileSync4(w.file, w.after ?? "");
10429
+ mkdirSync4(dirname8(w.file), { recursive: true });
10430
+ writeFileSync5(w.file, w.after ?? "");
10228
10431
  }
10229
10432
  written.push(w);
10230
10433
  }
@@ -10233,9 +10436,9 @@ async function applyActionCc(plan, _options) {
10233
10436
  for (const w of written) {
10234
10437
  try {
10235
10438
  if (w.kind === "create")
10236
- rmSync2(w.file, { force: true });
10439
+ rmSync3(w.file, { force: true });
10237
10440
  else
10238
- writeFileSync4(w.file, w.before ?? "");
10441
+ writeFileSync5(w.file, w.before ?? "");
10239
10442
  } catch {
10240
10443
  failures.push(w.file);
10241
10444
  }
@@ -10244,12 +10447,12 @@ async function applyActionCc(plan, _options) {
10244
10447
  return { ok: false, error: `\u5199\u5165\u5931\u8D25:${e.message};${rollbackNote}` };
10245
10448
  }
10246
10449
  for (const w of plan.writes) {
10247
- if (basename4(w.file) !== ".claude.json" || w.kind !== "modify" || w.after === void 0) {
10450
+ if (basename5(w.file) !== ".claude.json" || w.kind !== "modify" || w.after === void 0) {
10248
10451
  continue;
10249
10452
  }
10250
10453
  let verified = false;
10251
10454
  try {
10252
- verified = deepEqual(JSON.parse(readFileSync6(w.file, "utf8")), JSON.parse(w.after));
10455
+ verified = deepEqual(JSON.parse(readFileSync7(w.file, "utf8")), JSON.parse(w.after));
10253
10456
  } catch {
10254
10457
  verified = false;
10255
10458
  }
@@ -10275,9 +10478,9 @@ var init_actions = __esm({
10275
10478
  });
10276
10479
 
10277
10480
  // packages/adapter-cc/dist/hooks.js
10278
- import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync7, rmSync as rmSync3, writeFileSync as writeFileSync5 } from "node:fs";
10481
+ import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync8, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "node:fs";
10279
10482
  import { homedir as homedir8 } from "node:os";
10280
- import { dirname as dirname8, join as join12 } from "node:path";
10483
+ import { dirname as dirname9, join as join13 } from "node:path";
10281
10484
  function wingmanUrl(port) {
10282
10485
  return `http://127.0.0.1:${port}${SIGNATURE}`;
10283
10486
  }
@@ -10289,18 +10492,18 @@ function isWingmanHandler(h) {
10289
10492
  return rec?.type === "http" && typeof rec.url === "string" && rec.url.includes(SIGNATURE);
10290
10493
  }
10291
10494
  function wingmanRoot(homeDir) {
10292
- return join12(homeDir, ".wingman");
10495
+ return join13(homeDir, ".wingman");
10293
10496
  }
10294
10497
  function statePath(homeDir) {
10295
- return join12(wingmanRoot(homeDir), "state", "cc-hooks.json");
10498
+ return join13(wingmanRoot(homeDir), "state", "cc-hooks.json");
10296
10499
  }
10297
10500
  function readState3(homeDir) {
10298
10501
  const file = statePath(homeDir);
10299
- if (!existsSync7(file))
10502
+ if (!existsSync8(file))
10300
10503
  return void 0;
10301
10504
  let parsed;
10302
10505
  try {
10303
- parsed = JSON.parse(readFileSync7(file, "utf8"));
10506
+ parsed = JSON.parse(readFileSync8(file, "utf8"));
10304
10507
  } catch {
10305
10508
  return void 0;
10306
10509
  }
@@ -10321,23 +10524,23 @@ function readState3(homeDir) {
10321
10524
  }
10322
10525
  function writeState3(homeDir, state) {
10323
10526
  const file = statePath(homeDir);
10324
- mkdirSync4(dirname8(file), { recursive: true });
10325
- writeFileSync5(file, `${JSON.stringify(state, null, 2)}
10527
+ mkdirSync5(dirname9(file), { recursive: true });
10528
+ writeFileSync6(file, `${JSON.stringify(state, null, 2)}
10326
10529
  `);
10327
10530
  }
10328
10531
  function makeBackupDir(homeDir) {
10329
10532
  const ts = (/* @__PURE__ */ new Date()).toISOString().replaceAll(":", "-");
10330
- const root = join12(wingmanRoot(homeDir), "backups");
10331
- let dir = join12(root, ts);
10332
- for (let n = 2; existsSync7(dir); n++)
10333
- dir = join12(root, `${ts}-${n}`);
10334
- mkdirSync4(dir, { recursive: true });
10533
+ const root = join13(wingmanRoot(homeDir), "backups");
10534
+ let dir = join13(root, ts);
10535
+ for (let n = 2; existsSync8(dir); n++)
10536
+ dir = join13(root, `${ts}-${n}`);
10537
+ mkdirSync5(dir, { recursive: true });
10335
10538
  return dir;
10336
10539
  }
10337
- function readTarget(target) {
10338
- if (!existsSync7(target))
10540
+ function readTarget2(target) {
10541
+ if (!existsSync8(target))
10339
10542
  return { bytes: null, settings: {} };
10340
- const bytes = readFileSync7(target, "utf8");
10543
+ const bytes = readFileSync8(target, "utf8");
10341
10544
  let parsed;
10342
10545
  try {
10343
10546
  parsed = JSON.parse(bytes);
@@ -10440,13 +10643,13 @@ function deepEqual2(a, b) {
10440
10643
  return false;
10441
10644
  }
10442
10645
  function targetPath(homeDir) {
10443
- return join12(homeDir, ".claude", "settings.json");
10646
+ return join13(homeDir, ".claude", "settings.json");
10444
10647
  }
10445
10648
  async function installHooksCc(port, options) {
10446
10649
  const homeDir = options?.homeDir ?? homedir8();
10447
10650
  const target = targetPath(homeDir);
10448
10651
  const url = wingmanUrl(port);
10449
- const { bytes, settings } = readTarget(target);
10652
+ const { bytes, settings } = readTarget2(target);
10450
10653
  if (isFullyWired(settings, url))
10451
10654
  return;
10452
10655
  if (settings.hooks !== void 0 && !asRecord3(settings.hooks)) {
@@ -10462,7 +10665,7 @@ async function installHooksCc(port, options) {
10462
10665
  }
10463
10666
  const backupDir = makeBackupDir(homeDir);
10464
10667
  if (bytes !== null)
10465
- writeFileSync5(join12(backupDir, "settings.json"), bytes);
10668
+ writeFileSync6(join13(backupDir, "settings.json"), bytes);
10466
10669
  const prev = readState3(homeDir);
10467
10670
  const now = (/* @__PURE__ */ new Date()).toISOString();
10468
10671
  writeState3(homeDir, prev ? { ...prev, port, installedAt: now } : { target, original: bytes, backupDir, port, installedAt: now });
@@ -10474,44 +10677,44 @@ async function installHooksCc(port, options) {
10474
10677
  groups.push({ hooks: [{ type: "http", url }] });
10475
10678
  hooks[event] = groups;
10476
10679
  }
10477
- mkdirSync4(dirname8(target), { recursive: true });
10478
- writeFileSync5(target, `${JSON.stringify(settings, null, 2)}
10680
+ mkdirSync5(dirname9(target), { recursive: true });
10681
+ writeFileSync6(target, `${JSON.stringify(settings, null, 2)}
10479
10682
  `);
10480
10683
  }
10481
10684
  async function uninstallHooksCc(options) {
10482
10685
  const homeDir = options?.homeDir ?? homedir8();
10483
10686
  const target = targetPath(homeDir);
10484
10687
  const state = readState3(homeDir);
10485
- if (!existsSync7(target)) {
10486
- rmSync3(statePath(homeDir), { force: true });
10688
+ if (!existsSync8(target)) {
10689
+ rmSync4(statePath(homeDir), { force: true });
10487
10690
  return;
10488
10691
  }
10489
- const { bytes, settings } = readTarget(target);
10692
+ const { bytes, settings } = readTarget2(target);
10490
10693
  const changed = removeWingmanEntries(settings);
10491
10694
  if (!changed) {
10492
- rmSync3(statePath(homeDir), { force: true });
10695
+ rmSync4(statePath(homeDir), { force: true });
10493
10696
  return;
10494
10697
  }
10495
10698
  const backupDir = makeBackupDir(homeDir);
10496
10699
  if (bytes !== null)
10497
- writeFileSync5(join12(backupDir, "settings.json"), bytes);
10700
+ writeFileSync6(join13(backupDir, "settings.json"), bytes);
10498
10701
  if (state && state.original !== null) {
10499
10702
  const originalParsed = asRecord3(JSON.parse(state.original));
10500
10703
  if (originalParsed && deepEqual2(normalizeForCompare(settings), normalizeForCompare(originalParsed))) {
10501
- writeFileSync5(target, state.original);
10502
- rmSync3(statePath(homeDir), { force: true });
10704
+ writeFileSync6(target, state.original);
10705
+ rmSync4(statePath(homeDir), { force: true });
10503
10706
  return;
10504
10707
  }
10505
10708
  } else if (state && state.original === null) {
10506
10709
  if (deepEqual2(normalizeForCompare(settings), {})) {
10507
- rmSync3(target, { force: true });
10508
- rmSync3(statePath(homeDir), { force: true });
10710
+ rmSync4(target, { force: true });
10711
+ rmSync4(statePath(homeDir), { force: true });
10509
10712
  return;
10510
10713
  }
10511
10714
  }
10512
- writeFileSync5(target, `${JSON.stringify(settings, null, 2)}
10715
+ writeFileSync6(target, `${JSON.stringify(settings, null, 2)}
10513
10716
  `);
10514
- rmSync3(statePath(homeDir), { force: true });
10717
+ rmSync4(statePath(homeDir), { force: true });
10515
10718
  }
10516
10719
  var WIRED_EVENTS, SIGNATURE;
10517
10720
  var init_hooks2 = __esm({
@@ -10532,60 +10735,60 @@ var init_hooks2 = __esm({
10532
10735
  });
10533
10736
 
10534
10737
  // packages/adapter-cc/dist/protocol.js
10535
- import { existsSync as existsSync8, mkdirSync as mkdirSync5, readdirSync as readdirSync2, readFileSync as readFileSync8, rmdirSync, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "node:fs";
10738
+ import { existsSync as existsSync9, mkdirSync as mkdirSync6, readdirSync as readdirSync2, readFileSync as readFileSync9, rmdirSync, rmSync as rmSync5, writeFileSync as writeFileSync7 } from "node:fs";
10536
10739
  import { homedir as homedir9 } from "node:os";
10537
- import { basename as basename5, dirname as dirname9, join as join13, resolve as resolve5 } from "node:path";
10740
+ import { basename as basename6, dirname as dirname10, join as join14, resolve as resolve5 } from "node:path";
10538
10741
  function protocolStatusCc(options) {
10539
- const paths = resolveOptions2(options);
10540
- if (!existsSync8(paths.targetPath)) {
10541
- return { harness: "cc", state: "not_installed", targetPath: paths.targetPath };
10742
+ const paths3 = resolveOptions2(options);
10743
+ if (!existsSync9(paths3.targetPath)) {
10744
+ return { harness: "cc", state: "not_installed", targetPath: paths3.targetPath };
10542
10745
  }
10543
10746
  try {
10544
- return statusFromIdentity(paths.targetPath, inspectPlanProtocolFile(readFileSync8(paths.targetPath), paths.targetPath));
10747
+ return statusFromIdentity(paths3.targetPath, inspectPlanProtocolFile(readFileSync9(paths3.targetPath), paths3.targetPath));
10545
10748
  } catch (error) {
10546
10749
  return {
10547
10750
  harness: "cc",
10548
10751
  state: "invalid",
10549
- targetPath: paths.targetPath,
10752
+ targetPath: paths3.targetPath,
10550
10753
  reason: error.message
10551
10754
  };
10552
10755
  }
10553
10756
  }
10554
10757
  function installProtocolCc(options) {
10555
- const paths = resolveOptions2(options);
10556
- const existing = readExisting(paths.targetPath);
10758
+ const paths3 = resolveOptions2(options);
10759
+ const existing = readExisting(paths3.targetPath);
10557
10760
  const previousState = stateForIdentity2(existing?.identity);
10558
10761
  if (previousState === "installed") {
10559
- return result2(paths.targetPath, "install", false, previousState, existing?.text ?? "", true);
10762
+ return result3(paths3.targetPath, "install", false, previousState, existing?.text ?? "", true);
10560
10763
  }
10561
10764
  if (previousState === "modified")
10562
- throw modifiedError2(paths.targetPath, "\u5B89\u88C5");
10765
+ throw modifiedError2(paths3.targetPath, "\u5B89\u88C5");
10563
10766
  const before = existing?.text ?? "";
10564
- const backupDir = nextBackupDir2(paths.homeDir);
10767
+ const backupDir = nextBackupDir3(paths3.homeDir);
10565
10768
  const installedSha256 = sha256Hex(PLAN_PROTOCOL_TEXT);
10566
- if (!paths.dryRun) {
10567
- const claudeDir = join13(paths.projectDir, ".claude");
10568
- const rulesDir = dirname9(paths.targetPath);
10569
- const prior = readState4(paths.statePath);
10570
- backupTarget2(backupDir, paths.targetPath, existing?.bytes);
10571
- writeState4(paths.statePath, {
10769
+ if (!paths3.dryRun) {
10770
+ const claudeDir = join14(paths3.projectDir, ".claude");
10771
+ const rulesDir = dirname10(paths3.targetPath);
10772
+ const prior = readState4(paths3.statePath);
10773
+ backupTarget3(backupDir, paths3.targetPath, existing?.bytes);
10774
+ writeState4(paths3.statePath, {
10572
10775
  version: 1,
10573
10776
  harness: "cc",
10574
- projectDir: paths.projectDir,
10575
- targetPath: paths.targetPath,
10777
+ projectDir: paths3.projectDir,
10778
+ targetPath: paths3.targetPath,
10576
10779
  protocolVersion: PLAN_PROTOCOL_VERSION,
10577
10780
  installedSha256,
10578
10781
  installedAt: (/* @__PURE__ */ new Date()).toISOString(),
10579
10782
  backupDir,
10580
10783
  original: prior?.original ?? (existing === void 0 ? { existed: false } : { existed: true, base64: existing.bytes.toString("base64") }),
10581
- createdClaudeDir: prior?.createdClaudeDir ?? !existsSync8(claudeDir),
10582
- createdRulesDir: prior?.createdRulesDir ?? !existsSync8(rulesDir)
10784
+ createdClaudeDir: prior?.createdClaudeDir ?? !existsSync9(claudeDir),
10785
+ createdRulesDir: prior?.createdRulesDir ?? !existsSync9(rulesDir)
10583
10786
  });
10584
- mkdirSync5(rulesDir, { recursive: true });
10585
- writeFileSync6(paths.targetPath, PLAN_PROTOCOL_TEXT);
10787
+ mkdirSync6(rulesDir, { recursive: true });
10788
+ writeFileSync7(paths3.targetPath, PLAN_PROTOCOL_TEXT);
10586
10789
  }
10587
10790
  return {
10588
- ...result2(paths.targetPath, "install", true, previousState, before, true),
10791
+ ...result3(paths3.targetPath, "install", true, previousState, before, true),
10589
10792
  state: "installed",
10590
10793
  version: PLAN_PROTOCOL_VERSION,
10591
10794
  sha256: installedSha256,
@@ -10595,31 +10798,31 @@ function installProtocolCc(options) {
10595
10798
  };
10596
10799
  }
10597
10800
  function uninstallProtocolCc(options) {
10598
- const paths = resolveOptions2(options);
10599
- const existing = readExisting(paths.targetPath);
10801
+ const paths3 = resolveOptions2(options);
10802
+ const existing = readExisting(paths3.targetPath);
10600
10803
  if (existing === void 0) {
10601
- return result2(paths.targetPath, "uninstall", false, "not_installed", "", false);
10804
+ return result3(paths3.targetPath, "uninstall", false, "not_installed", "", false);
10602
10805
  }
10603
10806
  const previousState = stateForIdentity2(existing.identity);
10604
10807
  if (previousState === "modified")
10605
- throw modifiedError2(paths.targetPath, "\u5378\u8F7D");
10606
- const state = readState4(paths.statePath);
10808
+ throw modifiedError2(paths3.targetPath, "\u5378\u8F7D");
10809
+ const state = readState4(paths3.statePath);
10607
10810
  const restored = restoredOriginal(state);
10608
10811
  const after = restored?.toString("utf8") ?? "";
10609
10812
  const afterExists = restored !== void 0;
10610
- const backupDir = nextBackupDir2(paths.homeDir);
10611
- if (!paths.dryRun) {
10612
- backupTarget2(backupDir, paths.targetPath, existing.bytes);
10813
+ const backupDir = nextBackupDir3(paths3.homeDir);
10814
+ if (!paths3.dryRun) {
10815
+ backupTarget3(backupDir, paths3.targetPath, existing.bytes);
10613
10816
  if (restored === void 0)
10614
- rmSync4(paths.targetPath, { force: true });
10817
+ rmSync5(paths3.targetPath, { force: true });
10615
10818
  else
10616
- writeFileSync6(paths.targetPath, restored);
10819
+ writeFileSync7(paths3.targetPath, restored);
10617
10820
  if (restored === void 0)
10618
- removeCreatedEmptyDirs(paths, state);
10619
- rmSync4(paths.statePath, { force: true });
10821
+ removeCreatedEmptyDirs(paths3, state);
10822
+ rmSync5(paths3.statePath, { force: true });
10620
10823
  }
10621
10824
  return {
10622
- ...result2(paths.targetPath, "uninstall", true, previousState, existing.text, afterExists),
10825
+ ...result3(paths3.targetPath, "uninstall", true, previousState, existing.text, afterExists),
10623
10826
  state: "not_installed",
10624
10827
  after,
10625
10828
  backupDir,
@@ -10629,20 +10832,20 @@ function uninstallProtocolCc(options) {
10629
10832
  function resolveOptions2(options) {
10630
10833
  const homeDir = resolve5(options?.homeDir ?? homedir9());
10631
10834
  const projectDir = resolve5(options?.projectDir ?? process.cwd());
10632
- const targetPath2 = join13(projectDir, ".claude", "rules", "wingman-plan-protocol.md");
10835
+ const targetPath2 = join14(projectDir, ".claude", "rules", "wingman-plan-protocol.md");
10633
10836
  const projectHash = sha256Hex(projectDir);
10634
10837
  return {
10635
10838
  homeDir,
10636
10839
  projectDir,
10637
10840
  dryRun: options?.dryRun ?? false,
10638
10841
  targetPath: targetPath2,
10639
- statePath: join13(homeDir, ".wingman", "state", `plan-protocol-cc-${projectHash}.json`)
10842
+ statePath: join14(homeDir, ".wingman", "state", `plan-protocol-cc-${projectHash}.json`)
10640
10843
  };
10641
10844
  }
10642
10845
  function readExisting(targetPath2) {
10643
- if (!existsSync8(targetPath2))
10846
+ if (!existsSync9(targetPath2))
10644
10847
  return void 0;
10645
- const bytes = readFileSync8(targetPath2);
10848
+ const bytes = readFileSync9(targetPath2);
10646
10849
  const identity = inspectPlanProtocolFile(bytes, targetPath2);
10647
10850
  return { bytes, text: bytes.toString("utf8"), identity };
10648
10851
  }
@@ -10651,7 +10854,7 @@ function stateForIdentity2(identity) {
10651
10854
  return "not_installed";
10652
10855
  if (identity.kind === "current")
10653
10856
  return "installed";
10654
- if (identity.kind === "legacy")
10857
+ if (identity.kind === "outdated")
10655
10858
  return "outdated";
10656
10859
  return "modified";
10657
10860
  }
@@ -10665,7 +10868,7 @@ function statusFromIdentity(targetPath2, identity) {
10665
10868
  ...identity.kind === "modified" ? { reason: "\u53D7\u7BA1\u534F\u8BAE\u6587\u4EF6\u5DF2\u88AB\u4FEE\u6539" } : {}
10666
10869
  };
10667
10870
  }
10668
- function result2(targetPath2, operation, changed, previousState, before, afterExists) {
10871
+ function result3(targetPath2, operation, changed, previousState, before, afterExists) {
10669
10872
  return {
10670
10873
  harness: "cc",
10671
10874
  operation,
@@ -10683,32 +10886,32 @@ function result2(targetPath2, operation, changed, previousState, before, afterEx
10683
10886
  function modifiedError2(targetPath2, operation) {
10684
10887
  return new Error(`\u53D7\u7BA1\u534F\u8BAE\u6587\u4EF6\u5DF2\u88AB\u4FEE\u6539(${targetPath2})\uFF0C\u62D2\u7EDD${operation}\u5E76\u4FDD\u7559\u7528\u6237\u5185\u5BB9`);
10685
10888
  }
10686
- function nextBackupDir2(homeDir) {
10889
+ function nextBackupDir3(homeDir) {
10687
10890
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replaceAll(":", "-");
10688
- const root = join13(homeDir, ".wingman", "backups");
10689
- let dir = join13(root, stamp);
10690
- for (let n = 2; existsSync8(dir); n += 1)
10691
- dir = join13(root, `${stamp}-${n}`);
10891
+ const root = join14(homeDir, ".wingman", "backups");
10892
+ let dir = join14(root, stamp);
10893
+ for (let n = 2; existsSync9(dir); n += 1)
10894
+ dir = join14(root, `${stamp}-${n}`);
10692
10895
  return dir;
10693
10896
  }
10694
- function backupTarget2(backupDir, targetPath2, bytes) {
10695
- mkdirSync5(backupDir, { recursive: true });
10897
+ function backupTarget3(backupDir, targetPath2, bytes) {
10898
+ mkdirSync6(backupDir, { recursive: true });
10696
10899
  if (bytes !== void 0)
10697
- writeFileSync6(join13(backupDir, basename5(targetPath2)), bytes);
10900
+ writeFileSync7(join14(backupDir, basename6(targetPath2)), bytes);
10698
10901
  }
10699
10902
  function readState4(statePath2) {
10700
- if (!existsSync8(statePath2))
10903
+ if (!existsSync9(statePath2))
10701
10904
  return void 0;
10702
10905
  try {
10703
- const state = JSON.parse(readFileSync8(statePath2, "utf8"));
10906
+ const state = JSON.parse(readFileSync9(statePath2, "utf8"));
10704
10907
  return state.version === 1 && state.harness === "cc" && typeof state.targetPath === "string" ? state : void 0;
10705
10908
  } catch {
10706
10909
  return void 0;
10707
10910
  }
10708
10911
  }
10709
10912
  function writeState4(statePath2, state) {
10710
- mkdirSync5(dirname9(statePath2), { recursive: true });
10711
- writeFileSync6(statePath2, `${JSON.stringify(state, null, 2)}
10913
+ mkdirSync6(dirname10(statePath2), { recursive: true });
10914
+ writeFileSync7(statePath2, `${JSON.stringify(state, null, 2)}
10712
10915
  `);
10713
10916
  }
10714
10917
  function restoredOriginal(state) {
@@ -10716,13 +10919,13 @@ function restoredOriginal(state) {
10716
10919
  return void 0;
10717
10920
  return Buffer.from(state.original.base64 ?? "", "base64");
10718
10921
  }
10719
- function removeCreatedEmptyDirs(paths, state) {
10720
- const rulesDir = dirname9(paths.targetPath);
10721
- const claudeDir = dirname9(rulesDir);
10722
- if (state?.createdRulesDir && existsSync8(rulesDir) && readdirSync2(rulesDir).length === 0) {
10922
+ function removeCreatedEmptyDirs(paths3, state) {
10923
+ const rulesDir = dirname10(paths3.targetPath);
10924
+ const claudeDir = dirname10(rulesDir);
10925
+ if (state?.createdRulesDir && existsSync9(rulesDir) && readdirSync2(rulesDir).length === 0) {
10723
10926
  rmdirSync(rulesDir);
10724
10927
  }
10725
- if (state?.createdClaudeDir && existsSync8(claudeDir) && readdirSync2(claudeDir).length === 0) {
10928
+ if (state?.createdClaudeDir && existsSync9(claudeDir) && readdirSync2(claudeDir).length === 0) {
10726
10929
  rmdirSync(claudeDir);
10727
10930
  }
10728
10931
  }
@@ -10733,6 +10936,33 @@ var init_protocol2 = __esm({
10733
10936
  }
10734
10937
  });
10735
10938
 
10939
+ // packages/adapter-cc/dist/protocol-user.js
10940
+ import { homedir as homedir10 } from "node:os";
10941
+ import { join as join15, resolve as resolve6 } from "node:path";
10942
+ function paths(options) {
10943
+ const homeDir = resolve6(options?.homeDir ?? homedir10());
10944
+ return {
10945
+ homeDir,
10946
+ targetPath: join15(homeDir, ".claude", "CLAUDE.md"),
10947
+ dryRun: options?.dryRun ?? false
10948
+ };
10949
+ }
10950
+ function protocolStatusCcUser(options) {
10951
+ return { harness: "cc", ...statusPlanProtocolUser(paths(options).targetPath) };
10952
+ }
10953
+ function installProtocolCcUser(options) {
10954
+ return { harness: "cc", ...installPlanProtocolUser(paths(options)) };
10955
+ }
10956
+ function uninstallProtocolCcUser(options) {
10957
+ return { harness: "cc", ...uninstallPlanProtocolUser(paths(options)) };
10958
+ }
10959
+ var init_protocol_user = __esm({
10960
+ "packages/adapter-cc/dist/protocol-user.js"() {
10961
+ "use strict";
10962
+ init_dist();
10963
+ }
10964
+ });
10965
+
10736
10966
  // packages/adapter-cc/dist/index.js
10737
10967
  var dist_exports2 = {};
10738
10968
  __export(dist_exports2, {
@@ -10740,8 +10970,11 @@ __export(dist_exports2, {
10740
10970
  createAdapter: () => createAdapter2,
10741
10971
  feedbackSignals: () => feedbackSignalsCc,
10742
10972
  installProtocolCc: () => installProtocolCc,
10973
+ installProtocolCcUser: () => installProtocolCcUser,
10743
10974
  protocolStatusCc: () => protocolStatusCc,
10744
- uninstallProtocolCc: () => uninstallProtocolCc
10975
+ protocolStatusCcUser: () => protocolStatusCcUser,
10976
+ uninstallProtocolCc: () => uninstallProtocolCc,
10977
+ uninstallProtocolCcUser: () => uninstallProtocolCcUser
10745
10978
  });
10746
10979
  function createAdapter2(_options) {
10747
10980
  return {
@@ -10764,6 +10997,7 @@ var init_dist3 = __esm({
10764
10997
  init_hooks2();
10765
10998
  init_protocol2();
10766
10999
  init_scan();
11000
+ init_protocol_user();
10767
11001
  }
10768
11002
  });
10769
11003
 
@@ -11476,15 +11710,15 @@ var init_dist4 = __esm({
11476
11710
  });
11477
11711
 
11478
11712
  // packages/adapter-codex/dist/shared.js
11479
- import { homedir as homedir10 } from "node:os";
11480
- import { join as join14 } from "node:path";
11713
+ import { homedir as homedir11 } from "node:os";
11714
+ import { join as join16 } from "node:path";
11481
11715
  function resolvePaths(options) {
11482
- const homeDir = options?.homeDir ?? homedir10();
11716
+ const homeDir = options?.homeDir ?? homedir11();
11483
11717
  const projectDir = options?.projectDir ?? process.cwd();
11484
- return { homeDir, projectDir, codexHome: join14(homeDir, ".codex") };
11718
+ return { homeDir, projectDir, codexHome: join16(homeDir, ".codex") };
11485
11719
  }
11486
- function wingmanStateRoot(paths) {
11487
- return join14(paths.homeDir, ".wingman");
11720
+ function wingmanStateRoot(paths3) {
11721
+ return join16(paths3.homeDir, ".wingman");
11488
11722
  }
11489
11723
  function isTable(value) {
11490
11724
  return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date);
@@ -11793,26 +12027,26 @@ var init_toml_edit = __esm({
11793
12027
  });
11794
12028
 
11795
12029
  // packages/adapter-codex/dist/actions.js
11796
- import { existsSync as existsSync9, mkdirSync as mkdirSync6, readdirSync as readdirSync3, readFileSync as readFileSync9, statSync as statSync3, writeFileSync as writeFileSync7 } from "node:fs";
11797
- import { basename as basename6, dirname as dirname10, join as join15 } from "node:path";
12030
+ import { existsSync as existsSync10, mkdirSync as mkdirSync7, readdirSync as readdirSync3, readFileSync as readFileSync10, statSync as statSync3, writeFileSync as writeFileSync8 } from "node:fs";
12031
+ import { basename as basename7, dirname as dirname11, join as join17 } from "node:path";
11798
12032
  async function planAction(action, options) {
11799
- const paths = resolvePaths(options);
11800
- const resolved = resolveToggle(action, paths);
12033
+ const paths3 = resolvePaths(options);
12034
+ const resolved = resolveToggle(action, paths3);
11801
12035
  return {
11802
12036
  harness: "codex",
11803
12037
  action,
11804
12038
  writes: [
11805
12039
  { file: resolved.file, kind: "modify", before: resolved.before, after: resolved.after }
11806
12040
  ],
11807
- backupDir: nextBackupDir3(paths),
11808
- references: scanReferences(collectCorpus(paths), resolved.bareName),
12041
+ backupDir: nextBackupDir4(paths3),
12042
+ references: scanReferences(collectCorpus(paths3), resolved.bareName),
11809
12043
  // §4b 地面真值:config.toml 启动时读,外改对运行中会话不生效 → 如实报 next_session
11810
12044
  effectiveAt: "next_session"
11811
12045
  };
11812
12046
  }
11813
12047
  async function applyAction(plan, options) {
11814
12048
  try {
11815
- const paths = resolvePaths(options);
12049
+ const paths3 = resolvePaths(options);
11816
12050
  if (plan.harness !== "codex") {
11817
12051
  return { ok: false, error: `plan.harness=${String(plan.harness)} \u4E0D\u662F codex,\u62D2\u7EDD\u6267\u884C` };
11818
12052
  }
@@ -11823,38 +12057,38 @@ async function applyAction(plan, options) {
11823
12057
  error: "plan.writes \u4E0D\u662F\u672C adapter \u4EA7\u51FA\u7684\u5F62\u72B6(\u5E94\u6070\u4E3A\u4E00\u5904 modify),\u62D2\u7EDD\u6267\u884C"
11824
12058
  };
11825
12059
  }
11826
- const backupsRoot = join15(wingmanStateRoot(paths), "backups");
11827
- if (dirname10(plan.backupDir) !== backupsRoot) {
12060
+ const backupsRoot = join17(wingmanStateRoot(paths3), "backups");
12061
+ if (dirname11(plan.backupDir) !== backupsRoot) {
11828
12062
  return { ok: false, error: `backupDir \u4E0D\u5728 wingman \u5907\u4EFD\u6839(${backupsRoot})\u4E0B,\u62D2\u7EDD\u6267\u884C` };
11829
12063
  }
11830
- const currentRaw = readFileSync9(write.file);
12064
+ const currentRaw = readFileSync10(write.file);
11831
12065
  if (!currentRaw.equals(Buffer.from(write.before, "utf8"))) {
11832
12066
  return { ok: false, error: `\u6587\u4EF6\u5728 plan \u4E4B\u540E\u88AB\u4FEE\u6539(${write.file}),\u62D2\u7EDD\u6267\u884C;\u8BF7\u91CD\u65B0 plan` };
11833
12067
  }
11834
- const resolved = resolveToggle(plan.action, paths);
12068
+ const resolved = resolveToggle(plan.action, paths3);
11835
12069
  if (resolved.file !== write.file) {
11836
12070
  return { ok: false, error: "plan.writes \u7684\u76EE\u6807\u6587\u4EF6\u4E0E itemId \u5BF9\u4E0D\u4E0A,\u62D2\u7EDD\u6267\u884C" };
11837
12071
  }
11838
12072
  if (resolved.after !== write.after) {
11839
12073
  return { ok: false, error: "plan \u4E0E\u672C adapter \u7684\u63A8\u6F14\u4E0D\u4E00\u81F4,\u62D2\u7EDD\u6267\u884C;\u8BF7\u91CD\u65B0 plan" };
11840
12074
  }
11841
- mkdirSync6(plan.backupDir, { recursive: true });
11842
- writeFileSync7(join15(plan.backupDir, basename6(write.file)), currentRaw);
11843
- writeFileSync7(write.file, write.after);
12075
+ mkdirSync7(plan.backupDir, { recursive: true });
12076
+ writeFileSync8(join17(plan.backupDir, basename7(write.file)), currentRaw);
12077
+ writeFileSync8(write.file, write.after);
11844
12078
  return { ok: true, backupDir: plan.backupDir };
11845
12079
  } catch (error) {
11846
12080
  return { ok: false, error: error.message };
11847
12081
  }
11848
12082
  }
11849
- function nextBackupDir3(paths) {
12083
+ function nextBackupDir4(paths3) {
11850
12084
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replaceAll(":", "-");
11851
- const base = join15(wingmanStateRoot(paths), "backups");
11852
- let dir = join15(base, stamp);
11853
- for (let n = 1; existsSync9(dir); n += 1)
11854
- dir = join15(base, `${stamp}-${n}`);
12085
+ const base = join17(wingmanStateRoot(paths3), "backups");
12086
+ let dir = join17(base, stamp);
12087
+ for (let n = 1; existsSync10(dir); n += 1)
12088
+ dir = join17(base, `${stamp}-${n}`);
11855
12089
  return dir;
11856
12090
  }
11857
- function resolveToggle(action, paths) {
12091
+ function resolveToggle(action, paths3) {
11858
12092
  if (action.kind !== "toggle") {
11859
12093
  throw new Error(`\u672A\u77E5\u52A8\u4F5C\u79CD\u7C7B:${String(action.kind)}(v1 \u4EC5 toggle \u8D70 plan\u2192apply)`);
11860
12094
  }
@@ -11865,10 +12099,10 @@ function resolveToggle(action, paths) {
11865
12099
  const slot = m[1];
11866
12100
  const source = m[2];
11867
12101
  const nativeName = m[3];
11868
- const file = source === "user" ? join15(paths.codexHome, "config.toml") : join15(paths.projectDir, ".codex", "config.toml");
11869
- if (!existsSync9(file))
12102
+ const file = source === "user" ? join17(paths3.codexHome, "config.toml") : join17(paths3.projectDir, ".codex", "config.toml");
12103
+ if (!existsSync10(file))
11870
12104
  throw new Error(`itemId \u627E\u4E0D\u5230:\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728(${file})`);
11871
- const before = readFileSync9(file, "utf8");
12105
+ const before = readFileSync10(file, "utf8");
11872
12106
  let table;
11873
12107
  try {
11874
12108
  table = parse3(before);
@@ -12089,15 +12323,15 @@ function verifyEdit(table, edit, file) {
12089
12323
  throw new Error(`\u7F16\u8F91\u7ED3\u679C\u4E0E\u671F\u671B\u7684\u6700\u5C0F\u53D8\u66F4\u4E0D\u4E00\u81F4,\u62D2\u7EDD\u5199\u5165(${file})`);
12090
12324
  }
12091
12325
  }
12092
- function collectCorpus(paths) {
12326
+ function collectCorpus(paths3) {
12093
12327
  const candidates = [
12094
- join15(paths.codexHome, "AGENTS.md"),
12095
- join15(paths.projectDir, "AGENTS.md"),
12096
- join15(paths.codexHome, "config.toml"),
12097
- join15(paths.projectDir, ".codex", "config.toml"),
12098
- join15(paths.codexHome, "hooks.json"),
12099
- join15(paths.projectDir, ".codex", "hooks.json"),
12100
- ...listFilesRecursive(join15(paths.codexHome, "prompts"))
12328
+ join17(paths3.codexHome, "AGENTS.md"),
12329
+ join17(paths3.projectDir, "AGENTS.md"),
12330
+ join17(paths3.codexHome, "config.toml"),
12331
+ join17(paths3.projectDir, ".codex", "config.toml"),
12332
+ join17(paths3.codexHome, "hooks.json"),
12333
+ join17(paths3.projectDir, ".codex", "hooks.json"),
12334
+ ...listFilesRecursive(join17(paths3.codexHome, "prompts"))
12101
12335
  ];
12102
12336
  const sources = [];
12103
12337
  for (const file of candidates) {
@@ -12107,7 +12341,7 @@ function collectCorpus(paths) {
12107
12341
  } catch {
12108
12342
  continue;
12109
12343
  }
12110
- sources.push({ file, text: readFileSync9(file, "utf8") });
12344
+ sources.push({ file, text: readFileSync10(file, "utf8") });
12111
12345
  }
12112
12346
  return sources;
12113
12347
  }
@@ -12120,7 +12354,7 @@ function listFilesRecursive(dir) {
12120
12354
  }
12121
12355
  const files = [];
12122
12356
  for (const entry of [...entries].sort((a, b) => a.name.localeCompare(b.name))) {
12123
- const path = join15(dir, entry.name);
12357
+ const path = join17(dir, entry.name);
12124
12358
  if (entry.isDirectory())
12125
12359
  files.push(...listFilesRecursive(path));
12126
12360
  else if (entry.isFile())
@@ -12187,17 +12421,17 @@ var init_actions2 = __esm({
12187
12421
 
12188
12422
  // packages/adapter-codex/dist/hooks.js
12189
12423
  import { spawnSync } from "node:child_process";
12190
- import { existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync10, realpathSync, rmSync as rmSync5, writeFileSync as writeFileSync8 } from "node:fs";
12191
- import { basename as basename7, dirname as dirname11, join as join16 } from "node:path";
12424
+ import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync11, realpathSync, rmSync as rmSync6, writeFileSync as writeFileSync9 } from "node:fs";
12425
+ import { basename as basename8, dirname as dirname12, join as join18 } from "node:path";
12192
12426
  async function installHooks(port, options) {
12193
12427
  if (!Number.isInteger(port) || port <= 0 || port > 65535) {
12194
12428
  throw new Error(`\u975E\u6CD5\u7AEF\u53E3:${port}`);
12195
12429
  }
12196
- const paths = resolvePaths(options);
12197
- const root = wingmanStateRoot(paths);
12198
- const scriptPath = join16(root, FORWARD_SCRIPT_NAME);
12199
- const configPath = join16(paths.codexHome, "config.toml");
12200
- const raw = existsSync10(configPath) ? readFileSync10(configPath) : void 0;
12430
+ const paths3 = resolvePaths(options);
12431
+ const root = wingmanStateRoot(paths3);
12432
+ const scriptPath = join18(root, FORWARD_SCRIPT_NAME);
12433
+ const configPath = join18(paths3.codexHome, "config.toml");
12434
+ const raw = existsSync11(configPath) ? readFileSync11(configPath) : void 0;
12201
12435
  const text = raw?.toString("utf8") ?? "";
12202
12436
  const { before, after, remainder, block } = splitManagedBlock(text, configPath);
12203
12437
  const lineEnding = preferredLineEnding(text);
@@ -12206,8 +12440,8 @@ async function installHooks(port, options) {
12206
12440
  if (block !== void 0 && knownBlock === void 0) {
12207
12441
  throw new Error(`Wingman Codex hook \u53D7\u7BA1\u5757\u5DF2\u88AB\u4FEE\u6539\u6216\u6B8B\u7F3A(${configPath}),\u62D2\u7EDD\u8C0E\u62A5\u63A5\u7EBF\u6210\u529F;\u8BF7\u5148\u4ECE <wingman\u6839>/backups/ \u6062\u590D\u5B8C\u6574\u5757,\u6216\u4EBA\u5DE5\u6838\u5BF9\u540E\u79FB\u9664\u8BE5\u53D7\u7BA1\u5757\u518D\u91CD\u65B0\u5B89\u88C5\u5E76\u4FE1\u4EFB`);
12208
12442
  }
12209
- mkdirSync7(root, { recursive: true });
12210
- writeFileSync8(scriptPath, FORWARD_SCRIPT);
12443
+ mkdirSync8(root, { recursive: true });
12444
+ writeFileSync9(scriptPath, FORWARD_SCRIPT);
12211
12445
  const statePath2 = hooksStatePath(root);
12212
12446
  const prior = readState5(statePath2);
12213
12447
  if (knownBlock !== void 0 && knownBlock.state === void 0) {
@@ -12236,7 +12470,7 @@ async function installHooks(port, options) {
12236
12470
  ...backupDir !== void 0 ? { backupDir } : {}
12237
12471
  });
12238
12472
  const state = hasStateOutsideBlock ? "" : knownBlock.state;
12239
- writeFileSync8(configPath, before + knownBlock.managedBlock + state + after);
12473
+ writeFileSync9(configPath, before + knownBlock.managedBlock + state + after);
12240
12474
  return;
12241
12475
  }
12242
12476
  const original = prior?.original ?? (raw === void 0 ? { existed: false } : { existed: true, base64: raw.toString("base64") });
@@ -12252,17 +12486,17 @@ async function installHooks(port, options) {
12252
12486
  let base = remainder;
12253
12487
  if (base !== "" && !base.endsWith("\n"))
12254
12488
  base += lineEnding;
12255
- mkdirSync7(paths.codexHome, { recursive: true });
12256
- writeFileSync8(configPath, base + newBlock);
12489
+ mkdirSync8(paths3.codexHome, { recursive: true });
12490
+ writeFileSync9(configPath, base + newBlock);
12257
12491
  }
12258
12492
  async function uninstallHooks(options) {
12259
- const paths = resolvePaths(options);
12260
- const root = wingmanStateRoot(paths);
12261
- const scriptPath = join16(root, FORWARD_SCRIPT_NAME);
12493
+ const paths3 = resolvePaths(options);
12494
+ const root = wingmanStateRoot(paths3);
12495
+ const scriptPath = join18(root, FORWARD_SCRIPT_NAME);
12262
12496
  const statePath2 = hooksStatePath(root);
12263
- const configPath = join16(paths.codexHome, "config.toml");
12497
+ const configPath = join18(paths3.codexHome, "config.toml");
12264
12498
  const state = readState5(statePath2);
12265
- const raw = existsSync10(configPath) ? readFileSync10(configPath) : void 0;
12499
+ const raw = existsSync11(configPath) ? readFileSync11(configPath) : void 0;
12266
12500
  if (raw !== void 0) {
12267
12501
  const text = raw.toString("utf8");
12268
12502
  const { before, after, remainder, block } = splitManagedBlock(text, configPath);
@@ -12275,34 +12509,34 @@ async function uninstallHooks(options) {
12275
12509
  const preservedState = hasHooksState(remainder) ? "" : knownBlock.state ?? "";
12276
12510
  const restored = restoreTarget(before + preservedState + after, state);
12277
12511
  if (restored === null)
12278
- rmSync5(configPath);
12512
+ rmSync6(configPath);
12279
12513
  else
12280
- writeFileSync8(configPath, restored);
12514
+ writeFileSync9(configPath, restored);
12281
12515
  }
12282
12516
  }
12283
- rmSync5(scriptPath, { force: true });
12284
- rmSync5(statePath2, { force: true });
12517
+ rmSync6(scriptPath, { force: true });
12518
+ rmSync6(statePath2, { force: true });
12285
12519
  }
12286
- function hasManagedHooks2(paths) {
12287
- const configPath = join16(paths.codexHome, "config.toml");
12288
- if (!existsSync10(configPath))
12520
+ function hasManagedHooks2(paths3) {
12521
+ const configPath = join18(paths3.codexHome, "config.toml");
12522
+ if (!existsSync11(configPath))
12289
12523
  return false;
12290
12524
  try {
12291
- const { block } = splitManagedBlock(readFileSync10(configPath, "utf8"), configPath);
12292
- return block !== void 0 && inspectManagedBlock(block, join16(wingmanStateRoot(paths), FORWARD_SCRIPT_NAME)) !== void 0;
12525
+ const { block } = splitManagedBlock(readFileSync11(configPath, "utf8"), configPath);
12526
+ return block !== void 0 && inspectManagedBlock(block, join18(wingmanStateRoot(paths3), FORWARD_SCRIPT_NAME)) !== void 0;
12293
12527
  } catch {
12294
12528
  return false;
12295
12529
  }
12296
12530
  }
12297
12531
  function feedbackSignalsCodex(options) {
12298
- const paths = resolvePaths(options);
12299
- const configPath = join16(paths.codexHome, "config.toml");
12532
+ const paths3 = resolvePaths(options);
12533
+ const configPath = join18(paths3.codexHome, "config.toml");
12300
12534
  const wiredEvents = [];
12301
- if (existsSync10(configPath)) {
12535
+ if (existsSync11(configPath)) {
12302
12536
  try {
12303
- const { block } = splitManagedBlock(readFileSync10(configPath, "utf8"), configPath);
12537
+ const { block } = splitManagedBlock(readFileSync11(configPath, "utf8"), configPath);
12304
12538
  if (block !== void 0) {
12305
- const knownBlock = inspectManagedBlock(block, join16(wingmanStateRoot(paths), FORWARD_SCRIPT_NAME));
12539
+ const knownBlock = inspectManagedBlock(block, join18(wingmanStateRoot(paths3), FORWARD_SCRIPT_NAME));
12306
12540
  const hooks = knownBlock === void 0 ? void 0 : parse3(normalizeLineEndings(knownBlock.managedBlock)).hooks;
12307
12541
  if (isTable(hooks)) {
12308
12542
  for (const [event, groups] of Object.entries(hooks)) {
@@ -12343,7 +12577,7 @@ function restoreTarget(remainder, state) {
12343
12577
  }
12344
12578
  function resolveNodeExecutable(probe = {}) {
12345
12579
  const execPath = probe.execPath ?? process.execPath;
12346
- const exists = probe.exists ?? existsSync10;
12580
+ const exists = probe.exists ?? existsSync11;
12347
12581
  let executable = isNodeExecutable(execPath) ? execPath : void 0;
12348
12582
  if (executable === void 0) {
12349
12583
  const loginShellWhich = probe.loginShellWhich ?? defaultLoginShellWhich;
@@ -12390,13 +12624,13 @@ function defaultRealpath(path) {
12390
12624
  }
12391
12625
  }
12392
12626
  function defaultLoginShellWhich(shell) {
12393
- const result4 = spawnSync(shell, ["-lc", "command -v node"], {
12627
+ const result5 = spawnSync(shell, ["-lc", "command -v node"], {
12394
12628
  encoding: "utf8",
12395
12629
  timeout: 3e3
12396
12630
  });
12397
- if (result4.error !== void 0)
12631
+ if (result5.error !== void 0)
12398
12632
  return void 0;
12399
- return result4.stdout.trim() || void 0;
12633
+ return result5.stdout.trim() || void 0;
12400
12634
  }
12401
12635
  function buildManagedBlock(scriptPath, nodeExecutable = "node") {
12402
12636
  return buildManagedBlockForCommand(`${nodeExecutable} "${scriptPath}"`);
@@ -12548,28 +12782,28 @@ function hasHooksState(text) {
12548
12782
  }
12549
12783
  function backupFile(root, filePath, contents) {
12550
12784
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replaceAll(":", "-");
12551
- let dir = join16(root, "backups", stamp);
12552
- for (let n = 1; existsSync10(dir); n += 1)
12553
- dir = join16(root, "backups", `${stamp}-${n}`);
12554
- mkdirSync7(dir, { recursive: true });
12555
- writeFileSync8(join16(dir, basename7(filePath)), contents);
12785
+ let dir = join18(root, "backups", stamp);
12786
+ for (let n = 1; existsSync11(dir); n += 1)
12787
+ dir = join18(root, "backups", `${stamp}-${n}`);
12788
+ mkdirSync8(dir, { recursive: true });
12789
+ writeFileSync9(join18(dir, basename8(filePath)), contents);
12556
12790
  return dir;
12557
12791
  }
12558
12792
  function hooksStatePath(root) {
12559
- return join16(root, "state", "codex-hooks.json");
12793
+ return join18(root, "state", "codex-hooks.json");
12560
12794
  }
12561
12795
  function readState5(statePath2) {
12562
- if (!existsSync10(statePath2))
12796
+ if (!existsSync11(statePath2))
12563
12797
  return void 0;
12564
12798
  try {
12565
- return JSON.parse(readFileSync10(statePath2, "utf8"));
12799
+ return JSON.parse(readFileSync11(statePath2, "utf8"));
12566
12800
  } catch {
12567
12801
  return void 0;
12568
12802
  }
12569
12803
  }
12570
12804
  function writeState5(statePath2, state) {
12571
- mkdirSync7(dirname11(statePath2), { recursive: true });
12572
- writeFileSync8(statePath2, `${JSON.stringify(state, null, 2)}
12805
+ mkdirSync8(dirname12(statePath2), { recursive: true });
12806
+ writeFileSync9(statePath2, `${JSON.stringify(state, null, 2)}
12573
12807
  `);
12574
12808
  }
12575
12809
  function deepEqual3(a, b) {
@@ -12725,15 +12959,15 @@ process.stdin.on('end', async () => {
12725
12959
  });
12726
12960
 
12727
12961
  // packages/adapter-codex/dist/scan.js
12728
- import { existsSync as existsSync11, readdirSync as readdirSync4, readFileSync as readFileSync11, statSync as statSync4 } from "node:fs";
12729
- import { dirname as dirname12, isAbsolute as isAbsolute3, join as join17, resolve as resolve6 } from "node:path";
12962
+ import { existsSync as existsSync12, readdirSync as readdirSync4, readFileSync as readFileSync12, statSync as statSync4 } from "node:fs";
12963
+ import { dirname as dirname13, isAbsolute as isAbsolute3, join as join19, resolve as resolve7 } from "node:path";
12730
12964
  async function detect(options) {
12731
12965
  const { codexHome } = resolvePaths(options);
12732
- return { installed: existsSync11(codexHome) };
12966
+ return { installed: existsSync12(codexHome) };
12733
12967
  }
12734
12968
  async function scan(options) {
12735
- const paths = resolvePaths(options);
12736
- const layers = loadConfigLayers(paths);
12969
+ const paths3 = resolvePaths(options);
12970
+ const layers = loadConfigLayers(paths3);
12737
12971
  const slots = {
12738
12972
  base: [],
12739
12973
  rules: [],
@@ -12742,14 +12976,14 @@ async function scan(options) {
12742
12976
  gates: [],
12743
12977
  history: []
12744
12978
  };
12745
- collectRules(slots.rules, paths, layers);
12979
+ collectRules(slots.rules, paths3, layers);
12746
12980
  for (const layer of layers) {
12747
12981
  collectBase(slots.base, layer);
12748
12982
  collectSkills(slots.skills, layer);
12749
12983
  collectTools(slots.tools, layer);
12750
12984
  collectGates(slots.gates, layer);
12751
12985
  }
12752
- collectHistory(slots.history, paths, layers);
12986
+ collectHistory(slots.history, paths3, layers);
12753
12987
  assertUniqueIds(slots);
12754
12988
  return {
12755
12989
  harness: "codex",
@@ -12759,21 +12993,21 @@ async function scan(options) {
12759
12993
  // actions:M3 起 toggle(plan→apply)/scan_references(命中随 plan)已落地;
12760
12994
  // open_editor 是面板用 nativePath 跳转的即时动作,无需 adapter 方法
12761
12995
  capabilities: {
12762
- live: hasManagedHooks2(paths) ? "push" : "none",
12996
+ live: hasManagedHooks2(paths3) ? "push" : "none",
12763
12997
  actions: ["toggle", "open_editor", "scan_references"]
12764
12998
  }
12765
12999
  };
12766
13000
  }
12767
- function loadConfigLayers(paths) {
13001
+ function loadConfigLayers(paths3) {
12768
13002
  const candidates = [
12769
- ["user", join17(paths.codexHome, "config.toml")],
12770
- ["project", join17(paths.projectDir, ".codex", "config.toml")]
13003
+ ["user", join19(paths3.codexHome, "config.toml")],
13004
+ ["project", join19(paths3.projectDir, ".codex", "config.toml")]
12771
13005
  ];
12772
13006
  const layers = [];
12773
13007
  for (const [source, path] of candidates) {
12774
13008
  if (fileSize(path) === void 0)
12775
13009
  continue;
12776
- const text = readFileSync11(path, "utf8");
13010
+ const text = readFileSync12(path, "utf8");
12777
13011
  try {
12778
13012
  layers.push({ source, path, table: parse3(text) });
12779
13013
  } catch (error) {
@@ -12782,10 +13016,10 @@ function loadConfigLayers(paths) {
12782
13016
  }
12783
13017
  return layers;
12784
13018
  }
12785
- function collectRules(out, paths, layers) {
13019
+ function collectRules(out, paths3, layers) {
12786
13020
  const agentsChain = [
12787
- ["user", join17(paths.codexHome, "AGENTS.md")],
12788
- ["project", join17(paths.projectDir, "AGENTS.md")]
13021
+ ["user", join19(paths3.codexHome, "AGENTS.md")],
13022
+ ["project", join19(paths3.projectDir, "AGENTS.md")]
12789
13023
  ];
12790
13024
  for (const [source, file] of agentsChain) {
12791
13025
  const size = fileSize(file);
@@ -12820,7 +13054,7 @@ function collectRules(out, paths, layers) {
12820
13054
  }
12821
13055
  const instructionsFile = layer.table.model_instructions_file;
12822
13056
  if (typeof instructionsFile === "string") {
12823
- const filePath = isAbsolute3(instructionsFile) ? instructionsFile : resolve6(dirname12(layer.path), instructionsFile);
13057
+ const filePath = isAbsolute3(instructionsFile) ? instructionsFile : resolve7(dirname13(layer.path), instructionsFile);
12824
13058
  const item = {
12825
13059
  id: `codex:rules:${layer.source}:model_instructions_file`,
12826
13060
  slot: "rules",
@@ -12919,8 +13153,8 @@ function collectGates(out, layer) {
12919
13153
  });
12920
13154
  }
12921
13155
  }
12922
- function collectHistory(out, paths, layers) {
12923
- const historyFile = join17(paths.codexHome, "history.jsonl");
13156
+ function collectHistory(out, paths3, layers) {
13157
+ const historyFile = join19(paths3.codexHome, "history.jsonl");
12924
13158
  const historyBytes = fileSize(historyFile);
12925
13159
  if (historyBytes !== void 0) {
12926
13160
  out.push({
@@ -12935,7 +13169,7 @@ function collectHistory(out, paths, layers) {
12935
13169
  });
12936
13170
  }
12937
13171
  const configured = layers.find((layer) => layer.source === "user")?.table.log_dir;
12938
- const logDir = typeof configured === "string" ? expandPath(configured, paths) : join17(paths.codexHome, "log");
13172
+ const logDir = typeof configured === "string" ? expandPath(configured, paths3) : join19(paths3.codexHome, "log");
12939
13173
  if (isDirectory(logDir)) {
12940
13174
  out.push({
12941
13175
  id: "codex:history:user:log_dir",
@@ -12949,10 +13183,10 @@ function collectHistory(out, paths, layers) {
12949
13183
  });
12950
13184
  }
12951
13185
  }
12952
- function expandPath(value, paths) {
13186
+ function expandPath(value, paths3) {
12953
13187
  if (value === "~" || value.startsWith("~/"))
12954
- return join17(paths.homeDir, value.slice(2));
12955
- return isAbsolute3(value) ? value : resolve6(paths.codexHome, value);
13188
+ return join19(paths3.homeDir, value.slice(2));
13189
+ return isAbsolute3(value) ? value : resolve7(paths3.codexHome, value);
12956
13190
  }
12957
13191
  function assertUniqueIds(slots) {
12958
13192
  const seen = /* @__PURE__ */ new Set();
@@ -12983,7 +13217,7 @@ function isDirectory(path) {
12983
13217
  function directoryBytes(dir) {
12984
13218
  let total = 0;
12985
13219
  for (const entry of readdirSync4(dir, { withFileTypes: true })) {
12986
- const entryPath = join17(dir, entry.name);
13220
+ const entryPath = join19(dir, entry.name);
12987
13221
  if (entry.isDirectory())
12988
13222
  total += directoryBytes(entryPath);
12989
13223
  else if (entry.isFile())
@@ -13005,54 +13239,54 @@ var init_scan2 = __esm({
13005
13239
  });
13006
13240
 
13007
13241
  // packages/adapter-codex/dist/protocol.js
13008
- import { existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync12, rmSync as rmSync6, writeFileSync as writeFileSync9 } from "node:fs";
13009
- import { basename as basename8, dirname as dirname13, join as join18, resolve as resolve7 } from "node:path";
13242
+ import { existsSync as existsSync13, mkdirSync as mkdirSync9, readFileSync as readFileSync13, rmSync as rmSync7, writeFileSync as writeFileSync10 } from "node:fs";
13243
+ import { basename as basename9, dirname as dirname14, join as join20, resolve as resolve8 } from "node:path";
13010
13244
  function protocolStatusCodex(options) {
13011
- const paths = resolveOptions3(options);
13012
- if (!existsSync12(paths.targetPath))
13013
- return status2(paths.targetPath, "not_installed");
13245
+ const paths3 = resolveOptions3(options);
13246
+ if (!existsSync13(paths3.targetPath))
13247
+ return status2(paths3.targetPath, "not_installed");
13014
13248
  try {
13015
- const file = readAgents2(paths.targetPath);
13249
+ const file = readAgents2(paths3.targetPath);
13016
13250
  if (file.identity === void 0)
13017
- return status2(paths.targetPath, "not_installed");
13251
+ return status2(paths3.targetPath, "not_installed");
13018
13252
  const state = stateForIdentity3(file.identity);
13019
- return status2(paths.targetPath, state, file.identity);
13253
+ return status2(paths3.targetPath, state, file.identity);
13020
13254
  } catch (error) {
13021
- return status2(paths.targetPath, "invalid", void 0, error.message);
13255
+ return status2(paths3.targetPath, "invalid", void 0, error.message);
13022
13256
  }
13023
13257
  }
13024
13258
  function installProtocolCodex(options) {
13025
- const paths = resolveOptions3(options);
13026
- const existing = existsSync12(paths.targetPath) ? readAgents2(paths.targetPath) : void 0;
13259
+ const paths3 = resolveOptions3(options);
13260
+ const existing = existsSync13(paths3.targetPath) ? readAgents2(paths3.targetPath) : void 0;
13027
13261
  const previousState = stateForIdentity3(existing?.identity);
13028
13262
  if (previousState === "installed") {
13029
- return result3(paths.targetPath, "install", false, previousState, existing?.text ?? "", true);
13263
+ return result4(paths3.targetPath, "install", false, previousState, existing?.text ?? "", true);
13030
13264
  }
13031
13265
  if (previousState === "modified")
13032
- throw modifiedError3(paths.targetPath, "\u5B89\u88C5");
13266
+ throw modifiedError3(paths3.targetPath, "\u5B89\u88C5");
13033
13267
  const before = existing?.text ?? "";
13034
13268
  const lineEnding = preferredMarkdownLineEnding(before);
13035
13269
  const block = buildPlanProtocolBlock().replaceAll("\n", lineEnding);
13036
13270
  const after = existing?.split.block ? existing.split.before + block + existing.split.after : appendBlock2(before, block, lineEnding);
13037
- const installedRemainder = splitPlanProtocolBlock(after, paths.targetPath).remainder;
13038
- const backupDir = nextBackupDir4(paths.homeDir);
13039
- if (!paths.dryRun) {
13040
- const prior = readState6(paths.statePath, paths.targetPath);
13041
- backupTarget3(backupDir, paths.targetPath, existing?.bytes);
13042
- writeState6(paths.statePath, {
13271
+ const installedRemainder = splitPlanProtocolBlock(after, paths3.targetPath).remainder;
13272
+ const backupDir = nextBackupDir5(paths3.homeDir);
13273
+ if (!paths3.dryRun) {
13274
+ const prior = readState6(paths3.statePath, paths3.targetPath);
13275
+ backupTarget4(backupDir, paths3.targetPath, existing?.bytes);
13276
+ writeState6(paths3.statePath, {
13043
13277
  version: 1,
13044
- projectDir: paths.projectDir,
13045
- targetPath: paths.targetPath,
13278
+ projectDir: paths3.projectDir,
13279
+ targetPath: paths3.targetPath,
13046
13280
  protocolVersion: PLAN_PROTOCOL_VERSION,
13047
13281
  installedAt: (/* @__PURE__ */ new Date()).toISOString(),
13048
13282
  backupDir,
13049
- installedRemainderSha256: sha256Hex(installedRemainder),
13283
+ installedRemainderSha256: previousState === "outdated" && prior !== void 0 ? prior.installedRemainderSha256 : sha256Hex(installedRemainder),
13050
13284
  original: prior?.original ?? (existing === void 0 ? { existed: false } : { existed: true, base64: existing.bytes.toString("base64") })
13051
13285
  });
13052
- writeFileSync9(paths.targetPath, after);
13286
+ writeFileSync10(paths3.targetPath, after);
13053
13287
  }
13054
13288
  return {
13055
- ...result3(paths.targetPath, "install", true, previousState, before, true),
13289
+ ...result4(paths3.targetPath, "install", true, previousState, before, true),
13056
13290
  state: "installed",
13057
13291
  version: PLAN_PROTOCOL_VERSION,
13058
13292
  after,
@@ -13061,33 +13295,33 @@ function installProtocolCodex(options) {
13061
13295
  };
13062
13296
  }
13063
13297
  function uninstallProtocolCodex(options) {
13064
- const paths = resolveOptions3(options);
13065
- if (!existsSync12(paths.targetPath)) {
13066
- return result3(paths.targetPath, "uninstall", false, "not_installed", "", false);
13298
+ const paths3 = resolveOptions3(options);
13299
+ if (!existsSync13(paths3.targetPath)) {
13300
+ return result4(paths3.targetPath, "uninstall", false, "not_installed", "", false);
13067
13301
  }
13068
- const existing = readAgents2(paths.targetPath);
13302
+ const existing = readAgents2(paths3.targetPath);
13069
13303
  if (existing.identity === void 0) {
13070
- return result3(paths.targetPath, "uninstall", false, "not_installed", existing.text, true);
13304
+ return result4(paths3.targetPath, "uninstall", false, "not_installed", existing.text, true);
13071
13305
  }
13072
13306
  const previousState = stateForIdentity3(existing.identity);
13073
13307
  if (previousState === "modified")
13074
- throw modifiedError3(paths.targetPath, "\u5378\u8F7D");
13075
- const state = readState6(paths.statePath, paths.targetPath);
13308
+ throw modifiedError3(paths3.targetPath, "\u5378\u8F7D");
13309
+ const state = readState6(paths3.statePath, paths3.targetPath);
13076
13310
  const canRestore = state !== void 0 && sha256Hex(existing.split.remainder) === state.installedRemainderSha256;
13077
13311
  const restored = canRestore ? originalBytes2(state) : void 0;
13078
13312
  const deleteTarget = canRestore ? state?.original.existed === false : existing.split.remainder.trim() === "";
13079
13313
  const after = deleteTarget ? "" : restored?.toString("utf8") ?? existing.split.remainder;
13080
- const backupDir = nextBackupDir4(paths.homeDir);
13081
- if (!paths.dryRun) {
13082
- backupTarget3(backupDir, paths.targetPath, existing.bytes);
13314
+ const backupDir = nextBackupDir5(paths3.homeDir);
13315
+ if (!paths3.dryRun) {
13316
+ backupTarget4(backupDir, paths3.targetPath, existing.bytes);
13083
13317
  if (deleteTarget)
13084
- rmSync6(paths.targetPath, { force: true });
13318
+ rmSync7(paths3.targetPath, { force: true });
13085
13319
  else
13086
- writeFileSync9(paths.targetPath, restored ?? existing.split.remainder);
13087
- rmSync6(paths.statePath, { force: true });
13320
+ writeFileSync10(paths3.targetPath, restored ?? existing.split.remainder);
13321
+ rmSync7(paths3.statePath, { force: true });
13088
13322
  }
13089
13323
  return {
13090
- ...result3(paths.targetPath, "uninstall", true, previousState, existing.text, !deleteTarget),
13324
+ ...result4(paths3.targetPath, "uninstall", true, previousState, existing.text, !deleteTarget),
13091
13325
  state: "not_installed",
13092
13326
  message: canRestore ? SHARED_MESSAGE2 : `${SHARED_MESSAGE2}\uFF1B\u5DF2\u79FB\u9664\u5757\u5E76\u4FDD\u7559\u7528\u6237\u6539\u52A8`,
13093
13327
  after,
@@ -13098,15 +13332,16 @@ function uninstallProtocolCodex(options) {
13098
13332
  }
13099
13333
  function resolveOptions3(options) {
13100
13334
  const base = resolvePaths(options);
13101
- const homeDir = resolve7(base.homeDir);
13102
- const projectDir = resolve7(base.projectDir);
13103
- const targetPath2 = join18(projectDir, "AGENTS.md");
13104
- const statePath2 = join18(wingmanStateRoot({ ...base, homeDir, projectDir }), "state", `plan-protocol-agents-${sha256Hex(projectDir)}.json`);
13335
+ const homeDir = resolve8(base.homeDir);
13336
+ const projectDir = resolve8(base.projectDir);
13337
+ const targetPath2 = join20(projectDir, "AGENTS.md");
13338
+ const statePath2 = join20(wingmanStateRoot({ ...base, homeDir, projectDir }), "state", `plan-protocol-agents-${sha256Hex(projectDir)}.json`);
13105
13339
  return { homeDir, projectDir, targetPath: targetPath2, statePath: statePath2, dryRun: options?.dryRun ?? false };
13106
13340
  }
13107
13341
  function readAgents2(targetPath2) {
13108
- const bytes = readFileSync12(targetPath2);
13109
- const text = decodeUtf8Strict2(bytes, targetPath2);
13342
+ const bytes = readFileSync13(targetPath2);
13343
+ decodeUtf8Strict2(bytes, targetPath2);
13344
+ const text = bytes.toString("utf8");
13110
13345
  let split;
13111
13346
  try {
13112
13347
  split = splitPlanProtocolBlock(text, targetPath2);
@@ -13135,7 +13370,7 @@ function stateForIdentity3(identity) {
13135
13370
  return "not_installed";
13136
13371
  if (identity.kind === "current")
13137
13372
  return "installed";
13138
- if (identity.kind === "legacy")
13373
+ if (identity.kind === "outdated")
13139
13374
  return "outdated";
13140
13375
  return "modified";
13141
13376
  }
@@ -13150,7 +13385,7 @@ function status2(targetPath2, state, identity, reason) {
13150
13385
  ...reason !== void 0 ? { reason } : {}
13151
13386
  };
13152
13387
  }
13153
- function result3(targetPath2, operation, changed, previousState, before, afterExists) {
13388
+ function result4(targetPath2, operation, changed, previousState, before, afterExists) {
13154
13389
  return {
13155
13390
  ...status2(targetPath2, previousState),
13156
13391
  operation,
@@ -13166,32 +13401,32 @@ function result3(targetPath2, operation, changed, previousState, before, afterEx
13166
13401
  function modifiedError3(targetPath2, operation) {
13167
13402
  return new Error(`${targetPath2}: \u53D7\u7BA1\u5757\u5DF2\u88AB\u4FEE\u6539\uFF0C\u62D2\u7EDD${operation}\u5E76\u4FDD\u7559\u7528\u6237\u5185\u5BB9`);
13168
13403
  }
13169
- function nextBackupDir4(homeDir) {
13404
+ function nextBackupDir5(homeDir) {
13170
13405
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replaceAll(":", "-");
13171
- const root = join18(homeDir, ".wingman", "backups");
13172
- let dir = join18(root, stamp);
13173
- for (let n = 2; existsSync12(dir); n += 1)
13174
- dir = join18(root, `${stamp}-${n}`);
13406
+ const root = join20(homeDir, ".wingman", "backups");
13407
+ let dir = join20(root, stamp);
13408
+ for (let n = 2; existsSync13(dir); n += 1)
13409
+ dir = join20(root, `${stamp}-${n}`);
13175
13410
  return dir;
13176
13411
  }
13177
- function backupTarget3(backupDir, targetPath2, bytes) {
13178
- mkdirSync8(backupDir, { recursive: true });
13412
+ function backupTarget4(backupDir, targetPath2, bytes) {
13413
+ mkdirSync9(backupDir, { recursive: true });
13179
13414
  if (bytes !== void 0)
13180
- writeFileSync9(join18(backupDir, basename8(targetPath2)), bytes);
13415
+ writeFileSync10(join20(backupDir, basename9(targetPath2)), bytes);
13181
13416
  }
13182
13417
  function readState6(statePath2, targetPath2) {
13183
- if (!existsSync12(statePath2))
13418
+ if (!existsSync13(statePath2))
13184
13419
  return void 0;
13185
13420
  try {
13186
- const value = JSON.parse(readFileSync12(statePath2, "utf8"));
13421
+ const value = JSON.parse(readFileSync13(statePath2, "utf8"));
13187
13422
  return value.version === 1 && value.targetPath === targetPath2 ? value : void 0;
13188
13423
  } catch {
13189
13424
  return void 0;
13190
13425
  }
13191
13426
  }
13192
13427
  function writeState6(statePath2, state) {
13193
- mkdirSync8(dirname13(statePath2), { recursive: true });
13194
- writeFileSync9(statePath2, `${JSON.stringify(state, null, 2)}
13428
+ mkdirSync9(dirname14(statePath2), { recursive: true });
13429
+ writeFileSync10(statePath2, `${JSON.stringify(state, null, 2)}
13195
13430
  `);
13196
13431
  }
13197
13432
  function originalBytes2(state) {
@@ -13207,6 +13442,33 @@ var init_protocol3 = __esm({
13207
13442
  }
13208
13443
  });
13209
13444
 
13445
+ // packages/adapter-codex/dist/protocol-user.js
13446
+ import { homedir as homedir12 } from "node:os";
13447
+ import { join as join21, resolve as resolve9 } from "node:path";
13448
+ function paths2(options) {
13449
+ const homeDir = resolve9(options?.homeDir ?? homedir12());
13450
+ return {
13451
+ homeDir,
13452
+ targetPath: join21(homeDir, ".codex", "AGENTS.md"),
13453
+ dryRun: options?.dryRun ?? false
13454
+ };
13455
+ }
13456
+ function protocolStatusCodexUser(options) {
13457
+ return { harness: "codex", ...statusPlanProtocolUser(paths2(options).targetPath) };
13458
+ }
13459
+ function installProtocolCodexUser(options) {
13460
+ return { harness: "codex", ...installPlanProtocolUser(paths2(options)) };
13461
+ }
13462
+ function uninstallProtocolCodexUser(options) {
13463
+ return { harness: "codex", ...uninstallPlanProtocolUser(paths2(options)) };
13464
+ }
13465
+ var init_protocol_user2 = __esm({
13466
+ "packages/adapter-codex/dist/protocol-user.js"() {
13467
+ "use strict";
13468
+ init_dist();
13469
+ }
13470
+ });
13471
+
13210
13472
  // packages/adapter-codex/dist/index.js
13211
13473
  var dist_exports3 = {};
13212
13474
  __export(dist_exports3, {
@@ -13214,9 +13476,12 @@ __export(dist_exports3, {
13214
13476
  createAdapter: () => createAdapter3,
13215
13477
  feedbackSignals: () => feedbackSignalsCodex,
13216
13478
  installProtocolCodex: () => installProtocolCodex,
13479
+ installProtocolCodexUser: () => installProtocolCodexUser,
13217
13480
  protocolStatusCodex: () => protocolStatusCodex,
13481
+ protocolStatusCodexUser: () => protocolStatusCodexUser,
13218
13482
  resolveNodeExecutable: () => resolveNodeExecutable,
13219
- uninstallProtocolCodex: () => uninstallProtocolCodex
13483
+ uninstallProtocolCodex: () => uninstallProtocolCodex,
13484
+ uninstallProtocolCodexUser: () => uninstallProtocolCodexUser
13220
13485
  });
13221
13486
  function createAdapter3(_options) {
13222
13487
  return {
@@ -13237,23 +13502,24 @@ var init_dist5 = __esm({
13237
13502
  init_scan2();
13238
13503
  init_hooks3();
13239
13504
  init_protocol3();
13505
+ init_protocol_user2();
13240
13506
  }
13241
13507
  });
13242
13508
 
13243
13509
  // apps/cli/dist/main.js
13244
13510
  init_dist2();
13245
13511
  init_dist();
13246
- import { readFileSync as readFileSync18 } from "node:fs";
13247
- import { homedir as homedir13 } from "node:os";
13248
- import { dirname as dirname19, resolve as resolve12 } from "node:path";
13512
+ import { readFileSync as readFileSync19 } from "node:fs";
13513
+ import { homedir as homedir16 } from "node:os";
13514
+ import { dirname as dirname20, resolve as resolve14 } from "node:path";
13249
13515
  import { fileURLToPath as fileURLToPath2 } from "node:url";
13250
13516
 
13251
13517
  // packages/fixtures/dist/index.js
13252
- import { dirname as dirname4, join as join5 } from "node:path";
13518
+ import { dirname as dirname5, join as join6 } from "node:path";
13253
13519
  import { fileURLToPath } from "node:url";
13254
- var fixturesRoot = join5(dirname4(dirname4(fileURLToPath(import.meta.url))), "data");
13520
+ var fixturesRoot = join6(dirname5(dirname5(fileURLToPath(import.meta.url))), "data");
13255
13521
  function fixturePath(...segments) {
13256
- return join5(fixturesRoot, ...segments);
13522
+ return join6(fixturesRoot, ...segments);
13257
13523
  }
13258
13524
 
13259
13525
  // packages/live/dist/receiver.js
@@ -13373,7 +13639,7 @@ function isHookPayload(value) {
13373
13639
  }
13374
13640
  var HOOK_BODY_LIMIT = 1024 * 1024;
13375
13641
  function readBody(req) {
13376
- return new Promise((resolve13, reject) => {
13642
+ return new Promise((resolve15, reject) => {
13377
13643
  const chunks = [];
13378
13644
  let size = 0;
13379
13645
  req.on("data", (chunk) => {
@@ -13385,7 +13651,7 @@ function readBody(req) {
13385
13651
  }
13386
13652
  chunks.push(chunk);
13387
13653
  });
13388
- req.on("end", () => resolve13(Buffer.concat(chunks).toString("utf8")));
13654
+ req.on("end", () => resolve15(Buffer.concat(chunks).toString("utf8")));
13389
13655
  req.on("error", reject);
13390
13656
  });
13391
13657
  }
@@ -13400,9 +13666,9 @@ function sendText(res, status3, body) {
13400
13666
 
13401
13667
  // apps/cli/dist/license.js
13402
13668
  import { verify } from "node:crypto";
13403
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync, writeFileSync as writeFileSync2 } from "node:fs";
13669
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync, writeFileSync as writeFileSync3 } from "node:fs";
13404
13670
  import { homedir as homedir3 } from "node:os";
13405
- import { join as join6 } from "node:path";
13671
+ import { join as join7 } from "node:path";
13406
13672
  var OFFLINE_GRACE_DAYS = 14;
13407
13673
  var PROD_PUBLIC_KEY_PEM = "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAyU4yO0SJcflt/CV77wqVxIwCkM52CYGC6qrPGP8dMME=\n-----END PUBLIC KEY-----\n";
13408
13674
  function checkLicense(options = {}) {
@@ -13416,7 +13682,7 @@ function licenseStatus(options = {}) {
13416
13682
  const home = options.homeDir ?? homedir3();
13417
13683
  let raw;
13418
13684
  try {
13419
- raw = readFileSync2(join6(home, ".wingman", "license.json"), "utf8");
13685
+ raw = readFileSync3(join7(home, ".wingman", "license.json"), "utf8");
13420
13686
  } catch {
13421
13687
  return { state: "none", detail: "\u672A\u5B89\u88C5 license(anatomy \u4E0E\u5B9E\u51B5\u514D\u8D39\u53EF\u7528;\u5199\u52A8\u4F5C\u9700\u8BA2\u9605)" };
13422
13688
  }
@@ -13483,7 +13749,7 @@ function verifyEntitlement(raw, now, publicKeyPem) {
13483
13749
  function nextLicenseBackupPath(licensePath, now) {
13484
13750
  const base = `${licensePath}.bak-${now.toISOString().replaceAll(":", "-")}`;
13485
13751
  let candidate = base;
13486
- for (let index = 2; existsSync3(candidate); index++)
13752
+ for (let index = 2; existsSync4(candidate); index++)
13487
13753
  candidate = `${base}-${index}`;
13488
13754
  return candidate;
13489
13755
  }
@@ -13504,13 +13770,13 @@ function installLicense(raw, options = {}) {
13504
13770
  return { ok: false, error: status3.detail };
13505
13771
  }
13506
13772
  }
13507
- const dir = join6(options.homeDir ?? homedir3(), ".wingman");
13508
- const licensePath = join6(dir, "license.json");
13509
- const tmpPath = join6(dir, `.license.json.tmp-${process.pid}`);
13773
+ const dir = join7(options.homeDir ?? homedir3(), ".wingman");
13774
+ const licensePath = join7(dir, "license.json");
13775
+ const tmpPath = join7(dir, `.license.json.tmp-${process.pid}`);
13510
13776
  try {
13511
- mkdirSync2(dir, { recursive: true });
13512
- writeFileSync2(tmpPath, raw);
13513
- if (existsSync3(licensePath)) {
13777
+ mkdirSync3(dir, { recursive: true });
13778
+ writeFileSync3(tmpPath, raw);
13779
+ if (existsSync4(licensePath)) {
13514
13780
  renameSync(licensePath, nextLicenseBackupPath(licensePath, options.now ?? /* @__PURE__ */ new Date()));
13515
13781
  }
13516
13782
  renameSync(tmpPath, licensePath);
@@ -13522,17 +13788,17 @@ function installLicense(raw, options = {}) {
13522
13788
  }
13523
13789
 
13524
13790
  // apps/cli/dist/license-refresh.js
13525
- import { copyFileSync, readFileSync as readFileSync3, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "node:fs";
13791
+ import { copyFileSync, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "node:fs";
13526
13792
  import { homedir as homedir4 } from "node:os";
13527
- import { dirname as dirname5, join as join7 } from "node:path";
13793
+ import { dirname as dirname6, join as join8 } from "node:path";
13528
13794
  var DEFAULT_LICENSE_SERVER = "https://api.getwingman.dev";
13529
13795
  async function refreshLicense(options = {}) {
13530
13796
  const home = options.homeDir ?? homedir4();
13531
13797
  const baseUrl = options.baseUrl ?? process.env.WINGMAN_LICENSE_SERVER ?? DEFAULT_LICENSE_SERVER;
13532
- const licensePath = join7(home, ".wingman", "license.json");
13798
+ const licensePath = join8(home, ".wingman", "license.json");
13533
13799
  let raw;
13534
13800
  try {
13535
- raw = readFileSync3(licensePath, "utf8");
13801
+ raw = readFileSync4(licensePath, "utf8");
13536
13802
  } catch {
13537
13803
  return {
13538
13804
  ok: false,
@@ -13602,7 +13868,7 @@ async function refreshLicense(options = {}) {
13602
13868
  }
13603
13869
  }
13604
13870
  try {
13605
- if (readFileSync3(licensePath, "utf8") !== raw) {
13871
+ if (readFileSync4(licensePath, "utf8") !== raw) {
13606
13872
  return {
13607
13873
  ok: false,
13608
13874
  message: "\u5237\u65B0\u671F\u95F4\u672C\u673A\u6388\u6743\u5DF2\u88AB\u66F4\u6362;\u5DF2\u4FDD\u7559\u8F83\u65B0\u7684\u6587\u4EF6,\u8BF7\u518D\u70B9\u4E00\u6B21\u5237\u65B0",
@@ -13616,9 +13882,9 @@ async function refreshLicense(options = {}) {
13616
13882
  reason: "changed"
13617
13883
  };
13618
13884
  }
13619
- const tmpPath = join7(dirname5(licensePath), `.license.json.tmp-${process.pid}`);
13885
+ const tmpPath = join8(dirname6(licensePath), `.license.json.tmp-${process.pid}`);
13620
13886
  try {
13621
- writeFileSync3(tmpPath, next);
13887
+ writeFileSync4(tmpPath, next);
13622
13888
  copyFileSync(licensePath, nextLicenseBackupPath(licensePath, options.now ?? /* @__PURE__ */ new Date()));
13623
13889
  renameSync2(tmpPath, licensePath);
13624
13890
  } catch (error) {
@@ -13646,7 +13912,7 @@ init_dist5();
13646
13912
  init_dist2();
13647
13913
  init_dist();
13648
13914
  import { readdir as readdir2 } from "node:fs/promises";
13649
- import { isAbsolute as isAbsolute6, join as join22, resolve as resolve9 } from "node:path";
13915
+ import { isAbsolute as isAbsolute6, join as join25, resolve as resolve11 } from "node:path";
13650
13916
 
13651
13917
  // packages/narrative/dist/attribute.js
13652
13918
  function extractSteps(lines2) {
@@ -13671,13 +13937,13 @@ function extractSteps(lines2) {
13671
13937
  byToolUseId.set(block.id, step);
13672
13938
  }
13673
13939
  } else if (line.kind === "user") {
13674
- for (const result4 of line.toolResults) {
13675
- const step = byToolUseId.get(result4.toolUseId);
13940
+ for (const result5 of line.toolResults) {
13941
+ const step = byToolUseId.get(result5.toolUseId);
13676
13942
  if (step === void 0)
13677
13943
  continue;
13678
13944
  if (line.timestamp !== void 0)
13679
13945
  step.endTs = line.timestamp;
13680
- if (result4.isError)
13946
+ if (result5.isError)
13681
13947
  step.isError = true;
13682
13948
  }
13683
13949
  }
@@ -13849,17 +14115,17 @@ function parseResponseItem(payload, timestamp) {
13849
14115
  return call;
13850
14116
  }
13851
14117
  if (payload !== void 0 && (payloadType === "function_call_output" || payloadType === "custom_tool_call_output")) {
13852
- const result4 = { kind: "tool_result", resultType: payloadType };
13853
- assignString(result4, "timestamp", timestamp);
13854
- assignString(result4, "callId", optionalString(payload.call_id));
13855
- assignString(result4, "itemId", optionalString(payload.id));
13856
- assignString(result4, "turnId", extractTurnId(payload));
14118
+ const result5 = { kind: "tool_result", resultType: payloadType };
14119
+ assignString(result5, "timestamp", timestamp);
14120
+ assignString(result5, "callId", optionalString(payload.call_id));
14121
+ assignString(result5, "itemId", optionalString(payload.id));
14122
+ assignString(result5, "turnId", extractTurnId(payload));
13857
14123
  if (payload.output !== void 0) {
13858
- result4.output = payload.output;
14124
+ result5.output = payload.output;
13859
14125
  if (codexToolResultIsError(payload.output))
13860
- result4.isError = true;
14126
+ result5.isError = true;
13861
14127
  }
13862
- return result4;
14128
+ return result5;
13863
14129
  }
13864
14130
  return otherLine("response_item", payload, timestamp);
13865
14131
  }
@@ -14041,13 +14307,13 @@ function parseUser(raw, common) {
14041
14307
  if (!isRecord3(block))
14042
14308
  continue;
14043
14309
  if (block.type === "tool_result" && typeof block.tool_use_id === "string") {
14044
- const result4 = {
14310
+ const result5 = {
14045
14311
  toolUseId: block.tool_use_id,
14046
14312
  // 实测:成功结果常无 is_error 字段;仅显式 true 视为失败
14047
14313
  isError: block.is_error === true,
14048
14314
  content: block.content
14049
14315
  };
14050
- line.toolResults.push(result4);
14316
+ line.toolResults.push(result5);
14051
14317
  } else if (block.type === "text" && typeof block.text === "string") {
14052
14318
  texts.push(block.text);
14053
14319
  }
@@ -14570,11 +14836,11 @@ function buildTaskCreateResultIndex(lines2) {
14570
14836
  for (const line of lines2) {
14571
14837
  if (line.kind !== "user")
14572
14838
  continue;
14573
- const result4 = line.toolUseResult;
14574
- if (!isRecord3(result4) || !isRecord3(result4.task) || typeof result4.task.id !== "string")
14839
+ const result5 = line.toolUseResult;
14840
+ if (!isRecord3(result5) || !isRecord3(result5.task) || typeof result5.task.id !== "string")
14575
14841
  continue;
14576
14842
  for (const toolResult of line.toolResults)
14577
- index.set(toolResult.toolUseId, result4.task.id);
14843
+ index.set(toolResult.toolUseId, result5.task.id);
14578
14844
  }
14579
14845
  return index;
14580
14846
  }
@@ -14708,7 +14974,7 @@ function turnUsage(line) {
14708
14974
  if (inputTokens === void 0 || cacheCreationInputTokens === void 0 || cacheReadInputTokens === void 0 || outputTokens === void 0) {
14709
14975
  return void 0;
14710
14976
  }
14711
- const result4 = {
14977
+ const result5 = {
14712
14978
  inputTokens,
14713
14979
  cacheCreationInputTokens,
14714
14980
  cacheReadInputTokens,
@@ -14723,11 +14989,11 @@ function turnUsage(line) {
14723
14989
  const fiveMinute = finiteNumber(breakdown.ephemeral_5m_input_tokens);
14724
14990
  const oneHour = finiteNumber(breakdown.ephemeral_1h_input_tokens);
14725
14991
  if (fiveMinute !== void 0)
14726
- result4.cacheCreation5mTokens = fiveMinute;
14992
+ result5.cacheCreation5mTokens = fiveMinute;
14727
14993
  if (oneHour !== void 0)
14728
- result4.cacheCreation1hTokens = oneHour;
14994
+ result5.cacheCreation1hTokens = oneHour;
14729
14995
  }
14730
- return result4;
14996
+ return result5;
14731
14997
  }
14732
14998
  function finiteNumber(value) {
14733
14999
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
@@ -15101,9 +15367,9 @@ function fromTool(harness, name, input, source, at) {
15101
15367
  return [];
15102
15368
  if (harness === "codex" && name === "exec") {
15103
15369
  const inputText = toolText(input, ["input"]);
15104
- const paths = codexExecPatchPaths(inputText);
15105
- if (paths.length > 0) {
15106
- return paths.map((path) => fileObservation(path, "codex apply_patch via exec", source, false, at));
15370
+ const paths3 = codexExecPatchPaths(inputText);
15371
+ if (paths3.length > 0) {
15372
+ return paths3.map((path) => fileObservation(path, "codex apply_patch via exec", source, false, at));
15107
15373
  }
15108
15374
  }
15109
15375
  if (name === "Bash" || name === "exec") {
@@ -15145,13 +15411,13 @@ function fileObservation(path, method, source, wholeFile, at) {
15145
15411
  function patchPaths(patch) {
15146
15412
  if (patch === void 0)
15147
15413
  return [];
15148
- const paths = [];
15414
+ const paths3 = [];
15149
15415
  for (const line of patch.split("\n")) {
15150
15416
  const match = /^\*\*\* (?:Update|Add) File: (.+?)\s*$/u.exec(line);
15151
15417
  if (match?.[1] !== void 0 && isPlanPath(match[1]))
15152
- paths.push(match[1]);
15418
+ paths3.push(match[1]);
15153
15419
  }
15154
- return paths;
15420
+ return paths3;
15155
15421
  }
15156
15422
  function codexExecPatchPaths(input) {
15157
15423
  if (input === void 0 || !input.includes("*** Begin Patch"))
@@ -15212,22 +15478,29 @@ function isRecord5(value) {
15212
15478
 
15213
15479
  // apps/cli/dist/project-index.js
15214
15480
  import { lstat, readFile as readFile3, realpath, stat as stat3 } from "node:fs/promises";
15215
- import { dirname as dirname14, isAbsolute as isAbsolute4, join as join19, relative as relative3, resolve as resolve8 } from "node:path";
15481
+ import { dirname as dirname15, isAbsolute as isAbsolute4, join as join22, relative as relative3, resolve as resolve10 } from "node:path";
15216
15482
  var PROJECT_ROOT_MAX_DIRECTORIES = 8;
15217
15483
  var PROJECT_PLAN_POLL_MS = 2e3;
15218
15484
  async function resolveProjectRoot(cwd, options) {
15219
- const root = resolve8(cwd);
15220
- const homeDir = resolve8(options.homeDir);
15221
- const boundaryDir = options.boundaryDir === void 0 ? void 0 : resolve8(options.boundaryDir);
15485
+ const root = resolve10(cwd);
15486
+ const homeDir = resolve10(options.homeDir);
15487
+ const boundaryDir = options.boundaryDir === void 0 ? void 0 : resolve10(options.boundaryDir);
15222
15488
  const [rootIdentity, homeIdentity, boundaryIdentity] = await Promise.all([
15223
15489
  pathIdentity(root),
15224
15490
  pathIdentity(homeDir),
15225
15491
  boundaryDir === void 0 ? void 0 : pathIdentity(boundaryDir)
15226
15492
  ]);
15227
- const wingmanHomeIdentity = await pathIdentity(join19(homeIdentity, ".wingman"));
15228
- const planPathIdentity = await pathIdentity(join19(rootIdentity, ".wingman", "plan.md"));
15493
+ const wingmanHomeIdentity = await pathIdentity(join22(homeIdentity, ".wingman"));
15494
+ const planPathIdentity = await pathIdentity(join22(rootIdentity, ".wingman", "plan.md"));
15229
15495
  if (rootIdentity === homeIdentity || rootIdentity === wingmanHomeIdentity || boundaryIdentity !== void 0 && !isWithin(boundaryIdentity, rootIdentity)) {
15230
- return { root, rootIdentity, planPathIdentity, lookedUp: [], higherPlanPaths: [] };
15496
+ return {
15497
+ root,
15498
+ rootIdentity,
15499
+ planPathIdentity,
15500
+ lookedUp: [],
15501
+ higherPlanPaths: [],
15502
+ ...rootIdentity === homeIdentity ? { isHome: true } : {}
15503
+ };
15231
15504
  }
15232
15505
  const lookedUp = [];
15233
15506
  const found = [];
@@ -15239,7 +15512,7 @@ async function resolveProjectRoot(cwd, options) {
15239
15512
  break;
15240
15513
  if (boundaryIdentity !== void 0 && !isWithin(boundaryIdentity, currentIdentity))
15241
15514
  break;
15242
- const planPath = join19(current, ".wingman", "plan.md");
15515
+ const planPath = join22(current, ".wingman", "plan.md");
15243
15516
  lookedUp.push(planPath);
15244
15517
  try {
15245
15518
  await lstat(planPath);
@@ -15251,7 +15524,7 @@ async function resolveProjectRoot(cwd, options) {
15251
15524
  });
15252
15525
  } catch {
15253
15526
  }
15254
- const parent = dirname14(current);
15527
+ const parent = dirname15(current);
15255
15528
  if (parent === current)
15256
15529
  break;
15257
15530
  current = parent;
@@ -15329,7 +15602,7 @@ function watchProjectPlan(planPath, options) {
15329
15602
  };
15330
15603
  }
15331
15604
  async function pathIdentity(path) {
15332
- const resolved = resolve8(path);
15605
+ const resolved = resolve10(path);
15333
15606
  try {
15334
15607
  return normalizedPath(await realpath(resolved));
15335
15608
  } catch {
@@ -15344,7 +15617,7 @@ async function pathsReferToSameLocation(left, right) {
15344
15617
  return relative3(leftIdentity, rightIdentity) === "";
15345
15618
  }
15346
15619
  function normalizedPath(path) {
15347
- const resolved = resolve8(path);
15620
+ const resolved = resolve10(path);
15348
15621
  return process.platform === "win32" ? resolved.toLowerCase() : resolved;
15349
15622
  }
15350
15623
  function isWithin(parent, child) {
@@ -15354,17 +15627,17 @@ function isWithin(parent, child) {
15354
15627
 
15355
15628
  // apps/cli/dist/project-roots.js
15356
15629
  import { randomBytes as randomBytes2 } from "node:crypto";
15357
- import { closeSync, mkdirSync as mkdirSync9, openSync, readFileSync as readFileSync13, renameSync as renameSync3, rmSync as rmSync7, statSync as statSync5, writeFileSync as writeFileSync10 } from "node:fs";
15358
- import { dirname as dirname15, isAbsolute as isAbsolute5, join as join20 } from "node:path";
15630
+ import { closeSync, mkdirSync as mkdirSync10, openSync, readFileSync as readFileSync14, renameSync as renameSync3, rmSync as rmSync8, statSync as statSync5, writeFileSync as writeFileSync11 } from "node:fs";
15631
+ import { dirname as dirname16, isAbsolute as isAbsolute5, join as join23 } from "node:path";
15359
15632
  var PROJECT_ROOTS_MAX_ENTRIES = 200;
15360
15633
  function projectRootsPath(homeDir) {
15361
- return join20(homeDir, ".wingman", "state", "projects.json");
15634
+ return join23(homeDir, ".wingman", "state", "projects.json");
15362
15635
  }
15363
15636
  function readProjectRoots(homeDir) {
15364
15637
  const path = projectRootsPath(homeDir);
15365
15638
  let raw;
15366
15639
  try {
15367
- raw = readFileSync13(path, "utf8");
15640
+ raw = readFileSync14(path, "utf8");
15368
15641
  } catch (error) {
15369
15642
  if (isErrno(error, "ENOENT"))
15370
15643
  return { version: 1, roots: {} };
@@ -15404,7 +15677,7 @@ function pruneProjectRoots(homeDir) {
15404
15677
  return current;
15405
15678
  const roots = Object.fromEntries(Object.entries(current.roots).filter(([, entry]) => {
15406
15679
  try {
15407
- statSync5(join20(entry.root, ".wingman", "plan.md"));
15680
+ statSync5(join23(entry.root, ".wingman", "plan.md"));
15408
15681
  return true;
15409
15682
  } catch (error) {
15410
15683
  return !isErrno(error, "ENOENT") && !isErrno(error, "ENOTDIR");
@@ -15428,12 +15701,12 @@ function limitRoots(roots) {
15428
15701
  }
15429
15702
  function writeProjectRoots(homeDir, state) {
15430
15703
  const path = projectRootsPath(homeDir);
15431
- const tempPath = join20(dirname15(path), `.projects-${randomBytes2(8).toString("hex")}.tmp`);
15704
+ const tempPath = join23(dirname16(path), `.projects-${randomBytes2(8).toString("hex")}.tmp`);
15432
15705
  let fd;
15433
15706
  try {
15434
- mkdirSync9(dirname15(path), { recursive: true, mode: 448 });
15707
+ mkdirSync10(dirname16(path), { recursive: true, mode: 448 });
15435
15708
  fd = openSync(tempPath, "wx", 384);
15436
- writeFileSync10(fd, `${JSON.stringify(state)}
15709
+ writeFileSync11(fd, `${JSON.stringify(state)}
15437
15710
  `, "utf8");
15438
15711
  closeSync(fd);
15439
15712
  fd = void 0;
@@ -15446,7 +15719,7 @@ function writeProjectRoots(homeDir, state) {
15446
15719
  }
15447
15720
  }
15448
15721
  try {
15449
- rmSync7(tempPath, { force: true });
15722
+ rmSync8(tempPath, { force: true });
15450
15723
  } catch {
15451
15724
  }
15452
15725
  throw error;
@@ -15475,16 +15748,16 @@ function isErrno(error, code) {
15475
15748
 
15476
15749
  // apps/cli/dist/task-overlay.js
15477
15750
  import { randomBytes as randomBytes3 } from "node:crypto";
15478
- import { closeSync as closeSync2, mkdirSync as mkdirSync10, openSync as openSync2, readFileSync as readFileSync14, renameSync as renameSync4, rmSync as rmSync8, writeFileSync as writeFileSync11 } from "node:fs";
15479
- import { dirname as dirname16, join as join21 } from "node:path";
15751
+ import { closeSync as closeSync2, mkdirSync as mkdirSync11, openSync as openSync2, readFileSync as readFileSync15, renameSync as renameSync4, rmSync as rmSync9, writeFileSync as writeFileSync12 } from "node:fs";
15752
+ import { dirname as dirname17, join as join24 } from "node:path";
15480
15753
  function taskOverlayPath(homeDir) {
15481
- return join21(homeDir, ".wingman", "state", "task-overlay.json");
15754
+ return join24(homeDir, ".wingman", "state", "task-overlay.json");
15482
15755
  }
15483
15756
  function readTaskOverlay(homeDir) {
15484
15757
  const path = taskOverlayPath(homeDir);
15485
15758
  let raw;
15486
15759
  try {
15487
- raw = readFileSync14(path, "utf8");
15760
+ raw = readFileSync15(path, "utf8");
15488
15761
  } catch (error) {
15489
15762
  if (isErrno2(error, "ENOENT"))
15490
15763
  return { version: 1, entries: {} };
@@ -15536,12 +15809,12 @@ function patchTaskOverlay(homeDir, key, patch, now) {
15536
15809
  }
15537
15810
  function writeTaskOverlay(homeDir, overlay) {
15538
15811
  const path = taskOverlayPath(homeDir);
15539
- const tempPath = join21(dirname16(path), `.task-overlay-${randomBytes3(8).toString("hex")}.tmp`);
15812
+ const tempPath = join24(dirname17(path), `.task-overlay-${randomBytes3(8).toString("hex")}.tmp`);
15540
15813
  let fd;
15541
15814
  try {
15542
- mkdirSync10(dirname16(path), { recursive: true, mode: 448 });
15815
+ mkdirSync11(dirname17(path), { recursive: true, mode: 448 });
15543
15816
  fd = openSync2(tempPath, "wx", 384);
15544
- writeFileSync11(fd, `${JSON.stringify(overlay)}
15817
+ writeFileSync12(fd, `${JSON.stringify(overlay)}
15545
15818
  `, "utf8");
15546
15819
  closeSync2(fd);
15547
15820
  fd = void 0;
@@ -15554,7 +15827,7 @@ function writeTaskOverlay(homeDir, overlay) {
15554
15827
  }
15555
15828
  }
15556
15829
  try {
15557
- rmSync8(tempPath, { force: true });
15830
+ rmSync9(tempPath, { force: true });
15558
15831
  } catch {
15559
15832
  }
15560
15833
  throw error;
@@ -15587,7 +15860,7 @@ function errorMessage(error) {
15587
15860
  }
15588
15861
 
15589
15862
  // apps/cli/dist/version.js
15590
- import { readFileSync as readFileSync15 } from "node:fs";
15863
+ import { readFileSync as readFileSync16 } from "node:fs";
15591
15864
  function resolveWingmanVersion({ defined, moduleUrl = import.meta.url, readPackage }) {
15592
15865
  if (typeof defined === "string" && defined.trim() !== "")
15593
15866
  return defined;
@@ -15606,10 +15879,10 @@ function resolveWingmanVersion({ defined, moduleUrl = import.meta.url, readPacka
15606
15879
  return void 0;
15607
15880
  }
15608
15881
  function wingmanVersion() {
15609
- const defined = false ? void 0 : "0.8.0";
15882
+ const defined = false ? void 0 : "0.8.2";
15610
15883
  return resolveWingmanVersion({
15611
15884
  defined,
15612
- readPackage: (url) => JSON.parse(readFileSync15(url, "utf8"))
15885
+ readPackage: (url) => JSON.parse(readFileSync16(url, "utf8"))
15613
15886
  });
15614
15887
  }
15615
15888
 
@@ -15692,6 +15965,9 @@ function createNarrativeService(options = {}) {
15692
15965
  generation: 0,
15693
15966
  lines: [],
15694
15967
  codexLines: [],
15968
+ instructionSeq: 0,
15969
+ sessionPlanSeq: 0,
15970
+ hookInstructions: [],
15695
15971
  pendingPlanWrites: [],
15696
15972
  confirmedPlanWrites: [],
15697
15973
  nonPlanToolSteps: 0,
@@ -15725,6 +16001,8 @@ function createNarrativeService(options = {}) {
15725
16001
  if (closed || session.cwd !== cwd)
15726
16002
  return;
15727
16003
  session.projectResolution = resolution;
16004
+ if (resolution.isHome)
16005
+ session.label = "\u65E0\u9879\u76EE\u76EE\u5F55(\u5BB6\u76EE\u5F55)";
15728
16006
  seenProjectRoots.add(resolution.rootIdentity);
15729
16007
  rememberResolution(resolution);
15730
16008
  watchResolution(resolution);
@@ -15778,7 +16056,7 @@ function createNarrativeService(options = {}) {
15778
16056
  function watchResolution(resolution) {
15779
16057
  if (resolution.lookedUp.length === 0)
15780
16058
  return;
15781
- const planPath = resolution.planPath ?? join22(resolution.root, ".wingman", "plan.md");
16059
+ const planPath = resolution.planPath ?? join25(resolution.root, ".wingman", "plan.md");
15782
16060
  const planPathIdentity = resolution.planPathIdentity;
15783
16061
  if (projectWatchers.has(planPathIdentity))
15784
16062
  return;
@@ -15867,7 +16145,7 @@ function createNarrativeService(options = {}) {
15867
16145
  for (const session of sessions.values()) {
15868
16146
  const resolution = session.projectResolution;
15869
16147
  if (resolution?.planPathIdentity === planPathIdentity) {
15870
- const planPath = resolution.planPath ?? join22(resolution.root, ".wingman", "plan.md");
16148
+ const planPath = resolution.planPath ?? join25(resolution.root, ".wingman", "plan.md");
15871
16149
  void applyPendingPlanWrites(session, planPath, planPathIdentity).then(() => {
15872
16150
  session.dirty = true;
15873
16151
  notify(harness);
@@ -15912,7 +16190,7 @@ function createNarrativeService(options = {}) {
15912
16190
  }
15913
16191
  const resolution = session.projectResolution;
15914
16192
  if (resolution !== void 0) {
15915
- const planPath = resolution.planPath ?? join22(resolution.root, ".wingman", "plan.md");
16193
+ const planPath = resolution.planPath ?? join25(resolution.root, ".wingman", "plan.md");
15916
16194
  void applyPendingPlanWrites(session, planPath, resolution.planPathIdentity).then(() => {
15917
16195
  session.dirty = true;
15918
16196
  notify(harness);
@@ -15942,12 +16220,12 @@ function createNarrativeService(options = {}) {
15942
16220
  at: observation.at ?? versions.current.info.mtime,
15943
16221
  nonPlanStepsBefore: pending.nonPlanStepsBefore
15944
16222
  });
15945
- const result4 = attributePlanWrite(before, after, observation);
15946
- if ("attachedTo" in result4) {
15947
- session.planAttachment = result4;
16223
+ const result5 = attributePlanWrite(before, after, observation);
16224
+ if ("attachedTo" in result5) {
16225
+ session.planAttachment = result5;
15948
16226
  session.planUnattachedReason = void 0;
15949
16227
  } else {
15950
- session.planUnattachedReason = result4.reason;
16228
+ session.planUnattachedReason = result5.reason;
15951
16229
  }
15952
16230
  }
15953
16231
  session.pendingPlanWrites = remaining;
@@ -16002,8 +16280,13 @@ function createNarrativeService(options = {}) {
16002
16280
  session.lines = [];
16003
16281
  session.codexLines = [];
16004
16282
  session.hookIntervals = [];
16005
- session.hookPrompt = void 0;
16006
- session.hookPromptAt = void 0;
16283
+ if (session.transcriptPath !== void 0) {
16284
+ session.hookPrompt = void 0;
16285
+ session.hookPromptAt = void 0;
16286
+ session.hookInstructions = [];
16287
+ }
16288
+ session.instructionSeq = 0;
16289
+ session.sessionPlanSeq = 0;
16007
16290
  session.mockNote = void 0;
16008
16291
  session.transcriptPath = path;
16009
16292
  session.dirty = true;
@@ -16040,7 +16323,7 @@ function createNarrativeService(options = {}) {
16040
16323
  const sessionDir = transcriptPath.replace(/\.jsonl$/, "");
16041
16324
  if (sessionDir === transcriptPath)
16042
16325
  return;
16043
- const subagentsDir = join22(sessionDir, "subagents");
16326
+ const subagentsDir = join25(sessionDir, "subagents");
16044
16327
  const generation = session.generation;
16045
16328
  const poll = async () => {
16046
16329
  try {
@@ -16050,7 +16333,7 @@ function createNarrativeService(options = {}) {
16050
16333
  }
16051
16334
  for (const entry of entries) {
16052
16335
  if (/^agent-.*\.jsonl$/.test(entry)) {
16053
- startFollowing(harness, session, join22(subagentsDir, entry), generation);
16336
+ startFollowing(harness, session, join25(subagentsDir, entry), generation);
16054
16337
  }
16055
16338
  }
16056
16339
  } catch {
@@ -16073,7 +16356,7 @@ function createNarrativeService(options = {}) {
16073
16356
  if (cwd !== void 0) {
16074
16357
  anchorCwd(event.harness, session, cwd);
16075
16358
  const base = pathBasename(cwd);
16076
- if (base !== "")
16359
+ if (base !== "" && !session.projectResolution?.isHome)
16077
16360
  session.label = base;
16078
16361
  }
16079
16362
  recordToolObservations(event.harness, session, extractToolObservations(event.harness, [{ ...payload, received_at: event.received_at }]));
@@ -16086,11 +16369,17 @@ function createNarrativeService(options = {}) {
16086
16369
  }
16087
16370
  }
16088
16371
  }
16089
- if (name === "UserPromptSubmit" && typeof payload.prompt === "string") {
16090
- const prompt = payload.prompt.trim();
16091
- if (prompt !== "" && !isHarnessSystemNotice(prompt)) {
16092
- session.hookPrompt = truncate(prompt, DETAIL_LIMIT);
16093
- session.hookPromptAt = event.received_at;
16372
+ if (name === "UserPromptSubmit") {
16373
+ const prompt = typeof payload.prompt === "string" ? payload.prompt.trim() : void 0;
16374
+ if (prompt === void 0 || prompt !== "" && !isHarnessSystemNotice(prompt)) {
16375
+ session.hookInstructions.push({
16376
+ at: event.received_at,
16377
+ ...prompt === void 0 ? {} : { text: prompt }
16378
+ });
16379
+ if (prompt !== void 0) {
16380
+ session.hookPrompt = truncate(prompt, DETAIL_LIMIT);
16381
+ session.hookPromptAt = event.received_at;
16382
+ }
16094
16383
  }
16095
16384
  }
16096
16385
  if (name === "SubagentStart") {
@@ -16176,7 +16465,7 @@ function createNarrativeService(options = {}) {
16176
16465
  if (cwd !== void 0) {
16177
16466
  anchorCwd(harness, session2, cwd);
16178
16467
  const base = pathBasename(cwd);
16179
- if (base !== "")
16468
+ if (base !== "" && !session2.projectResolution?.isHome)
16180
16469
  session2.label = base;
16181
16470
  }
16182
16471
  session2.dirty = true;
@@ -16203,7 +16492,7 @@ function createNarrativeService(options = {}) {
16203
16492
  if (typeof cwd === "string") {
16204
16493
  anchorCwd(harness, session, cwd);
16205
16494
  const base = pathBasename(cwd);
16206
- if (base !== "")
16495
+ if (base !== "" && !session.projectResolution?.isHome)
16207
16496
  session.label = base;
16208
16497
  break;
16209
16498
  }
@@ -16291,7 +16580,7 @@ function createNarrativeService(options = {}) {
16291
16580
  let state;
16292
16581
  if (observed.state === "installed_not_loaded")
16293
16582
  state = "installed_not_loaded";
16294
- else if (observed.state === "installed") {
16583
+ else if (observed.state === "installed" || observed.state === "outdated") {
16295
16584
  state = planMtime === void 0 ? "installed" : "plan_present";
16296
16585
  } else
16297
16586
  state = "not_installed";
@@ -16345,7 +16634,7 @@ function createNarrativeService(options = {}) {
16345
16634
  for (const session of sessions.values()) {
16346
16635
  if (session.cwd === void 0)
16347
16636
  continue;
16348
- const rootIdentity = session.projectResolution?.rootIdentity ?? resolve9(session.cwd);
16637
+ const rootIdentity = session.projectResolution?.rootIdentity ?? resolve11(session.cwd);
16349
16638
  const group = grouped.get(rootIdentity);
16350
16639
  if (group === void 0) {
16351
16640
  grouped.set(rootIdentity, {
@@ -16365,8 +16654,8 @@ function createNarrativeService(options = {}) {
16365
16654
  for (const [rootIdentity, group] of grouped) {
16366
16655
  const { members } = group;
16367
16656
  const resolution = members.find((member) => member.session.projectResolution !== void 0)?.session.projectResolution ?? group.resolution;
16368
- const root = resolution?.root ?? resolve9(members[0]?.session.cwd ?? "");
16369
- const planPath = resolution?.planPath ?? join22(root, ".wingman", "plan.md");
16657
+ const root = resolution?.root ?? resolve11(members[0]?.session.cwd ?? "");
16658
+ const planPath = resolution?.planPath ?? join25(root, ".wingman", "plan.md");
16370
16659
  const runtime = projectFiles.get(resolution?.planPathIdentity ?? planPath);
16371
16660
  const parsed = runtime?.missing === true ? void 0 : runtime?.parsed;
16372
16661
  const planMtime = parsed?.availability === "available" ? runtime?.current?.info.mtime : void 0;
@@ -16384,12 +16673,13 @@ function createNarrativeService(options = {}) {
16384
16673
  const verification = state?.taskWorkflow?.verification;
16385
16674
  const attachedTitle = session.planAttachment?.attachedTo.split(" > ").at(-1);
16386
16675
  const instructionTitle = state?.taskWorkflow?.latestInstruction?.text;
16676
+ const planInstruction = state?.taskWorkflow?.plan.availability === "available" ? session.sessionPlanInstruction : void 0;
16387
16677
  return {
16388
16678
  harness,
16389
16679
  id: session.id,
16390
16680
  label,
16391
16681
  ended: info?.ended ?? false,
16392
- title: attachedTitle !== void 0 ? { text: attachedTitle, source: "plan.md \u6B65\u9AA4" } : instructionTitle !== void 0 ? { text: truncate(instructionTitle, DETAIL_LIMIT), source: "\u6700\u65B0\u6307\u4EE4" } : { text: label, source: "\u5DE5\u4F5C\u76EE\u5F55" },
16682
+ title: attachedTitle !== void 0 ? { text: attachedTitle, source: "plan.md \u6B65\u9AA4" } : planInstruction !== void 0 ? { text: truncate(planInstruction, DETAIL_LIMIT), source: "\u8BA1\u5212\u6240\u5C5E\u6307\u4EE4" } : instructionTitle !== void 0 ? { text: truncate(instructionTitle, DETAIL_LIMIT), source: "\u6700\u65B0\u6307\u4EE4" } : { text: label, source: "\u5DE5\u4F5C\u76EE\u5F55" },
16393
16683
  user: {
16394
16684
  ...userEntry?.title === void 0 ? {} : { title: userEntry.title },
16395
16685
  pinned: userEntry?.pinned ?? false,
@@ -16434,14 +16724,14 @@ function createNarrativeService(options = {}) {
16434
16724
  id: `${session.harness}:${session.id}`,
16435
16725
  ...session.attachedTo === void 0 ? {} : { attachedTo: session.attachedTo },
16436
16726
  ended: session.ended,
16437
- ...session.sessionPlan?.availability === "available" && session.sessionPlan.steps.length > 0 ? {
16727
+ ...session.sessionPlan?.availability === "available" && session.sessionPlan.forInstruction === "current" && session.sessionPlan.steps.length > 0 ? {
16438
16728
  sessionPlanAllCompleted: session.sessionPlan.steps.every((step) => step.status === "completed")
16439
16729
  } : {},
16440
16730
  ...session.attachedBy?.at === void 0 ? {} : { wrotePlanAt: session.attachedBy.at }
16441
16731
  })), now().toISOString());
16442
16732
  const lastWriter = [...sessionViews].filter((session) => typeof session.attachedBy?.at === "string").sort((left, right) => right.attachedBy.at.localeCompare(left.attachedBy.at))[0];
16443
- const titleText = parsed?.availability === "available" && parsed.title !== void 0 ? parsed.title : pathBasename(root) || root;
16444
- const titleSource = parsed?.availability === "available" && parsed.title !== void 0 ? ".wingman/plan.md H1" : "\u5DE5\u4F5C\u76EE\u5F55";
16733
+ const titleText = resolution?.isHome ? "\u65E0\u9879\u76EE\u76EE\u5F55(\u5BB6\u76EE\u5F55)" : parsed?.availability === "available" && parsed.title !== void 0 ? parsed.title : pathBasename(root) || root;
16734
+ const titleSource = resolution?.isHome ? "\u5DE5\u4F5C\u76EE\u5F55 = \u5BB6\u76EE\u5F55" : parsed?.availability === "available" && parsed.title !== void 0 ? ".wingman/plan.md H1" : "\u5DE5\u4F5C\u76EE\u5F55";
16445
16735
  let plan;
16446
16736
  if (parsed?.availability === "available") {
16447
16737
  plan = {
@@ -16680,8 +16970,8 @@ function extractRawToolObservations(harness, rawLine) {
16680
16970
  }
16681
16971
  function resolveObservedPath(path, cwd) {
16682
16972
  if (isAbsolute6(path))
16683
- return resolve9(path);
16684
- return cwd === void 0 ? void 0 : resolve9(cwd, path);
16973
+ return resolve11(path);
16974
+ return cwd === void 0 ? void 0 : resolve11(cwd, path);
16685
16975
  }
16686
16976
  function agentIdOf(payload) {
16687
16977
  const id = payload.agent_id ?? payload.agentId;
@@ -16745,9 +17035,9 @@ function derive(harness, session, nowIso) {
16745
17035
  const attributed = attributeSteps(steps, timeline, intervals);
16746
17036
  const results = collectResults(lines2);
16747
17037
  const resultBriefs = /* @__PURE__ */ new Map();
16748
- for (const [toolUseId, result4] of results) {
16749
- if (result4.brief !== void 0)
16750
- resultBriefs.set(toolUseId, result4.brief);
17038
+ for (const [toolUseId, result5] of results) {
17039
+ if (result5.brief !== void 0)
17040
+ resultBriefs.set(toolUseId, result5.brief);
16751
17041
  }
16752
17042
  const checks = deriveCheckStats(allSteps, resultBriefs);
16753
17043
  const todoChecks = deriveTodoCheckStats(attributed);
@@ -16856,11 +17146,16 @@ function derive(harness, session, nowIso) {
16856
17146
  const activeTodos = todos.filter((todo) => todo.status === "in_progress");
16857
17147
  const activeTodo = activeTodos.length === 1 ? activeTodos[0] : void 0;
16858
17148
  const activeChecks = activeTodo === void 0 ? void 0 : todoChecks.get(activeTodo.id);
16859
- const plan = workflowBase.plan;
17149
+ scopeSessionPlan(harness, session, lines2);
17150
+ const plan = workflowBase.plan.availability === "available" ? {
17151
+ ...workflowBase.plan,
17152
+ forInstruction: session.sessionPlanSeq === session.instructionSeq ? "current" : "previous"
17153
+ } : workflowBase.plan;
16860
17154
  const taskWorkflow = {
16861
17155
  ...workflowBase,
17156
+ plan,
16862
17157
  verification: {
16863
- agentMarkedComplete: plan.availability === "available" && plan.steps.length > 0 && plan.steps.every((step) => step.status === "completed"),
17158
+ agentMarkedComplete: plan.availability === "available" && plan.forInstruction === "current" && plan.steps.length > 0 && plan.steps.every((step) => step.status === "completed"),
16864
17159
  checks: { ...checks, source: CHECK_STATS_SOURCE },
16865
17160
  ...activeTodo === void 0 ? {} : {
16866
17161
  currentStep: {
@@ -16880,7 +17175,7 @@ function derive(harness, session, nowIso) {
16880
17175
  ...session.cwd === void 0 ? {} : { cwd: session.cwd },
16881
17176
  ...session.cwd === void 0 ? {} : {
16882
17177
  project: {
16883
- root: session.projectResolution?.root ?? resolve9(session.cwd),
17178
+ root: session.projectResolution?.root ?? resolve11(session.cwd),
16884
17179
  ...session.planAttachment === void 0 ? {} : { attachedTo: session.planAttachment.attachedTo }
16885
17180
  }
16886
17181
  },
@@ -16898,6 +17193,92 @@ function derive(harness, session, nowIso) {
16898
17193
  updatedAt: nowIso
16899
17194
  };
16900
17195
  }
17196
+ function scopeSessionPlan(harness, session, lines2) {
17197
+ const observations = [];
17198
+ const seenUsers = /* @__PURE__ */ new Set();
17199
+ const taskIds = /* @__PURE__ */ new Set();
17200
+ const resultLines = /* @__PURE__ */ new Map();
17201
+ for (const line of lines2) {
17202
+ if (line.kind === "user") {
17203
+ for (const result5 of line.toolResults)
17204
+ resultLines.set(result5.toolUseId, line);
17205
+ }
17206
+ }
17207
+ let at;
17208
+ for (const line of lines2) {
17209
+ if (line.kind === "unknown" || line.agentId !== void 0 || line.isSidechain === true) {
17210
+ continue;
17211
+ }
17212
+ at = line.timestamp ?? at;
17213
+ const timestamp = at === void 0 ? {} : { at };
17214
+ if (line.kind === "user" && line.toolResults.length === 0) {
17215
+ const text = line.text?.trim();
17216
+ if (text === void 0 || text === "" || isHarnessSystemNotice(text))
17217
+ continue;
17218
+ if (line.uuid !== void 0) {
17219
+ if (seenUsers.has(line.uuid))
17220
+ continue;
17221
+ seenUsers.add(line.uuid);
17222
+ }
17223
+ observations.push({ kind: "instruction", source: "transcript", text, ...timestamp });
17224
+ } else if (line.kind === "assistant") {
17225
+ for (const block of line.blocks) {
17226
+ if (block.kind !== "tool_use")
17227
+ continue;
17228
+ if (harness === "codex" && block.name === "update_plan") {
17229
+ observations.push({ kind: "plan", ...timestamp });
17230
+ } else if (harness === "cc") {
17231
+ if (block.name === "TaskCreate" || block.name === "TodoWrite") {
17232
+ const result5 = resultLines.get(block.id);
17233
+ const snapshot = extractTodoSnapshots([
17234
+ { ...line, blocks: [block] },
17235
+ ...result5 === void 0 ? [] : [result5]
17236
+ ]).at(-1);
17237
+ if (snapshot === void 0)
17238
+ continue;
17239
+ if (block.name === "TodoWrite")
17240
+ taskIds.clear();
17241
+ for (const todo of snapshot.todos)
17242
+ taskIds.add(todo.id);
17243
+ } else if (block.name === "TaskUpdate") {
17244
+ const taskId = block.input.taskId;
17245
+ if (typeof taskId !== "string" || !taskIds.has(taskId))
17246
+ continue;
17247
+ if (block.input.status === "deleted")
17248
+ taskIds.delete(taskId);
17249
+ } else {
17250
+ continue;
17251
+ }
17252
+ observations.push({ kind: "plan", ...timestamp });
17253
+ }
17254
+ }
17255
+ }
17256
+ }
17257
+ for (const hook of session.hookInstructions) {
17258
+ observations.push({ kind: "instruction", source: "hook", ...hook });
17259
+ }
17260
+ observations.sort((a, b) => (a.at ?? "").localeCompare(b.at ?? ""));
17261
+ session.instructionSeq = 0;
17262
+ session.sessionPlanSeq = 0;
17263
+ const instructions = /* @__PURE__ */ new Map();
17264
+ let unpaired;
17265
+ for (const observation of observations) {
17266
+ if (observation.kind === "plan") {
17267
+ session.sessionPlanSeq = session.instructionSeq;
17268
+ unpaired = void 0;
17269
+ } else if (unpaired !== void 0 && unpaired.source !== observation.source && (unpaired.text === void 0 || observation.text === void 0 || unpaired.text === observation.text)) {
17270
+ if (observation.text !== void 0)
17271
+ instructions.set(session.instructionSeq, observation.text);
17272
+ unpaired = void 0;
17273
+ } else {
17274
+ session.instructionSeq += 1;
17275
+ if (observation.text !== void 0)
17276
+ instructions.set(session.instructionSeq, observation.text);
17277
+ unpaired = observation;
17278
+ }
17279
+ }
17280
+ session.sessionPlanInstruction = instructions.get(session.sessionPlanSeq);
17281
+ }
16901
17282
  function todoInProgressAt(timeline, ts) {
16902
17283
  const active = timeline.filter((entry) => entry.spans.some((span) => span.status === "in_progress" && span.from !== void 0 && span.from <= ts && (span.to === void 0 || ts < span.to)));
16903
17284
  const only = active[0];
@@ -17053,18 +17434,18 @@ function collectResults(lines2) {
17053
17434
  for (const line of lines2) {
17054
17435
  if (line.kind !== "user")
17055
17436
  continue;
17056
- for (const result4 of line.toolResults) {
17057
- if (result4.content === void 0)
17437
+ for (const result5 of line.toolResults) {
17438
+ if (result5.content === void 0)
17058
17439
  continue;
17059
17440
  const info = {};
17060
17441
  try {
17061
- info.bytes = Buffer.byteLength(JSON.stringify(result4.content), "utf8");
17442
+ info.bytes = Buffer.byteLength(JSON.stringify(result5.content), "utf8");
17062
17443
  } catch {
17063
17444
  }
17064
- const brief = errorBrief(result4.content);
17445
+ const brief = errorBrief(result5.content);
17065
17446
  if (brief !== void 0)
17066
17447
  info.brief = brief;
17067
- results.set(result4.toolUseId, info);
17448
+ results.set(result5.toolUseId, info);
17068
17449
  }
17069
17450
  }
17070
17451
  return results;
@@ -17370,16 +17751,22 @@ function errorBrief(content) {
17370
17751
  init_dist3();
17371
17752
  init_dist5();
17372
17753
  init_dist2();
17754
+ import { homedir as homedir13 } from "node:os";
17373
17755
  import { createInterface } from "node:readline/promises";
17374
17756
  var ProtocolUsageError = class extends Error {
17375
17757
  };
17376
- async function runProtocolCli(args) {
17758
+ async function runProtocolCli(args, options = { homeDir: homedir13() }) {
17377
17759
  const parsed = parseProtocolArgs(args);
17760
+ if (parsed.user && parsed.harness === "dsh") {
17761
+ throw new ProtocolUsageError(protocolStatusDshUser(options).unsupported);
17762
+ }
17378
17763
  if (parsed.action === "status") {
17379
- printStatus(getStatus(parsed.harness, parsed.projectDir));
17764
+ const user = getUserStatus(parsed.harness, options.homeDir);
17765
+ printStatus(user, "\u7528\u6237\u7EA7");
17766
+ printStatus(getStatus(parsed.harness, parsed.projectDir, options.homeDir), "\u9879\u76EE\u7EA7");
17380
17767
  return 0;
17381
17768
  }
17382
- const preview = mutate(parsed.action, parsed.harness, parsed.projectDir, true);
17769
+ const preview = mutate(parsed, options.homeDir, true);
17383
17770
  printPreview(preview);
17384
17771
  if (!preview.changed)
17385
17772
  return 0;
@@ -17389,7 +17776,7 @@ async function runProtocolCli(args) {
17389
17776
  process.stdout.write("wingman:\u5DF2\u53D6\u6D88\uFF0C\u672A\u5199\u5165\u4EFB\u4F55\u6587\u4EF6\u3002\n");
17390
17777
  return 0;
17391
17778
  }
17392
- const applied = mutate(parsed.action, parsed.harness, parsed.projectDir, false);
17779
+ const applied = mutate(parsed, options.homeDir, false);
17393
17780
  process.stdout.write(`wingman:${parsed.harness} protocol ${parsed.action} \u5B8C\u6210
17394
17781
  state: ${applied.state}
17395
17782
  backupDir: ${applied.backupDir ?? "(no backup)"}
@@ -17401,12 +17788,15 @@ ${applied.message ?? ""}${applied.message === void 0 ? "" : "\n"}`);
17401
17788
  function parseProtocolArgs(args) {
17402
17789
  const [actionText, harnessText, ...tail] = args;
17403
17790
  if (actionText !== "install" && actionText !== "uninstall" && actionText !== "status") {
17404
- throw new ProtocolUsageError("protocol \u7528\u6CD5:wingman protocol install|uninstall|status <cc|codex|dsh> [--project <dir>] [--dry-run] [--yes]");
17791
+ throw new ProtocolUsageError("protocol \u7528\u6CD5:wingman protocol install|uninstall|status <cc|codex|dsh> [--project <dir> | --user] [--dry-run] [--yes]");
17405
17792
  }
17406
17793
  if (harnessText !== "cc" && harnessText !== "codex" && harnessText !== "dsh") {
17407
17794
  throw new ProtocolUsageError(`protocol \u9700\u8981 harness \u2208 cc|codex|dsh,\u5F97\u5230 ${harnessText ?? "(\u7F3A\u53C2)"}`);
17408
17795
  }
17409
17796
  let projectDir = process.cwd();
17797
+ let user = false;
17798
+ let project = false;
17799
+ let fixtures = false;
17410
17800
  let dryRun = false;
17411
17801
  let yes = false;
17412
17802
  const rest = [...tail];
@@ -17414,9 +17804,14 @@ function parseProtocolArgs(args) {
17414
17804
  const arg = rest.shift();
17415
17805
  if (arg === "--project") {
17416
17806
  const value = rest.shift();
17417
- if (value === void 0)
17807
+ if (value === void 0 || value.startsWith("--"))
17418
17808
  throw new ProtocolUsageError("--project \u9700\u8981\u76EE\u5F55\u8DEF\u5F84,\u5F97\u5230(\u7F3A\u53C2)");
17809
+ project = true;
17419
17810
  projectDir = value;
17811
+ } else if (arg === "--user") {
17812
+ user = true;
17813
+ } else if (arg === "--fixtures") {
17814
+ fixtures = true;
17420
17815
  } else if (arg === "--dry-run") {
17421
17816
  dryRun = true;
17422
17817
  } else if (arg === "--yes") {
@@ -17425,36 +17820,57 @@ function parseProtocolArgs(args) {
17425
17820
  throw new ProtocolUsageError(`protocol \u4E0D\u8BA4\u8BC6\u53C2\u6570:${arg}`);
17426
17821
  }
17427
17822
  }
17428
- return { action: actionText, harness: harnessText, projectDir, dryRun, yes };
17823
+ if (user && project)
17824
+ throw new ProtocolUsageError("--user \u4E0E --project \u4E92\u65A5");
17825
+ if (fixtures && user)
17826
+ throw new ProtocolUsageError("fixtures \u6A21\u5F0F\u62D2\u7EDD --user\uFF0C\u4E0D\u80FD\u8BBF\u95EE\u7528\u6237\u7EA7\u6307\u4EE4\u6587\u4EF6");
17827
+ if (fixtures)
17828
+ throw new ProtocolUsageError("protocol \u4E0D\u652F\u6301 --fixtures");
17829
+ return { action: actionText, harness: harnessText, projectDir, user, dryRun, yes };
17429
17830
  }
17430
- function getStatus(harness, projectDir) {
17831
+ function getStatus(harness, projectDir, homeDir) {
17431
17832
  switch (harness) {
17432
17833
  case "cc":
17433
- return protocolStatusCc({ projectDir });
17834
+ return protocolStatusCc({ projectDir, homeDir });
17434
17835
  case "codex":
17435
- return protocolStatusCodex({ projectDir });
17836
+ return protocolStatusCodex({ projectDir, homeDir });
17436
17837
  case "dsh":
17437
- return protocolStatusDsh({ projectDir });
17838
+ return protocolStatusDsh({ projectDir, homeDir });
17438
17839
  }
17439
17840
  }
17440
- function mutate(action, harness, projectDir, dryRun) {
17841
+ function getUserStatus(harness, homeDir) {
17441
17842
  switch (harness) {
17442
17843
  case "cc":
17443
- return action === "install" ? installProtocolCc({ projectDir, dryRun }) : uninstallProtocolCc({ projectDir, dryRun });
17844
+ return protocolStatusCcUser({ homeDir });
17444
17845
  case "codex":
17445
- return action === "install" ? installProtocolCodex({ projectDir, dryRun }) : uninstallProtocolCodex({ projectDir, dryRun });
17846
+ return protocolStatusCodexUser({ homeDir });
17446
17847
  case "dsh":
17447
- return action === "install" ? installProtocolDsh({ projectDir, dryRun }) : uninstallProtocolDsh({ projectDir, dryRun });
17848
+ return protocolStatusDshUser({ homeDir });
17448
17849
  }
17449
17850
  }
17450
- function printStatus(value) {
17451
- process.stdout.write(`harness: ${value.harness}
17452
- target: ${value.targetPath}
17453
- state: ${value.state}
17454
- ${value.version === void 0 ? "" : `version: ${value.version}
17455
- `}${value.message === void 0 ? "" : `${value.message}
17456
- `}${value.reason === void 0 ? "" : `reason: ${value.reason}
17457
- `}`);
17851
+ function mutate(parsed, homeDir, dryRun) {
17852
+ const { action, harness, projectDir, user } = parsed;
17853
+ switch (harness) {
17854
+ case "cc":
17855
+ return action === "install" ? (user ? installProtocolCcUser : installProtocolCc)({ projectDir, homeDir, dryRun }) : (user ? uninstallProtocolCcUser : uninstallProtocolCc)({ projectDir, homeDir, dryRun });
17856
+ case "codex":
17857
+ return action === "install" ? (user ? installProtocolCodexUser : installProtocolCodex)({ projectDir, homeDir, dryRun }) : (user ? uninstallProtocolCodexUser : uninstallProtocolCodex)({
17858
+ projectDir,
17859
+ homeDir,
17860
+ dryRun
17861
+ });
17862
+ case "dsh":
17863
+ return action === "install" ? installProtocolDsh({ projectDir, homeDir, dryRun }) : uninstallProtocolDsh({ projectDir, homeDir, dryRun });
17864
+ }
17865
+ }
17866
+ function printStatus(value, scope) {
17867
+ if ("unsupported" in value) {
17868
+ process.stdout.write(`${scope}: unsupported \u2014 ${value.unsupported}
17869
+ `);
17870
+ return;
17871
+ }
17872
+ process.stdout.write(`${scope}: ${value.state} | target: ${value.targetPath} | state: ${value.state}${value.version === void 0 ? "" : ` | version: ${value.version}`}${value.message === void 0 ? "" : ` | ${value.message}`}${value.reason === void 0 ? "" : ` | reason: ${value.reason}`}
17873
+ `);
17458
17874
  }
17459
17875
  function printPreview(value) {
17460
17876
  process.stdout.write(`${unifiedDiff(value.targetPath, value.before, value.after)}
@@ -17504,8 +17920,8 @@ async function confirmWrite() {
17504
17920
  }
17505
17921
 
17506
17922
  // apps/cli/dist/registry.js
17507
- import { existsSync as existsSync13 } from "node:fs";
17508
- import { homedir as homedir11 } from "node:os";
17923
+ import { existsSync as existsSync14 } from "node:fs";
17924
+ import { homedir as homedir14 } from "node:os";
17509
17925
  async function importHarnessModule(harness) {
17510
17926
  const mod = await importAdapterModule(harness);
17511
17927
  if (typeof mod.createAdapter !== "function") {
@@ -17527,7 +17943,7 @@ function importAdapterModule(harness) {
17527
17943
  }
17528
17944
  }
17529
17945
  function fixtureScanOptions(harness) {
17530
- if (!existsSync13(fixturePath())) {
17946
+ if (!existsSync14(fixturePath())) {
17531
17947
  throw new Error("--fixtures \u9700\u8981\u4ED3\u5E93\u5185\u7684 packages/fixtures \u6570\u636E;\u53D1\u5E03\u5B89\u88C5\u5305/npx \u4EA7\u7269\u4E0D\u5305\u542B\u6837\u4F8B");
17532
17948
  }
17533
17949
  switch (harness) {
@@ -17548,16 +17964,16 @@ async function loadHarness(harness, mode) {
17548
17964
  return {
17549
17965
  harness,
17550
17966
  adapter,
17551
- scanOptions: mode.fixtures ? fixtureScanOptions(harness) : { homeDir: homedir11() },
17967
+ scanOptions: mode.fixtures ? fixtureScanOptions(harness) : { homeDir: homedir14() },
17552
17968
  feedbackSignals
17553
17969
  };
17554
17970
  }
17555
17971
 
17556
17972
  // apps/cli/dist/runtime-state.js
17557
17973
  import { randomBytes as randomBytes4 } from "node:crypto";
17558
- import { closeSync as closeSync3, mkdirSync as mkdirSync11, openSync as openSync3, readFileSync as readFileSync16, renameSync as renameSync5, rmSync as rmSync9, writeFileSync as writeFileSync12 } from "node:fs";
17559
- import { homedir as homedir12 } from "node:os";
17560
- import { dirname as dirname17, join as join23 } from "node:path";
17974
+ import { closeSync as closeSync3, mkdirSync as mkdirSync12, openSync as openSync3, readFileSync as readFileSync17, renameSync as renameSync5, rmSync as rmSync10, writeFileSync as writeFileSync13 } from "node:fs";
17975
+ import { homedir as homedir15 } from "node:os";
17976
+ import { dirname as dirname18, join as join26 } from "node:path";
17561
17977
  function createHookToken() {
17562
17978
  return randomBytes4(32).toString("base64url");
17563
17979
  }
@@ -17568,15 +17984,15 @@ function writeServeRuntimeState(port, token, options = {}) {
17568
17984
  const pid = options.pid ?? process.pid;
17569
17985
  const suffix = randomBytes4(8).toString("base64url");
17570
17986
  const owner = `serve-${startedAtMs}-${pid}-${suffix}`;
17571
- const path = join23(options.homeDir ?? homedir12(), ".wingman", "state", "serve", `${owner}.json`);
17572
- const tempPath = join23(dirname17(path), `.${owner}.tmp`);
17987
+ const path = join26(options.homeDir ?? homedir15(), ".wingman", "state", "serve", `${owner}.json`);
17988
+ const tempPath = join26(dirname18(path), `.${owner}.tmp`);
17573
17989
  const contents = Buffer.from(`${JSON.stringify({ version: 2, owner, pid, port, startedAtMs, token })}
17574
17990
  `, "utf8");
17575
17991
  let fd;
17576
17992
  try {
17577
- mkdirSync11(dirname17(path), { recursive: true, mode: 448 });
17993
+ mkdirSync12(dirname18(path), { recursive: true, mode: 448 });
17578
17994
  fd = openSync3(tempPath, "wx", 384);
17579
- writeFileSync12(fd, contents);
17995
+ writeFileSync13(fd, contents);
17580
17996
  closeSync3(fd);
17581
17997
  fd = void 0;
17582
17998
  renameSync5(tempPath, path);
@@ -17589,7 +18005,7 @@ function writeServeRuntimeState(port, token, options = {}) {
17589
18005
  }
17590
18006
  }
17591
18007
  try {
17592
- rmSync9(tempPath, { force: true });
18008
+ rmSync10(tempPath, { force: true });
17593
18009
  } catch {
17594
18010
  }
17595
18011
  warn(`Codex hook \u8FD0\u884C\u6001\u5199\u5165\u5931\u8D25,\u9762\u677F\u7EE7\u7EED\u8FD0\u884C:${errorMessage2(error)}`);
@@ -17600,9 +18016,9 @@ function removeServeRuntimeState(registration) {
17600
18016
  if (registration === void 0)
17601
18017
  return;
17602
18018
  try {
17603
- const current = readFileSync16(registration.path);
18019
+ const current = readFileSync17(registration.path);
17604
18020
  if (current.equals(registration.contents))
17605
- rmSync9(registration.path, { force: true });
18021
+ rmSync10(registration.path, { force: true });
17606
18022
  } catch {
17607
18023
  }
17608
18024
  }
@@ -17623,17 +18039,20 @@ async function scanValidated(adapter, options) {
17623
18039
  }
17624
18040
 
17625
18041
  // apps/cli/dist/server.js
18042
+ init_dist3();
18043
+ init_dist5();
17626
18044
  init_dist();
17627
18045
  import { execFile as execFile2 } from "node:child_process";
17628
18046
  import { createHmac, timingSafeEqual } from "node:crypto";
17629
18047
  import { readFile as readFile4 } from "node:fs/promises";
17630
18048
  import { createServer } from "node:http";
17631
- import { extname, resolve as resolve11, sep as sep2 } from "node:path";
18049
+ import { hostname } from "node:os";
18050
+ import { extname, relative as relative4, resolve as resolve13, sep as sep2 } from "node:path";
17632
18051
 
17633
18052
  // apps/cli/dist/return-target.js
17634
18053
  import { randomBytes as randomBytes5 } from "node:crypto";
17635
- import { closeSync as closeSync4, copyFileSync as copyFileSync2, mkdirSync as mkdirSync12, openSync as openSync4, readFileSync as readFileSync17, renameSync as renameSync6, rmSync as rmSync10, statSync as statSync6, writeFileSync as writeFileSync13 } from "node:fs";
17636
- import { dirname as dirname18, join as join24, resolve as resolve10 } from "node:path";
18054
+ import { closeSync as closeSync4, copyFileSync as copyFileSync2, mkdirSync as mkdirSync13, openSync as openSync4, readFileSync as readFileSync18, renameSync as renameSync6, rmSync as rmSync11, statSync as statSync6, writeFileSync as writeFileSync14 } from "node:fs";
18055
+ import { dirname as dirname19, join as join27, resolve as resolve12 } from "node:path";
17637
18056
  var BUNDLES = [
17638
18057
  ["Terminal", "Terminal.app"],
17639
18058
  ["iTerm", "iTerm.app"],
@@ -17644,11 +18063,11 @@ var BUNDLES = [
17644
18063
  ["kitty", "kitty.app"],
17645
18064
  ["VS Code", "Visual Studio Code.app"]
17646
18065
  ];
17647
- function detectReturnTargets(homeDir, roots = ["/Applications", join24(homeDir, "Applications")]) {
18066
+ function detectReturnTargets(homeDir, roots = ["/Applications", join27(homeDir, "Applications")]) {
17648
18067
  const available = [];
17649
18068
  for (const [name, bundle] of BUNDLES) {
17650
- for (const root of new Set(roots.map((root2) => resolve10(root2)))) {
17651
- const bundlePath = join24(root, bundle);
18069
+ for (const root of new Set(roots.map((root2) => resolve12(root2)))) {
18070
+ const bundlePath = join27(root, bundle);
17652
18071
  try {
17653
18072
  if (statSync6(bundlePath).isDirectory())
17654
18073
  available.push({ name, bundlePath });
@@ -17659,12 +18078,12 @@ function detectReturnTargets(homeDir, roots = ["/Applications", join24(homeDir,
17659
18078
  return available;
17660
18079
  }
17661
18080
  function settingsPath(homeDir) {
17662
- return join24(homeDir, ".wingman", "state", "settings.json");
18081
+ return join27(homeDir, ".wingman", "state", "settings.json");
17663
18082
  }
17664
18083
  function readReturnTargetSettings(homeDir) {
17665
18084
  let raw;
17666
18085
  try {
17667
- raw = readFileSync17(settingsPath(homeDir), "utf8");
18086
+ raw = readFileSync18(settingsPath(homeDir), "utf8");
17668
18087
  } catch (error) {
17669
18088
  if (isRecord8(error) && error.code === "ENOENT")
17670
18089
  return { version: 1 };
@@ -17685,10 +18104,10 @@ function saveReturnTarget(homeDir, bundlePath) {
17685
18104
  return current;
17686
18105
  const settings = { version: 1, returnTarget: { bundlePath } };
17687
18106
  const path = settingsPath(homeDir);
17688
- const tempPath = join24(dirname18(path), `.settings-${randomBytes5(8).toString("hex")}.tmp`);
18107
+ const tempPath = join27(dirname19(path), `.settings-${randomBytes5(8).toString("hex")}.tmp`);
17689
18108
  let fd;
17690
18109
  try {
17691
- mkdirSync12(dirname18(path), { recursive: true, mode: 448 });
18110
+ mkdirSync13(dirname19(path), { recursive: true, mode: 448 });
17692
18111
  try {
17693
18112
  copyFileSync2(path, `${path}.bak`);
17694
18113
  } catch (error) {
@@ -17696,7 +18115,7 @@ function saveReturnTarget(homeDir, bundlePath) {
17696
18115
  throw error;
17697
18116
  }
17698
18117
  fd = openSync4(tempPath, "wx", 384);
17699
- writeFileSync13(fd, `${JSON.stringify(settings)}
18118
+ writeFileSync14(fd, `${JSON.stringify(settings)}
17700
18119
  `, "utf8");
17701
18120
  closeSync4(fd);
17702
18121
  fd = void 0;
@@ -17712,7 +18131,7 @@ function saveReturnTarget(homeDir, bundlePath) {
17712
18131
  }
17713
18132
  }
17714
18133
  try {
17715
- rmSync10(tempPath, { force: true });
18134
+ rmSync11(tempPath, { force: true });
17716
18135
  } catch {
17717
18136
  }
17718
18137
  }
@@ -18037,8 +18456,18 @@ async function handle(req, res, options, warn, runtime) {
18037
18456
  }
18038
18457
  if (url.pathname === "/api/anatomy") {
18039
18458
  const configs = await scanAll(options.harnesses, warn);
18459
+ const anatomy = configs.map((config) => {
18460
+ const scanOptions = options.harnesses.find((entry) => entry.harness === config.harness)?.scanOptions;
18461
+ const homeDir = scanOptions?.homeDir ?? options.homeDir;
18462
+ if (homeDir === void 0)
18463
+ throw new Error("anatomy \u9700\u8981\u663E\u5F0F homeDir");
18464
+ const user = config.harness === "cc" ? protocolStatusCcUser({ homeDir }).state : config.harness === "codex" ? protocolStatusCodexUser({ homeDir }).state : "unsupported";
18465
+ const projectDir = scanOptions?.projectDir;
18466
+ const project = projectDir === void 0 ? "not_installed" : config.harness === "cc" ? protocolStatusCc({ homeDir, projectDir }).state : protocolStatusCodex({ homeDir, projectDir }).state;
18467
+ return { ...config, planProtocol: { user, project } };
18468
+ });
18040
18469
  res.writeHead(200, { "content-type": "application/json; charset=utf-8" });
18041
- res.end(JSON.stringify(configs));
18470
+ res.end(JSON.stringify(anatomy));
18042
18471
  return;
18043
18472
  }
18044
18473
  if (url.pathname === "/api/version") {
@@ -18157,6 +18586,10 @@ async function handleActionPlan(req, res, options) {
18157
18586
  sendJson2(res, 400, { error: "\u8BF7\u6C42\u4F53\u5FC5\u987B\u662F\u5408\u6CD5 JSON" });
18158
18587
  return;
18159
18588
  }
18589
+ if (isProtocolUserRequest(body)) {
18590
+ handleProtocolUserAction(body, res, options);
18591
+ return;
18592
+ }
18160
18593
  const { harness, action } = body;
18161
18594
  const loaded = pickHarness(options, harness);
18162
18595
  if (!loaded) {
@@ -18188,6 +18621,10 @@ async function handleActionApply(req, res, options, runtime) {
18188
18621
  sendJson2(res, 400, { error: "\u8BF7\u6C42\u4F53\u5FC5\u987B\u662F\u5408\u6CD5 JSON" });
18189
18622
  return;
18190
18623
  }
18624
+ if (isProtocolUserRequest(body)) {
18625
+ handleProtocolUserAction(body, res, options, runtime);
18626
+ return;
18627
+ }
18191
18628
  const { harness, plan } = body;
18192
18629
  const loaded = pickHarness(options, harness);
18193
18630
  if (!loaded) {
@@ -18199,15 +18636,68 @@ async function handleActionApply(req, res, options, runtime) {
18199
18636
  return;
18200
18637
  }
18201
18638
  try {
18202
- const result4 = await loaded.adapter.applyAction(plan, loaded.scanOptions);
18203
- if (result4.ok) {
18639
+ const result5 = await loaded.adapter.applyAction(plan, loaded.scanOptions);
18640
+ if (result5.ok) {
18204
18641
  runtime.anatomy = null;
18205
18642
  }
18206
- sendJson2(res, 200, result4);
18643
+ sendJson2(res, 200, result5);
18207
18644
  } catch (error) {
18208
18645
  sendJson2(res, 400, { error: errorMessage3(error) });
18209
18646
  }
18210
18647
  }
18648
+ function isProtocolUserRequest(body) {
18649
+ return isRecord9(body) && (body.kind === "protocol_user_install" || body.kind === "protocol_user_uninstall");
18650
+ }
18651
+ function handleProtocolUserAction(body, res, options, runtime) {
18652
+ if (options.readonlyActions) {
18653
+ sendJson2(res, 403, { error: "fixtures \u6A21\u5F0F\u53EA\u8BFB:\u4E0D\u9884\u89C8\u6216\u5199\u5165\u7528\u6237\u7EA7\u534F\u8BAE" });
18654
+ return;
18655
+ }
18656
+ if (body.harness === "dsh") {
18657
+ sendJson2(res, 400, { error: "unsupported: dsh \u65E0\u7528\u6237\u7EA7\u6307\u4EE4\u6587\u4EF6\uFF0C\u8BF7\u6309\u9879\u76EE\u5B89\u88C5\u8BA1\u5212\u534F\u8BAE" });
18658
+ return;
18659
+ }
18660
+ const loaded = pickHarness(options, body.harness);
18661
+ if (!loaded || body.harness !== "cc" && body.harness !== "codex") {
18662
+ sendJson2(res, 400, { error: "\u7528\u6237\u7EA7\u8BA1\u5212\u534F\u8BAE harness \u9700\u8981 cc|codex" });
18663
+ return;
18664
+ }
18665
+ const homeDir = loaded.scanOptions.homeDir ?? options.homeDir;
18666
+ if (homeDir === void 0) {
18667
+ sendJson2(res, 500, { error: "\u7528\u6237\u7EA7\u8BA1\u5212\u534F\u8BAE\u9700\u8981\u663E\u5F0F homeDir" });
18668
+ return;
18669
+ }
18670
+ const install = body.kind === "protocol_user_install";
18671
+ const operation = body.harness === "cc" ? install ? installProtocolCcUser : uninstallProtocolCcUser : install ? installProtocolCodexUser : uninstallProtocolCodexUser;
18672
+ try {
18673
+ const result5 = operation({ homeDir, dryRun: runtime === void 0 });
18674
+ if (runtime === void 0) {
18675
+ const before = splitPlanProtocolBlock(result5.before, result5.targetPath, "user");
18676
+ const after = splitPlanProtocolBlock(result5.after, result5.targetPath, "user");
18677
+ const block = install ? after.block : before.block;
18678
+ sendJson2(res, 200, {
18679
+ kind: body.kind,
18680
+ harness: body.harness,
18681
+ targetPath: body.harness === "cc" ? "~/.claude/CLAUDE.md" : "~/.codex/AGENTS.md",
18682
+ hasBlock: before.block !== void 0,
18683
+ ...install && before.version !== void 0 && after.version !== void 0 && before.version < after.version ? { fromVersion: before.version, toVersion: after.version } : {},
18684
+ blockBytes: Buffer.byteLength(block ?? ""),
18685
+ backupDir: "~/.wingman/backups/<ISO \u65F6\u95F4\u6233>\uFF08\u91CD\u540D\u8FFD\u52A0 -N\uFF09",
18686
+ hostname: hostname()
18687
+ });
18688
+ } else {
18689
+ runtime.anatomy = null;
18690
+ const user = body.harness === "cc" ? protocolStatusCcUser({ homeDir }).state : protocolStatusCodexUser({ homeDir }).state;
18691
+ sendJson2(res, 200, {
18692
+ ok: true,
18693
+ planProtocol: { user },
18694
+ ...result5.backupDir === void 0 ? {} : { backupDir: `~/${relative4(homeDir, result5.backupDir).split(sep2).join("/")}` }
18695
+ });
18696
+ }
18697
+ } catch (error) {
18698
+ sendJson2(res, 400, { error: errorSummary(error) });
18699
+ }
18700
+ }
18211
18701
  async function handleReturn(req, res, options, activate) {
18212
18702
  if (req.method !== "POST" && (activate || req.method !== "GET")) {
18213
18703
  sendText2(res, 405, "method not allowed");
@@ -18283,12 +18773,12 @@ async function handleTaskOverlay(req, res, options) {
18283
18773
  return;
18284
18774
  }
18285
18775
  const key = `${body.harness}:${body.sessionId}`;
18286
- const result4 = patchTaskOverlay(options.homeDir, key, body.patch, /* @__PURE__ */ new Date());
18287
- if ("unavailable" in result4) {
18288
- sendJson2(res, 409, { error: result4.unavailable });
18776
+ const result5 = patchTaskOverlay(options.homeDir, key, body.patch, /* @__PURE__ */ new Date());
18777
+ if ("unavailable" in result5) {
18778
+ sendJson2(res, 409, { error: result5.unavailable });
18289
18779
  return;
18290
18780
  }
18291
- sendJson2(res, 200, { key, entry: result4.entry });
18781
+ sendJson2(res, 200, { key, entry: result5.entry });
18292
18782
  }
18293
18783
  var LICENSE_BODY_LIMIT = 64 * 1024;
18294
18784
  async function handleLicenseInstall(req, res, options) {
@@ -18297,12 +18787,12 @@ async function handleLicenseInstall(req, res, options) {
18297
18787
  sendJson2(res, 400, { error: "license \u6587\u4EF6\u8D85\u8FC7 64KB \u4E0A\u9650\u6216\u8BFB\u53D6\u5931\u8D25" });
18298
18788
  return;
18299
18789
  }
18300
- const result4 = installLicense(raw, options.licenseOptions);
18301
- if (!result4.ok) {
18302
- sendJson2(res, 400, { error: result4.error });
18790
+ const result5 = installLicense(raw, options.licenseOptions);
18791
+ if (!result5.ok) {
18792
+ sendJson2(res, 400, { error: result5.error });
18303
18793
  return;
18304
18794
  }
18305
- sendJson2(res, 200, publicLicenseStatus(result4.status));
18795
+ sendJson2(res, 200, publicLicenseStatus(result5.status));
18306
18796
  }
18307
18797
  async function handleLicenseRefresh(res, options) {
18308
18798
  const homeDir = options.licenseRefreshOptions?.homeDir ?? options.licenseOptions?.homeDir;
@@ -18314,11 +18804,11 @@ async function handleLicenseRefresh(res, options) {
18314
18804
  ...publicKeyPem === void 0 ? {} : { publicKeyPem },
18315
18805
  ...now === void 0 ? {} : { now }
18316
18806
  };
18317
- const result4 = await refreshLicense(refreshOptions);
18318
- if (!result4.ok) {
18807
+ const result5 = await refreshLicense(refreshOptions);
18808
+ if (!result5.ok) {
18319
18809
  sendJson2(res, 400, {
18320
- error: result4.message,
18321
- canSubscribe: result4.reason === "inactive"
18810
+ error: result5.message,
18811
+ canSubscribe: result5.reason === "inactive"
18322
18812
  });
18323
18813
  return;
18324
18814
  }
@@ -18330,7 +18820,7 @@ async function handleLicenseRefresh(res, options) {
18330
18820
  };
18331
18821
  sendJson2(res, 200, {
18332
18822
  ...publicLicenseStatus(licenseStatus(statusOptions)),
18333
- message: result4.message
18823
+ message: result5.message
18334
18824
  });
18335
18825
  }
18336
18826
  function publicLicenseStatus(status3) {
@@ -18425,8 +18915,8 @@ async function serveStatic(pathname, res, panelDistDir) {
18425
18915
  return;
18426
18916
  }
18427
18917
  const rel = decoded === "/" ? "/index.html" : decoded;
18428
- const distDir = resolve11(panelDistDir);
18429
- const filePath = resolve11(distDir, `.${rel}`);
18918
+ const distDir = resolve13(panelDistDir);
18919
+ const filePath = resolve13(distDir, `.${rel}`);
18430
18920
  if (filePath !== distDir && !filePath.startsWith(distDir + sep2)) {
18431
18921
  sendText2(res, 403, "forbidden");
18432
18922
  return;
@@ -18463,8 +18953,8 @@ var HELP = `wingman \u2014 Not your copilot. Your wingman.
18463
18953
  wingman hook install <harness> [--port 7333] \u5B9E\u51B5\u63A5\u7EBF(\u5199\u524D\u5907\u4EFD,\u5E42\u7B49)
18464
18954
  [--profile <p>] dsh:\u53EA\u5904\u7406\u6307\u5B9A profile
18465
18955
  wingman hook uninstall <harness> [--profile <p>] \u89E3\u7EBF(\u914D\u7F6E\u6062\u590D,\u5E42\u7B49)
18466
- wingman protocol install|uninstall|status <harness> \u6309\u9879\u76EE\u7BA1\u7406 Plan Protocol
18467
- [--project <dir>] [--dry-run] [--yes]
18956
+ wingman protocol install|uninstall|status <harness> \u7BA1\u7406\u7528\u6237\u7EA7 / \u9879\u76EE\u7EA7 Plan Protocol
18957
+ [--project <dir> | --user] [--dry-run] [--yes]
18468
18958
  wingman license status \u67E5\u770B\u8BA2\u9605\u72B6\u6001(\u5199\u52A8\u4F5C\u7684\u95F8)
18469
18959
  wingman license refresh \u8054\u7F51\u5411\u7B7E\u53D1\u7AEF\u6362\u65B0 license(\u7EED\u671F)
18470
18960
  wingman --version | -v | version \u663E\u793A\u7248\u672C
@@ -18493,7 +18983,7 @@ async function main(argv) {
18493
18983
  case "hook":
18494
18984
  return runHook(rest);
18495
18985
  case "protocol":
18496
- return runProtocolCli(rest);
18986
+ return runProtocolCli(rest, { homeDir: homedir16() });
18497
18987
  case "license": {
18498
18988
  if (rest[0] === "status") {
18499
18989
  const status3 = licenseStatus();
@@ -18502,10 +18992,10 @@ async function main(argv) {
18502
18992
  return 0;
18503
18993
  }
18504
18994
  if (rest[0] === "refresh") {
18505
- const result4 = await refreshLicense();
18506
- process.stdout.write(`${result4.message}
18995
+ const result5 = await refreshLicense();
18996
+ process.stdout.write(`${result5.message}
18507
18997
  `);
18508
- if (!result4.ok)
18998
+ if (!result5.ok)
18509
18999
  return 1;
18510
19000
  const status3 = licenseStatus();
18511
19001
  process.stdout.write(`${status3.state}:${status3.detail}
@@ -18544,7 +19034,7 @@ ${counts}
18544
19034
  }
18545
19035
  async function runServe(args) {
18546
19036
  const { port, fixtures, panelDist } = parseServeArgs(args);
18547
- const homeDir = fixtures ? fixturesRoot : homedir13();
19037
+ const homeDir = fixtures ? fixturesRoot : homedir16();
18548
19038
  const hookToken = createHookToken();
18549
19039
  let dshRetirementNotice;
18550
19040
  if (!fixtures) {
@@ -18579,7 +19069,7 @@ async function runServe(args) {
18579
19069
  `);
18580
19070
  }
18581
19071
  }
18582
- const panelDistDir = panelDist === void 0 ? resolve12(dirname19(fileURLToPath2(import.meta.url)), "../../panel/dist") : resolve12(panelDist);
19072
+ const panelDistDir = panelDist === void 0 ? resolve14(dirname20(fileURLToPath2(import.meta.url)), "../../panel/dist") : resolve14(panelDist);
18583
19073
  const narrative = createNarrativeService({
18584
19074
  followTranscripts: !fixtures,
18585
19075
  homeDir,
@@ -18592,7 +19082,7 @@ async function runServe(args) {
18592
19082
  });
18593
19083
  if (fixtures) {
18594
19084
  try {
18595
- const raw = readFileSync18(fixturePath("cc", "sessions", "session-todos.jsonl"), "utf8");
19085
+ const raw = readFileSync19(fixturePath("cc", "sessions", "session-todos.jsonl"), "utf8");
18596
19086
  narrative.seedFixture("cc", raw.split("\n"), "MOCK \u2014 fixtures \u6F14\u793A:\u53D9\u4E8B\u6570\u636E\u6765\u81EA packages/fixtures \u7684 session-todos.jsonl \u6837\u4F8B\u4F1A\u8BDD,\u975E\u672C\u673A\u771F\u5B9E transcript\u3002");
18597
19087
  } catch (error) {
18598
19088
  const message = error instanceof Error ? error.message : String(error);
@@ -18666,8 +19156,8 @@ async function runHook(args) {
18666
19156
  const { adapter, scanOptions } = await loadHarness(harness, { fixtures: false });
18667
19157
  if (action === "install") {
18668
19158
  if (harness === "dsh") {
18669
- const result4 = await installDshHooks(port, scanOptions);
18670
- writeDshInstallReport(await dshHookInstallReport(scanOptions), result4);
19159
+ const result5 = await installDshHooks(port, scanOptions);
19160
+ writeDshInstallReport(await dshHookInstallReport(scanOptions), result5);
18671
19161
  process.stdout.write(`wingman:dsh profile \u63A5\u7EBF\u5904\u7406\u5B8C\u6210(POST http://127.0.0.1:${port}/hook?harness=dsh)\u3002
18672
19162
  \u5199\u524D\u5DF2\u5907\u4EFD;\u91CD\u590D\u6267\u884C\u5E42\u7B49;\u89E3\u7EBF:wingman hook uninstall dsh
18673
19163
  `);
@@ -18681,14 +19171,14 @@ async function runHook(args) {
18681
19171
  `);
18682
19172
  }
18683
19173
  } else if (harness === "dsh") {
18684
- const result4 = await uninstallDshHooks(scanOptions);
19174
+ const result5 = await uninstallDshHooks(scanOptions);
18685
19175
  const messages = {
18686
19176
  unwired: "\u5DF2\u89E3\u7EBF",
18687
19177
  state: "\u5DF2\u6062\u590D",
18688
19178
  removed: "\u5DF2\u79FB\u9664\u6B8B\u7559\u5757",
18689
19179
  cleared: "\u5DF2\u6E05\u7406\u8BB0\u5F55"
18690
19180
  };
18691
- for (const profile2 of result4.profiles) {
19181
+ for (const profile2 of result5.profiles) {
18692
19182
  process.stdout.write(`${profile2.profile}:${messages[profile2.restored]}
18693
19183
  `);
18694
19184
  }
@@ -18709,16 +19199,16 @@ function writeDshInstallReport(report, installResult) {
18709
19199
  process.stdout.write("\u672A\u53D1\u73B0\u542B package.json \u7684 dsh profile\u3002\n");
18710
19200
  return;
18711
19201
  }
18712
- for (const result4 of report.profiles) {
18713
- if (result4.wired) {
18714
- process.stdout.write(`${result4.profile}:\u5DF2\u63A5\u7EBF
19202
+ for (const result5 of report.profiles) {
19203
+ if (result5.wired) {
19204
+ process.stdout.write(`${result5.profile}:\u5DF2\u63A5\u7EBF
18715
19205
  `);
18716
- } else if (result4.missingPackages.length > 0) {
18717
- const removed = installResult.removedProfiles.includes(result4.profile) ? "\u5DF2\u79FB\u9664\u65E7\u63A5\u7EBF\u5757," : "";
18718
- process.stdout.write(`${result4.profile}:\u672A\u63A5\u7EBF,${removed}\u7F3A ${result4.missingPackages.join("\u3001")} \u2192 ${result4.installCommand ?? ""}
19206
+ } else if (result5.missingPackages.length > 0) {
19207
+ const removed = installResult.removedProfiles.includes(result5.profile) ? "\u5DF2\u79FB\u9664\u65E7\u63A5\u7EBF\u5757," : "";
19208
+ process.stdout.write(`${result5.profile}:\u672A\u63A5\u7EBF,${removed}\u7F3A ${result5.missingPackages.join("\u3001")} \u2192 ${result5.installCommand ?? ""}
18719
19209
  `);
18720
19210
  } else {
18721
- process.stdout.write(`${result4.profile}:\u672A\u63A5\u7EBF
19211
+ process.stdout.write(`${result5.profile}:\u672A\u63A5\u7EBF
18722
19212
  `);
18723
19213
  }
18724
19214
  }
@@ -18798,7 +19288,7 @@ main(process.argv.slice(2)).then((code) => {
18798
19288
  process.stderr.write(`
18799
19289
  ${HELP}`);
18800
19290
  }
18801
- process.exitCode = 1;
19291
+ process.exitCode = error instanceof ProtocolUsageError ? 2 : 1;
18802
19292
  });
18803
19293
  /*! Bundled license information:
18804
19294