@my-life-buddies/cli 0.13.3 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/core.js CHANGED
@@ -16,6 +16,12 @@ function runtimeDependencyVersion(pkg) {
16
16
  const version = dependencies2[BUDDY_RUNTIME_PACKAGE];
17
17
  return typeof version === "string" && /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u.test(version) ? version : void 0;
18
18
  }
19
+ function runtimeUsesEnvironmentIdentity(pkg) {
20
+ const version = runtimeDependencyVersion(pkg);
21
+ if (!version) return false;
22
+ const [major, minor] = version.split(".").map(Number);
23
+ return major > 0 || minor >= 16;
24
+ }
19
25
 
20
26
  // packages/cli-core/src/config/runtime-catalog.ts
21
27
  async function loadRuntime(projectRoot) {
@@ -529,7 +535,7 @@ import { lstat as lstat4 } from "node:fs/promises";
529
535
  import { join as join5 } from "node:path";
530
536
 
531
537
  // packages/cli-core/src/init/scaffold.ts
532
- import { lstat as lstat3, mkdir as mkdir4, open as open2, readFile as readFile6, rmdir as rmdir2, unlink as unlink3 } from "node:fs/promises";
538
+ import { lstat as lstat3, mkdir as mkdir4, open as open2, readFile as readFile6, rmdir as rmdir2, unlink as unlink3, writeFile as writeFile5 } from "node:fs/promises";
533
539
  import { resolve as resolve3 } from "node:path";
534
540
 
535
541
  // packages/cli-core/src/config/models.ts
@@ -766,8 +772,6 @@ process.on("SIGTERM", stop);
766
772
  let runtime;
767
773
  try {
768
774
  runtime = await BuddyServer.start({
769
- buddyId: process.env.BUDDY_ID,
770
- token: process.env.BUDDY_TOKEN,
771
775
  dataRequirements: config.datasets ?? [],
772
776
  buddy: createBuddyOptions,
773
777
  });
@@ -786,6 +790,32 @@ try {
786
790
  }
787
791
  `;
788
792
  }
793
+ function legacyPlatformStartTemplate() {
794
+ return platformStartTemplate().replace(" dataRequirements: config.datasets ?? [],", " buddyId: process.env.BUDDY_ID,\n token: process.env.BUDDY_TOKEN,\n dataRequirements: config.datasets ?? [],");
795
+ }
796
+ async function migrateRuntimeStartup(projectRoot) {
797
+ const packagePath = resolve3(projectRoot, BUDDY_PLATFORM_PACKAGE_JSON);
798
+ const entryPath = resolve3(projectRoot, BUDDY_PLATFORM_START_ENTRY);
799
+ for (const path of [packagePath, entryPath]) {
800
+ if (!(await lstat3(path)).isFile()) throw new Error("\u542F\u52A8\u6587\u4EF6\u5FC5\u987B\u662F\u666E\u901A\u6587\u4EF6\uFF0C\u4E0D\u80FD\u4F7F\u7528\u7B26\u53F7\u94FE\u63A5");
801
+ }
802
+ const pkg = JSON.parse(await readFile6(packagePath, "utf8"));
803
+ if (!runtimeUsesEnvironmentIdentity(pkg)) return false;
804
+ const current = await readFile6(entryPath, "utf8");
805
+ const latest = platformStartTemplate();
806
+ const legacy = legacyPlatformStartTemplate();
807
+ let changed2 = false;
808
+ if (current.replace(/\r\n/gu, "\n") === legacy) {
809
+ await writeFile5(entryPath, latest, "utf8");
810
+ changed2 = true;
811
+ }
812
+ if (pkg.scripts?.start === "node start.mjs") {
813
+ pkg.scripts.start = "node --env-file-if-exists=.env start.mjs";
814
+ await writeFile5(packagePath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
815
+ changed2 = true;
816
+ }
817
+ return changed2;
818
+ }
789
819
  async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
790
820
  const path = resolve3(projectRoot, BUDDY_PLATFORM_AGENT_ENTRY);
791
821
  const hasAlternateLockfile = (await Promise.all(["pnpm-lock.yaml", "yarn.lock"].map(async (name2) => {
@@ -804,7 +834,9 @@ async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
804
834
  { path: resolve3(projectRoot, BUDDY_PLATFORM_FACTORY_ENTRY), content: platformFactoryTemplate() },
805
835
  { path: resolve3(projectRoot, BUDDY_PLATFORM_PACKAGE_JSON), content: await readFile6(new URL("../../resources/agent-template/package.json", import.meta.url), "utf8") },
806
836
  ...hasAlternateLockfile ? [] : [{ path: resolve3(projectRoot, BUDDY_PLATFORM_PACKAGE_LOCK), content: await readFile6(new URL("../../resources/agent-template/package-lock.json", import.meta.url), "utf8") }],
807
- { path: resolve3(projectRoot, BUDDY_PLATFORM_START_ENTRY), content: platformStartTemplate() }
837
+ { path: resolve3(projectRoot, BUDDY_PLATFORM_START_ENTRY), content: platformStartTemplate() },
838
+ { path: resolve3(projectRoot, ".gitignore"), content: "node_modules/\n/.env\n" },
839
+ { path: resolve3(projectRoot, ".env.example"), content: "# \u9996\u6B21\u8FD0\u884C buddy-cli dev \u6216\u5728\u540E\u53F0\u542F\u52A8 DEV \u65F6\uFF0CCLI \u4F1A\u51C6\u5907 .env\u3002\nBUDDY_ID=\nBUDDY_TOKEN=\n# \u53EF\u9009\uFF1A\u4F7F\u7528\u5176\u4ED6\u5E73\u53F0\u65F6\u8BBE\u7F6E MLB_GATEWAY_URL\u3002\n" }
808
840
  ];
809
841
  const handles = [];
810
842
  const createdDirectories = [];
@@ -847,12 +879,17 @@ async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
847
879
  throw new Error("\u5DF2\u6709 package.json \u4E0E\u5F85\u8865\u9F50\u7684\u9501\u6587\u4EF6\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u7528\u5DE5\u7A0B\u7684\u5305\u7BA1\u7406\u5668\u6062\u590D\u5339\u914D\u7684\u4F9D\u8D56\u6587\u4EF6\u540E\u91CD\u8BD5");
848
880
  }
849
881
  }
882
+ const effectivePackage = handles.some((file) => file.path === packageFile.path) ? packageFile.content : await readFile6(packageFile.path, "utf8");
883
+ if (!runtimeUsesEnvironmentIdentity(JSON.parse(effectivePackage))) {
884
+ files.find((file) => file.path === resolve3(projectRoot, BUDDY_PLATFORM_START_ENTRY)).content = legacyPlatformStartTemplate();
885
+ }
850
886
  for (const { path: filePath, handle } of handles) {
851
887
  const file = files.find((candidate) => candidate.path === filePath);
852
888
  await handle.writeFile(file.content, "utf8");
853
889
  await handle.sync();
854
890
  }
855
- return Object.freeze({ path, created: handles.length > 0 || createdDirectories.length > 0 });
891
+ const migrated = await migrateRuntimeStartup(projectRoot);
892
+ return Object.freeze({ path, created: migrated || handles.length > 0 || createdDirectories.length > 0 });
856
893
  } catch (cause) {
857
894
  await Promise.all(handles.map(({ handle }) => handle.close().catch(() => void 0)));
858
895
  await Promise.all(handles.map(({ path: createdPath }) => unlink3(createdPath).catch(() => void 0)));
@@ -1635,7 +1672,7 @@ ${DATASETS_COMMAND_HELP}`);
1635
1672
 
1636
1673
  // packages/cli-core/src/commands/knowledge.ts
1637
1674
  import { createHash as createHash2, randomUUID as randomUUID4 } from "node:crypto";
1638
- import { lstat as lstat7, mkdir as mkdir6, readFile as readFile8, rename as rename5, unlink as unlink5, writeFile as writeFile5 } from "node:fs/promises";
1675
+ import { lstat as lstat7, mkdir as mkdir6, readFile as readFile8, rename as rename5, unlink as unlink5, writeFile as writeFile6 } from "node:fs/promises";
1639
1676
  import { dirname as dirname2, join as join8, resolve as resolve8 } from "node:path";
1640
1677
  var MANIFEST = "knowledge-manifest.json";
1641
1678
  var INDEX = "resources/knowledge/index.md";
@@ -1705,7 +1742,7 @@ async function atomicWrite(root, path, value) {
1705
1742
  const full = await safePath(root, path);
1706
1743
  await mkdir6(dirname2(full), { recursive: true });
1707
1744
  const temporary = `${full}.${randomUUID4()}.tmp`;
1708
- await writeFile5(temporary, value, { flag: "wx", mode: 384 });
1745
+ await writeFile6(temporary, value, { flag: "wx", mode: 384 });
1709
1746
  try {
1710
1747
  await rename5(temporary, full);
1711
1748
  } finally {
@@ -1947,11 +1984,11 @@ ${KNOWLEDGE_HELP}`);
1947
1984
  }
1948
1985
 
1949
1986
  // packages/cli-core/src/index.ts
1950
- import { join as join15, resolve as resolve16 } from "node:path";
1987
+ import { join as join16, resolve as resolve16 } from "node:path";
1951
1988
 
1952
1989
  // packages/cli-core/src/init/creator.ts
1953
1990
  import { randomUUID as randomUUID5 } from "node:crypto";
1954
- import { link as link2, lstat as lstat8, mkdir as mkdir7, readFile as readFile9, unlink as unlink6, writeFile as writeFile6 } from "node:fs/promises";
1991
+ import { link as link2, lstat as lstat8, mkdir as mkdir7, readFile as readFile9, unlink as unlink6, writeFile as writeFile7 } from "node:fs/promises";
1955
1992
  import { join as join9 } from "node:path";
1956
1993
  import { fileURLToPath as fileURLToPath2 } from "node:url";
1957
1994
 
@@ -2022,7 +2059,7 @@ ${KNOWLEDGE_GUIDE}
2022
2059
  | \u56DE\u7B54\u65F6\u9700\u8981\u53C2\u8003\u7684\u5386\u53F2\u3001\u8BA1\u5212\u548C\u72B6\u6001 | Runtime \u4F1A\u4ECE MLB \u91CD\u5EFA\u4F1A\u8BDD\u5386\u53F2\uFF1B\u957F\u671F\u8BA1\u5212\u548C\u7ED3\u6784\u5316\u72B6\u6001\u4E0D\u80FD\u53EA\u4F9D\u8D56\u5B83\u4E00\u76F4\u7559\u5728\u6700\u8FD1\u804A\u5929\u91CC\u3002\u6309\u9700\u6C42\u4F7F\u7528 Memory\u3001\u6388\u6743\u6570\u636E\u6216\u4E1A\u52A1 Tool\uFF0C\u4E0D\u8981\u627F\u8BFA\u9ED8\u8BA4\u914D\u7F6E\u5DF2\u7ECF\u8986\u76D6\u3002 |
2023
2060
  | \u6A21\u578B\u548C\u5E73\u53F0\u8D44\u6E90 | \u5DF2\u786E\u5B9A\u7684\u6A21\u578B\u76F4\u63A5\u6CBF\u7528\uFF1B\u672A\u6307\u5B9A\u65F6\u67E5\u8BE2 \`buddy-cli models\`\uFF0C\u6838\u5BF9\u53EF\u7528\u6027\u5E76\u91C7\u7528\u6EE1\u8DB3\u9700\u6C42\u7684\u9009\u62E9\uFF0C\u4E0D\u9ED8\u8BA4\u518D\u95EE\u4E00\u8F6E\u9009\u578B\u95EE\u9898\uFF0C\u4E5F\u4E0D\u7F16\u9020\u4EF7\u683C\u6216\u80FD\u529B\u3002\u6A21\u677F\u628A\u914D\u7F6E\u4E2D\u7684\u6A21\u578B\u4EA4\u7ED9 \`initialState.model\`\uFF1B\u81EA\u5B9A\u4E49\u5DE5\u5382\u4E5F\u53EF\u6309\u4F1A\u8BDD\u9009\u62E9\u53D7\u652F\u6301\u6A21\u578B\uFF1B\u4F1A\u4EA7\u751F\u65B0\u7684\u8D39\u7528\u3001\u6570\u636E\u4F7F\u7528\u6216\u6743\u9650\u8FB9\u754C\u65F6\u5148\u786E\u8BA4\u3002 |
2024
2061
 
2025
- \`src/buddy-options.mjs\` \u662F\u6BCF\u573A\u4F1A\u8BDD\u7684\u4E1A\u52A1\u88C5\u914D\u5165\u53E3\uFF0C\u5BFC\u51FA \`createBuddyOptions(conversation)\`\uFF0C\u8FD4\u56DE \`initialState\`\u3001\u5728 \`initialState.tools\` \u6CE8\u518C\u7684\u4E1A\u52A1\u53CA\u5E73\u53F0\u5DE5\u5177\u548C\u53EF\u9009\u56DE\u5408\u94A9\u5B50\u3002\`start.mjs\` \u4ECE \`./src/buddy-options.mjs\` \u5BFC\u5165\u5DE5\u5382\u5E76\u4F20\u7ED9 \`BuddyServer.start({ buddyId: process.env.BUDDY_ID, token: process.env.BUDDY_TOKEN, dataRequirements: config.datasets ?? [], buddy: createBuddyOptions })\`\uFF1B\u7EC4\u88C5\u5668\u8BFB\u53D6 \`buddy.agent.json.model\`\uFF0C\u7701\u7565\u65F6\u7528 \`kimi-k2.6\`\uFF0C\u653E\u5165 \`initialState.model\`\uFF1B\u7528 \`new URL("../agent.md", import.meta.url)\` \u8BFB\u53D6\u6839\u76EE\u5F55 Prompt\u3002\u9ED8\u8BA4\u6A21\u677F\u53EA\u662F\u8D77\u70B9\uFF0C\u53EA\u6539\u8BF4\u660E\u4E0D\u7B49\u4E8E\u6539\u53D8\u4E86\u4FDD\u5B58\u3001\u67E5\u8BE2\u6216\u5904\u7406\u903B\u8F91\u3002
2062
+ \`src/buddy-options.mjs\` \u662F\u6BCF\u573A\u4F1A\u8BDD\u7684\u4E1A\u52A1\u88C5\u914D\u5165\u53E3\uFF0C\u5BFC\u51FA \`createBuddyOptions(conversation)\`\uFF0C\u8FD4\u56DE \`initialState\`\u3001\u5728 \`initialState.tools\` \u6CE8\u518C\u7684\u4E1A\u52A1\u53CA\u5E73\u53F0\u5DE5\u5177\u548C\u53EF\u9009\u56DE\u5408\u94A9\u5B50\u3002\`start.mjs\` \u4ECE \`./src/buddy-options.mjs\` \u5BFC\u5165\u5DE5\u5382\u5E76\u4F20\u7ED9 \`BuddyServer.start({ dataRequirements: config.datasets ?? [], buddy: createBuddyOptions })\`\uFF1B\u7EC4\u88C5\u5668\u8BFB\u53D6 \`buddy.agent.json.model\`\uFF0C\u7701\u7565\u65F6\u7528 \`kimi-k2.6\`\uFF0C\u653E\u5165 \`initialState.model\`\uFF1B\u7528 \`new URL("../agent.md", import.meta.url)\` \u8BFB\u53D6\u6839\u76EE\u5F55 Prompt\u3002\u9ED8\u8BA4\u6A21\u677F\u53EA\u662F\u8D77\u70B9\uFF0C\u53EA\u6539\u8BF4\u660E\u4E0D\u7B49\u4E8E\u6539\u53D8\u4E86\u4FDD\u5B58\u3001\u67E5\u8BE2\u6216\u5904\u7406\u903B\u8F91\u3002 Runtime 0.16.0 \u4ECE\u73AF\u5883\u53D8\u91CF\u8BFB\u53D6\u8EAB\u4EFD\u548C\u4EE4\u724C\uFF1B\u9996\u6B21\u542F\u52A8 DEV \u65F6 CLI \u51C6\u5907\u5DE5\u7A0B \`.env\`\uFF0CNode \u7528 \`--env-file-if-exists=.env\` \u52A0\u8F7D\u3002\u4E0D\u8981\u5C06 token \u5199\u5165\u4E1A\u52A1\u4EE3\u7801\u3002
2026
2063
 
2027
2064
  ### \u6309\u76EE\u5F55\u804C\u8D23\u7EC4\u7EC7\u5B9E\u73B0
2028
2065
 
@@ -2052,11 +2089,11 @@ Tool \u548C Hook \u662F Runtime \u7684\u6269\u5C55\u70B9\uFF1BService \u53EA\u66
2052
2089
 
2053
2090
  \u5E73\u53F0\u80FD\u529B\u8981\u4EE5\u5B9E\u9645\u63A5\u5165\u4E3A\u51C6\u3002\u5F53\u524D Runtime \u63D0\u4F9B\u4F1A\u8BDD\u6D88\u606F\u3001Memory\u3001\u6388\u6743\u6570\u636E\u3001\u5C0F\u6302\u4EF6\u548C\u672C\u5730 Markdown \u8D44\u6599\u80FD\u529B\uFF1B\u6CA1\u6709\u63A5\u901A\u7684 Files\u3001Knowledge \u4E0D\u80FD\u56E0\u624B\u518C\u63D0\u5230\u5C31\u5BA3\u79F0\u53EF\u7528\u3002\u666E\u901A Tool \u4E5F\u4E0D\u4EE3\u8868\u5DF2\u7ECF\u63D0\u4F9B\u5B9A\u65F6\u3001\u957F\u671F\u4EFB\u52A1\u3001\u540E\u53F0\u8C03\u5EA6\u6216\u4E3B\u52A8\u89E6\u8FBE\u3002\u624B\u518C\u63CF\u8FF0\u7684\u4ED8\u8D39\u3001\u53D1\u5E03\u7B49\u670D\u52A1\u8BBE\u8BA1\u4E5F\u4E0D\u6784\u6210\u6267\u884C\u6536\u8D39\u6216\u53D1\u5E03\u52A8\u4F5C\u7684\u6388\u6743\u3002
2054
2091
 
2055
- \u9700\u8981\u7528\u6237\u6570\u636E\u65F6\uFF0C\u5148\u5728\u5DE5\u7A0B\u76EE\u5F55\u6267\u884C \`buddy-cli datasets\`\uFF08\u811A\u672C\u53EF\u7528 \`--json\`\uFF09\uFF0C\u4ECE\u5F53\u524D\u5B89\u88C5\u7684 Runtime \u5BFC\u51FA\u8BFB\u53D6\u5168\u90E8\u6570\u636E\u96C6\uFF1B\u4E0D\u8981\u6C42\u767B\u5F55\uFF0C\u4E0D\u4ECE Server \u62C9\u76EE\u5F55\u3002Runtime 0.12.2 \u542B 10 \u9879\uFF0CCLI \u4E0D\u590D\u5236\u679A\u4E3E\u3002\u628A\u5B9E\u9645\u9700\u8981\u7684 \`id\` \u548C\u7528\u9014 \`purpose\` \u5199\u5165 \`buddy.agent.json.datasets\`\uFF0C\u540C\u4E00 ID \u53EA\u5199\u4E00\u6B21\uFF0C\u7528\u9014\u4E0D\u80FD\u4E3A\u7A7A\u4E14\u6700\u591A 200 \u5B57\uFF1B\u65E0\u9700\u6C42\u65F6\u4FDD\u7559\u7A7A\u6570\u7EC4\u3002DEV \u548C\u58F0\u660E\u975E\u7A7A\u65F6\u7684 push \u9884\u68C0\u7528\u8FD9\u4EFD\u5DE5\u7A0B\u4F9D\u8D56\u6821\u9A8C ID\uFF1B\u9700\u8981\u5148\u5B89\u88C5\u4E0E package.json \u51C6\u786E\u7248\u672C\u4E00\u81F4\u7684 Runtime\u3002\u6E05\u5355\u58F0\u660E\u6570\u91CF\u4E0D\u7B49\u4E8E\u5355\u6B21\u67E5\u8BE2\u4E0A\u9650\uFF0C\u5F53\u524D\u4E00\u6B21\u67E5\u8BE2\u6700\u591A 8 \u9879\u3002
2092
+ \u9700\u8981\u7528\u6237\u6570\u636E\u65F6\uFF0C\u5148\u5728\u5DE5\u7A0B\u76EE\u5F55\u6267\u884C \`buddy-cli datasets\`\uFF08\u811A\u672C\u53EF\u7528 \`--json\`\uFF09\uFF0C\u4ECE\u5F53\u524D\u5B89\u88C5\u7684 Runtime \u5BFC\u51FA\u8BFB\u53D6\u5168\u90E8\u6570\u636E\u96C6\uFF1B\u4E0D\u8981\u6C42\u767B\u5F55\uFF0C\u4E0D\u4ECE Server \u62C9\u76EE\u5F55\u3002\u4EE5\u5DE5\u7A0B\u5B89\u88C5\u7248\u672C\u5BFC\u51FA\u7684\u76EE\u5F55\u4E3A\u51C6\uFF0CCLI \u4E0D\u590D\u5236\u679A\u4E3E\u3002\u628A\u5B9E\u9645\u9700\u8981\u7684 \`id\` \u548C\u7528\u9014 \`purpose\` \u5199\u5165 \`buddy.agent.json.datasets\`\uFF0C\u540C\u4E00 ID \u53EA\u5199\u4E00\u6B21\uFF0C\u7528\u9014\u4E0D\u80FD\u4E3A\u7A7A\u4E14\u6700\u591A 200 \u5B57\uFF1B\u65E0\u9700\u6C42\u65F6\u4FDD\u7559\u7A7A\u6570\u7EC4\u3002DEV \u548C\u58F0\u660E\u975E\u7A7A\u65F6\u7684 push \u9884\u68C0\u7528\u8FD9\u4EFD\u5DE5\u7A0B\u4F9D\u8D56\u6821\u9A8C ID\uFF1B\u9700\u8981\u5148\u5B89\u88C5\u4E0E package.json \u51C6\u786E\u7248\u672C\u4E00\u81F4\u7684 Runtime\u3002\u6E05\u5355\u58F0\u660E\u6570\u91CF\u4E0D\u7B49\u4E8E\u5355\u6B21\u67E5\u8BE2\u4E0A\u9650\uFF0C\u5F53\u524D\u4E00\u6B21\u67E5\u8BE2\u6700\u591A 8 \u9879\u3002
2056
2093
 
2057
2094
  \`start.mjs\` \u5C06\u58F0\u660E\u4EA4\u7ED9 \`StartOptions.dataRequirements\`\u3002Runtime \u5728\u5B9E\u9645\u6570\u636E\u67E5\u8BE2\u3001HealthKit \u6388\u6743\u548C\u4E3B\u52A8\u670D\u52A1\u8BF7\u6C42\u4E2D\u643A\u5E26\u5B8C\u6574\u58F0\u660E\uFF0C\u7531 Server \u6821\u9A8C\u8303\u56F4\u4E0E\u7528\u6237\u540C\u610F\uFF1B\u586B\u5199\u914D\u7F6E\u4E0D\u8868\u793A\u5DF2\u7ECF\u6388\u6743\u3002\u670D\u52A1\u7AEF\u4ECE\u4E0A\u4F20\u5305\u89E3\u6790\u5E76\u7ED1\u5B9A\u53D1\u5E03\u7248\u672C\u4ECD\u5F85\u5B9E\u73B0\u3002
2058
2095
 
2059
- \u6A21\u578B\u9700\u8981\u67E5\u6570\u636E\u65F6\uFF0C\u5728 \`src/buddy-options.mjs\` \u7684 \`initialState.tools\` \u4E2D\u52A0\u5165 \`conversation.tools.data_access_query\`\uFF1B\u9700\u8981\u5411\u7528\u6237\u7533\u8BF7\u65F6\u52A0\u5165 \`conversation.tools.data_access_request\`\uFF0C\u4F4D\u7F6E\u3001\u65E5\u5386\u7684\u4E00\u6B21\u6027\u7ED3\u679C\u901A\u8FC7 \`data_access_read_result\` \u8BFB\u53D6\uFF0CHealthKit \u5219\u91CD\u65B0\u67E5\u8BE2 Dataset\u3002\u4E1A\u52A1\u4EE3\u7801\u5BF9\u5E94\u4F7F\u7528 \`conversation.dataAccess.query/request/readResult\`\u3002\u65B0\u5EFA\u5DE5\u7A0B\u52A8\u6001\u9009\u62E9\u516C\u5171 npm latest \u5E76\u9501\u5B9A\u51C6\u786E\u7248\u672C\uFF1B\u8054\u7F51\u5931\u8D25\u65F6\u660E\u786E\u63D0\u793A\u4F7F\u7528\u968F CLI \u9644\u5E26\u7684 Runtime 0.12.2\u3002\u5DF2\u6709\u5DE5\u7A0B\u901A\u8FC7\u5305\u7BA1\u7406\u5668\u663E\u5F0F\u5347\u7EA7\u4F9D\u8D56\u3002
2096
+ \u6A21\u578B\u9700\u8981\u67E5\u6570\u636E\u65F6\uFF0C\u5728 \`src/buddy-options.mjs\` \u7684 \`initialState.tools\` \u4E2D\u52A0\u5165 \`conversation.tools.data_access_query\`\uFF1B\u9700\u8981\u5411\u7528\u6237\u7533\u8BF7\u65F6\u52A0\u5165 \`conversation.tools.data_access_request\`\uFF0C\u4F4D\u7F6E\u3001\u65E5\u5386\u7684\u4E00\u6B21\u6027\u7ED3\u679C\u901A\u8FC7 \`data_access_read_result\` \u8BFB\u53D6\uFF0CHealthKit \u5219\u91CD\u65B0\u67E5\u8BE2 Dataset\u3002\u4E1A\u52A1\u4EE3\u7801\u5BF9\u5E94\u4F7F\u7528 \`conversation.dataAccess.query/request/readResult\`\u3002\u65B0\u5EFA\u5DE5\u7A0B\u52A8\u6001\u9009\u62E9\u516C\u5171 npm latest \u5E76\u9501\u5B9A\u51C6\u786E\u7248\u672C\uFF1B\u8054\u7F51\u5931\u8D25\u65F6\u660E\u786E\u63D0\u793A\u4F7F\u7528\u968F CLI \u9644\u5E26\u7684 Runtime 0.16.0\u3002\u5DF2\u6709\u5DE5\u7A0B\u901A\u8FC7\u5305\u7BA1\u7406\u5668\u663E\u5F0F\u5347\u7EA7\u4F9D\u8D56\u3002
2060
2097
 
2061
2098
  \u5C0F\u6302\u4EF6\u7684\u6A21\u578B\u5DE5\u5177\u4E3A \`widget_create\`\u3001\`widget_read\`\uFF08\u6574\u4E2A\u5C0F\u6302\u4EF6\uFF09\u3001\`widget_read_module\`\uFF08\u4E00\u4E2A\u6A21\u5757\uFF09\u3001\`widget_rename\`\u3001\`widget_write_record\`\u3001\`widget_delete_record\`\u3001\`widget_delete\`\uFF08\u6574\u4E2A\u5C0F\u6302\u4EF6\u8FDE\u8BB0\u5F55\uFF09\u548C \`widget_send\`\uFF0C\u6309\u4E1A\u52A1\u9700\u8981\u6CE8\u518C\u5230 \`initialState.tools\`\u3002\u4FEE\u6539\u8BB0\u5F55\u7528 \`conversation.widget.writeRecord(id, input)\`\uFF1B\u5220\u4E00\u6761\u8BB0\u5F55\u7528 \`conversation.widget.deleteRecord(id, module, recordId)\`\uFF0C\u4E0D\u80FD\u7528\u5220\u9664\u6574\u4E2A\u5C0F\u6302\u4EF6\u7684 \`conversation.widget.delete(id)\` \u4EE3\u66FF\u3002\u4E24\u4E2A\u8BFB\u53D6\u5DE5\u5177\u53EF\u7528\u4E8E\u4E3B\u52A8\u56DE\u5408\uFF0C\u5176\u4F59\u516D\u4E2A\u5199\u5165\u5DE5\u5177\u7531 Runtime \u963B\u6B62\u5728\u4E3B\u52A8\u56DE\u5408\u6267\u884C\u3002
2062
2099
 
@@ -2153,7 +2190,7 @@ async function safeRead(path) {
2153
2190
  }
2154
2191
  async function writeOnce(path, bytes) {
2155
2192
  const temporary = `${path}.${randomUUID5()}.tmp`;
2156
- await writeFile6(temporary, bytes, { flag: "wx", mode: 384 });
2193
+ await writeFile7(temporary, bytes, { flag: "wx", mode: 384 });
2157
2194
  try {
2158
2195
  await link2(temporary, path).catch((cause) => {
2159
2196
  if (cause.code !== "EEXIST") throw cause;
@@ -2376,6 +2413,13 @@ function resolvePlatformUrl(options = {}) {
2376
2413
  return normalizePlatformUrl(options.override ?? configured ?? DEFAULT_MLB_TEST_URL);
2377
2414
  }
2378
2415
 
2416
+ // packages/cli-core/src/dev/project-env.ts
2417
+ import { constants } from "node:fs";
2418
+ import { open as open4, rename as rename6, unlink as unlink7 } from "node:fs/promises";
2419
+ import { randomUUID as randomUUID6 } from "node:crypto";
2420
+ import { join as join10 } from "node:path";
2421
+ import { parseEnv } from "node:util";
2422
+
2379
2423
  // packages/cli-core/src/dev/errors.ts
2380
2424
  var BuddyDevError = class extends Error {
2381
2425
  code;
@@ -2404,6 +2448,124 @@ function throwIfDevAborted(signal) {
2404
2448
  if (signal?.aborted) throw abortedDevError(signal);
2405
2449
  }
2406
2450
 
2451
+ // packages/cli-core/src/dev/project-env.ts
2452
+ function invalid(message) {
2453
+ return new BuddyDevError({ code: "DEV_CONFIG_INVALID", phase: "config", message });
2454
+ }
2455
+ async function readLocalFile(path) {
2456
+ let file;
2457
+ try {
2458
+ file = await open4(path, constants.O_RDONLY | constants.O_NOFOLLOW);
2459
+ const stat2 = await file.stat();
2460
+ if (!stat2.isFile() || stat2.nlink !== 1 || stat2.size > 256 * 1024) throw invalid("\u672C\u5730\u914D\u7F6E\u5FC5\u987B\u662F\u5C0F\u4E8E 256 KB \u7684\u666E\u901A\u6587\u4EF6\uFF0C\u4E0D\u80FD\u4F7F\u7528\u94FE\u63A5\u3002");
2461
+ return await file.readFile("utf8");
2462
+ } catch (cause) {
2463
+ if (cause.code === "ENOENT") return "";
2464
+ if (cause instanceof BuddyDevError) throw cause;
2465
+ throw invalid("\u65E0\u6CD5\u8BFB\u53D6\u5DE5\u7A0B\u672C\u5730\u914D\u7F6E\uFF0C\u8BF7\u68C0\u67E5 .env \u548C .gitignore \u7684\u6587\u4EF6\u7C7B\u578B\u4E0E\u6743\u9650\u3002");
2466
+ } finally {
2467
+ await file?.close();
2468
+ }
2469
+ }
2470
+ async function readProjectEnvironment(projectRoot, buddyId) {
2471
+ const source = await readLocalFile(join10(projectRoot, ".env"));
2472
+ let values;
2473
+ try {
2474
+ values = parseEnv(source);
2475
+ } catch {
2476
+ throw invalid("\u5DE5\u7A0B .env \u683C\u5F0F\u65E0\u6548\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5\u3002");
2477
+ }
2478
+ if (values.BUDDY_ID && values.BUDDY_ID !== buddyId) throw invalid(".env \u7684 BUDDY_ID \u4E0E buddy.agent.json \u4E0D\u4E00\u81F4\uFF0C\u8BF7\u5148\u4FEE\u6B63\u5DE5\u7A0B\u8EAB\u4EFD\u3002");
2479
+ return values;
2480
+ }
2481
+ async function projectBuddyToken(projectRoot, buddyId, gatewayUrl) {
2482
+ const values = await readProjectEnvironment(projectRoot, buddyId);
2483
+ if (!values.BUDDY_TOKEN) return void 0;
2484
+ if (!values.BUDDY_ID) throw invalid(".env \u4E2D\u6709 BUDDY_TOKEN\uFF0C\u4F46\u7F3A\u5C11 BUDDY_ID\uFF0C\u8BF7\u8865\u9F50\u540E\u91CD\u8BD5\u3002");
2485
+ if (values.MLB_GATEWAY_URL) {
2486
+ let gateway;
2487
+ try {
2488
+ gateway = normalizePlatformUrl(values.MLB_GATEWAY_URL);
2489
+ } catch {
2490
+ throw invalid(".env \u4E2D\u7684 MLB_GATEWAY_URL \u65E0\u6548\u3002");
2491
+ }
2492
+ if (gateway.href !== gatewayUrl.href) throw invalid(".env \u7684\u5E73\u53F0\u5730\u5740\u4E0E\u672C\u6B21\u542F\u52A8\u4E0D\u540C\uFF1B\u8BF7\u786E\u8BA4\u5E73\u53F0\u540E\u4F7F\u7528 --refresh-token \u91CD\u65B0\u9886\u53D6\u5F00\u53D1\u4EE4\u724C\u3002");
2493
+ }
2494
+ if (!values.BUDDY_TOKEN.trim() || /[\u0000-\u001f\u007f]/u.test(values.BUDDY_TOKEN)) throw invalid(".env \u4E2D\u7684\u5F00\u53D1\u4EE4\u724C\u683C\u5F0F\u65E0\u6548\uFF0C\u8BF7\u4F7F\u7528 --refresh-token \u91CD\u65B0\u9886\u53D6\u3002");
2495
+ return values.BUDDY_TOKEN;
2496
+ }
2497
+ function quote(value) {
2498
+ if (/[\u0000-\u001f\u007f]/u.test(value)) throw invalid("\u672C\u5730\u8FD0\u884C\u914D\u7F6E\u4E0D\u80FD\u5305\u542B\u63A7\u5236\u5B57\u7B26\u3002");
2499
+ const delimiter = ["'", '"', "`"].find((character) => !value.includes(character));
2500
+ if (!delimiter) throw invalid("\u672C\u5730\u8FD0\u884C\u914D\u7F6E\u5305\u542B\u65E0\u6CD5\u5199\u5165 .env \u7684\u5F15\u53F7\u7EC4\u5408\u3002");
2501
+ return `${delimiter}${value}${delimiter}`;
2502
+ }
2503
+ function updateValues(source, values) {
2504
+ const assignment = /^[\t ]*(?:export[\t ]+)?([A-Za-z_][A-Za-z0-9_]*)[\t ]*=[\t ]*/gm;
2505
+ let output = "", cursor = 0, match;
2506
+ const written = /* @__PURE__ */ new Set();
2507
+ while (match = assignment.exec(source)) {
2508
+ const valueStart = assignment.lastIndex;
2509
+ let end = source.indexOf("\n", valueStart);
2510
+ if (end < 0) end = source.length;
2511
+ let commentStart = valueStart;
2512
+ const delimiter = source[valueStart];
2513
+ if (delimiter && ["'", '"', "`"].includes(delimiter)) {
2514
+ const close = source.indexOf(delimiter, valueStart + 1);
2515
+ if (close < 0) throw invalid(".env \u4E2D\u6709\u672A\u95ED\u5408\u7684\u5F15\u53F7\uFF0C\u8BF7\u4FEE\u6B63\u540E\u91CD\u8BD5\u3002");
2516
+ commentStart = close + 1;
2517
+ end = source.indexOf("\n", close + 1);
2518
+ if (end < 0) end = source.length;
2519
+ }
2520
+ assignment.lastIndex = end;
2521
+ const name = match[1];
2522
+ if (!(name in values)) continue;
2523
+ const comment = source.slice(commentStart, end).match(/[\t ]*#[^\r\n]*/u)?.[0] ?? "";
2524
+ output += source.slice(cursor, match.index);
2525
+ output += written.has(name) ? comment : `${name}=${quote(values[name])}${comment ? ` ${comment.trimStart()}` : ""}`;
2526
+ if (source[end - 1] === "\r") output += "\r";
2527
+ cursor = end;
2528
+ written.add(name);
2529
+ }
2530
+ output += source.slice(cursor);
2531
+ const newline = source.includes("\r\n") ? "\r\n" : "\n";
2532
+ for (const [name, value] of Object.entries(values)) if (!written.has(name)) {
2533
+ if (output && !output.endsWith("\n")) output += newline;
2534
+ output += `${name}=${quote(value)}${newline}`;
2535
+ }
2536
+ const parsed = parseEnv(output);
2537
+ if (Object.entries(values).some(([name, value]) => parsed[name] !== value)) throw invalid("\u65E0\u6CD5\u5B8C\u6574\u66F4\u65B0 .env\uFF0C\u8BF7\u68C0\u67E5\u6587\u4EF6\u683C\u5F0F\u3002");
2538
+ return output;
2539
+ }
2540
+ async function replaceFile(path, contents, mode) {
2541
+ const temporary = `${path}.${randomUUID6()}.tmp`;
2542
+ let file;
2543
+ try {
2544
+ file = await open4(temporary, "wx", mode);
2545
+ await file.writeFile(contents, "utf8");
2546
+ await file.sync();
2547
+ await file.close();
2548
+ file = void 0;
2549
+ await rename6(temporary, path);
2550
+ } finally {
2551
+ await file?.close();
2552
+ await unlink7(temporary).catch((cause) => {
2553
+ if (cause.code !== "ENOENT") throw cause;
2554
+ });
2555
+ }
2556
+ }
2557
+ async function writeProjectEnvironment(projectRoot, values) {
2558
+ await readProjectEnvironment(projectRoot, values.BUDDY_ID);
2559
+ const envPath = join10(projectRoot, ".env"), ignorePath = join10(projectRoot, ".gitignore");
2560
+ const contents = updateValues(await readLocalFile(envPath), values);
2561
+ const ignored = await readLocalFile(ignorePath);
2562
+ if (ignored.trimEnd().split(/\r?\n/u).at(-1) !== "/.env") {
2563
+ await replaceFile(ignorePath, `${ignored}${ignored && !ignored.endsWith("\n") ? "\n" : ""}/.env
2564
+ `, 420);
2565
+ }
2566
+ await replaceFile(envPath, contents, 384);
2567
+ }
2568
+
2407
2569
  // packages/cli-core/src/dev/app-server.ts
2408
2570
  var MAX_JSON_BODY_LENGTH = 1048576;
2409
2571
  function safeCredential(value, name) {
@@ -2543,6 +2705,11 @@ var MlbDevRegistrationClient = class {
2543
2705
  });
2544
2706
  }
2545
2707
  options.signal.throwIfAborted();
2708
+ if (request.projectRoot) {
2709
+ await readProjectEnvironment(request.projectRoot, request.devAgentId);
2710
+ const localToken = this.#refreshToken ? void 0 : await projectBuddyToken(request.projectRoot, request.devAgentId, this.#baseUrl);
2711
+ if (localToken !== void 0) return Object.freeze({ devAgentId: request.devAgentId, appServerUrl: new URL(this.#baseUrl), agentToken: localToken });
2712
+ }
2546
2713
  const store = this.#tokenStoreFor?.(request.devAgentId);
2547
2714
  const cached = this.#refreshToken ? void 0 : await store?.load();
2548
2715
  if (cached !== void 0) {
@@ -2565,7 +2732,7 @@ var MlbDevRegistrationClient = class {
2565
2732
  }
2566
2733
  const token = safeCredential(body.token, "agentToken");
2567
2734
  options.signal.throwIfAborted();
2568
- await store?.save(token);
2735
+ if (!request.projectRoot) await store?.save(token);
2569
2736
  return Object.freeze({
2570
2737
  devAgentId: request.devAgentId,
2571
2738
  appServerUrl: new URL(this.#baseUrl),
@@ -2667,7 +2834,7 @@ function buildAgentEnvironment(options) {
2667
2834
  // packages/cli-core/src/dev/orchestrator.ts
2668
2835
  import { createHash as createHash4 } from "node:crypto";
2669
2836
  import { readFile as readFile10 } from "node:fs/promises";
2670
- import { join as join11, resolve as resolve10 } from "node:path";
2837
+ import { join as join12, resolve as resolve10 } from "node:path";
2671
2838
 
2672
2839
  // packages/cli-core/src/dev/launch.ts
2673
2840
  import { lstatSync, readFileSync } from "node:fs";
@@ -2712,9 +2879,10 @@ async function officialAgentLaunchPlan(input) {
2712
2879
  cause
2713
2880
  });
2714
2881
  }
2882
+ await migrateRuntimeStartup(input.projectRoot);
2715
2883
  return Object.freeze({
2716
2884
  command: process.execPath,
2717
- args: Object.freeze([entry2])
2885
+ args: Object.freeze(["--env-file-if-exists=.env", entry2])
2718
2886
  });
2719
2887
  }
2720
2888
 
@@ -2917,14 +3085,14 @@ function processTreeControllerFor(platform) {
2917
3085
  // packages/cli-core/src/dev/instance-lock.ts
2918
3086
  import { createHash as createHash3 } from "node:crypto";
2919
3087
  import { homedir as homedir2 } from "node:os";
2920
- import { join as join10 } from "node:path";
3088
+ import { join as join11 } from "node:path";
2921
3089
  function alreadyRunningError() {
2922
3090
  const message = "\u8FD9\u4E2A\u642D\u5B50\u5DF2\u6709 DEV \u5B9E\u4F8B\u5728\u8FD0\u884C\u3002\u8BF7\u5148\u5728\u539F\u9884\u89C8\u9875\u70B9\u51FB\u300C\u505C\u6B62 DEV\u300D\uFF0C\u6216\u5728\u8FD0\u884C dev \u7684\u7EC8\u7AEF\u6309 Ctrl+C\uFF0C\u518D\u542F\u52A8\u3002";
2923
3091
  return Object.assign(new BuddyDevError({ code: "DEV_ALREADY_RUNNING", phase: "launch", message }), { publicMessage: message });
2924
3092
  }
2925
3093
  async function acquireDevInstanceLock(options) {
2926
3094
  return acquireProcessLock({
2927
- directory: options.directory ?? join10(homedir2(), ".buddy", "dev-locks"),
3095
+ directory: options.directory ?? join11(homedir2(), ".buddy", "dev-locks"),
2928
3096
  key: createHash3("sha256").update(`${new URL(options.gatewayUrl).origin}
2929
3097
  ${options.devAgentId}`).digest("hex"),
2930
3098
  busyError: alreadyRunningError
@@ -2993,6 +3161,7 @@ async function launchPlanFor(config, options, projectRoot, signal) {
2993
3161
  async function registerDevAgent(options) {
2994
3162
  try {
2995
3163
  return validateRegistration(await options.client.register({
3164
+ projectRoot: options.projectRoot,
2996
3165
  devAgentId: options.devAgentId,
2997
3166
  configSource: options.configSource,
2998
3167
  configDigest: options.configDigest
@@ -3183,7 +3352,7 @@ async function startBuddyDev(options) {
3183
3352
  let config;
3184
3353
  let configSource;
3185
3354
  try {
3186
- configSource = await readFile10(join11(projectRoot, BUDDY_AGENT_FILENAME), "utf8");
3355
+ configSource = await readFile10(join12(projectRoot, BUDDY_AGENT_FILENAME), "utf8");
3187
3356
  config = combineBuddyProject(parseBuddyAgentConfig(configSource));
3188
3357
  } catch (cause) {
3189
3358
  throw new BuddyDevError({
@@ -3193,8 +3362,10 @@ async function startBuddyDev(options) {
3193
3362
  cause
3194
3363
  });
3195
3364
  }
3365
+ await readProjectEnvironment(projectRoot, devAgentId);
3196
3366
  const launchPlan = await launchPlanFor(config, options, projectRoot, signal);
3197
3367
  const registration = await registerDevAgent({
3368
+ projectRoot,
3198
3369
  client: options.registrationClient,
3199
3370
  devAgentId,
3200
3371
  configSource,
@@ -3218,13 +3389,19 @@ async function startBuddyDev(options) {
3218
3389
  buddyToken: registration.agentToken,
3219
3390
  gatewayUrl: registration.appServerUrl
3220
3391
  });
3392
+ await writeProjectEnvironment(projectRoot, {
3393
+ BUDDY_ID: environment.BUDDY_ID,
3394
+ BUDDY_TOKEN: environment.BUDDY_TOKEN,
3395
+ MLB_GATEWAY_URL: environment.MLB_GATEWAY_URL
3396
+ });
3397
+ const { BUDDY_ID: _id, BUDDY_TOKEN: _token, MLB_GATEWAY_URL: _gateway, ...childEnvironment } = environment;
3221
3398
  const launcher = options.processLauncher ?? new NodeAgentProcessLauncher();
3222
3399
  processTree = options.processTree ?? processTreeControllerFor(platform);
3223
3400
  agentProcess = await launcher.spawn({
3224
3401
  command: launchPlan.command,
3225
3402
  args: launchPlan.args,
3226
3403
  cwd: projectRoot,
3227
- env: environment,
3404
+ env: childEnvironment,
3228
3405
  shell: false,
3229
3406
  detached: platform === "darwin",
3230
3407
  ...options.onLog === void 0 ? {} : {
@@ -3495,7 +3672,7 @@ var DEV_COMMAND_HELP = `\u7528\u6CD5:
3495
3672
  \u8BF4\u660E:
3496
3673
  \u672A\u914D\u7F6E\u5730\u5740\u65F6\u8FDE\u63A5 MLB \u6D4B\u8BD5\u73AF\u5883 ${DEFAULT_MLB_TEST_URL}\uFF08HTTP \u4EC5\u9650\u6D4B\u8BD5\uFF09\u3002
3497
3674
  CLI \u7EDF\u4E00\u542F\u52A8\u5E76\u7BA1\u7406\u5DE5\u7A0B\u4E2D\u7684\u5B98\u65B9 Runtime\u3002
3498
- DEV \u4F1A\u901A\u8FC7\u6D4F\u89C8\u5668\u767B\u5F55\u83B7\u53D6\u5F00\u53D1\u8005\u4F1A\u8BDD\uFF0C\u518D\u8BFB\u53D6\u5F53\u524D buddy.agent.json \u4E2D\u7684 buddyId \u5BF9\u5E94\u7684\u5F00\u53D1 Token\uFF0C\u4FDD\u5B58\u5230\u7CFB\u7EDF\u94A5\u5319\u4E32\u4F9B\u540E\u7EED\u590D\u7528\u3002
3675
+ DEV \u4F1A\u901A\u8FC7\u6D4F\u89C8\u5668\u767B\u5F55\u83B7\u53D6\u5F00\u53D1\u8005\u4F1A\u8BDD\uFF0C\u5C06\u5F53\u524D\u642D\u5B50\u7684\u5F00\u53D1 Token \u5199\u5165\u5DE5\u7A0B .env\uFF0C\u540E\u7EED\u4F18\u5148\u590D\u7528\uFF1B\u767B\u5F55\u51ED\u636E\u4ECD\u4F7F\u7528\u7CFB\u7EDF\u51ED\u636E\u5B58\u50A8\u3002
3499
3676
  --refresh-token \u91CD\u65B0\u9886\u53D6\u5DF2\u6709\u5F00\u53D1 Token\uFF0C\u7528\u4E8E\u670D\u52A1\u7AEF\u91CD\u7F6E\u540E\u7684\u672C\u673A\u66F4\u65B0\uFF1B\u4E0D\u4F1A\u751F\u6210\u65B0\u5BC6\u94A5\u3002`;
3500
3677
  function valueAfter(args, index, flag2) {
3501
3678
  const value = args[index + 1];
@@ -3625,7 +3802,7 @@ async function runDevCommand(args, io, options = {}) {
3625
3802
  import { resolve as resolve13 } from "node:path";
3626
3803
 
3627
3804
  // packages/cli-core/src/cloud/auth.ts
3628
- import { randomUUID as randomUUID6 } from "node:crypto";
3805
+ import { randomUUID as randomUUID7 } from "node:crypto";
3629
3806
 
3630
3807
  // packages/cli-core/src/cloud/validation.ts
3631
3808
  function record(value, path = "request") {
@@ -3693,7 +3870,7 @@ var CloudAuthenticator = class {
3693
3870
  this.#adapter = adapter;
3694
3871
  this.#store = store;
3695
3872
  this.#now = options.now ?? Date.now;
3696
- this.#createState = options.createState ?? randomUUID6;
3873
+ this.#createState = options.createState ?? randomUUID7;
3697
3874
  this.#minimumValidityMs = options.minimumValidityMs ?? 3e4;
3698
3875
  if (!Number.isSafeInteger(this.#minimumValidityMs) || this.#minimumValidityMs < 0) {
3699
3876
  throw new TypeError("minimumValidityMs must be a non-negative safe integer");
@@ -3795,17 +3972,17 @@ function positiveTimeout(value, fallback, name) {
3795
3972
  }
3796
3973
  function object3(value, path) {
3797
3974
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
3798
- throw invalid(`${path} \u5FC5\u987B\u662F\u5BF9\u8C61`);
3975
+ throw invalid2(`${path} \u5FC5\u987B\u662F\u5BF9\u8C61`);
3799
3976
  }
3800
3977
  return value;
3801
3978
  }
3802
- function invalid(message) {
3979
+ function invalid2(message) {
3803
3980
  return new CloudLifecycleError("PLATFORM_RESPONSE_INVALID", message);
3804
3981
  }
3805
3982
  function safeText(value, path, allowNewlines = false, allowEmpty = false) {
3806
- if (typeof value !== "string" || !allowEmpty && !value.trim()) throw invalid(`${path} \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`);
3983
+ if (typeof value !== "string" || !allowEmpty && !value.trim()) throw invalid2(`${path} \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`);
3807
3984
  const invalidControl = allowNewlines ? /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/u : /[\u0000-\u001f\u007f]/u;
3808
- if (invalidControl.test(value)) throw invalid(`${path} \u5305\u542B\u975E\u6CD5\u63A7\u5236\u5B57\u7B26`);
3985
+ if (invalidControl.test(value)) throw invalid2(`${path} \u5305\u542B\u975E\u6CD5\u63A7\u5236\u5B57\u7B26`);
3809
3986
  return value;
3810
3987
  }
3811
3988
  function optionalText(value, path, allowNewlines = false) {
@@ -3827,23 +4004,23 @@ function meta(value, path) {
3827
4004
  });
3828
4005
  }
3829
4006
  function flag(value, path) {
3830
- if (typeof value !== "boolean") throw invalid(`${path} \u5FC5\u987B\u662F boolean`);
4007
+ if (typeof value !== "boolean") throw invalid2(`${path} \u5FC5\u987B\u662F boolean`);
3831
4008
  return value;
3832
4009
  }
3833
4010
  function timestamp(value, path) {
3834
- if (!Number.isSafeInteger(value) || value < 0) throw invalid(`${path} \u5FC5\u987B\u662F\u975E\u8D1F\u6BEB\u79D2\u65F6\u95F4\u6233`);
4011
+ if (!Number.isSafeInteger(value) || value < 0) throw invalid2(`${path} \u5FC5\u987B\u662F\u975E\u8D1F\u6BEB\u79D2\u65F6\u95F4\u6233`);
3835
4012
  return value;
3836
4013
  }
3837
4014
  function nullableText(value, path) {
3838
4015
  return value === null ? null : safeText(value, path);
3839
4016
  }
3840
4017
  function nonNegativeInteger(value, path) {
3841
- if (!Number.isSafeInteger(value) || value < 0) throw invalid(`${path} \u5FC5\u987B\u662F\u975E\u8D1F\u6574\u6570`);
4018
+ if (!Number.isSafeInteger(value) || value < 0) throw invalid2(`${path} \u5FC5\u987B\u662F\u975E\u8D1F\u6574\u6570`);
3842
4019
  return value;
3843
4020
  }
3844
4021
  function auditStatus(value, path) {
3845
4022
  if (value !== "auditing" && value !== "approved" && value !== "rejected") {
3846
- throw invalid(`${path} \u5FC5\u987B\u662F auditing\u3001approved \u6216 rejected`);
4023
+ throw invalid2(`${path} \u5FC5\u987B\u662F auditing\u3001approved \u6216 rejected`);
3847
4024
  }
3848
4025
  return value;
3849
4026
  }
@@ -3891,7 +4068,7 @@ async function boundedJson(response) {
3891
4068
  total += item.value.byteLength;
3892
4069
  if (total > MAX_RESPONSE_BYTES) {
3893
4070
  void reader.cancel().catch(() => void 0);
3894
- throw invalid("\u5E73\u53F0\u54CD\u5E94\u8D85\u8FC7 1 MiB");
4071
+ throw invalid2("\u5E73\u53F0\u54CD\u5E94\u8D85\u8FC7 1 MiB");
3895
4072
  }
3896
4073
  chunks.push(item.value);
3897
4074
  }
@@ -3907,7 +4084,7 @@ async function boundedJson(response) {
3907
4084
  try {
3908
4085
  return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
3909
4086
  } catch {
3910
- throw invalid("\u5E73\u53F0\u54CD\u5E94\u4E0D\u662F\u6709\u6548 JSON");
4087
+ throw invalid2("\u5E73\u53F0\u54CD\u5E94\u4E0D\u662F\u6709\u6548 JSON");
3911
4088
  }
3912
4089
  }
3913
4090
  function serverError(response, body) {
@@ -3978,7 +4155,7 @@ var HttpDeveloperPlatformClient = class {
3978
4155
  const mediaType = response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
3979
4156
  if (mediaType !== "application/json") {
3980
4157
  await response.body?.cancel().catch(() => void 0);
3981
- throw invalid(`\u5E73\u53F0\u54CD\u5E94 Content-Type \u65E0\u6548\uFF08HTTP ${response.status}\uFF09`);
4158
+ throw invalid2(`\u5E73\u53F0\u54CD\u5E94 Content-Type \u65E0\u6548\uFF08HTTP ${response.status}\uFF09`);
3982
4159
  }
3983
4160
  const payload = await boundedJson(response);
3984
4161
  if (!response.ok) throw serverError(response, payload);
@@ -4003,7 +4180,7 @@ var HttpDeveloperPlatformClient = class {
4003
4180
  }
4004
4181
  async listBuddies() {
4005
4182
  const source = object3(await this.#request("/cli/buddies", "GET"), "response");
4006
- if (!Array.isArray(source.buddies)) throw invalid("response.buddies \u5FC5\u987B\u662F\u6570\u7EC4");
4183
+ if (!Array.isArray(source.buddies)) throw invalid2("response.buddies \u5FC5\u987B\u662F\u6570\u7EC4");
4007
4184
  return Object.freeze({
4008
4185
  buddies: Object.freeze(source.buddies.map((item) => buddy(item, false)))
4009
4186
  });
@@ -4023,7 +4200,7 @@ var HttpDeveloperPlatformClient = class {
4023
4200
  `/cli/buddies/${encodeURIComponent(request.id)}/packages${suffix}`,
4024
4201
  "GET"
4025
4202
  ), "response");
4026
- if (!Array.isArray(source.items)) throw invalid("response.items \u5FC5\u987B\u662F\u6570\u7EC4");
4203
+ if (!Array.isArray(source.items)) throw invalid2("response.items \u5FC5\u987B\u662F\u6570\u7EC4");
4027
4204
  return Object.freeze({
4028
4205
  total: nonNegativeInteger(source.total, "response.total"),
4029
4206
  page: nonNegativeInteger(source.page, "response.page"),
@@ -4059,7 +4236,7 @@ var HttpDeveloperPlatformClient = class {
4059
4236
  }
4060
4237
  async logout(accessToken) {
4061
4238
  const source = object3(await this.#request("/cli/auth/logout", "POST", { accessToken }), "response");
4062
- if (source.ok !== true) throw invalid("response.ok \u5FC5\u987B\u662F true");
4239
+ if (source.ok !== true) throw invalid2("response.ok \u5FC5\u987B\u662F true");
4063
4240
  }
4064
4241
  };
4065
4242
 
@@ -4634,8 +4811,8 @@ async function runCloudCommand(command, args, io, options = {}) {
4634
4811
  var CLOUD_COMMAND_HELP = HELP;
4635
4812
 
4636
4813
  // packages/cli-core/src/migration/index.ts
4637
- import { lstat as lstat9, open as open4, readdir as readdir4, realpath as realpath3, stat } from "node:fs/promises";
4638
- import { extname, isAbsolute as isAbsolute2, join as join12, relative, resolve as resolve14, sep, win32 as win322 } from "node:path";
4814
+ import { lstat as lstat9, open as open5, readdir as readdir4, realpath as realpath3, stat } from "node:fs/promises";
4815
+ import { extname, isAbsolute as isAbsolute2, join as join13, relative, resolve as resolve14, sep, win32 as win322 } from "node:path";
4639
4816
  var DEFAULT_SKILL_SCAN_LIMITS = Object.freeze({
4640
4817
  maxFiles: 128,
4641
4818
  maxFileBytes: 256 * 1024,
@@ -4804,7 +4981,7 @@ async function existingProjectRoot(value) {
4804
4981
  }
4805
4982
  }
4806
4983
  async function existingSkillRoot(projectRoot, skillPath) {
4807
- const candidate = skillPath === "." ? projectRoot : join12(projectRoot, ...skillPath.split("/"));
4984
+ const candidate = skillPath === "." ? projectRoot : join13(projectRoot, ...skillPath.split("/"));
4808
4985
  try {
4809
4986
  await lstat9(candidate);
4810
4987
  } catch (cause) {
@@ -4841,7 +5018,7 @@ async function existingSkillRoot(projectRoot, skillPath) {
4841
5018
  }
4842
5019
  async function assertEntrypoint(context) {
4843
5020
  const entryPath = reportChild(context.skillPath, "SKILL.md");
4844
- const candidate = join12(context.skillRoot, "SKILL.md");
5021
+ const candidate = join13(context.skillRoot, "SKILL.md");
4845
5022
  try {
4846
5023
  await lstat9(candidate);
4847
5024
  const target = await realpath3(candidate);
@@ -4945,7 +5122,7 @@ async function walkDirectory(actualDirectory, reportDirectory, ancestors, contex
4945
5122
  }
4946
5123
  for (const entry2 of entries) {
4947
5124
  const childReportPath = reportChild(reportDirectory, entry2.name);
4948
- const childPath = join12(directory, entry2.name);
5125
+ const childPath = join13(directory, entry2.name);
4949
5126
  let target;
4950
5127
  try {
4951
5128
  target = await realpath3(childPath);
@@ -4987,7 +5164,7 @@ async function scanFile(actualPath, reportPath, context) {
4987
5164
  }
4988
5165
  let handle;
4989
5166
  try {
4990
- handle = await open4(actualPath, "r");
5167
+ handle = await open5(actualPath, "r");
4991
5168
  } catch (cause) {
4992
5169
  return rejectScan("SKILL_SCAN_IO_ERROR", reportPath, "\u65E0\u6CD5\u6253\u5F00 Skill \u6587\u4EF6\u3002", cause);
4993
5170
  }
@@ -5400,8 +5577,8 @@ async function scanExternalSkillPortability(options) {
5400
5577
 
5401
5578
  // packages/cli-core/src/push/preflight.ts
5402
5579
  import { createHash as createHash8 } from "node:crypto";
5403
- import { lstat as lstat10, open as open5, readdir as readdir5, realpath as realpath4 } from "node:fs/promises";
5404
- import { isAbsolute as isAbsolute3, join as join13, relative as relative2, resolve as resolve15, sep as sep2, win32 as win323 } from "node:path";
5580
+ import { lstat as lstat10, open as open6, readdir as readdir5, realpath as realpath4 } from "node:fs/promises";
5581
+ import { isAbsolute as isAbsolute3, join as join14, relative as relative2, resolve as resolve15, sep as sep2, win32 as win323 } from "node:path";
5405
5582
 
5406
5583
  // packages/cli-core/src/push/errors.ts
5407
5584
  var PushPreflightError = class extends Error {
@@ -5620,7 +5797,7 @@ async function canonicalProjectRoot(projectRoot) {
5620
5797
  }
5621
5798
  }
5622
5799
  async function captureConfigWithinLimit(projectRoot, maxFileBytes, filename) {
5623
- const path = join13(projectRoot, filename);
5800
+ const path = join14(projectRoot, filename);
5624
5801
  let entry2;
5625
5802
  try {
5626
5803
  entry2 = await lstat10(path);
@@ -5730,7 +5907,7 @@ function sameFileIdentity(left, right) {
5730
5907
  return left.dev === right.dev && left.ino === right.ino && left.size === right.size && left.mtimeMs === right.mtimeMs;
5731
5908
  }
5732
5909
  async function hashRegularFile(options) {
5733
- const handle = await open5(options.absolutePath, "r").catch((cause) => error({
5910
+ const handle = await open6(options.absolutePath, "r").catch((cause) => error({
5734
5911
  code: "PUSH_PROJECT_INVALID",
5735
5912
  path: options.portablePath,
5736
5913
  message: `\u65E0\u6CD5\u8BFB\u53D6\u63D0\u4EA4\u6587\u4EF6\uFF1A${options.portablePath}`,
@@ -5823,7 +6000,7 @@ async function createManifest(options) {
5823
6000
  sensitiveEntriesExcluded += 1;
5824
6001
  continue;
5825
6002
  }
5826
- const absolutePath = join13(directory, name);
6003
+ const absolutePath = join14(directory, name);
5827
6004
  let entry2;
5828
6005
  try {
5829
6006
  entry2 = await lstat10(absolutePath);
@@ -6049,11 +6226,12 @@ function assertOfficialProjectIncluded(files) {
6049
6226
  message: `package.json \u7684 dependencies \u5FC5\u987B\u58F0\u660E ${BUDDY_RUNTIME_PACKAGE} \u7684\u51C6\u786E\u7248\u672C\uFF0C\u5E76\u63D0\u4EA4\u76F8\u5E94\u9501\u6587\u4EF6\u3002`
6050
6227
  });
6051
6228
  }
6052
- if (typeof pkg !== "object" || pkg === null || Array.isArray(pkg) || !("scripts" in pkg) || typeof pkg.scripts !== "object" || pkg.scripts === null || !("start" in pkg.scripts) || pkg.scripts.start !== `node ${BUDDY_PLATFORM_START_ENTRY}`) {
6229
+ const expectedStart = `node ${runtimeUsesEnvironmentIdentity(pkg) ? "--env-file-if-exists=.env " : ""}${BUDDY_PLATFORM_START_ENTRY}`;
6230
+ if (typeof pkg !== "object" || pkg === null || Array.isArray(pkg) || !("scripts" in pkg) || typeof pkg.scripts !== "object" || pkg.scripts === null || !("start" in pkg.scripts) || pkg.scripts.start !== expectedStart) {
6053
6231
  error({
6054
6232
  code: "PUSH_PROJECT_INVALID",
6055
6233
  path: BUDDY_PLATFORM_PACKAGE_JSON,
6056
- message: `\u5B98\u65B9 Runtime \u5DE5\u7A0B\u7684 package.json \u5FC5\u987B\u8BBE\u7F6E scripts.start \u4E3A "node ${BUDDY_PLATFORM_START_ENTRY}"\uFF0C\u4F7F\u4E91\u7AEF\u4E0E\u672C\u5730\u4F7F\u7528\u540C\u4E00\u542F\u52A8\u5165\u53E3\u3002`
6234
+ message: `\u5B98\u65B9 Runtime \u5DE5\u7A0B\u7684 package.json \u5FC5\u987B\u8BBE\u7F6E scripts.start \u4E3A "${expectedStart}"\uFF0C\u4F7F\u4E91\u7AEF\u4E0E\u672C\u5730\u4F7F\u7528\u540C\u4E00\u542F\u52A8\u5165\u53E3\u3002`
6057
6235
  });
6058
6236
  }
6059
6237
  }
@@ -6075,7 +6253,7 @@ async function assertCapturedConfigStable(options) {
6075
6253
  }
6076
6254
  let current;
6077
6255
  try {
6078
- const path = join13(options.projectRoot, options.filename);
6256
+ const path = join14(options.projectRoot, options.filename);
6079
6257
  const entry2 = await lstat10(path);
6080
6258
  if (!entry2.isFile() || entry2.isSymbolicLink()) {
6081
6259
  error({
@@ -6206,7 +6384,7 @@ async function createPushPreflight(options) {
6206
6384
  // packages/cli-core/src/push/bundle.ts
6207
6385
  import { createHash as createHash9 } from "node:crypto";
6208
6386
  import { lstat as lstat11, readFile as readFile11, realpath as realpath5 } from "node:fs/promises";
6209
- import { join as join14, relative as relative3, sep as sep3, win32 as win324 } from "node:path";
6387
+ import { join as join15, relative as relative3, sep as sep3, win32 as win324 } from "node:path";
6210
6388
  import { Writable } from "node:stream";
6211
6389
  import { pipeline } from "node:stream/promises";
6212
6390
  import { createGzip } from "node:zlib";
@@ -6228,7 +6406,7 @@ function inside(root, target) {
6228
6406
  return path === "" || path !== ".." && !path.startsWith(`..${sep3}`) && !path.startsWith("/") && !win324.isAbsolute(path);
6229
6407
  }
6230
6408
  async function capture(root, file) {
6231
- const absolute = join14(root, ...file.path.split("/"));
6409
+ const absolute = join15(root, ...file.path.split("/"));
6232
6410
  try {
6233
6411
  const entry2 = await lstat11(absolute);
6234
6412
  if (!entry2.isFile() || entry2.isSymbolicLink() || entry2.size !== file.bytes) {
@@ -6687,7 +6865,7 @@ async function resumeProjectArguments(args, cwd, options) {
6687
6865
  await assertInitializableBuddyTarget(root);
6688
6866
  let entry2;
6689
6867
  try {
6690
- entry2 = await lstat12(join15(root, "buddy.agent.json"));
6868
+ entry2 = await lstat12(join16(root, "buddy.agent.json"));
6691
6869
  } catch (cause) {
6692
6870
  if (cause.code === "ENOENT") {
6693
6871
  const draft = await readMetaDraft(root);
@@ -6942,6 +7120,7 @@ export {
6942
7120
  isSafeProjectRelativePath,
6943
7121
  isWindowsReservedPathSegment,
6944
7122
  latestRuntimeTemplate,
7123
+ migrateRuntimeStartup,
6945
7124
  normalizePlatformUrl,
6946
7125
  openExternalUrl,
6947
7126
  parseBuddyAgentConfig,