aitable-workflow-cli 0.1.28-beta.1789632898670 → 0.1.28
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/assistant/assets/index-B3LvYfRW.js +79 -0
- package/dist/assistant/assets/index-CCEHOkkJ.css +1 -0
- package/dist/assistant/index.html +13 -0
- package/dist/cli.js +557 -69
- package/dist/web/assets/index-DPc2WOdp.css +1 -0
- package/dist/web/assets/index-HTw8K38o.js +332 -0
- package/dist/web/index.html +2 -2
- package/package.json +3 -3
- package/dist/web/assets/index-C4Nj98-I.js +0 -332
- package/dist/web/assets/index-DQWzpxYZ.css +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,99 +1,587 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{a as
|
|
3
|
-
\u26A0 \u53EF\u89C6\u5316\u754C\u9762\u5F02\u5E38\uFF0C\u56DE\u9000\u5230\u547D\u4EE4\u884C\u4EA4\u4E92: ${
|
|
4
|
-
`)}}}if(!
|
|
2
|
+
import{a as st,b as it,m as at}from"./chunk-YDJTCQW4.js";import"./chunk-4B6V7VHM.js";import{b as Q,d as G,e as Se,f as ct,g as ee}from"./chunk-N2ATMPTO.js";import{a as c}from"./chunk-EI7MMDWY.js";import{config as jn}from"dotenv";import{Command as si}from"commander";import{logger as On,activateGlobalDwsOnPath as ii,initSlsReport as ai}from"aitable-workflow-core";import{createRequire as Hn}from"module";var lt="aitable-workflow-",Fn=/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;function dt(){try{return Hn(import.meta.url)("../package.json")}catch{return{}}}c(dt,"loadCliPackageManifest");function Ie(o){return o.version??"0.0.0"}c(Ie,"resolveCliVersion");function pt(o){let e=Ie(o),t={};o.name?.startsWith(lt)&&(t[o.name]=e);for(let[n,r]of Object.entries(o.dependencies??{}))n.startsWith(lt)&&(t[n]=Fn.test(r)?r:e);return t}c(pt,"resolveMonorepoPackageVersions");import Mn from"path";import{fileURLToPath as ci}from"url";var ut="./aitable-workflow.config.yml";import{runInit as Nn,logger as Un}from"aitable-workflow-core";import Wn from"path";function mt(o,e){o.command("init").description("\u4EA4\u4E92\u5F0F\u521D\u59CB\u5316 \u2014 \u9009\u62E9 Coding Agent\u3001\u914D\u7F6E\u5DE5\u4F5C\u76EE\u5F55\u3001\u63CF\u8FF0\u4E1A\u52A1\u573A\u666F\uFF1B\u6216\u7528 --template \u4ECE\u53EF\u7528\u6A21\u677F\u811A\u624B\u67B6").option("-c, --config <path>","\u76EE\u6807\u76EE\u5F55\u6216\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\uFF08\u9ED8\u8BA4\u5F53\u524D\u76EE\u5F55\uFF09").option("-f, --force","\u8986\u76D6\u5DF2\u6709\u914D\u7F6E\u6587\u4EF6").option("-y, --yes","\u4F7F\u7528\u9ED8\u8BA4\u503C\u8DF3\u8FC7\u4EA4\u4E92\u5F0F\u5411\u5BFC").option("-t, --template <name>","\u4ECE\u5F53\u524D\u53D1\u884C\u5305\u63D0\u4F9B\u7684\u6A21\u677F\u811A\u624B\u67B6\uFF0C\u62F7\u8D1D\u5B8C\u6574\u53EF\u8FD0\u884C\u9879\u76EE\u5230\u76EE\u6807\u76EE\u5F55").option("--profile <name>","\u9009\u5B9A\u6A21\u677F\u4E0B\u7684 profile \u4E1A\u52A1\u5305\uFF0C\u8986\u76D6\u5F0F\u53E0\u52A0\u5230\u5B9E\u4F8B").action(async t=>{try{await Nn({config:t.config,force:!!t.force,yes:!!t.yes,template:t.template,profile:t.profile,templatesDir:Wn.resolve(e.cliDir,"..","templates"),templatePackageVersions:e.packageVersions,cliVersion:e.version})}catch(n){n instanceof Error&&n.message.includes("cancelled")&&process.exit(0),Un.error("cli","\u521D\u59CB\u5316\u5931\u8D25",{error:n instanceof Error?n.message:String(n)}),process.exit(1)}})}c(mt,"registerInitCommand");import{runMigrate as Gn,logger as qn}from"aitable-workflow-core";import zn from"path";function ft(o,e){o.command("migrate").description("\u5347\u7EA7\u9879\u76EE\u76EE\u5F55\u5230\u6700\u65B0\u6A21\u677F\u7248\u672C\uFF0C\u81EA\u52A8\u4FDD\u7559\u7528\u6237\u914D\u7F6E\uFF1B\u6216\u7528 --from/--to \u5728\u4E24\u4E2A\u76EE\u5F55\u95F4\u505A\u5408\u5E76\u8FC1\u79FB").option("-c, --config <path>","\u9879\u76EE\u76EE\u5F55\u8DEF\u5F84",e.defaultConfig).option("--from <dir>","\u6E90\u76EE\u5F55\uFF1A\u4EE5\u8BE5\u76EE\u5F55\u4E3A\u8FC1\u79FB\u57FA\u51C6\uFF08\u4E0D\u6309\u540D scaffold \u6A21\u677F\uFF09\uFF0C\u4E0E --template/--profile \u4E92\u65A5").option("--to <dir>","\u76EE\u6807\u9879\u76EE\u76EE\u5F55\uFF08--config \u7684\u540C\u4E49\u53C2\u6570\uFF0C\u4F18\u5148\u751F\u6548\uFF09").option("--dry-run","\u4EC5\u9884\u89C8\u53D8\u66F4\uFF0C\u4E0D\u5B9E\u9645\u5199\u5165").option("--no-backup","\u8DF3\u8FC7\u81EA\u52A8\u5907\u4EFD").option("--force","\u8DF3\u8FC7\u786E\u8BA4\u63D0\u793A").option("--template <name>","\u6307\u5B9A\u76EE\u6807\u6A21\u677F").option("--profile <name>","\u6307\u5B9A\u76EE\u6807 profile").option("--rollback","\u56DE\u6EDA\u5230\u4E0A\u4E00\u6B21\u8FC1\u79FB\u524D\u7684\u72B6\u6001").option("--list","\u5217\u51FA\u6240\u6709\u5907\u4EFD").action(async t=>{try{await Gn({config:t.config,from:t.from,to:t.to,dryRun:t.dryRun,noBackup:t.backup===!1,force:t.force,template:t.template,profile:t.profile,rollback:t.rollback,list:t.list,templatesDir:zn.resolve(e.cliDir,"..","templates"),templatePackageVersions:e.packageVersions,cliVersion:e.version})}catch(n){n instanceof Error&&n.message.includes("cancelled")&&process.exit(0),qn.error("cli","migrate \u5931\u8D25",{error:n instanceof Error?n.message:String(n)}),process.exit(1)}})}c(ft,"registerMigrateCommand");import{runDesignCommand as Jn,logger as Yn}from"aitable-workflow-core";function gt(o,e){o.command("design").description("\u8BA9 Coding Agent \u6839\u636E\u573A\u666F\u63CF\u8FF0\u751F\u6210\u5B8C\u6574\u7684 workflow \u548C recipes").option("-c, --config <path>","\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84",e.defaultConfig).option("-y, --yes","\u8DF3\u8FC7\u4EA4\u4E92\u5F0F\u8865\u5145\uFF0C\u76F4\u63A5\u4F7F\u7528 config \u4E2D\u7684 scene").option("--skip-questions","\u4E0D\u56DE\u7B54 Agent \u7684\u6F84\u6E05\u63D0\u95EE\uFF08Agent \u6309\u5047\u8BBE\u751F\u6210\u5E76\u5217\u51FA\u5F85\u786E\u8BA4\u9879\uFF09").action(async t=>{try{await Jn(t)}catch(n){n instanceof Error&&n.message.includes("cancelled")&&process.exit(0),Yn.error("cli","design \u5931\u8D25",{error:n instanceof Error?n.message:String(n)}),process.exit(1)}})}c(gt,"registerDesignCommand");import{runCheck as Vn,runSetupCommand as Kn,checkMigrateHint as Xn,logger as Zn,reportCliEvent as te,setReportProject as Qn}from"aitable-workflow-core";import vt from"path";function Te(o){return o.skipConfig||o.skipConfigIfValid&&o.configValid===!0}c(Te,"canSkipSetupConfig");function ht(o){return Te(o)?"setup":o.uiEnabled&&o.webAvailable?"web":"cli"}c(ht,"resolveSetupConfigRoute");function wt(o,e){o.command("setup").description("\u6821\u9A8C\u5E76\u8865\u9F50\u9879\u76EE\u914D\u7F6E\uFF0C\u518D\u521D\u59CB\u5316 AI \u8868\u683C\u7ED3\u6784 + \u51C6\u5907\u77E5\u8BC6\u5E93 \u2014 \u4E00\u6B21\u5B8C\u6210 config + \u5EFA\u8868").option("-c, --config <path>","\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84",e.defaultConfig).option("--no-clean","\u4E0D\u6E05\u7406\u7A7A\u767D\u884C").option("--no-kb","\u8DF3\u8FC7\u77E5\u8BC6\u5E93\u51C6\u5907/\u7F16\u8BD1").option("--kb-full","\u5F3A\u5236\u5168\u91CF\u91CD\u7F16\u8BD1\u77E5\u8BC6\u5E93").option("--skip-config","\u8DF3\u8FC7\u524D\u7F6E\u7684\u4EA4\u4E92\u5F0F\u914D\u7F6E\u6821\u9A8C\uFF08CI/\u5DF2\u786E\u8BA4\u914D\u7F6E\u65F6\u4F7F\u7528\uFF09").option("--skip-config-if-valid","\u5148\u6821\u9A8C\u914D\u7F6E\uFF1B\u65E0\u963B\u65AD\u9879\u65F6\u8DF3\u8FC7\u914D\u7F6E\u754C\u9762\u5E76\u76F4\u63A5\u5F00\u59CB\u642D\u5EFA").option("--no-ui","\u5F3A\u5236\u4F7F\u7528\u547D\u4EE4\u884C\u4EA4\u4E92\uFF08\u8DF3\u8FC7\u53EF\u89C6\u5316\u914D\u7F6E\u754C\u9762\uFF09").option("--only <round>","\u53EA\u6267\u884C\u6307\u5B9A\u73AF\u8282\uFF1B\u5F53\u524D\u4EC5\u652F\u6301 automations\uFF08\u6309 profile \u5F00\u5173\u5BF9\u9F50\u81EA\u52A8\u5316\uFF0C\u4E0D\u5EFA\u8868\u3001\u4E0D\u7F16\u77E5\u8BC6\u5E93\uFF09").action(async t=>{t.only!==void 0&&t.only!=="automations"&&(console.error(`\u2717 --only \u4E0D\u652F\u6301\u300C${t.only}\u300D\uFF0C\u5F53\u524D\u552F\u4E00\u5408\u6CD5\u503C\uFF1Aautomations`),process.exit(1));let n=t.only==="automations";Qn(t.config);let r=Date.now();te("setup.start",{skipConfig:t.skipConfig===!0,clean:t.clean,kb:t.kb,kbFull:t.kbFull===!0,ui:t.ui!==!1,...n?{only:"automations"}:{}});try{if(await Xn(vt.dirname(vt.resolve(t.config)),e.version),!t.skipConfig&&!n){let s=t.ui!==!1,i=!1;if(t.skipConfigIfValid){console.log("\u{1F4CB} \u6B65\u9AA4 1/2\uFF1A\u6821\u9A8C\u9879\u76EE\u914D\u7F6E");let a=await Vn({configPath:t.config});if(i=Te({skipConfig:!1,skipConfigIfValid:!0,configValid:a.ok}),i){let l=[];a.summary.warnings>0&&l.push(`${a.summary.warnings} \u9879\u8B66\u544A`),a.summary.suggestions>0&&l.push(`${a.summary.suggestions} \u9879\u5EFA\u8BAE`);let d=l.length>0?`\uFF08${l.join("\uFF0C")}\uFF0C\u5747\u4E0D\u963B\u65AD\uFF09`:"";console.log(`\u2713 \u914D\u7F6E\u65E0\u963B\u65AD\u9879${d}\uFF0C\u8DF3\u8FC7\u914D\u7F6E\u754C\u9762\u5E76\u7EE7\u7EED\u642D\u5EFA\u3002`)}else console.log(`\u2139 \u68C0\u6D4B\u5230 ${a.summary.errors} \u9879\u963B\u65AD\uFF0C\u8FDB\u5165\u914D\u7F6E\u73AF\u8282\u3002`)}if(!i&&s){let{hasWebRoot:a,runConfigUI:l}=await import("./config-ui-server-4SVD42Z3.js");if(ht({skipConfig:!1,skipConfigIfValid:t.skipConfigIfValid===!0,uiEnabled:s,webAvailable:a(),configValid:i})==="web"){console.log("\u{1F4CB} \u6B65\u9AA4 1/2\uFF1A\u53EF\u89C6\u5316\u914D\u7F6E\u754C\u9762");try{await l({configPath:t.config,setupOptions:{clean:t.clean,kb:t.kb,kbFull:t.kbFull}}),te("setup.finish",{success:!0,route:"web",durationMs:Date.now()-r});return}catch(p){console.warn(`
|
|
3
|
+
\u26A0 \u53EF\u89C6\u5316\u754C\u9762\u5F02\u5E38\uFF0C\u56DE\u9000\u5230\u547D\u4EE4\u884C\u4EA4\u4E92: ${p instanceof Error?p.message:String(p)}
|
|
4
|
+
`)}}}if(!i){console.log("\u{1F4CB} \u6B65\u9AA4 1/2\uFF1A\u6821\u9A8C\u5E76\u8865\u9F50\u9879\u76EE\u914D\u7F6E");let{runConfigCommand:a}=await import("./config-command-7ECUJOEU.js");(await a({configPath:t.config,interactive:!0,offerSkipToBuild:!0})).ok||(console.error(`
|
|
5
5
|
\u2717 \u9879\u76EE\u914D\u7F6E\u4ECD\u4E0D\u5B8C\u6574\uFF0C\u5DF2\u4E2D\u6B62 setup\u3002\u8BF7\u8865\u9F50\u5FC5\u586B\u9879\u540E\u91CD\u8BD5\uFF08\u6216\u7528 --skip-config \u8DF3\u8FC7\uFF09\u3002`),process.exit(1))}console.log(`
|
|
6
6
|
\u{1F527} \u6B65\u9AA4 2/2\uFF1A\u521D\u59CB\u5316\u8868\u7ED3\u6784 + \u51C6\u5907\u77E5\u8BC6\u5E93
|
|
7
|
-
`)}await En({config:e.config,clean:e.clean,kb:e.kb,...e.kbFull?{kbFull:!0}:{},...n?{only:"automations"}:{}}),await Z("setup.finish",{success:!0,durationMs:Date.now()-o})}catch(i){Tn.error("cli","setup \u5931\u8D25",{error:i instanceof Error?i.message:String(i)}),await Z("setup.finish",{success:!1,error:(i instanceof Error?i.message:String(i)).slice(0,500),durationMs:Date.now()-o}),process.exit(1)}})}c(ot,"registerSetupCommand");import rt from"path";import{createApp as it,ensureTsxRegistered as Pn,checkMigrateHint as jn,logger as k,runCheck as On}from"aitable-workflow-core";function _n(){let e=[],n=c(()=>{let o=Date.now();for(e.push(o);e.length>0&&o-e[0]>6e4;)e.shift();e.length>=10&&(k.error("cli",`60000ms \u5185\u53D1\u751F ${e.length} \u6B21\u672A\u6355\u83B7\u5F02\u5E38\uFF0C\u7591\u4F3C\u975E\u5076\u53D1\u9519\u8BEF\uFF0C\u4E3B\u52A8\u9000\u51FA`),process.exit(1))},"recordCrashAndMaybeExit");process.on("uncaughtException",o=>{k.error("cli","\u6355\u83B7\u5230\u672A\u5904\u7406\u5F02\u5E38\uFF08\u5DF2\u5B58\u6D3B\uFF0C\u4EA4\u7531\u91CD\u8FDE/\u91CD\u8BD5\u903B\u8F91\u81EA\u6108\uFF09",{error:o instanceof Error?o.message:String(o),stack:o instanceof Error?o.stack:void 0}),n()}),process.on("unhandledRejection",o=>{k.error("cli","\u6355\u83B7\u5230\u672A\u5904\u7406 Promise \u62D2\u7EDD\uFF08\u5DF2\u5B58\u6D3B\uFF09",{error:o instanceof Error?o.message:String(o),stack:o instanceof Error?o.stack:void 0}),n()})}c(_n,"installLongRunningCrashGuards");function st(r,t){r.command("start").description("\u542F\u52A8\u7EDF\u4E00\u63A7\u5236\u53F0\uFF1A\u914D\u7F6E\u68C0\u6D4B + \u642D\u5EFA + \u8FD0\u884C\u4E00\u4F53\u5316").option("-c, --config <path>","\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84",t.defaultConfig).option("-p, --port <number>","\u63A7\u5236\u53F0\u7AEF\u53E3\u9996\u9009\u503C\uFF08\u7F3A\u7701 8788\uFF0C\u4E0D\u53EF\u7528\u65F6\u5411\u4E0A\u907F\u8BA9 13 \u4E2A\u7AEF\u53E3\uFF1B\u591A\u9879\u76EE\u5E76\u884C\u65F6\u5EFA\u8BAE\u663E\u5F0F\u6307\u5B9A\uFF09").option("--no-open","\u542F\u52A8\u540E\u4E0D\u8981\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668").option("--skip-config-if-valid","\u914D\u7F6E\u5DF2\u5B8C\u6574\u65F6\u76F4\u63A5\u542F\u52A8\u8FD0\u884C").action(async e=>{let n;if(e.port!==void 0){let o=Number.parseInt(e.port,10);(!Number.isFinite(o)||o<=0||o>65535)&&(k.error("cli",`--port \u53D6\u503C\u975E\u6CD5: "${e.port}"\uFF08\u9700\u4E3A 1-65535 \u6574\u6570\uFF09`),process.exit(1)),n=o}try{await jn(rt.dirname(rt.resolve(e.config)),t.version),_n(),await Pn();let o=await On({configPath:e.config}),i=!o.ok||o.summary.errors>0,s,a="setup";if(!i)try{a="runtime",s=await it(e.config,{})}catch(m){k.warn("cli","\u914D\u7F6E\u6821\u9A8C\u901A\u8FC7\u4F46\u88C5\u914D\u5931\u8D25\uFF0C\u56DE\u9000\u5230\u642D\u5EFA\u6A21\u5F0F",{error:m instanceof Error?m.message:String(m)}),a="setup",s=void 0}a==="runtime"&&s?e.skipConfigIfValid?(k.info("cli","\u914D\u7F6E\u5DF2\u5B8C\u6574\uFF0C\u76F4\u63A5\u542F\u52A8\u8FD0\u884C"),s.start().catch(m=>{k.error("cli","\u8FD0\u884C\u542F\u52A8\u5931\u8D25\uFF0C\u53EF\u5728\u63A7\u5236\u53F0\u91CD\u8BD5\u542F\u52A8",{error:m instanceof Error?m.message:String(m)})})):k.info("cli","\u914D\u7F6E\u5DF2\u5B8C\u6574\uFF0C\u8BF7\u5728\u63A7\u5236\u53F0\u70B9\u51FB\u300C\u5F00\u59CB\u8FD0\u884C\u300D\u542F\u52A8\u670D\u52A1"):k.info("cli","\u914D\u7F6E\u4E0D\u5B8C\u6574\uFF0C\u63A7\u5236\u53F0\u5C06\u5F15\u5BFC\u5B8C\u6210\u642D\u5EFA");let l=!1,p=c(async()=>{l&&(k.warn("cli","\u518D\u6B21\u6536\u5230\u9000\u51FA\u4FE1\u53F7\uFF0C\u5F3A\u5236\u9000\u51FA"),process.exit(1)),l=!0,k.info("cli","\u6536\u5230\u9000\u51FA\u4FE1\u53F7\uFF0C\u6B63\u5728\u505C\u6B62\u8FD0\u884C...");try{await s?.stop()}finally{process.exit(0)}},"shutdown");process.on("SIGINT",p),process.on("SIGTERM",p),await Ve({configPath:e.config,mode:a,app:s,port:n,open:e.open,exitOnSetupError:!1,...a==="runtime"&&e.skipConfigIfValid?{initialRunStatus:{status:"running",since:new Date().toISOString(),lastError:null}}:{},...a==="setup"?{assembleApp:c(m=>it(m,{}),"assembleApp"),onAppAssembled:c(m=>{s=m,k.info("cli","\u63A7\u5236\u53F0\u5DF2\u5B8C\u6210 setup\u2192runtime \u664B\u5347\uFF0C\u53EF\u5728\u63A7\u5236\u53F0\u542F\u52A8\u8FD0\u884C")},"onAppAssembled")}:{}})}catch(o){k.error("cli","start \u547D\u4EE4\u5931\u8D25",{error:o instanceof Error?o.message:String(o)}),process.exit(1)}})}c(st,"registerStartCommand");import{createApp as Dn,ensureTsxRegistered as Ln,checkMigrateHint as Mn,logger as O,reportCliEvent as ee,setReportProject as Bn}from"aitable-workflow-core";import at from"path";function Fn(){let e=[],n=c(async()=>{let o=Date.now();for(e.push(o);e.length>0&&o-e[0]>6e4;)e.shift();e.length>=10&&(O.error("cli",`60000ms \u5185\u53D1\u751F ${e.length} \u6B21\u672A\u6355\u83B7\u5F02\u5E38\uFF0C\u7591\u4F3C\u975E\u5076\u53D1\u9519\u8BEF\uFF0C\u4E3B\u52A8\u9000\u51FA`),await ee("run.exit",{reason:"crash-loop",crashes:e.length}),process.exit(1))},"recordCrashAndMaybeExit");process.on("uncaughtException",o=>{O.error("cli","\u6355\u83B7\u5230\u672A\u5904\u7406\u5F02\u5E38\uFF08\u5DF2\u5B58\u6D3B\uFF0C\u4EA4\u7531\u91CD\u8FDE/\u91CD\u8BD5\u903B\u8F91\u81EA\u6108\uFF09",{error:o instanceof Error?o.message:String(o),stack:o instanceof Error?o.stack:void 0}),n()}),process.on("unhandledRejection",o=>{O.error("cli","\u6355\u83B7\u5230\u672A\u5904\u7406 Promise \u62D2\u7EDD\uFF08\u5DF2\u5B58\u6D3B\uFF09",{error:o instanceof Error?o.message:String(o),stack:o instanceof Error?o.stack:void 0}),n()})}c(Fn,"installLongRunningCrashGuards");function ct(r,t){r.command("run").description("\u542F\u52A8\u7F16\u6392\u5F15\u64CE\uFF0C\u5F00\u59CB\u8F6E\u8BE2\u5904\u7406\u5DE5\u5355").option("-c, --config <path>","\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84",t.defaultConfig).option("--emit-events <channel>","\u8FD0\u884C\u4E8B\u4EF6\u4E0A\u629B\u901A\u9053\uFF1Aipc = \u7ECF process.send \u53D1\u7ED9\u7236\u8FDB\u7A0B\uFF08daemon runner \u7528\uFF09\uFF0C\u7F3A\u7701\u4E0D\u4E0A\u629B").option("-p, --port <number>","\uFF08\u4EC5\u517C\u5BB9 launcher \u900F\u4F20\uFF0Crun \u547D\u4EE4\u4E0D\u4F7F\u7528\u6B64\u53C2\u6570\uFF09").action(async e=>{Bn(e.config);try{await Mn(at.dirname(at.resolve(e.config)),t.version),Fn(),await Ln();let n=e.emitEvents==="ipc"&&typeof process.send=="function",o=await Dn(e.config,n?{onRunEvent:c(a=>{process.send?.({type:"run-event",event:a})},"onRunEvent")}:{});ee("run.start",{emitEvents:e.emitEvents??null});let i=!1,s=c(async()=>{i&&(O.warn("cli","\u518D\u6B21\u6536\u5230\u9000\u51FA\u4FE1\u53F7\uFF0C\u5F3A\u5236\u9000\u51FA"),process.exit(1)),i=!0,O.info("cli","\u6536\u5230\u9000\u51FA\u4FE1\u53F7\uFF0C\u6B63\u5728\u7B49\u5F85\u8FDB\u884C\u4E2D\u7684\u4EFB\u52A1\u5B8C\u6210...");try{await o.stop()}finally{await ee("run.exit",{reason:"signal"}),process.exit(0)}},"shutdown");process.on("SIGINT",s),process.on("SIGTERM",s),await o.start()}catch(n){O.error("cli","\u542F\u52A8\u5931\u8D25",{error:n instanceof Error?n.message:String(n)}),await ee("run.exit",{reason:"start-failure",error:(n instanceof Error?n.message:String(n)).slice(0,500)}),process.exit(1)}})}c(ct,"registerRunCommand");import{readFile as Un}from"fs/promises";import dt from"path";import{createApp as Wn,ensureTsxRegistered as Nn,logger as Ce,resolveConfigPath as Gn}from"aitable-workflow-core";function Hn(r,t){let e=`\u5DE5\u4F5C\u6D41 ${r} / \u4E8B\u4EF6\u6E90 ${t.sourceName}\uFF08handler: ${t.handlerRecipe}\uFF09`;return t.actions===0?`${e}\uFF1A\u5DF2\u89E6\u53D1\u4F46\u6CA1\u6709\u4EA7\u51FA\u52A8\u4F5C\uFF08\u8017\u65F6 ${t.durationMs}ms\uFF09\u3002\u8BF7\u68C0\u67E5\u6570\u636E\u6E90\u662F\u5426\u6709\u53EF\u7528\u884C\u3002`:`${e}\uFF1A\u4EA7\u51FA ${t.actions} \u4E2A\u52A8\u4F5C\uFF08\u843D\u5E93 ${t.applied}\uFF0C\u77AC\u6001 ${t.transient}\uFF09\uFF0C\u8017\u65F6 ${t.durationMs}ms\u3002`}c(Hn,"formatTriggerOnceResult");function lt(r){return new Promise(t=>{r.write("",()=>t())})}c(lt,"flushStream");function pt(){return Promise.all([lt(process.stdout),lt(process.stderr)])}c(pt,"flushOutputs");function mt(r){let t;try{t=JSON.parse(r)}catch(n){throw new Error(`\u81EA\u5B9A\u4E49\u4E8B\u4EF6 JSON \u89E3\u6790\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`)}if(!t||typeof t!="object"||Array.isArray(t))throw new Error("\u81EA\u5B9A\u4E49\u4E8B\u4EF6\u5FC5\u987B\u662F JSON \u5BF9\u8C61");let e=t;if(typeof e.type!="string"||e.type.trim().length===0)throw new Error("\u81EA\u5B9A\u4E49\u4E8B\u4EF6 type \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(!e.payload||typeof e.payload!="object"||Array.isArray(e.payload))throw new Error("\u81EA\u5B9A\u4E49\u4E8B\u4EF6 payload \u5FC5\u987B\u662F\u5BF9\u8C61");if(e.timestamp!==void 0&&(typeof e.timestamp!="string"||e.timestamp.trim().length===0))throw new Error("\u81EA\u5B9A\u4E49\u4E8B\u4EF6 timestamp \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(e.itemId!==void 0&&e.itemId!==null&&typeof e.itemId!="string")throw new Error("\u81EA\u5B9A\u4E49\u4E8B\u4EF6 itemId \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6216 null");return{type:e.type,payload:e.payload,...typeof e.timestamp=="string"?{timestamp:e.timestamp}:{},...e.itemId!==void 0?{itemId:e.itemId}:{}}}c(mt,"parseTriggerEventJson");async function Jn(){let r=[];for await(let t of process.stdin)r.push(Buffer.isBuffer(t)?t:Buffer.from(String(t)));return Buffer.concat(r).toString("utf8")}c(Jn,"readStdin");async function Vn(r,t=process.cwd()){if(r.eventJson&&r.eventStdin)throw new Error("--event-json \u4E0E --event-stdin \u53EA\u80FD\u4E8C\u9009\u4E00");if(r.eventJson){let e=dt.resolve(t,r.eventJson);return mt(await Un(e,"utf8"))}if(r.eventStdin)return mt(await Jn())}c(Vn,"loadTriggerEvent");function ut(r,t){r.command("trigger-once").description("\u5355\u6B21\u89E6\u53D1\u67D0\u4E2A\u5DE5\u4F5C\u6D41\u7684\u4E8B\u4EF6\u6E90 handler \u8DD1\u4E00\u904D\uFF08\u53EA\u8DD1\u4E8B\u4EF6\u6E90 handler\uFF0C\u4E0D\u542F\u52A8\u5E38\u9A7B\u5F15\u64CE\uFF1B\u6B65\u9AA4\u94FE\u7531\u8FD0\u884C\u4E2D\u7684\u5F15\u64CE\u63A8\u8FDB\uFF09").requiredOption("-w, --workflow <id>","\u5DE5\u4F5C\u6D41 ID\uFF08\u591A\u5DE5\u4F5C\u6D41\u9879\u76EE\u91CC\u7684\u76EE\u5F55\u540D\uFF09").option("-c, --config <path>","\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84",t.defaultConfig).option("-s, --source <name>","\u53EA\u89E6\u53D1\u6307\u5B9A\u4E8B\u4EF6\u6E90\uFF1B\u7F3A\u7701\u7528\u8BE5\u5DE5\u4F5C\u6D41\u7684\u7B2C\u4E00\u4E2A\u4E8B\u4EF6\u6E90").option("--event-json <path>","\u4ECE JSON \u6587\u4EF6\u8BFB\u53D6\u81EA\u5B9A\u4E49 ExternalEvent\uFF08\u53EA\u89E6\u53D1 handler\uFF0C\u4E0D\u6A21\u62DF\u5B8C\u6574\u6B65\u9AA4\u94FE\uFF09").option("--event-stdin","\u4ECE stdin \u8BFB\u53D6\u81EA\u5B9A\u4E49 ExternalEvent JSON").option("--json","\u4EE5 JSON \u8F93\u51FA\u7ED3\u679C\uFF08\u4F9B\u811A\u672C\u6D88\u8D39\uFF09").action(async e=>{e.json&&Ce.setSink((n,o)=>process.stderr.write(`${o}
|
|
8
|
-
`));try{await
|
|
9
|
-
`):
|
|
10
|
-
`):
|
|
11
|
-
`));let
|
|
12
|
-
\u6B65\u9AA4\u94FE:`);for(let[l,
|
|
13
|
-
\u914D\u7F6E\u6458\u8981:`),console.log(` AI \u8868\u683C: base=${
|
|
14
|
-
\u5DE5\u4F5C\u6D41: ${
|
|
15
|
-
`+"\u2500".repeat(56));let
|
|
7
|
+
`)}await Kn({config:t.config,clean:t.clean,kb:t.kb,...t.kbFull?{kbFull:!0}:{},...n?{only:"automations"}:{}}),await te("setup.finish",{success:!0,durationMs:Date.now()-r})}catch(s){Zn.error("cli","setup \u5931\u8D25",{error:s instanceof Error?s.message:String(s)}),await te("setup.finish",{success:!1,error:(s instanceof Error?s.message:String(s)).slice(0,500),durationMs:Date.now()-r}),process.exit(1)}})}c(wt,"registerSetupCommand");import yt from"path";import{createApp as kt,ensureTsxRegistered as er,checkMigrateHint as tr,logger as C,runCheck as nr}from"aitable-workflow-core";function rr(){let t=[],n=c(()=>{let r=Date.now();for(t.push(r);t.length>0&&r-t[0]>6e4;)t.shift();t.length>=10&&(C.error("cli",`60000ms \u5185\u53D1\u751F ${t.length} \u6B21\u672A\u6355\u83B7\u5F02\u5E38\uFF0C\u7591\u4F3C\u975E\u5076\u53D1\u9519\u8BEF\uFF0C\u4E3B\u52A8\u9000\u51FA`),process.exit(1))},"recordCrashAndMaybeExit");process.on("uncaughtException",r=>{C.error("cli","\u6355\u83B7\u5230\u672A\u5904\u7406\u5F02\u5E38\uFF08\u5DF2\u5B58\u6D3B\uFF0C\u4EA4\u7531\u91CD\u8FDE/\u91CD\u8BD5\u903B\u8F91\u81EA\u6108\uFF09",{error:r instanceof Error?r.message:String(r),stack:r instanceof Error?r.stack:void 0}),n()}),process.on("unhandledRejection",r=>{C.error("cli","\u6355\u83B7\u5230\u672A\u5904\u7406 Promise \u62D2\u7EDD\uFF08\u5DF2\u5B58\u6D3B\uFF09",{error:r instanceof Error?r.message:String(r),stack:r instanceof Error?r.stack:void 0}),n()})}c(rr,"installLongRunningCrashGuards");function bt(o,e){o.command("start").description("\u542F\u52A8\u7EDF\u4E00\u63A7\u5236\u53F0\uFF1A\u914D\u7F6E\u68C0\u6D4B + \u642D\u5EFA + \u8FD0\u884C\u4E00\u4F53\u5316").option("-c, --config <path>","\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84",e.defaultConfig).option("-p, --port <number>","\u63A7\u5236\u53F0\u7AEF\u53E3\u9996\u9009\u503C\uFF08\u7F3A\u7701 8788\uFF0C\u4E0D\u53EF\u7528\u65F6\u5411\u4E0A\u907F\u8BA9 13 \u4E2A\u7AEF\u53E3\uFF1B\u591A\u9879\u76EE\u5E76\u884C\u65F6\u5EFA\u8BAE\u663E\u5F0F\u6307\u5B9A\uFF09").option("--no-open","\u542F\u52A8\u540E\u4E0D\u8981\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668").option("--skip-config-if-valid","\u914D\u7F6E\u5DF2\u5B8C\u6574\u65F6\u76F4\u63A5\u542F\u52A8\u8FD0\u884C").action(async t=>{let n;if(t.port!==void 0){let r=Number.parseInt(t.port,10);(!Number.isFinite(r)||r<=0||r>65535)&&(C.error("cli",`--port \u53D6\u503C\u975E\u6CD5: "${t.port}"\uFF08\u9700\u4E3A 1-65535 \u6574\u6570\uFF09`),process.exit(1)),n=r}try{await tr(yt.dirname(yt.resolve(t.config)),e.version),rr(),await er();let r=await nr({configPath:t.config}),s=!r.ok||r.summary.errors>0,i,a="setup";if(!s)try{a="runtime",i=await kt(t.config,{})}catch(p){C.warn("cli","\u914D\u7F6E\u6821\u9A8C\u901A\u8FC7\u4F46\u88C5\u914D\u5931\u8D25\uFF0C\u56DE\u9000\u5230\u642D\u5EFA\u6A21\u5F0F",{error:p instanceof Error?p.message:String(p)}),a="setup",i=void 0}a==="runtime"&&i?t.skipConfigIfValid?(C.info("cli","\u914D\u7F6E\u5DF2\u5B8C\u6574\uFF0C\u76F4\u63A5\u542F\u52A8\u8FD0\u884C"),i.start().catch(p=>{C.error("cli","\u8FD0\u884C\u542F\u52A8\u5931\u8D25\uFF0C\u53EF\u5728\u63A7\u5236\u53F0\u91CD\u8BD5\u542F\u52A8",{error:p instanceof Error?p.message:String(p)})})):C.info("cli","\u914D\u7F6E\u5DF2\u5B8C\u6574\uFF0C\u8BF7\u5728\u63A7\u5236\u53F0\u70B9\u51FB\u300C\u5F00\u59CB\u8FD0\u884C\u300D\u542F\u52A8\u670D\u52A1"):C.info("cli","\u914D\u7F6E\u4E0D\u5B8C\u6574\uFF0C\u63A7\u5236\u53F0\u5C06\u5F15\u5BFC\u5B8C\u6210\u642D\u5EFA");let l=!1,d=c(async()=>{l&&(C.warn("cli","\u518D\u6B21\u6536\u5230\u9000\u51FA\u4FE1\u53F7\uFF0C\u5F3A\u5236\u9000\u51FA"),process.exit(1)),l=!0,C.info("cli","\u6536\u5230\u9000\u51FA\u4FE1\u53F7\uFF0C\u6B63\u5728\u505C\u6B62\u8FD0\u884C...");try{await i?.stop()}finally{process.exit(0)}},"shutdown");process.on("SIGINT",d),process.on("SIGTERM",d),await at({configPath:t.config,mode:a,app:i,port:n,open:t.open,exitOnSetupError:!1,...a==="runtime"&&t.skipConfigIfValid?{initialRunStatus:{status:"running",since:new Date().toISOString(),lastError:null}}:{},...a==="setup"?{assembleApp:c(p=>kt(p,{}),"assembleApp"),onAppAssembled:c(p=>{i=p,C.info("cli","\u63A7\u5236\u53F0\u5DF2\u5B8C\u6210 setup\u2192runtime \u664B\u5347\uFF0C\u53EF\u5728\u63A7\u5236\u53F0\u542F\u52A8\u8FD0\u884C")},"onAppAssembled")}:{}})}catch(r){C.error("cli","start \u547D\u4EE4\u5931\u8D25",{error:r instanceof Error?r.message:String(r)}),process.exit(1)}})}c(bt,"registerStartCommand");import{createApp as or,ensureTsxRegistered as sr,checkMigrateHint as ir,logger as F,reportCliEvent as ne,setReportProject as ar}from"aitable-workflow-core";import Rt from"path";function cr(){let t=[],n=c(async()=>{let r=Date.now();for(t.push(r);t.length>0&&r-t[0]>6e4;)t.shift();t.length>=10&&(F.error("cli",`60000ms \u5185\u53D1\u751F ${t.length} \u6B21\u672A\u6355\u83B7\u5F02\u5E38\uFF0C\u7591\u4F3C\u975E\u5076\u53D1\u9519\u8BEF\uFF0C\u4E3B\u52A8\u9000\u51FA`),await ne("run.exit",{reason:"crash-loop",crashes:t.length}),process.exit(1))},"recordCrashAndMaybeExit");process.on("uncaughtException",r=>{F.error("cli","\u6355\u83B7\u5230\u672A\u5904\u7406\u5F02\u5E38\uFF08\u5DF2\u5B58\u6D3B\uFF0C\u4EA4\u7531\u91CD\u8FDE/\u91CD\u8BD5\u903B\u8F91\u81EA\u6108\uFF09",{error:r instanceof Error?r.message:String(r),stack:r instanceof Error?r.stack:void 0}),n()}),process.on("unhandledRejection",r=>{F.error("cli","\u6355\u83B7\u5230\u672A\u5904\u7406 Promise \u62D2\u7EDD\uFF08\u5DF2\u5B58\u6D3B\uFF09",{error:r instanceof Error?r.message:String(r),stack:r instanceof Error?r.stack:void 0}),n()})}c(cr,"installLongRunningCrashGuards");function Ct(o,e){o.command("run").description("\u542F\u52A8\u7F16\u6392\u5F15\u64CE\uFF0C\u5F00\u59CB\u8F6E\u8BE2\u5904\u7406\u5DE5\u5355").option("-c, --config <path>","\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84",e.defaultConfig).option("--emit-events <channel>","\u8FD0\u884C\u4E8B\u4EF6\u4E0A\u629B\u901A\u9053\uFF1Aipc = \u7ECF process.send \u53D1\u7ED9\u7236\u8FDB\u7A0B\uFF08daemon runner \u7528\uFF09\uFF0C\u7F3A\u7701\u4E0D\u4E0A\u629B").option("-p, --port <number>","\uFF08\u4EC5\u517C\u5BB9 launcher \u900F\u4F20\uFF0Crun \u547D\u4EE4\u4E0D\u4F7F\u7528\u6B64\u53C2\u6570\uFF09").action(async t=>{ar(t.config);try{await ir(Rt.dirname(Rt.resolve(t.config)),e.version),cr(),await sr();let n=t.emitEvents==="ipc"&&typeof process.send=="function",r=await or(t.config,n?{onRunEvent:c(a=>{process.send?.({type:"run-event",event:a})},"onRunEvent")}:{});ne("run.start",{emitEvents:t.emitEvents??null});let s=!1,i=c(async()=>{s&&(F.warn("cli","\u518D\u6B21\u6536\u5230\u9000\u51FA\u4FE1\u53F7\uFF0C\u5F3A\u5236\u9000\u51FA"),process.exit(1)),s=!0,F.info("cli","\u6536\u5230\u9000\u51FA\u4FE1\u53F7\uFF0C\u6B63\u5728\u7B49\u5F85\u8FDB\u884C\u4E2D\u7684\u4EFB\u52A1\u5B8C\u6210...");try{await r.stop()}finally{await ne("run.exit",{reason:"signal"}),process.exit(0)}},"shutdown");process.on("SIGINT",i),process.on("SIGTERM",i),await r.start()}catch(n){F.error("cli","\u542F\u52A8\u5931\u8D25",{error:n instanceof Error?n.message:String(n)}),await ne("run.exit",{reason:"start-failure",error:(n instanceof Error?n.message:String(n)).slice(0,500)}),process.exit(1)}})}c(Ct,"registerRunCommand");import{readFile as lr}from"fs/promises";import St from"path";import{createApp as dr,ensureTsxRegistered as pr,logger as _e,resolveConfigPath as ur}from"aitable-workflow-core";function mr(o,e){let t=`\u5DE5\u4F5C\u6D41 ${o} / \u4E8B\u4EF6\u6E90 ${e.sourceName}\uFF08handler: ${e.handlerRecipe}\uFF09`;return e.actions===0?`${t}\uFF1A\u5DF2\u89E6\u53D1\u4F46\u6CA1\u6709\u4EA7\u51FA\u52A8\u4F5C\uFF08\u8017\u65F6 ${e.durationMs}ms\uFF09\u3002\u8BF7\u68C0\u67E5\u6570\u636E\u6E90\u662F\u5426\u6709\u53EF\u7528\u884C\u3002`:`${t}\uFF1A\u4EA7\u51FA ${e.actions} \u4E2A\u52A8\u4F5C\uFF08\u843D\u5E93 ${e.applied}\uFF0C\u77AC\u6001 ${e.transient}\uFF09\uFF0C\u8017\u65F6 ${e.durationMs}ms\u3002`}c(mr,"formatTriggerOnceResult");function xt(o){return new Promise(e=>{o.write("",()=>e())})}c(xt,"flushStream");function At(){return Promise.all([xt(process.stdout),xt(process.stderr)])}c(At,"flushOutputs");function Et(o){let e;try{e=JSON.parse(o)}catch(n){throw new Error(`\u81EA\u5B9A\u4E49\u4E8B\u4EF6 JSON \u89E3\u6790\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`)}if(!e||typeof e!="object"||Array.isArray(e))throw new Error("\u81EA\u5B9A\u4E49\u4E8B\u4EF6\u5FC5\u987B\u662F JSON \u5BF9\u8C61");let t=e;if(typeof t.type!="string"||t.type.trim().length===0)throw new Error("\u81EA\u5B9A\u4E49\u4E8B\u4EF6 type \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(!t.payload||typeof t.payload!="object"||Array.isArray(t.payload))throw new Error("\u81EA\u5B9A\u4E49\u4E8B\u4EF6 payload \u5FC5\u987B\u662F\u5BF9\u8C61");if(t.timestamp!==void 0&&(typeof t.timestamp!="string"||t.timestamp.trim().length===0))throw new Error("\u81EA\u5B9A\u4E49\u4E8B\u4EF6 timestamp \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(t.itemId!==void 0&&t.itemId!==null&&typeof t.itemId!="string")throw new Error("\u81EA\u5B9A\u4E49\u4E8B\u4EF6 itemId \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6216 null");return{type:t.type,payload:t.payload,...typeof t.timestamp=="string"?{timestamp:t.timestamp}:{},...t.itemId!==void 0?{itemId:t.itemId}:{}}}c(Et,"parseTriggerEventJson");async function fr(){let o=[];for await(let e of process.stdin)o.push(Buffer.isBuffer(e)?e:Buffer.from(String(e)));return Buffer.concat(o).toString("utf8")}c(fr,"readStdin");async function gr(o,e=process.cwd()){if(o.eventJson&&o.eventStdin)throw new Error("--event-json \u4E0E --event-stdin \u53EA\u80FD\u4E8C\u9009\u4E00");if(o.eventJson){let t=St.resolve(e,o.eventJson);return Et(await lr(t,"utf8"))}if(o.eventStdin)return Et(await fr())}c(gr,"loadTriggerEvent");function It(o,e){o.command("trigger-once").description("\u5355\u6B21\u89E6\u53D1\u67D0\u4E2A\u5DE5\u4F5C\u6D41\u7684\u4E8B\u4EF6\u6E90 handler \u8DD1\u4E00\u904D\uFF08\u53EA\u8DD1\u4E8B\u4EF6\u6E90 handler\uFF0C\u4E0D\u542F\u52A8\u5E38\u9A7B\u5F15\u64CE\uFF1B\u6B65\u9AA4\u94FE\u7531\u8FD0\u884C\u4E2D\u7684\u5F15\u64CE\u63A8\u8FDB\uFF09").requiredOption("-w, --workflow <id>","\u5DE5\u4F5C\u6D41 ID\uFF08\u591A\u5DE5\u4F5C\u6D41\u9879\u76EE\u91CC\u7684\u76EE\u5F55\u540D\uFF09").option("-c, --config <path>","\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84",e.defaultConfig).option("-s, --source <name>","\u53EA\u89E6\u53D1\u6307\u5B9A\u4E8B\u4EF6\u6E90\uFF1B\u7F3A\u7701\u7528\u8BE5\u5DE5\u4F5C\u6D41\u7684\u7B2C\u4E00\u4E2A\u4E8B\u4EF6\u6E90").option("--event-json <path>","\u4ECE JSON \u6587\u4EF6\u8BFB\u53D6\u81EA\u5B9A\u4E49 ExternalEvent\uFF08\u53EA\u89E6\u53D1 handler\uFF0C\u4E0D\u6A21\u62DF\u5B8C\u6574\u6B65\u9AA4\u94FE\uFF09").option("--event-stdin","\u4ECE stdin \u8BFB\u53D6\u81EA\u5B9A\u4E49 ExternalEvent JSON").option("--json","\u4EE5 JSON \u8F93\u51FA\u7ED3\u679C\uFF08\u4F9B\u811A\u672C\u6D88\u8D39\uFF09").action(async t=>{t.json&&_e.setSink((n,r)=>process.stderr.write(`${r}
|
|
8
|
+
`));try{await pr();let n=await ur(t.config),r=await gr(t,St.dirname(n)),s=await dr(t.config),i={...t.source?{sourceName:t.source}:{},...r?{event:r}:{}},a=await s.triggerWorkflowOnce(t.workflow,i);t.json?process.stdout.write(`${JSON.stringify({ok:!0,workflowId:t.workflow,...a})}
|
|
9
|
+
`):_e.info("cli",mr(t.workflow,a)),await At(),process.exit(0)}catch(n){let r=n instanceof Error?n.message:String(n);t.json?process.stdout.write(`${JSON.stringify({ok:!1,error:r})}
|
|
10
|
+
`):_e.error("cli","\u89E6\u53D1\u5931\u8D25",{error:r}),await At(),process.exit(1)}})}c(It,"registerTriggerCommand");import{readFile as Tt}from"fs/promises";import oe from"path";import _t from"yaml";import{logger as hr,loadSettings as Pt,loadWorkflowTemplate as vr,resolveConfigPath as wr,scanWorkflowDirs as yr,buildEnvSource as kr,loadProfileConfig as br,resetProfileCache as Rr,runWorkflowGates as Cr}from"aitable-workflow-core";function $t(o,e){o.command("validate").description("\u9A8C\u8BC1\u914D\u7F6E\u6587\u4EF6\u548C\u5DE5\u4F5C\u6D41\u95E8\u7981\uFF08\u7ED3\u6784 / recipe \u7ED1\u5B9A / \u7C7B\u578B / \u914D\u7F6E\u5951\u7EA6 / \u53C2\u6570\u6D41\u8F6C\uFF09").option("-c, --config <path>","\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84",e.defaultConfig).option("--workflow <id>","\u53EA\u6821\u9A8C\u6307\u5B9A\u5DE5\u4F5C\u6D41\uFF08\u591A\u5DE5\u4F5C\u6D41\u6A21\u5F0F\uFF09").option("--strict","warning \u7EA7\u95EE\u9898\u5347\u7EA7\u4E3A error").option("--no-typecheck","\u8DF3\u8FC7 recipe TS \u7C7B\u578B\u68C0\u67E5\uFF08\u6279\u91CF\u573A\u666F\u63D0\u901F\uFF09").option("--json","\u8F93\u51FA\u673A\u5668\u53EF\u8BFB GateReport JSON").action(async t=>{try{await xr(t.config,t)}catch(n){console.error(`\u2717 \u9A8C\u8BC1\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`),process.exit(1)}})}c($t,"registerValidateCommand");async function xr(o,e){e.json&&hr.setSink((a,l)=>process.stderr.write(`${l}
|
|
11
|
+
`));let t=await wr(o),n=oe.dirname(t),r=await Er(t,e.workflow);r.length===0&&(console.error("\u2717 \u672A\u627E\u5230\u4EFB\u4F55\u5DE5\u4F5C\u6D41"),process.exit(1));let s=await Ir(n),i=await Cr(r,{strict:e.strict===!0,includeTypecheck:e.typecheck!==!1,profile:s});i.configPath=t,e.json?console.log(JSON.stringify(i,null,2)):(await Ar(t),_r(i)),process.exit(i.ok?0:1)}c(xr,"runValidateWorkflow");async function Ar(o){let e=await Pt(o,{lenientEnv:!0});console.log("\u2713 \u914D\u7F6E\u6587\u4EF6\u9A8C\u8BC1\u901A\u8FC7");let t=await vr(e.workflowTemplatePath,{envSource:e.envSource});console.log(`\u2713 \u5DE5\u4F5C\u6D41\u6A21\u677F\u9A8C\u8BC1\u901A\u8FC7: ${t.meta.name} (${t.orderedStepIds.length} \u6B65)`),console.log(`
|
|
12
|
+
\u6B65\u9AA4\u94FE:`);for(let[l,d]of t.orderedStepIds.entries()){let p=t.steps.find(m=>m.id===d),u=l<t.orderedStepIds.length-1?" \u2192":" \u2713";console.log(` ${l+1}. [${d}] ${p?.name??"?"}${u}`)}let n=await Tt(o,"utf8"),r=_t.parse(n),s=re(r.agent)?r.agent:{},a=typeof s.engine=="string"&&s.engine!==""?e.agent.engine:`\u672A\u914D\u7F6E\uFF08\u9ED8\u8BA4 ${e.agent.engine}\uFF09`;console.log(`
|
|
13
|
+
\u914D\u7F6E\u6458\u8981:`),console.log(` AI \u8868\u683C: base=${e.tracker.base_id} table=${e.tracker.table_id}`),console.log(` \u5F15\u64CE: ${a}`),console.log(` \u8F6E\u8BE2\u95F4\u9694: ${e.polling.interval_ms}ms`),console.log()}c(Ar,"printConfigSummary");async function Er(o,e){let t=oe.dirname(o),n;try{n=(await Pt(o,{lenientEnv:!0})).workflowEntries}catch{n=await Sr(o,t)}if(e&&(n=n.filter(r=>r.id===e),n.length===0))throw new Error(`\u672A\u627E\u5230\u5DE5\u4F5C\u6D41\u300C${e}\u300D`);return n}c(Er,"resolveWorkflowEntries");function re(o){return typeof o=="object"&&o!==null&&!Array.isArray(o)}c(re,"isRecord");async function Sr(o,e){let t=await Tt(o,"utf8"),n=_t.parse(t);if(!re(n))throw new Error("\u914D\u7F6E\u6587\u4EF6\u5FC5\u987B\u662F\u4E00\u4E2A\u5BF9\u8C61");if(re(n.workflow)){let r=n.workflow.template,s=n.workflow.recipe_dir??"./recipes";if(typeof r=="string")return[{id:"default",templatePath:oe.resolve(e,r),recipeDir:oe.resolve(e,String(s))}]}if(re(n.workflows)&&typeof n.workflows.dir=="string")return await yr(e,n.workflows.dir);throw new Error("\u914D\u7F6E\u4E2D\u672A\u627E\u5230 workflow / workflows \u6BB5")}c(Sr,"inferEntriesFromRawYaml");async function Ir(o){try{Rr();let e=await kr(o);return br(o,e,{lenientEnv:!0})}catch{return null}}c(Ir,"tryLoadProfile");var Tr={structure:"\u7ED3\u6784\u5B8C\u6574\u6027",recipe_bind:"Recipe \u7ED1\u5B9A",recipe_typecheck:"\u7C7B\u578B\u68C0\u67E5",config_contract:"\u914D\u7F6E\u5951\u7EA6",dataflow:"\u53C2\u6570\u6D41\u8F6C"};function _r(o){console.log(`\u5DE5\u4F5C\u6D41\u95E8\u7981\u6821\u9A8C${o.strict?"\uFF08--strict\uFF09":""}`),console.log("\u2550".repeat(56));for(let t of o.workflows){console.log(`
|
|
14
|
+
\u5DE5\u4F5C\u6D41: ${t.id} ${t.ok?"\u2713 \u901A\u8FC7":"\u2717 \u672A\u901A\u8FC7"}`);for(let n of t.gates)Pr(n)}console.log(`
|
|
15
|
+
`+"\u2500".repeat(56));let e=Lr(o);console.log(`${o.workflows.length} \u4E2A\u5DE5\u4F5C\u6D41\uFF1A${o.ok?"\u5168\u90E8\u901A\u8FC7 \u2713":"\u5B58\u5728\u9519\u8BEF \u2717"}\uFF5Cerror ${e.errors}\uFF5Cwarning ${e.warnings}\uFF5Csuggestion ${e.suggestions}`),o.ok||console.log("\u4FEE\u590D\u4E0A\u8FF0 error \u540E\u91CD\u65B0\u8FD0\u884C\uFF1Berror \u8BA1\u5165\u9000\u51FA\u7801\uFF08CI \u53EF\u4F5C\u95E8\u7981\uFF09\u3002")}c(_r,"printReport");function Pr(o){let e=Tr[o.gate]??o.gate;if(o.status==="skipped"){console.log(` \u25CB ${e}: \u8DF3\u8FC7\uFF08${o.skipReason??""}\uFF09`);return}let t=o.status==="passed"?"\u2713":"\u2717",n=o.issues.filter(s=>s.severity==="error").length,r=o.status==="passed"?o.issues.length>0?`\uFF08${o.issues.length} \u6761\u63D0\u793A\uFF09`:"":`\uFF08${n} \u4E2A\u9519\u8BEF\uFF09`;console.log(` ${t} ${e}${r} [${o.durationMs}ms]`);for(let s of o.issues)$r(s)}c(Pr,"printGate");function $r(o){let e=o.severity==="error"?"\u2717":o.severity==="warning"?"\u25B3":"\xB7",t=o.location?[o.location.file,o.location.stepId,o.location.key].filter(Boolean).join(" \u203A "):"";console.log(` ${e} [${o.code}]${t?` ${t}`:""}`),console.log(` ${o.message}`)}c($r,"printIssue");function Lr(o){let e=0,t=0,n=0;for(let r of o.workflows)for(let s of r.gates)for(let i of s.issues)i.severity==="error"?e++:i.severity==="warning"?t++:n++;return{errors:e,warnings:t,suggestions:n}}c(Lr,"summarize");import{logger as Or}from"aitable-workflow-core";function jr(o,e){if(o.getOptionValueSource("config")!=="default")return e;let t=o.parent?.getOptionValue("config");return typeof t=="string"?t:e}c(jr,"effectiveConfigPath");function Lt(o,e){o.command("config").description("\u6821\u9A8C\u9879\u76EE\u914D\u7F6E\u5B8C\u6574\u6027\uFF0C\u5E76\u53EF\u4EA4\u4E92\u5F0F\u4FEE\u6539\u53C2\u6570").option("-c, --config <path>","\u9879\u76EE\u76EE\u5F55\u6216\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84",e.defaultConfig).option("-w, --workflow <id>","\u591A\u5DE5\u4F5C\u6D41\u6A21\u5F0F\uFF1A\u6307\u5B9A\u6821\u9A8C\u7684\u5DE5\u4F5C\u6D41 ID\uFF08\u7F3A\u7701\u6821\u9A8C\u5168\u90E8\uFF09").option("--json","JSON \u683C\u5F0F\u8F93\u51FA\u6821\u9A8C\u7ED3\u679C").option("--summary","\u4E0E --json \u5408\u7528\uFF1A\u53EA\u8F93\u51FA ok \u4E0E summary").option("--errors-only","\u4E0E --json \u5408\u7528\uFF1A\u53EA\u8F93\u51FA status \u4E3A error \u7684\u9879").option("--no-interactive","\u4EC5\u6821\u9A8C\uFF0C\u8DF3\u8FC7\u4EA4\u4E92\u5F0F\u4FEE\u6539").action(async n=>{try{let{runConfigCommand:r}=await import("./config-command-7ECUJOEU.js");await r({configPath:n.config,workflowId:n.workflow,json:n.json,interactive:n.interactive,summary:n.summary,errorsOnly:n.errorsOnly})}catch(r){r instanceof Error&&r.message.includes("cancelled")&&process.exit(0),Or.error("cli","config \u547D\u4EE4\u5931\u8D25",{error:r instanceof Error?r.message:String(r)}),process.exit(1)}}).command("set").description("\u975E\u4EA4\u4E92\u5199\u914D\u7F6E\u9879\uFF08key \u53D6\u81EA config --json \u7684 item.key\uFF09").option("-c, --config <path>","\u9879\u76EE\u76EE\u5F55\u6216\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84",e.defaultConfig).option("-w, --workflow <id>","\u591A\u5DE5\u4F5C\u6D41\u9879\u76EE\u91CC\u7ED9 key \u6D88\u6B67\uFF08\u540C\u540D key \u547D\u4E2D\u591A\u4E2A\u5DE5\u4F5C\u6D41\u65F6\u5FC5\u586B\uFF09").option("--set <key=value>","\u5199\u4E00\u9879\uFF1B\u53EF\u91CD\u590D\u3002\u654F\u611F\u9879\u62D2\u6536\uFF08\u503C\u4F1A\u8FDB argv\uFF09\uFF0C\u6539\u7528 --set-stdin",(n,r)=>[...r,n],[]).option("--set-stdin <key>","\u5199\u4E00\u9879\uFF0C\u503C\u4ECE stdin \u9010\u884C\u6309\u987A\u5E8F\u8BFB\uFF1B\u53EF\u91CD\u590D\u3002\u654F\u611F\u9879\u8D70\u8FD9\u6761",(n,r)=>[...r,n],[]).option("--dry-run","\u53EA\u6253\u5370\u5C06\u5199\u54EA\u4E2A\u6587\u4EF6\u7684\u54EA\u4E2A\u8DEF\u5F84\uFF0C\u4E0D\u5199\u76D8\uFF08\u654F\u611F\u503C\u53EA\u6253\u952E\u540D\uFF09").option("--json","JSON \u683C\u5F0F\u8F93\u51FA\u7ED3\u679C").action(async(n,r)=>{try{let{runConfigSet:s,printConfigSetResult:i}=await import("./config-set-FBOQBRSJ.js"),a=await s({configPath:jr(r,n.config),...n.workflow?{workflowId:n.workflow}:{},set:n.set,setStdin:n.setStdin,...n.dryRun?{dryRun:!0}:{},...n.json?{json:!0}:{}});i(a,n.json===!0)}catch(s){let i=s instanceof Error?s.message:String(s);n.json?process.stdout.write(JSON.stringify({ok:!1,error:i},null,2)+`
|
|
16
16
|
`):console.error(`
|
|
17
|
-
\u2717 ${
|
|
18
|
-
`),process.exit(1)}})}c(
|
|
19
|
-
`);return}let
|
|
20
|
-
\u652F\u6301 ${n.length} \u4E2A Coding Agent\uFF0C\u672C\u673A\u5DF2\u63A2\u6D4B\u5230 ${
|
|
21
|
-
`);for(let i of n){let s=i.installed?"\u2713":"\u2717",a=[i.bin,...i.fallbackBins].join(" / "),l=i.installed?`\u5DF2\u5B89\u88C5 (${i.detectedCmd}${i.detectedVersion?` ${i.detectedVersion}`:""})`:"\u672A\u63A2\u6D4B\u5230";console.log(` ${s} ${i.name.padEnd(16)} [${i.id}] bin: ${a.padEnd(24)} ${l}`)}console.log("")}catch(n){wo.error("cli","\u5217\u51FA agents \u5931\u8D25",{error:n instanceof Error?n.message:String(n)}),process.exit(1)}})}c(kt,"registerAgentsCommand");import{logger as yo}from"aitable-workflow-core";import{startServer as vo,resolveServeConfig as ko}from"aitable-workflow-server";import oe from"path";import{existsSync as bt}from"fs";function Rt(r,t){r.command("serve").description("\u542F\u52A8\u672C\u5730 HTTP API \u670D\u52A1\u5E76\u6258\u7BA1 Web \u524D\u7AEF\u9875\u9762\uFF08local \u6A21\u5F0F\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF09").option("-p, --port <number>","\u76D1\u542C\u7AEF\u53E3\uFF08\u9ED8\u8BA4 8787\uFF0C\u53EF\u7528 AITABLE_WORKFLOW_PORT \u8986\u76D6\uFF09").option("--host <host>","\u76D1\u542C\u5730\u5740\uFF08\u9ED8\u8BA4 127.0.0.1\uFF0C\u53EF\u7528 AITABLE_WORKFLOW_HOST \u8986\u76D6\uFF09").option("--data-root <path>","\u9879\u76EE\u5DE5\u4F5C\u533A\u6570\u636E\u76EE\u5F55\uFF08\u9ED8\u8BA4 .sandbox/aitable-workflow-server\uFF0C\u53EF\u7528 AITABLE_WORKFLOW_DATA_DIR \u8986\u76D6\uFF09").option("--web-root <path>","Web \u524D\u7AEF\u9759\u6001\u8D44\u6E90\u76EE\u5F55\uFF08\u9ED8\u8BA4\u4F7F\u7528\u968F CLI \u6253\u5305\u7684 dist/web\uFF09").option("--no-open","\u542F\u52A8\u540E\u4E0D\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF08\u9ED8\u8BA4\u81EA\u52A8\u6253\u5F00\uFF09").action(async e=>{try{let n={};if(e.port!==void 0){let i=Number.parseInt(e.port,10);Number.isFinite(i)&&i>0&&(n.port=i)}if(e.host!==void 0&&(n.host=e.host),e.dataRoot!==void 0&&(n.dataRoot=e.dataRoot),e.webRoot!==void 0)n.webRoot=e.webRoot;else{let i=oe.join(t.cliDir,"web");if(bt(oe.join(i,"index.html")))n.webRoot=i;else{let s=oe.resolve(t.cliDir,"..","..","web","dist");bt(oe.join(s,"index.html"))&&(n.webRoot=s)}}let o=ko(n);if(await vo(o),o.webRoot&&e.open!==!1){let i=o.host==="0.0.0.0"?"127.0.0.1":o.host;Je(`http://${i}:${o.port}`)}}catch(n){yo.error("cli","HTTP \u670D\u52A1\u542F\u52A8\u5931\u8D25",{error:n instanceof Error?n.message:String(n)}),process.exit(1)}})}c(Rt,"registerServeCommand");import{Command as Le}from"commander";import{logger as S,listCredentials as Vt,getActiveCredential as j,maskSecret as _r}from"aitable-workflow-core";import B from"os";import M from"path";import{mkdir as cr,readFile as lr}from"fs/promises";import{mkdirSync as pr}from"fs";import{logger as w,detectInstalledAgents as mr,runCodingAgent as dr,DwsClient as ur,getActiveCredential as gr,assertPortableId as Bt,resolveInsideRoot as Mt,probeCommand as fr,dwsCommandOptions as hr}from"aitable-workflow-core";import Ie from"ws";import{logger as x,RELAY_REJECTED_CODE as bo,isRelayMessage as Ro}from"aitable-workflow-core";var T="relay:conn",Ct=1e3,Co=3e4,Io=Number(process.env.AITABLE_RELAY_SERVER_STALE_MS??9e4),re=class{static{c(this,"RelayConnection")}ws=null;delay=Ct;timer=null;watchdog=null;should=!0;permanentlyRejected=!1;accepted=!1;lastServerFrameAt=0;serverUrl;key;token;onMessage;onOpen;onAccepted;onPermanentReject;mkWs;staleMs;constructor(t){this.serverUrl=t.serverUrl,this.key=t.key??"",this.token=t.token??"",this.onMessage=t.onMessage,this.onOpen=t.onOpen,this.onAccepted=t.onAccepted,this.onPermanentReject=t.onPermanentReject,this.mkWs=t.mkWs??(e=>new Ie(e)),this.staleMs=t.staleMs??Io}connect(){this.permanentlyRejected||(this.should=!0,this.doConnect())}send(t){this.ws&&this.ws.readyState===Ie.OPEN&&this.ws.send(JSON.stringify(t))}close(){this.should=!1,this.timer&&(clearTimeout(this.timer),this.timer=null),this.watchdog&&(clearTimeout(this.watchdog),this.watchdog=null),this.ws?.close()}isPermanentlyRejected(){return this.permanentlyRejected}currentSocket(){return this.ws}buildUrl(){let t=this.serverUrl.replace(/\/+$/,"").replace(/^http/,"ws"),e=this.token?`token=${encodeURIComponent(this.token)}`:`key=${encodeURIComponent(this.key)}`;return`${t}/api/relay/connect?${e}`}doConnect(){if(!this.should||this.permanentlyRejected)return;let t=this.buildUrl();x.info(T,"connecting",{serverUrl:this.serverUrl}),this.watchdog&&(clearTimeout(this.watchdog),this.watchdog=null),this.accepted=!1,this.lastServerFrameAt=0;let e=this.mkWs(t);this.ws=e,e.on("open",()=>{x.info(T,"connected"),this.onOpen?.(e)}),e.on("message",n=>{this.accepted||(this.accepted=!0,this.delay=Ct,this.onAccepted?.(e)),this.lastServerFrameAt=Date.now(),this.armWatchdog();let o;try{o=JSON.parse(typeof n=="string"?n:String(n))}catch{return}Ro(o)&&(o.type==="ping"&&this.send({type:"pong"}),this.onMessage(o))}),e.on("close",(n,o)=>{this.watchdog&&(clearTimeout(this.watchdog),this.watchdog=null);let i=o==null?"":String(o);if(n===bo){this.permanentlyRejected=!0,this.should=!1,x.error(T,"server permanently rejected this machine: its connection key is unknown or was removed; re-issue the relay connect command and restart with the new key",{code:n,reason:i}),this.onPermanentReject?.({code:n,reason:i});return}x.warn(T,"disconnected",{code:n}),this.scheduleReconnect()}),e.on("error",n=>{x.error(T,"ws error",{detail:n instanceof Error?n.message:String(n)})})}armWatchdog(){this.watchdog&&clearTimeout(this.watchdog),this.watchdog=setTimeout(()=>{if(!(!this.accepted||!this.lastServerFrameAt||this.ws?.readyState!==Ie.OPEN)){x.warn(T,"server heartbeat stale; closing socket to reconnect",{staleMs:Date.now()-this.lastServerFrameAt});try{this.ws.close()}catch{}}},this.staleMs+1),this.watchdog.unref?.()}scheduleReconnect(){!this.should||this.permanentlyRejected||this.timer||(x.info(T,"reconnecting",{ms:this.delay}),this.timer=setTimeout(()=>{this.timer=null,this.doConnect()},this.delay),this.timer.unref?.(),this.delay=Math.min(this.delay*2,Co))}};import{createHash as So}from"crypto";import{readdir as Ao,readFile as Eo,stat as xo}from"fs/promises";import It from"path";import{isAllowedArtifactPath as To,normalizeArtifactRelPath as $o}from"aitable-workflow-core";var St={async upload(r,t,e){let n=await fetch(r,{method:"PUT",body:t,headers:{...e}});if(!n.ok)throw new Error(`artifact PUT failed: ${n.status} ${n.statusText}`)}};async function At(r){let t=[];return await Et(r,r,t),t.sort((e,n)=>e.relPath.localeCompare(n.relPath))}c(At,"scanArtifacts");async function Et(r,t,e){let n;try{n=await Ao(t,{withFileTypes:!0})}catch{return}for(let o of n){if(o.name==="node_modules"||o.name.startsWith("."))continue;let i=It.join(t,o.name);if(o.isDirectory())await Et(r,i,e);else if(o.isFile()){let s=It.relative(r,i).replace(/\\/g,"/");if(!To(s))continue;let a=await xo(i),l=await Eo(i),p=So("sha256").update(l).digest("hex");e.push({relPath:$o(s),absPath:i,size:a.size,sha256:p})}}}c(Et,"walk");import Lt from"path";import{logger as b}from"aitable-workflow-core";import{logger as _,spawnManagedProcess as Po}from"aitable-workflow-core";var D="engine-supervisor",ie=class{static{c(this,"EngineSupervisor")}options;doSpawn;setTimer;clearTimer;child=null;childGen=0;consecutiveFailures=0;lastExitCode=null;lastError=null;restartTimer=null;stopped=!0;constructor(t){this.options=t,this.doSpawn=t.spawnImpl??Po,this.setTimer=t.setTimeoutImpl??((e,n)=>setTimeout(e,n)),this.clearTimer=t.clearTimeoutImpl??(e=>clearTimeout(e))}get status(){return{running:this.child!=null,pid:this.child?.managed.child.pid??null,generation:this.childGen,startedAt:this.child?new Date(this.child.startedAt).toISOString():null,consecutiveFailures:this.consecutiveFailures,lastExitCode:this.lastExitCode,lastError:this.lastError}}start(){this.stopped=!1,!this.child&&this.spawnChild()}async stop(){this.stopped=!0,this.restartTimer&&(this.clearTimer(this.restartTimer),this.restartTimer=null);let t=this.child;if(!t)return;t.stopping=!0;let e=t.managed.child.pid;if(e==null){this.child=null;return}let n=t.gen;await t.managed.terminateTree({gracePeriodMs:this.options.drainTimeoutMs??2e4}),t.managed.child.exitCode==null&&t.managed.child.signalCode==null&&(_.error(D,"\u5F15\u64CE\u8FDB\u7A0B\u672A\u54CD\u5E94\u5F3A\u5236\u7EC8\u6B62\uFF0C\u653E\u5F03\u7B49\u5F85\uFF08\u53EF\u80FD\u6B8B\u7559\u5B64\u513F\u8FDB\u7A0B\uFF09",{projectId:this.options.projectId,pid:e,generation:n}),this.child?.gen===n&&(this.child=null))}spawnChild(){this.childGen+=1;let t=this.childGen,e=["run","--config",this.options.workspaceDir,"--emit-events","ipc"],n=this.doSpawn({command:process.execPath,args:[this.options.cliPath,...e],cwd:this.options.workspaceDir,stdio:["ignore","pipe","pipe","ipc"],...this.options.env?{env:this.options.env}:{}}),o=n.child,i={managed:n,gen:t,startedAt:Date.now(),stopping:!1};this.child=i,_.info(D,"engine started",{projectId:this.options.projectId,pid:o.pid,generation:t}),o.on("message",s=>{jo(s)&&this.options.onRunEvent?.(s.event)}),o.on("error",s=>{this.lastError=s.message,_.error(D,"engine spawn error",{projectId:this.options.projectId,error:s.message})}),o.on("exit",(s,a)=>this.handleExit(i,s,a))}handleExit(t,e,n){if(this.child?.gen===t.gen&&(this.child=null),this.lastExitCode=e,_.info(D,"engine exited",{projectId:this.options.projectId,generation:t.gen,code:e,signal:n}),t.stopping||this.stopped)return;this.consecutiveFailures+=1;let o=this.options.maxConsecutiveFailures??5;if(this.consecutiveFailures>=o){_.error(D,"engine crash loop\uFF0C\u505C\u6B62\u91CD\u542F\u5E76\u4E0A\u62A5",{projectId:this.options.projectId,failures:this.consecutiveFailures}),this.stopped=!0,this.options.onCrashLoop?.({projectId:this.options.projectId,failures:this.consecutiveFailures,lastExitCode:e});return}let i=this.options.restartBackoffMs??1e3,s=this.options.restartBackoffMaxMs??6e4,a=Math.min(s,i*2**(this.consecutiveFailures-1));_.warn(D,"engine \u5F02\u5E38\u9000\u51FA\uFF0C\u9000\u907F\u91CD\u542F",{projectId:this.options.projectId,failures:this.consecutiveFailures,delayMs:a}),this.restartTimer=this.setTimer(()=>{this.restartTimer=null,!this.stopped&&!this.child&&this.spawnChild()},a)}markHealthy(){this.consecutiveFailures=0}};function jo(r){return typeof r=="object"&&r!==null&&r.type==="run-event"&&"event"in r}c(jo,"isRunEventMessage");import{appendFile as Oo,mkdir as _o,rename as Do,stat as Lo}from"fs/promises";import Mo from"path";import{logger as se}from"aitable-workflow-core";var ae="event-spool",ce=class{static{c(this,"EventSpool")}options;setInterval;clearInterval;now;buffer=[];pending=[];seq=0;timer=null;flushing=!1;constructor(t){this.options=t,this.setInterval=t.setIntervalImpl??((e,n)=>setInterval(e,n)),this.clearInterval=t.clearIntervalImpl??(e=>clearInterval(e)),this.now=t.now??Date.now}get lastSeq(){return this.seq}get pendingCount(){return this.pending.length}start(){this.timer||(this.timer=this.setInterval(()=>{this.flush()},this.options.flushIntervalMs??500))}async stop(){this.timer&&(this.clearInterval(this.timer),this.timer=null),await this.flush()}append(t){this.seq+=1;let e={seq:this.seq,ts:new Date(this.now()).toISOString(),event:t};this.pending.push(e),this.buffer.push(e);let n=this.options.maxPending??5e3;if(this.pending.length>n){let i=this.pending.splice(0,this.pending.length-n);se.warn(ae,"\u5F85\u53D1\u4E8B\u4EF6\u8D85\u4E0A\u9650\uFF0C\u4E22\u5F03\u6700\u65E7\u7684\u6279\u6B21",{projectId:this.options.projectId,dropped:i.length,untilSeq:i[i.length-1]?.seq})}let o=this.options.retain??2e3;this.buffer.length>o&&this.buffer.splice(0,this.buffer.length-o),this.options.persist!==!1&&this.persist(e)}async flush(){if(this.flushing||this.pending.length===0)return;this.flushing=!0;let t=this.pending.slice(0,this.options.maxBatch??200);try{await this.options.send(t);let e=new Set(t.map(n=>n.seq));this.pending=this.pending.filter(n=>!e.has(n.seq))}catch(e){se.warn(ae,"\u4E8B\u4EF6\u6279\u4E0A\u884C\u5931\u8D25\uFF08\u4FDD\u7559\u5F85\u4E0B\u8F6E\u91CD\u8BD5\uFF09",{projectId:this.options.projectId,count:t.length,error:e instanceof Error?e.message:String(e)})}finally{this.flushing=!1}}replayFrom(t){let e=new Set(this.pending.map(o=>o.seq)),n=this.buffer.filter(o=>o.seq>t&&!e.has(o.seq));return n.length===0?0:(this.pending=[...this.pending,...n].sort((o,i)=>o.seq-i.seq),se.info(ae,"\u8865\u4F20\u7F3A\u53E3\u4E8B\u4EF6",{projectId:this.options.projectId,serverLastSeq:t,replay:n.length}),n.length)}async persist(t){let e=Mo.join(this.options.spoolDir,"run-events.jsonl");try{await _o(this.options.spoolDir,{recursive:!0}),await Lo(e).then(o=>o.size).catch(()=>0)>(this.options.rotateBytes??10*1024*1024)&&await Do(e,`${e}.1`).catch(()=>{}),await Oo(e,`${JSON.stringify(t)}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
\u2717 ${i}
|
|
18
|
+
`),process.exit(1)}})}c(Lt,"registerConfigCommand");import{runSync as Mr,logger as Dr}from"aitable-workflow-core";function Ot(o,e){o.command("sync").description("\u68C0\u6D4B\u914D\u7F6E\u4E0E\u8868\u7684\u504F\u5DEE\uFF08\u5B57\u6BB5\u7C7B\u578B/\u9009\u9879 drift\uFF09\uFF0C\u8F93\u51FA\u8BCA\u65AD\u62A5\u544A\u548C\u4FEE\u590D\u5EFA\u8BAE").option("-c, --config <path>","\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84",e.defaultConfig).option("-y, --yes","\u975E\u4EA4\u4E92\u6A21\u5F0F").action(async t=>{try{await Mr({configPath:t.config,yes:t.yes})}catch(n){Dr.error("cli","sync \u5931\u8D25",{error:n instanceof Error?n.message:String(n)}),process.exit(1)}})}c(Ot,"registerSyncCommand");import{listCodingAgents as Br,logger as Hr}from"aitable-workflow-core";function jt(o,e){o.command("agents").description("\u5217\u51FA\u5168\u90E8\u652F\u6301\u7684 Coding Agent \u9002\u914D\u5668\uFF0C\u5E76\u6807\u6CE8\u672C\u673A\u5DF2\u63A2\u6D4B\u5230\u5B89\u88C5\u7684").option("--json","\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA").action(t=>{try{let n=Br();if(t.json){process.stdout.write(JSON.stringify(n,null,2)+`
|
|
19
|
+
`);return}let r=n.filter(s=>s.installed).length;console.log(`
|
|
20
|
+
\u652F\u6301 ${n.length} \u4E2A Coding Agent\uFF0C\u672C\u673A\u5DF2\u63A2\u6D4B\u5230 ${r} \u4E2A\uFF1A
|
|
21
|
+
`);for(let s of n){let i=s.installed?"\u2713":"\u2717",a=[s.bin,...s.fallbackBins].join(" / "),l=s.installed?`\u5DF2\u5B89\u88C5 (${s.detectedCmd}${s.detectedVersion?` ${s.detectedVersion}`:""})`:"\u672A\u63A2\u6D4B\u5230";console.log(` ${i} ${s.name.padEnd(16)} [${s.id}] bin: ${a.padEnd(24)} ${l}`)}console.log("")}catch(n){Hr.error("cli","\u5217\u51FA agents \u5931\u8D25",{error:n instanceof Error?n.message:String(n)}),process.exit(1)}})}c(jt,"registerAgentsCommand");import{logger as Fr}from"aitable-workflow-core";import{startServer as Nr,resolveServeConfig as Ur}from"aitable-workflow-server";import se from"path";import{existsSync as Mt}from"fs";function Dt(o,e){o.command("serve").description("\u542F\u52A8\u672C\u5730 HTTP API \u670D\u52A1\u5E76\u6258\u7BA1 Web \u524D\u7AEF\u9875\u9762\uFF08local \u6A21\u5F0F\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF09").option("-p, --port <number>","\u76D1\u542C\u7AEF\u53E3\uFF08\u9ED8\u8BA4 8787\uFF0C\u53EF\u7528 AITABLE_WORKFLOW_PORT \u8986\u76D6\uFF09").option("--host <host>","\u76D1\u542C\u5730\u5740\uFF08\u9ED8\u8BA4 127.0.0.1\uFF0C\u53EF\u7528 AITABLE_WORKFLOW_HOST \u8986\u76D6\uFF09").option("--data-root <path>","\u9879\u76EE\u5DE5\u4F5C\u533A\u6570\u636E\u76EE\u5F55\uFF08\u9ED8\u8BA4 .sandbox/aitable-workflow-server\uFF0C\u53EF\u7528 AITABLE_WORKFLOW_DATA_DIR \u8986\u76D6\uFF09").option("--web-root <path>","Web \u524D\u7AEF\u9759\u6001\u8D44\u6E90\u76EE\u5F55\uFF08\u9ED8\u8BA4\u4F7F\u7528\u968F CLI \u6253\u5305\u7684 dist/web\uFF09").option("--no-open","\u542F\u52A8\u540E\u4E0D\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF08\u9ED8\u8BA4\u81EA\u52A8\u6253\u5F00\uFF09").action(async t=>{try{let n={};if(t.port!==void 0){let s=Number.parseInt(t.port,10);Number.isFinite(s)&&s>0&&(n.port=s)}if(t.host!==void 0&&(n.host=t.host),t.dataRoot!==void 0&&(n.dataRoot=t.dataRoot),t.webRoot!==void 0)n.webRoot=t.webRoot;else{let s=se.join(e.cliDir,"web");if(Mt(se.join(s,"index.html")))n.webRoot=s;else{let i=se.resolve(e.cliDir,"..","..","web","dist");Mt(se.join(i,"index.html"))&&(n.webRoot=i)}}let r=Ur(n);if(await Nr(r),r.webRoot&&t.open!==!1){let s=r.host==="0.0.0.0"?"127.0.0.1":r.host;it(`http://${s}:${r.port}`)}}catch(n){Fr.error("cli","HTTP \u670D\u52A1\u542F\u52A8\u5931\u8D25",{error:n instanceof Error?n.message:String(n)}),process.exit(1)}})}c(Dt,"registerServeCommand");import{Command as Ze}from"commander";import{logger as T,listCredentials as hn,getActiveCredential as B,maskSecret as Ss}from"aitable-workflow-core";import M from"os";import I from"path";import{fileURLToPath as Bo}from"url";import{createServer as Ho}from"http";import{mkdir as Fo,readFile as sn,mkdtemp as No,writeFile as Uo,rm as Wo}from"fs/promises";import{mkdirSync as Go,existsSync as qo}from"fs";import{logger as w,detectInstalledAgents as zo,projectAgentEvents as rn,runCodingAgent as Jo,DwsClient as Yo,getActiveCredential as Vo,assertPortableId as Ko,probeCommand as Xo,dwsCommandOptions as Zo,substituteArgPath as Qo}from"aitable-workflow-core";var Bt=`<!doctype html>
|
|
22
|
+
<html lang="zh-CN">
|
|
23
|
+
<head>
|
|
24
|
+
<meta charset="utf-8" />
|
|
25
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
26
|
+
<title>Local Agent Workbench</title>
|
|
27
|
+
<link rel="stylesheet" href="/assets/workbench.css" />
|
|
28
|
+
</head>
|
|
29
|
+
<body>
|
|
30
|
+
<header class="topbar">
|
|
31
|
+
<div class="brand">
|
|
32
|
+
<span class="dot" id="health-dot" title="daemon \u72B6\u6001"></span>
|
|
33
|
+
<strong>aitable-workflow</strong>
|
|
34
|
+
<span class="muted">local agent workbench</span>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="topbar-right muted" id="meta">
|
|
37
|
+
<a id="assistant-link" class="assistant-link" href="/" title="assistant-ui \u8FD0\u884C/\u5BF9\u8BDD\u89C6\u56FE">Assistant \u89C6\u56FE \u2192</a>
|
|
38
|
+
<span id="meta-text">\u2014</span>
|
|
39
|
+
</div>
|
|
40
|
+
</header>
|
|
41
|
+
<main class="layout">
|
|
42
|
+
<aside class="runs">
|
|
43
|
+
<div class="pane-head">
|
|
44
|
+
<span>Runs</span>
|
|
45
|
+
<button id="refresh" class="ghost" title="\u7ACB\u5373\u5237\u65B0">\u21BB</button>
|
|
46
|
+
</div>
|
|
47
|
+
<ul id="run-list" class="run-list"></ul>
|
|
48
|
+
</aside>
|
|
49
|
+
<section class="timeline">
|
|
50
|
+
<div class="pane-head" id="timeline-head">\u9009\u62E9\u5DE6\u4FA7\u4E00\u4E2A run \u67E5\u770B\u6267\u884C\u6D41</div>
|
|
51
|
+
<div id="timeline" class="timeline-body"></div>
|
|
52
|
+
<div id="chat-bar" class="chat-bar hidden">
|
|
53
|
+
<div class="chat-row">
|
|
54
|
+
<select id="chat-agent" class="chat-agent" title="\u9009\u62E9\u6267\u884C\u672C\u8F6E\u5BF9\u8BDD\u7684 Agent"></select>
|
|
55
|
+
<span id="chat-session" class="chat-session muted" title="\u672C\u8F6E\u5C06\u590D\u7528\u4E0A\u4E00\u6B21\u5BF9\u8BDD\u7684 sessionId \u7EED\u804A\uFF1B\u6E05\u7A7A\u5219\u5F00\u542F\u65B0\u4F1A\u8BDD"></span>
|
|
56
|
+
<button id="chat-clear-session" class="ghost hidden" title="\u6E05\u7A7A sessionId\uFF0C\u5F00\u542F\u65B0\u4F1A\u8BDD">\u65B0\u4F1A\u8BDD</button>
|
|
57
|
+
</div>
|
|
58
|
+
<div class="chat-row">
|
|
59
|
+
<textarea id="chat-input" class="chat-input" rows="2" placeholder="\u5411\u672C\u673A Agent \u53D1\u4E00\u53E5\uFF08Ctrl/\u2318 + Enter \u53D1\u9001\uFF09"></textarea>
|
|
60
|
+
</div>
|
|
61
|
+
<div class="chat-row chat-actions">
|
|
62
|
+
<span id="chat-hint" class="muted"></span>
|
|
63
|
+
<span class="spacer"></span>
|
|
64
|
+
<button id="chat-send" class="primary" title="\u53D1\u8D77\u4E00\u8F6E\u5BF9\u8BDD">\u53D1\u9001</button>
|
|
65
|
+
<button id="chat-stop" class="ghost hidden" title="\u6253\u65AD\u5F53\u524D\u6D3B\u8DC3\u8F6E\u6B21">\u505C\u6B62</button>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
</section>
|
|
69
|
+
</main>
|
|
70
|
+
<script src="/assets/workbench.js"></script>
|
|
71
|
+
</body>
|
|
72
|
+
</html>`,Ht=`:root {
|
|
73
|
+
--bg: #0e1116;
|
|
74
|
+
--panel: #161b22;
|
|
75
|
+
--panel-2: #1c2230;
|
|
76
|
+
--border: #262d3a;
|
|
77
|
+
--text: #e6edf3;
|
|
78
|
+
--muted: #8b949e;
|
|
79
|
+
--accent: #4c8dff;
|
|
80
|
+
--ok: #3fb950;
|
|
81
|
+
--warn: #d29922;
|
|
82
|
+
--err: #f85149;
|
|
83
|
+
--tool: #a371f7;
|
|
84
|
+
--mono: ui-monospace, SFMonoRLG, "SF Mono", Menlo, Consolas, monospace;
|
|
85
|
+
}
|
|
86
|
+
* { box-sizing: border-box; }
|
|
87
|
+
html, body { height: 100%; margin: 0; }
|
|
88
|
+
body {
|
|
89
|
+
background: var(--bg);
|
|
90
|
+
color: var(--text);
|
|
91
|
+
font: 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
|
|
92
|
+
display: flex;
|
|
93
|
+
flex-direction: column;
|
|
94
|
+
}
|
|
95
|
+
.topbar {
|
|
96
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
97
|
+
padding: 10px 16px; border-bottom: 1px solid var(--border); background: var(--panel);
|
|
98
|
+
}
|
|
99
|
+
.brand { display: flex; align-items: center; gap: 8px; }
|
|
100
|
+
.brand strong { letter-spacing: .2px; }
|
|
101
|
+
.dot { width: 9px; height: 9px; border-radius: 50%; background: var(--muted); display: inline-block; }
|
|
102
|
+
.dot.ok { background: var(--ok); }
|
|
103
|
+
.dot.err { background: var(--err); }
|
|
104
|
+
.muted { color: var(--muted); font-size: 12px; }
|
|
105
|
+
.layout { flex: 1; display: grid; grid-template-columns: 320px 1fr; min-height: 0; }
|
|
106
|
+
.runs { border-right: 1px solid var(--border); background: var(--panel); display: flex; flex-direction: column; min-height: 0; }
|
|
107
|
+
.timeline { display: flex; flex-direction: column; min-height: 0; }
|
|
108
|
+
.pane-head {
|
|
109
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
110
|
+
padding: 10px 14px; border-bottom: 1px solid var(--border);
|
|
111
|
+
font-weight: 600; font-size: 13px; color: var(--text); background: var(--panel);
|
|
112
|
+
position: sticky; top: 0;
|
|
113
|
+
}
|
|
114
|
+
.ghost {
|
|
115
|
+
background: transparent; color: var(--muted); border: 1px solid var(--border);
|
|
116
|
+
border-radius: 6px; cursor: pointer; font-size: 13px; line-height: 1; padding: 3px 8px;
|
|
117
|
+
}
|
|
118
|
+
.ghost:hover { color: var(--text); border-color: var(--accent); }
|
|
119
|
+
.topbar-right { display: flex; align-items: center; gap: 10px; }
|
|
120
|
+
.assistant-link {
|
|
121
|
+
color: var(--muted); text-decoration: none; border: 1px solid var(--border);
|
|
122
|
+
border-radius: 6px; padding: 3px 8px; font-size: 12px; line-height: 1;
|
|
123
|
+
}
|
|
124
|
+
.assistant-link:hover { color: var(--text); border-color: var(--accent); }
|
|
125
|
+
.run-list { list-style: none; margin: 0; padding: 6px; overflow: auto; flex: 1; }
|
|
126
|
+
.run-item {
|
|
127
|
+
padding: 10px; border-radius: 8px; cursor: pointer; border: 1px solid transparent; margin-bottom: 4px;
|
|
128
|
+
}
|
|
129
|
+
.run-item:hover { background: var(--panel-2); }
|
|
130
|
+
.run-item.active { background: var(--panel-2); border-color: var(--accent); }
|
|
131
|
+
.run-item .row1 { display: flex; align-items: center; gap: 8px; }
|
|
132
|
+
.run-item .rid { font-family: var(--mono); font-size: 12px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
133
|
+
.run-item .row2 { margin-top: 4px; font-size: 12px; color: var(--muted); display: flex; gap: 8px; flex-wrap: wrap; }
|
|
134
|
+
.badge { font-size: 11px; padding: 1px 7px; border-radius: 999px; border: 1px solid var(--border); color: var(--muted); }
|
|
135
|
+
.badge.running { color: var(--accent); border-color: var(--accent); }
|
|
136
|
+
.badge.succeeded { color: var(--ok); border-color: var(--ok); }
|
|
137
|
+
.badge.failed { color: var(--err); border-color: var(--err); }
|
|
138
|
+
.badge.aborted { color: var(--warn); border-color: var(--warn); }
|
|
139
|
+
.badge.agent { color: var(--tool); border-color: var(--tool); }
|
|
140
|
+
.badge.source { color: var(--muted); border-color: var(--border); }
|
|
141
|
+
.badge.source-chat { color: var(--accent); border-color: var(--accent); }
|
|
142
|
+
.timeline-body { overflow: auto; padding: 18px 22px 60px; flex: 1; }
|
|
143
|
+
.group { margin-bottom: 16px; display: flex; flex-direction: column; gap: 8px; }
|
|
144
|
+
.item { max-width: 860px; }
|
|
145
|
+
.item.text { background: var(--panel-2); border: 1px solid var(--border); border-radius: 10px; padding: 10px 13px; white-space: pre-wrap; word-break: break-word; }
|
|
146
|
+
details { background: var(--panel); border: 1px solid var(--border); border-radius: 10px; max-width: 860px; }
|
|
147
|
+
details > summary { cursor: pointer; padding: 8px 13px; list-style: none; display: flex; align-items: center; gap: 8px; }
|
|
148
|
+
details > summary::-webkit-details-marker { display: none; }
|
|
149
|
+
details[open] > summary { border-bottom: 1px solid var(--border); }
|
|
150
|
+
.tag { font-size: 11px; text-transform: uppercase; letter-spacing: .4px; padding: 1px 7px; border-radius: 6px; border: 1px solid var(--border); color: var(--muted); flex: none; }
|
|
151
|
+
.tag.thinking { color: var(--warn); border-color: var(--warn); }
|
|
152
|
+
.tag.tool { color: var(--tool); border-color: var(--tool); }
|
|
153
|
+
.tag.tool_result { color: var(--accent); border-color: var(--accent); }
|
|
154
|
+
.tag.permission { color: var(--err); border-color: var(--err); }
|
|
155
|
+
.item .body { padding: 10px 13px; white-space: pre-wrap; word-break: break-word; font-family: var(--mono); font-size: 12.5px; color: var(--text); }
|
|
156
|
+
.item.status { display: flex; align-items: center; gap: 8px; color: var(--muted); font-size: 13px; }
|
|
157
|
+
.item.status .line { flex: 1; height: 1px; background: var(--border); }
|
|
158
|
+
.item.status.result { color: var(--ok); }
|
|
159
|
+
.item.status.error { color: var(--err); }
|
|
160
|
+
.tag.ask { color: var(--warn); border-color: var(--warn); }
|
|
161
|
+
.item.ask { max-width: 860px; border: 1px solid var(--warn); background: rgba(210,153,34,.10); border-radius: 10px; padding: 10px 13px; display: flex; flex-direction: column; gap: 6px; }
|
|
162
|
+
.item.ask .ask-head { display: flex; align-items: center; gap: 8px; font-weight: 600; color: var(--warn); }
|
|
163
|
+
.item.ask .ask-q { white-space: pre-wrap; word-break: break-word; }
|
|
164
|
+
.item.ask .ask-body { font-family: var(--mono); font-size: 12.5px; color: var(--muted); white-space: pre-wrap; word-break: break-word; }
|
|
165
|
+
.empty { color: var(--muted); padding: 40px; text-align: center; }
|
|
166
|
+
.mono { font-family: var(--mono); }
|
|
167
|
+
.hidden { display: none !important; }
|
|
168
|
+
.chat-bar {
|
|
169
|
+
border-top: 1px solid var(--border); background: var(--panel);
|
|
170
|
+
padding: 10px 14px; display: flex; flex-direction: column; gap: 8px;
|
|
171
|
+
}
|
|
172
|
+
.chat-row { display: flex; align-items: center; gap: 8px; }
|
|
173
|
+
.chat-actions { justify-content: flex-end; }
|
|
174
|
+
.chat-row .spacer { flex: 1; }
|
|
175
|
+
.chat-agent {
|
|
176
|
+
background: var(--panel-2); color: var(--text); border: 1px solid var(--border);
|
|
177
|
+
border-radius: 6px; padding: 4px 8px; font: inherit; font-size: 13px;
|
|
178
|
+
}
|
|
179
|
+
.chat-input {
|
|
180
|
+
flex: 1; resize: vertical; min-height: 36px; background: var(--panel-2); color: var(--text);
|
|
181
|
+
border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; font: inherit; font-size: 13px;
|
|
182
|
+
}
|
|
183
|
+
.chat-input:focus { outline: none; border-color: var(--accent); }
|
|
184
|
+
.chat-session { font-family: var(--mono); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 260px; }
|
|
185
|
+
button.primary {
|
|
186
|
+
background: var(--accent); color: #fff; border: 1px solid var(--accent);
|
|
187
|
+
border-radius: 6px; cursor: pointer; font-size: 13px; padding: 4px 14px;
|
|
188
|
+
}
|
|
189
|
+
button.primary:hover { filter: brightness(1.08); }
|
|
190
|
+
button.primary:disabled { opacity: .5; cursor: not-allowed; }
|
|
191
|
+
`,Ft=`(function () {
|
|
192
|
+
"use strict";
|
|
193
|
+
var REFRESH_MS = 1500;
|
|
194
|
+
var state = {
|
|
195
|
+
runs: [], activeId: null, timer: null, es: null,
|
|
196
|
+
// chat \u76F8\u5173\uFF08Task D\uFF09\uFF1AchatEnabled \u7531 /health \u63A2\u6D4B\uFF0C\u672A\u5F00\u542F\u65F6\u4E0B\u9762\u5176\u4F59\u5B57\u6BB5\u5168\u90E8\u65E0\u610F\u4E49\u3002
|
|
197
|
+
chatEnabled: false, chatAgents: [], chatAgentsLoaded: false,
|
|
198
|
+
chatSessionId: null, activeChatId: null,
|
|
199
|
+
};
|
|
200
|
+
var el = function (id) { return document.getElementById(id); };
|
|
201
|
+
|
|
202
|
+
function esc(s) {
|
|
203
|
+
return String(s == null ? "" : s).replace(/[&<>"]/g, function (c) {
|
|
204
|
+
return { "&": "&", "<": "<", ">": ">", '"': """ }[c];
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async function getJSON(path) {
|
|
209
|
+
var res = await fetch(path, { headers: { accept: "application/json" } });
|
|
210
|
+
if (!res.ok) throw new Error(path + " -> " + res.status);
|
|
211
|
+
return res.json();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async function pingHealth() {
|
|
215
|
+
var dot = el("health-dot");
|
|
216
|
+
try {
|
|
217
|
+
var h = await getJSON("/health");
|
|
218
|
+
dot.className = "dot " + (h && h.ok ? "ok" : "err");
|
|
219
|
+
applyChatCapability(h && h.chat === true);
|
|
220
|
+
} catch (e) {
|
|
221
|
+
dot.className = "dot err";
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* /health \u7684 chat \u5B57\u6BB5\u51B3\u5B9A Local Chat \u9762\u677F\u662F\u5426\u53EF\u7528\uFF08daemon \u4EE5 --trace-chat \u542F\u52A8\u624D\u662F true\uFF09\u3002
|
|
227
|
+
* \u9996\u6B21\u63A2\u6D4B\u5230 true \u65F6\u61D2\u52A0\u8F7D\u4E00\u6B21\u53EF\u7528 Agent \u5217\u8868\uFF0C\u4E4B\u540E\u4E0D\u91CD\u590D\u62C9\u53D6\u3002
|
|
228
|
+
*/
|
|
229
|
+
function applyChatCapability(enabled) {
|
|
230
|
+
state.chatEnabled = enabled;
|
|
231
|
+
el("chat-bar").classList.toggle("hidden", !enabled);
|
|
232
|
+
// assistant-link \u5E38\u9A7B\u53EF\u89C1\uFF1A/ \u9ED8\u8BA4\u5DF2\u662F assistant-ui \u8FD0\u884C\u89C6\u56FE\uFF0C\u4E0D\u4F9D\u8D56 chat \u5F00\u5173\u3002
|
|
233
|
+
if (enabled && !state.chatAgentsLoaded) loadChatAgents();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async function loadChatAgents() {
|
|
237
|
+
try {
|
|
238
|
+
var data = await getJSON("/api/chat/agents");
|
|
239
|
+
state.chatAgents = data.agents || [];
|
|
240
|
+
state.chatAgentsLoaded = true;
|
|
241
|
+
var sel = el("chat-agent");
|
|
242
|
+
sel.innerHTML = state.chatAgents.map(function (a) {
|
|
243
|
+
return '<option value="' + esc(a) + '">' + esc(a) + "</option>";
|
|
244
|
+
}).join("");
|
|
245
|
+
if (!state.chatAgents.length) setChatHint("\u672C\u673A\u672A\u68C0\u6D4B\u5230\u53EF\u7528\u7684\u7F16\u7A0B Agent");
|
|
246
|
+
} catch (e) {
|
|
247
|
+
setChatHint("\u65E0\u6CD5\u52A0\u8F7D Agent \u5217\u8868\uFF1A" + e.message);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function setChatHint(text) {
|
|
252
|
+
el("chat-hint").textContent = text || "";
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function updateSessionIndicator() {
|
|
256
|
+
var el2 = el("chat-session");
|
|
257
|
+
var btn = el("chat-clear-session");
|
|
258
|
+
if (state.chatSessionId) {
|
|
259
|
+
el2.textContent = "\u7EED\u804A\u4F1A\u8BDD " + state.chatSessionId.slice(0, 8) + "\u2026";
|
|
260
|
+
btn.classList.remove("hidden");
|
|
261
|
+
} else {
|
|
262
|
+
el2.textContent = "";
|
|
263
|
+
btn.classList.add("hidden");
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** \u4E00\u8F6E chat \u7ED3\u675F\uFF08\u65E0\u8BBA\u6210\u529F/\u6253\u65AD/\u5931\u8D25\uFF09\u540E\u8C03\u7528\uFF1A\u505C\u6B62\u6309\u94AE\u9690\u85CF\uFF0C\u5141\u8BB8\u518D\u6B21\u53D1\u9001\u3002 */
|
|
268
|
+
function endChatTurn() {
|
|
269
|
+
state.activeChatId = null;
|
|
270
|
+
el("chat-stop").classList.add("hidden");
|
|
271
|
+
el("chat-send").disabled = false;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async function sendChatTurn() {
|
|
275
|
+
if (!state.chatEnabled || state.activeChatId) return;
|
|
276
|
+
var prompt = el("chat-input").value.trim();
|
|
277
|
+
if (!prompt) { setChatHint("\u8BF7\u5148\u8F93\u5165\u5185\u5BB9"); return; }
|
|
278
|
+
var requestId = "chat-" + Date.now() + "-" + Math.random().toString(36).slice(2, 8);
|
|
279
|
+
var body = { requestId: requestId, prompt: prompt };
|
|
280
|
+
var agent = el("chat-agent").value;
|
|
281
|
+
if (agent) body.agent = agent;
|
|
282
|
+
if (state.chatSessionId) body.sessionId = state.chatSessionId;
|
|
283
|
+
|
|
284
|
+
state.activeChatId = requestId;
|
|
285
|
+
el("chat-send").disabled = true;
|
|
286
|
+
el("chat-stop").classList.remove("hidden");
|
|
287
|
+
setChatHint("");
|
|
288
|
+
|
|
289
|
+
var res;
|
|
290
|
+
try {
|
|
291
|
+
res = await fetch("/api/chat", {
|
|
292
|
+
method: "POST",
|
|
293
|
+
headers: { "content-type": "application/json" },
|
|
294
|
+
body: JSON.stringify(body),
|
|
295
|
+
});
|
|
296
|
+
} catch (e) {
|
|
297
|
+
setChatHint("\u53D1\u9001\u5931\u8D25\uFF1A" + e.message);
|
|
298
|
+
endChatTurn();
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (!res.ok) {
|
|
302
|
+
var errBody = await res.json().catch(function () { return {}; });
|
|
303
|
+
setChatHint("\u53D1\u9001\u5931\u8D25\uFF08" + res.status + "\uFF09\uFF1A" + (errBody.error || ""));
|
|
304
|
+
endChatTurn();
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
// 202 \u53D7\u7406\uFF1A\u7ACB\u5373\u5207\u5230\u8BE5 run \u7684 SSE \u6D41\u89C2\u770B\uFF0C\u4E0E\u300C\u770B\u670D\u52A1\u7AEF run\u300D\u590D\u7528\u540C\u4E00\u6761\u6D88\u8D39\u8DEF\u5F84\u3002
|
|
308
|
+
el("chat-input").value = "";
|
|
309
|
+
selectRun(requestId);
|
|
310
|
+
refreshRuns();
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
async function stopChatTurn() {
|
|
314
|
+
if (!state.activeChatId) return;
|
|
315
|
+
try {
|
|
316
|
+
var res = await fetch("/api/chat/" + encodeURIComponent(state.activeChatId) + "/stop", { method: "POST" });
|
|
317
|
+
if (!res.ok) setChatHint("\u6253\u65AD\u5931\u8D25\uFF08" + res.status + "\uFF09");
|
|
318
|
+
// \u6210\u529F\u4E0E\u5426\u90FD\u4E0D\u672C\u5730\u6E05\u7406 activeChatId\uFF1A\u7EC8\u6001\u4EE5 SSE finish \u5E27\u4E3A\u51C6\uFF0C\u907F\u514D\u4E0E\u6253\u65AD\u7ADE\u6001\u3002
|
|
319
|
+
} catch (e) {
|
|
320
|
+
setChatHint("\u6253\u65AD\u5931\u8D25\uFF1A" + e.message);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function timeAgo(iso) {
|
|
325
|
+
if (!iso) return "";
|
|
326
|
+
var t = new Date(iso).getTime();
|
|
327
|
+
if (isNaN(t)) return "";
|
|
328
|
+
var s = Math.round((Date.now() - t) / 1000);
|
|
329
|
+
if (s < 60) return s + "s \u524D";
|
|
330
|
+
if (s < 3600) return Math.round(s / 60) + "m \u524D";
|
|
331
|
+
if (s < 86400) return Math.round(s / 3600) + "h \u524D";
|
|
332
|
+
return Math.round(s / 86400) + "d \u524D";
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function renderRuns() {
|
|
336
|
+
var ul = el("run-list");
|
|
337
|
+
if (!state.runs.length) {
|
|
338
|
+
ul.innerHTML = '<li class="empty">\u6682\u65E0 run\u3002\u670D\u52A1\u7AEF\u89E6\u53D1\u4E00\u6B21 workflow agent step \u540E\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\u3002</li>';
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
ul.innerHTML = state.runs.map(function (r) {
|
|
342
|
+
var active = r.id === state.activeId ? " active" : "";
|
|
343
|
+
var dur = r.endedAt
|
|
344
|
+
? Math.max(0, Math.round((new Date(r.endedAt) - new Date(r.startedAt)) / 1000)) + "s"
|
|
345
|
+
: "\u2026";
|
|
346
|
+
var sourceBadge = r.source === "chat"
|
|
347
|
+
? '<span class="badge source source-chat">chat</span>'
|
|
348
|
+
: "";
|
|
349
|
+
return '<li class="run-item' + active + '" data-id="' + esc(r.id) + '">' +
|
|
350
|
+
'<div class="row1"><span class="badge ' + esc(r.status) + '">' + esc(r.status) + '</span>' +
|
|
351
|
+
'<span class="badge agent">' + esc(r.agent) + '</span>' + sourceBadge +
|
|
352
|
+
'<span class="rid">' + esc(r.requestId) + '</span></div>' +
|
|
353
|
+
'<div class="row2"><span>' + esc(r.projectId || "-") + '</span>' +
|
|
354
|
+
'<span>' + r.eventCount + ' events' + (r.droppedEvents ? ' (drop ' + r.droppedEvents + ')' : '') + '</span>' +
|
|
355
|
+
'<span>' + esc(timeAgo(r.startedAt)) + (r.status === "running" ? '' : ' \xB7 ' + dur) + '</span></div>' +
|
|
356
|
+
'</li>';
|
|
357
|
+
}).join("");
|
|
358
|
+
Array.prototype.forEach.call(ul.querySelectorAll(".run-item"), function (li) {
|
|
359
|
+
li.addEventListener("click", function () {
|
|
360
|
+
selectRun(li.getAttribute("data-id"));
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function renderGroup(g) {
|
|
366
|
+
return '<div class="group">' + g.items.map(renderItem).join("") + "</div>";
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function renderItem(it) {
|
|
370
|
+
if (it.kind === "text") {
|
|
371
|
+
return '<div class="item text">' + esc(it.text) + "</div>";
|
|
372
|
+
}
|
|
373
|
+
if (it.kind === "status") {
|
|
374
|
+
var cls = /\u9519\u8BEF|\u5931\u8D25|error/i.test(it.text) ? " error" : (/\u2713|\u5B8C\u6210|\u6210\u529F/.test(it.text) ? " result" : "");
|
|
375
|
+
return '<div class="item status' + cls + '"><span>' + esc(it.text) + '</span><span class="line"></span></div>';
|
|
376
|
+
}
|
|
377
|
+
if (it.kind === "ask") {
|
|
378
|
+
var html = '<div class="item ask"><div class="ask-head"><span class="tag ask">ask</span>' +
|
|
379
|
+
"<span>\u23F8 \u7B49\u5F85\u4EBA\u5DE5\u56DE\u7B54</span></div>" +
|
|
380
|
+
'<div class="ask-q">' + esc(it.text) + "</div>";
|
|
381
|
+
if (it.fullText) html += '<div class="ask-body">' + esc(it.fullText) + "</div>";
|
|
382
|
+
html += "</div>";
|
|
383
|
+
return html;
|
|
384
|
+
}
|
|
385
|
+
// thinking / tool / tool_result / permission -> collapsible
|
|
386
|
+
var body = it.fullText ? esc(it.fullText) : esc(it.text);
|
|
387
|
+
var title = it.kind === "tool" ? esc(it.text) : esc((it.toolName ? it.toolName + " " : "") + labelOf(it.kind));
|
|
388
|
+
return '<details class="item"><summary><span class="tag ' + esc(it.kind) + '">' + esc(it.kind) + "</span>" +
|
|
389
|
+
"<span>" + title + "</span></summary>" +
|
|
390
|
+
'<div class="body">' + body + "</div></details>";
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function labelOf(kind) {
|
|
394
|
+
return { thinking: "\u601D\u8003\u8FC7\u7A0B", tool: "\u5DE5\u5177\u8C03\u7528", tool_result: "\u8FD4\u56DE\u7ED3\u679C", permission: "\u5F85\u6388\u6743", ask: "\u5411\u4EBA\u63D0\u95EE" }[kind] || kind;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function stopStream() {
|
|
398
|
+
if (state.es) {
|
|
399
|
+
try { state.es.close(); } catch (e) { /* noop */ }
|
|
400
|
+
state.es = null;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function setHead(run) {
|
|
405
|
+
if (!run) { el("timeline-head").textContent = "\u9009\u62E9\u5DE6\u4FA7\u4E00\u4E2A run \u67E5\u770B\u6267\u884C\u6D41"; return; }
|
|
406
|
+
el("timeline-head").textContent =
|
|
407
|
+
"run " + run.requestId + " \xB7 " + run.agent + " \xB7 " + run.status +
|
|
408
|
+
" \xB7 " + (run.eventCount || 0) + " events";
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function renderDetail(data) {
|
|
412
|
+
var body = el("timeline");
|
|
413
|
+
var groups = (data.groups || []).filter(function (g) { return g.items && g.items.length; });
|
|
414
|
+
if (data.run) setHead(data.run);
|
|
415
|
+
if (!groups.length) {
|
|
416
|
+
body.innerHTML = '<div class="empty">\u8BE5 run \u6682\u65E0\u53EF\u5C55\u793A\u7684 agent \u4E8B\u4EF6\u3002</div>';
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
var atBottom = body.scrollHeight - body.scrollTop - body.clientHeight < 80;
|
|
420
|
+
body.innerHTML = groups.map(renderGroup).join("");
|
|
421
|
+
if (atBottom) body.scrollTop = body.scrollHeight;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function selectRun(id) {
|
|
425
|
+
if (state.activeId === id && state.es) return; // \u5DF2\u5728\u6D41\u5F0F\u89C2\u770B\u8BE5 run\uFF0C\u52FF\u91CD\u5EFA\u8FDE\u63A5
|
|
426
|
+
state.activeId = id;
|
|
427
|
+
renderRuns();
|
|
428
|
+
stopStream();
|
|
429
|
+
el("timeline").innerHTML = '<div class="empty">\u8FDE\u63A5\u4E2D\u2026</div>';
|
|
430
|
+
var es = new EventSource("/api/runs/" + encodeURIComponent(id) + "/stream");
|
|
431
|
+
state.es = es;
|
|
432
|
+
es.addEventListener("snapshot", function (e) { renderDetail(JSON.parse(e.data)); });
|
|
433
|
+
es.addEventListener("update", function (e) { renderDetail(JSON.parse(e.data)); });
|
|
434
|
+
es.addEventListener("finish", function (e) {
|
|
435
|
+
var data = JSON.parse(e.data);
|
|
436
|
+
renderDetail(data);
|
|
437
|
+
stopStream(); // \u7EC8\u6001\uFF1A\u5173\u95ED\u6D41\uFF0Crun \u72B6\u6001\u540E\u7EED\u7531\u5217\u8868\u8F6E\u8BE2\u7EF4\u62A4
|
|
438
|
+
onRunFinished(data.run);
|
|
439
|
+
});
|
|
440
|
+
es.onerror = function () { /* EventSource \u81EA\u52A8\u91CD\u8FDE\uFF1B\u65E0\u9700\u5904\u7406 */ };
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* run \u7EC8\u6001\u7EDF\u4E00\u6536\u53E3\uFF1A\u82E5\u662F\u521A\u53D1\u8D77\u7684 chat \u8F6E\u7ED3\u675F\uFF0C\u6062\u590D\u53D1\u9001\u6309\u94AE\u5E76\u6355\u83B7 sessionId\uFF08\u4F9B\u4E0B\u4E00\u8F6E\u7EED\u804A\uFF09\u3002
|
|
445
|
+
* \u975E chat \u6765\u6E90\u6216\u670D\u52A1\u7AEF workflow run \u4E0D\u5F71\u54CD chat \u9762\u677F\u72B6\u6001\u3002
|
|
446
|
+
*/
|
|
447
|
+
function onRunFinished(run) {
|
|
448
|
+
if (!run || run.source !== "chat") return;
|
|
449
|
+
if (run.requestId === state.activeChatId) endChatTurn();
|
|
450
|
+
if (run.sessionId) {
|
|
451
|
+
state.chatSessionId = run.sessionId;
|
|
452
|
+
updateSessionIndicator();
|
|
453
|
+
}
|
|
454
|
+
setChatHint("\u4E0A\u4E00\u8F6E\uFF1A" + run.status + (run.error ? "\uFF08" + run.error + "\uFF09" : ""));
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
async function refreshRuns() {
|
|
458
|
+
try {
|
|
459
|
+
var data = await getJSON("/api/runs");
|
|
460
|
+
state.runs = data.runs || [];
|
|
461
|
+
el("meta-text").textContent = state.runs.length + " runs";
|
|
462
|
+
renderRuns();
|
|
463
|
+
if (!state.activeId && state.runs.length) {
|
|
464
|
+
selectRun(state.runs[0].id);
|
|
465
|
+
} else if (state.activeId && !state.runs.some(function (r) { return r.id === state.activeId; })) {
|
|
466
|
+
// \u5F53\u524D\u67E5\u770B\u7684 run \u5DF2\u88AB ring buffer \u6DD8\u6C70\uFF1A\u505C\u6D41\u6E05\u7A7A
|
|
467
|
+
stopStream();
|
|
468
|
+
state.activeId = null;
|
|
469
|
+
el("timeline").innerHTML = '<div class="empty">\u8BE5 run \u5DF2\u4E0D\u5728\u6700\u8FD1\u8BB0\u5F55\u4E2D\u3002</div>';
|
|
470
|
+
setHead(null);
|
|
471
|
+
}
|
|
472
|
+
} catch (e) {
|
|
473
|
+
el("meta-text").textContent = "\u65E0\u6CD5\u8FDE\u63A5 daemon";
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function start() {
|
|
478
|
+
pingHealth();
|
|
479
|
+
refreshRuns();
|
|
480
|
+
state.timer = setInterval(function () {
|
|
481
|
+
refreshRuns();
|
|
482
|
+
pingHealth();
|
|
483
|
+
}, REFRESH_MS);
|
|
484
|
+
el("refresh").addEventListener("click", refreshRuns);
|
|
485
|
+
el("chat-send").addEventListener("click", sendChatTurn);
|
|
486
|
+
el("chat-stop").addEventListener("click", stopChatTurn);
|
|
487
|
+
el("chat-clear-session").addEventListener("click", function () {
|
|
488
|
+
state.chatSessionId = null;
|
|
489
|
+
updateSessionIndicator();
|
|
490
|
+
setChatHint("\u5DF2\u6E05\u7A7A\u7EED\u804A\u4F1A\u8BDD\uFF0C\u4E0B\u4E00\u8F6E\u5F00\u542F\u65B0\u4F1A\u8BDD");
|
|
491
|
+
});
|
|
492
|
+
el("chat-input").addEventListener("keydown", function (ev) {
|
|
493
|
+
if ((ev.metaKey || ev.ctrlKey) && ev.key === "Enter") {
|
|
494
|
+
ev.preventDefault();
|
|
495
|
+
sendChatTurn();
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
document.addEventListener("DOMContentLoaded", start);
|
|
501
|
+
})();
|
|
502
|
+
`;import{mkdir as Jr}from"fs/promises";import{logger as Pe}from"aitable-workflow-core";import Wr from"path";import{logger as Gr,resolveInsideRoot as Nt,assertPortableId as qr}from"aitable-workflow-core";var zr="relay:daemon";function ie(o,e,t){if(t&&t.trim()!=="")if(Wr.isAbsolute(t))Gr.warn(zr,"\u5FFD\u7565\u7EDD\u5BF9\u8DEF\u5F84 workDir\uFF0C\u56DE\u9000\u5230 workspaceRoot/projectId",{workDir:t,projectId:e});else return Nt(o,t,{allowRoot:!1});return Nt(o,qr(e,{label:"projectId"}),{allowRoot:!1})}c(ie,"resolveRelayWorkDir");var $e="relay:chat",Le="local-chat",Yr=128,Ut=32e3,ae=class{constructor(e){this.deps=e}deps;static{c(this,"ChatTurnManager")}active=new Map;listAgents(){return this.deps.detectAgents().map(e=>e.type)}start(e){if(typeof e.requestId!="string"||e.requestId.trim()===""||e.requestId.length>Yr)return{ok:!1,status:400,error:"requestId \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32\u4E14\u4E0D\u8D85\u8FC7 128 \u5B57\u7B26"};if(this.active.has(e.requestId))return{ok:!1,status:409,error:"\u8BE5 requestId \u4ECD\u6709\u6D3B\u8DC3\u8F6E\u6B21\u672A\u7ED3\u675F"};if(typeof e.prompt!="string"||e.prompt.trim()==="")return{ok:!1,status:400,error:"prompt \u4E0D\u80FD\u4E3A\u7A7A"};if(e.prompt.length>Ut)return{ok:!1,status:400,error:`prompt \u8D85\u8FC7\u957F\u5EA6\u4E0A\u9650 ${Ut}`};let t=new AbortController;return this.active.set(e.requestId,t),this.deps.enqueue(()=>this.runTurn(e,t)),{ok:!0}}stop(e){let t=this.active.get(e);return t?(t.abort(),!0):!1}activeCount(){return this.active.size}async runTurn(e,t){let{requestId:n}=e;try{let r=e.agent??this.listAgents()[0];if(!r){this.fail(n,"\u672C\u673A\u672A\u68C0\u6D4B\u5230\u53EF\u7528\u7684\u7F16\u7A0B Agent");return}let s;try{s=ie(this.deps.workspaceRoot,Le,e.workDir)}catch(d){let p=d instanceof Error?d.message:String(d);this.fail(n,`workDir \u8D8A\u754C\u6216\u975E\u6CD5\uFF1A${p}`);return}await Jr(s,{recursive:!0}),this.deps.store.startRun({requestId:n,projectId:Le,agent:r,workDir:s,source:"chat"});let i={agent:r,workDir:s,signal:t.signal,onEvent:c(d=>this.deps.store.appendEvent(n,d),"onEvent")};e.sessionId&&(i.sessionId=e.sessionId);let a=e.timeoutMs??this.deps.defaultTimeoutMs;a!=null&&(i.timeoutMs=a);let l;try{l=await this.deps.runAgent(e.prompt,i)}catch(d){let p=d instanceof Error?d.message:String(d),u=t.signal.aborted?"aborted":"failed";this.deps.store.finishRun(n,{status:u,error:p}),Pe.warn($e,"chat turn ended with error",{requestId:n,status:u,error:p});return}this.deps.store.finishRun(n,{status:"succeeded",response:l.response,sessionId:l.sessionId}),Pe.info($e,"chat turn succeeded",{requestId:n,sessionId:l.sessionId})}finally{this.active.delete(n)}}fail(e,t){this.deps.store.startRun({requestId:e,projectId:Le,agent:"qoder",workDir:"",source:"chat"}),this.deps.store.finishRun(e,{status:"failed",error:t}),Pe.warn($e,"chat turn rejected before agent run",{requestId:e,error:t})}};import Oe from"ws";import{logger as P,RELAY_REJECTED_CODE as Vr,isRelayMessage as Kr}from"aitable-workflow-core";var $="relay:conn",Wt=1e3,Xr=3e4,Zr=Number(process.env.AITABLE_RELAY_SERVER_STALE_MS??9e4),ce=class{static{c(this,"RelayConnection")}ws=null;delay=Wt;timer=null;watchdog=null;should=!0;permanentlyRejected=!1;accepted=!1;lastServerFrameAt=0;serverUrl;key;token;onMessage;onOpen;onAccepted;onPermanentReject;mkWs;staleMs;constructor(e){this.serverUrl=e.serverUrl,this.key=e.key??"",this.token=e.token??"",this.onMessage=e.onMessage,this.onOpen=e.onOpen,this.onAccepted=e.onAccepted,this.onPermanentReject=e.onPermanentReject,this.mkWs=e.mkWs??(t=>new Oe(t)),this.staleMs=e.staleMs??Zr}connect(){this.permanentlyRejected||(this.should=!0,this.doConnect())}send(e){this.ws&&this.ws.readyState===Oe.OPEN&&this.ws.send(JSON.stringify(e))}close(){this.should=!1,this.timer&&(clearTimeout(this.timer),this.timer=null),this.watchdog&&(clearTimeout(this.watchdog),this.watchdog=null),this.ws?.close()}isPermanentlyRejected(){return this.permanentlyRejected}currentSocket(){return this.ws}buildUrl(){let e=this.serverUrl.replace(/\/+$/,"").replace(/^http/,"ws"),t=this.token?`token=${encodeURIComponent(this.token)}`:`key=${encodeURIComponent(this.key)}`;return`${e}/api/relay/connect?${t}`}doConnect(){if(!this.should||this.permanentlyRejected)return;let e=this.buildUrl();P.info($,"connecting",{serverUrl:this.serverUrl}),this.watchdog&&(clearTimeout(this.watchdog),this.watchdog=null),this.accepted=!1,this.lastServerFrameAt=0;let t=this.mkWs(e);this.ws=t,t.on("open",()=>{P.info($,"connected"),this.onOpen?.(t)}),t.on("message",n=>{this.accepted||(this.accepted=!0,this.delay=Wt,this.onAccepted?.(t)),this.lastServerFrameAt=Date.now(),this.armWatchdog();let r;try{r=JSON.parse(typeof n=="string"?n:String(n))}catch{return}Kr(r)&&(r.type==="ping"&&this.send({type:"pong"}),this.onMessage(r))}),t.on("close",(n,r)=>{this.watchdog&&(clearTimeout(this.watchdog),this.watchdog=null);let s=r==null?"":String(r);if(n===Vr){this.permanentlyRejected=!0,this.should=!1,P.error($,"server permanently rejected this machine: its connection key is unknown or was removed; re-issue the relay connect command and restart with the new key",{code:n,reason:s}),this.onPermanentReject?.({code:n,reason:s});return}P.warn($,"disconnected",{code:n}),this.scheduleReconnect()}),t.on("error",n=>{P.error($,"ws error",{detail:n instanceof Error?n.message:String(n)})})}armWatchdog(){this.watchdog&&clearTimeout(this.watchdog),this.watchdog=setTimeout(()=>{if(!(!this.accepted||!this.lastServerFrameAt||this.ws?.readyState!==Oe.OPEN)){P.warn($,"server heartbeat stale; closing socket to reconnect",{staleMs:Date.now()-this.lastServerFrameAt});try{this.ws.close()}catch{}}},this.staleMs+1),this.watchdog.unref?.()}scheduleReconnect(){!this.should||this.permanentlyRejected||this.timer||(P.info($,"reconnecting",{ms:this.delay}),this.timer=setTimeout(()=>{this.timer=null,this.doConnect()},this.delay),this.timer.unref?.(),this.delay=Math.min(this.delay*2,Xr))}};import{createHash as Qr}from"crypto";import{readdir as eo,readFile as to,stat as no}from"fs/promises";import Gt from"path";import{isAllowedArtifactPath as ro,normalizeArtifactRelPath as oo}from"aitable-workflow-core";var qt={async upload(o,e,t){let n=await fetch(o,{method:"PUT",body:e,headers:{...t}});if(!n.ok)throw new Error(`artifact PUT failed: ${n.status} ${n.statusText}`)}};async function zt(o){let e=[];return await Jt(o,o,e),e.sort((t,n)=>t.relPath.localeCompare(n.relPath))}c(zt,"scanArtifacts");async function Jt(o,e,t){let n;try{n=await eo(e,{withFileTypes:!0})}catch{return}for(let r of n){if(r.name==="node_modules"||r.name.startsWith("."))continue;let s=Gt.join(e,r.name);if(r.isDirectory())await Jt(o,s,t);else if(r.isFile()){let i=Gt.relative(o,s).replace(/\\/g,"/");if(!ro(i))continue;let a=await no(s),l=await to(s),d=Qr("sha256").update(l).digest("hex");t.push({relPath:oo(i),absPath:s,size:a.size,sha256:d})}}}c(Jt,"walk");import nn from"path";import{logger as x}from"aitable-workflow-core";import{logger as L,spawnManagedProcess as so}from"aitable-workflow-core";var O="engine-supervisor",je=2e3,le=class{static{c(this,"EngineSupervisor")}options;doSpawn;setTimer;clearTimer;child=null;childGen=0;consecutiveFailures=0;lastExitCode=null;lastError=null;restartTimer=null;stopped=!0;constructor(e){this.options=e,this.doSpawn=e.spawnImpl??so,this.setTimer=e.setTimeoutImpl??((t,n)=>setTimeout(t,n)),this.clearTimer=e.clearTimeoutImpl??(t=>clearTimeout(t))}get status(){return{running:this.child!=null,pid:this.child?.managed.child.pid??null,generation:this.childGen,startedAt:this.child?new Date(this.child.startedAt).toISOString():null,consecutiveFailures:this.consecutiveFailures,lastExitCode:this.lastExitCode,lastError:this.lastError}}start(){this.stopped=!1,!this.child&&this.spawnChild()}async stop(){this.stopped=!0,this.restartTimer&&(this.clearTimer(this.restartTimer),this.restartTimer=null);let e=this.child;if(!e)return;e.stopping=!0;let t=e.managed.child.pid;if(t==null){this.child=null;return}let n=e.gen;await e.managed.terminateTree({gracePeriodMs:this.options.drainTimeoutMs??2e4}),e.managed.child.exitCode==null&&e.managed.child.signalCode==null&&(L.error(O,"\u5F15\u64CE\u8FDB\u7A0B\u672A\u54CD\u5E94\u5F3A\u5236\u7EC8\u6B62\uFF0C\u653E\u5F03\u7B49\u5F85\uFF08\u53EF\u80FD\u6B8B\u7559\u5B64\u513F\u8FDB\u7A0B\uFF09",{projectId:this.options.projectId,pid:t,generation:n}),this.child?.gen===n&&(this.child=null))}spawnChild(){this.childGen+=1;let e=this.childGen,t=["run","--config",this.options.workspaceDir,"--emit-events","ipc"],n=this.doSpawn({command:process.execPath,args:[this.options.cliPath,...t],cwd:this.options.workspaceDir,stdio:["ignore","pipe","pipe","ipc"],...this.options.env?{env:this.options.env}:{}}),r=n.child,s={managed:n,gen:e,startedAt:Date.now(),stopping:!1};this.child=s,L.info(O,"engine started",{projectId:this.options.projectId,pid:r.pid,generation:e}),r.on("message",i=>{io(i)&&this.options.onRunEvent?.(i.event)}),r.on("error",i=>{this.lastError=i.message,L.error(O,"engine spawn error",{projectId:this.options.projectId,error:i.message})}),r.on("exit",(i,a)=>this.handleExit(s,i,a)),this.forwardChildOutput(r.stdout,s,"stdout"),this.forwardChildOutput(r.stderr,s,"stderr")}forwardChildOutput(e,t,n){if(!e)return;e.setEncoding("utf8");let r="",s=c(i=>{let a=i.trim();if(!a)return;let l=a.length>je?`${a.slice(0,je)}\u2026[+${a.length-je}]`:a;L.info(O,l,{projectId:this.options.projectId,generation:t.gen,stream:n})},"emit");e.on("data",i=>{if(this.child?.gen!==t.gen)return;let l=(r+i).split(/\r?\n/);r=l.pop()??"";for(let d of l)s(d)}),e.on("end",()=>{r.trim()&&this.child?.gen===t.gen&&s(r),r=""})}handleExit(e,t,n){if(this.child?.gen===e.gen&&(this.child=null),this.lastExitCode=t,L.info(O,"engine exited",{projectId:this.options.projectId,generation:e.gen,code:t,signal:n}),e.stopping||this.stopped)return;this.consecutiveFailures+=1;let r=this.options.maxConsecutiveFailures??5;if(this.consecutiveFailures>=r){L.error(O,"engine crash loop\uFF0C\u505C\u6B62\u91CD\u542F\u5E76\u4E0A\u62A5",{projectId:this.options.projectId,failures:this.consecutiveFailures}),this.stopped=!0,this.options.onCrashLoop?.({projectId:this.options.projectId,failures:this.consecutiveFailures,lastExitCode:t});return}let s=this.options.restartBackoffMs??1e3,i=this.options.restartBackoffMaxMs??6e4,a=Math.min(i,s*2**(this.consecutiveFailures-1));L.warn(O,"engine \u5F02\u5E38\u9000\u51FA\uFF0C\u9000\u907F\u91CD\u542F",{projectId:this.options.projectId,failures:this.consecutiveFailures,delayMs:a}),this.restartTimer=this.setTimer(()=>{this.restartTimer=null,!this.stopped&&!this.child&&this.spawnChild()},a)}markHealthy(){this.consecutiveFailures=0}};function io(o){return typeof o=="object"&&o!==null&&o.type==="run-event"&&"event"in o}c(io,"isRunEventMessage");import{appendFile as ao,mkdir as co,rename as lo,stat as po}from"fs/promises";import uo from"path";import{logger as de}from"aitable-workflow-core";var pe="event-spool",ue=class{static{c(this,"EventSpool")}options;setInterval;clearInterval;now;buffer=[];pending=[];seq=0;timer=null;flushing=!1;constructor(e){this.options=e,this.setInterval=e.setIntervalImpl??((t,n)=>setInterval(t,n)),this.clearInterval=e.clearIntervalImpl??(t=>clearInterval(t)),this.now=e.now??Date.now}get lastSeq(){return this.seq}get pendingCount(){return this.pending.length}start(){this.timer||(this.timer=this.setInterval(()=>{this.flush()},this.options.flushIntervalMs??500))}async stop(){this.timer&&(this.clearInterval(this.timer),this.timer=null),await this.flush()}append(e){this.seq+=1;let t={seq:this.seq,ts:new Date(this.now()).toISOString(),event:e};this.pending.push(t),this.buffer.push(t);let n=this.options.maxPending??5e3;if(this.pending.length>n){let s=this.pending.splice(0,this.pending.length-n);de.warn(pe,"\u5F85\u53D1\u4E8B\u4EF6\u8D85\u4E0A\u9650\uFF0C\u4E22\u5F03\u6700\u65E7\u7684\u6279\u6B21",{projectId:this.options.projectId,dropped:s.length,untilSeq:s[s.length-1]?.seq})}let r=this.options.retain??2e3;this.buffer.length>r&&this.buffer.splice(0,this.buffer.length-r),this.options.persist!==!1&&this.persist(t)}async flush(){if(this.flushing||this.pending.length===0)return;this.flushing=!0;let e=this.pending.slice(0,this.options.maxBatch??200);try{await this.options.send(e);let t=new Set(e.map(n=>n.seq));this.pending=this.pending.filter(n=>!t.has(n.seq))}catch(t){de.warn(pe,"\u4E8B\u4EF6\u6279\u4E0A\u884C\u5931\u8D25\uFF08\u4FDD\u7559\u5F85\u4E0B\u8F6E\u91CD\u8BD5\uFF09",{projectId:this.options.projectId,count:e.length,error:t instanceof Error?t.message:String(t)})}finally{this.flushing=!1}}replayFrom(e){let t=new Set(this.pending.map(r=>r.seq)),n=this.buffer.filter(r=>r.seq>e&&!t.has(r.seq));return n.length===0?0:(this.pending=[...this.pending,...n].sort((r,s)=>r.seq-s.seq),de.info(pe,"\u8865\u4F20\u7F3A\u53E3\u4E8B\u4EF6",{projectId:this.options.projectId,serverLastSeq:e,replay:n.length}),n.length)}async persist(e){let t=uo.join(this.options.spoolDir,"run-events.jsonl");try{await co(this.options.spoolDir,{recursive:!0}),await po(t).then(r=>r.size).catch(()=>0)>(this.options.rotateBytes??10*1024*1024)&&await lo(t,`${t}.1`).catch(()=>{}),await ao(t,`${JSON.stringify(e)}
|
|
503
|
+
`,"utf8")}catch(n){de.warn(pe,"spool \u843D\u76D8\u5931\u8D25",{projectId:this.options.projectId,error:n instanceof Error?n.message:String(n)})}}};import{readdir as Fe,rm as He,stat as ge}from"fs/promises";import N from"path";import{logger as q}from"aitable-workflow-core";import{createHash as yo}from"crypto";import{mkdir as De,readFile as ko,rename as bo,rm as Ro,writeFile as Xt}from"fs/promises";import me from"path";import{decodeWorkspaceBundle as Co,logger as xo,resolveInsideRoot as Ao}from"aitable-workflow-core";import{chmod as mo,readFile as fo,rename as go,writeFile as ho}from"fs/promises";var Yt="# \u2500\u2500\u2500 aitable-workflow managed credentials (auto-generated, do not edit) \u2500\u2500\u2500",Vt="# \u2500\u2500\u2500 end managed credentials \u2500\u2500\u2500";function vo(o,e){let t=o.split(`
|
|
504
|
+
`),n=t.indexOf(Yt),r=t.indexOf(Vt),s;n!==-1&&r!==-1&&r>n?s=[...t.slice(0,n),...t.slice(r+1)].join(`
|
|
505
|
+
`):s=o,s=s.replace(/^\n+/,"");let i=Object.entries(e).sort(([l],[d])=>l.localeCompare(d));return i.length===0?s:`${[Yt,...i.map(([l,d])=>`${l}=${wo(d)}`),Vt].join(`
|
|
25
506
|
`)}
|
|
26
|
-
${
|
|
27
|
-
${
|
|
28
|
-
`,"utf8"),{projectId:t,revision:i.revision,action:l,written:s,deleted:a,envUpdated:g}}c(jt,"syncWorkspace");var G="runner-gc";async function _t(r){let t=0,e;try{e=await Te(r,{withFileTypes:!0})}catch{return 0}for(let n of e){let o=L.join(r,n.name);if(!n.isSymbolicLink()){if(n.isDirectory()){t+=await _t(o);continue}t+=await me(o).then(i=>i.size).catch(()=>0)}}return t}c(_t,"dirSize");async function tr(r){let t=L.join(r,"projects"),e;try{e=await Te(t,{withFileTypes:!0})}catch{return[]}let n=[];for(let o of e){if(!o.isDirectory())continue;let i=L.join(t,o.name),s=await me(L.join(i,pe)).then(l=>l.mtimeMs).catch(()=>null),a=await me(i).then(l=>l.mtimeMs).catch(()=>0);n.push({projectId:o.name,dir:i,lastTouchedMs:s??a,sizeBytes:await _t(i)})}return n}c(tr,"scanProjects");async function Ot(r,t){let e=L.join(r,"traces"),n;try{n=await Te(e,{withFileTypes:!0})}catch{return 0}let o=[];for(let a of n){if(!a.isFile())continue;let l=L.join(e,a.name),p=await me(l).catch(()=>null);p&&o.push({full:l,size:p.size,mtimeMs:p.mtimeMs})}let i=o.reduce((a,l)=>a+l.size,0);if(i<=t)return 0;o.sort((a,l)=>a.mtimeMs-l.mtimeMs);let s=0;for(let a of o){if(i<=t)break;await xe(a.full,{force:!0}).catch(()=>{}),i-=a.size,s+=a.size}return s}c(Ot,"pruneTraces");async function Dt(r){let t=(r.now??Date.now)(),e=(r.ttlDays??14)*24*60*60*1e3,n=r.tracesMaxBytes??500*1024*1024,o=r.maxDiskBytes??20*1024*1024*1024,i=new Set(r.activeProjectIds),s=await tr(r.workspaceRoot),a=[],l=0;for(let g of s){if(i.has(g.projectId)){l+=await Ot(g.dir,n);continue}if(t-g.lastTouchedMs>=e){await xe(g.dir,{recursive:!0,force:!0}).catch(d=>{N.warn(G,"\u9879\u76EE\u76EE\u5F55\u56DE\u6536\u5931\u8D25",{projectId:g.projectId,error:d instanceof Error?d.message:String(d)})}),a.push(g.projectId),N.info(G,"\u56DE\u6536\u8FC7\u671F\u9879\u76EE\u76EE\u5F55",{projectId:g.projectId,idleDays:Math.floor((t-g.lastTouchedMs)/864e5)});continue}l+=await Ot(g.dir,n)}let p=s.filter(g=>!a.includes(g.projectId)),m=p.reduce((g,d)=>g+d.sizeBytes,0)-l,u=!1;if(m>o){u=!0,N.warn(G,"\u5DE5\u4F5C\u533A\u8D85\u78C1\u76D8\u6C34\u4F4D\uFF0C\u5F00\u59CB\u56DE\u6536\u6700\u4E45\u672A\u8BA4\u9886\u9879\u76EE",{totalBytes:m,maxDiskBytes:o});let g=p.filter(d=>!i.has(d.projectId)).sort((d,v)=>d.lastTouchedMs-v.lastTouchedMs);for(let d of g){if(m<=o)break;await xe(d.dir,{recursive:!0,force:!0}).catch(()=>{}),a.push(d.projectId),m-=d.sizeBytes,N.warn(G,"\u6C34\u4F4D\u56DE\u6536\u9879\u76EE\u76EE\u5F55",{projectId:d.projectId,freedBytes:d.sizeBytes})}m>o&&N.error(G,"\u56DE\u6536\u540E\u4ECD\u8D85\u78C1\u76D8\u6C34\u4F4D\uFF08\u6D3B\u8DC3\u9879\u76EE\u5360\u7528\uFF09\uFF0C\u9700\u4EBA\u5DE5\u4ECB\u5165",{totalBytes:m,maxDiskBytes:o})}return{removedProjects:a,tracesFreedBytes:l,diskPressure:u,totalBytes:Math.max(0,m)}}c(Dt,"runGc");var R="runner-loop",de=class{static{c(this,"RunnerLoop")}options;maxWorkflows;setTimer;clearTimer;doSync;holdings=new Map;pollTimer=null;gcTimer=null;running=!1;claiming=!1;constructor(t){this.options=t,this.maxWorkflows=Math.max(1,Math.floor(t.maxWorkflows??3)),this.setTimer=t.setTimeoutImpl??((e,n)=>setTimeout(e,n)),this.clearTimer=t.clearTimeoutImpl??(e=>clearTimeout(e)),this.doSync=t.syncImpl??jt}get held(){return[...this.holdings.values()].map(t=>({projectId:t.projectId,generation:t.generation,revision:t.revision,engine:t.engine.status}))}get freeSlots(){return Math.max(0,this.maxWorkflows-this.holdings.size)}start(){this.running||(this.running=!0,b.info(R,"runner loop \u542F\u52A8",{maxWorkflows:this.maxWorkflows,workspaceRoot:this.options.workspaceRoot}),this.claimOnce(),this.scheduleGc(0))}async stop(){this.running=!1,this.pollTimer&&(this.clearTimer(this.pollTimer),this.pollTimer=null),this.gcTimer&&(this.clearTimer(this.gcTimer),this.gcTimer=null),await Promise.all([...this.holdings.keys()].map(t=>this.releaseHolding(t,"daemon_shutdown")))}scheduleGc(t){let e=this.options.gcIntervalMs??864e5;!this.running||e<=0||(this.gcTimer&&this.clearTimer(this.gcTimer),this.gcTimer=this.setTimer(()=>{this.gcTimer=null,this.gcOnce().finally(()=>this.scheduleGc(e))},t))}async gcOnce(){try{let t=await(this.options.gcImpl??Dt)({workspaceRoot:this.options.workspaceRoot,activeProjectIds:[...this.holdings.keys()],...this.options.gcOptions??{}});(t.removedProjects.length>0||t.tracesFreedBytes>0)&&b.info(R,"\u672C\u673A\u56DE\u6536\u5B8C\u6210",{removed:t.removedProjects.length,tracesFreedBytes:t.tracesFreedBytes,totalBytes:t.totalBytes})}catch(t){b.warn(R,"\u672C\u673A\u56DE\u6536\u5931\u8D25",{error:$(t)})}}onWakeup(){this.running&&this.claimOnce()}async claimOnce(){if(!this.running||this.claiming)return;this.claiming=!0;let t=this.options.defaultPollMs??1e4;try{let e=this.freeSlots;if(e>0){let n=await this.post("/api/runner/workflows/claim",{capacity:e});typeof n.nextPollAfterMs=="number"&&n.nextPollAfterMs>0&&(t=n.nextPollAfterMs);for(let o of n.grants??[])await this.acceptGrant(o,n.heartbeatIntervalSeconds)}}catch(e){b.warn(R,"claim \u5931\u8D25\uFF08\u9000\u907F\u540E\u91CD\u8BD5\uFF09",{error:$(e)}),t=Math.max(t,5e3)}finally{this.claiming=!1,this.scheduleNextPoll(t)}}scheduleNextPoll(t){this.running&&(this.pollTimer&&this.clearTimer(this.pollTimer),this.pollTimer=this.setTimer(()=>{this.pollTimer=null,this.claimOnce()},t))}async acceptGrant(t,e){if(this.holdings.has(t.projectId))return;let n=Lt.join(this.options.workspaceRoot,"projects",t.projectId);b.info(R,"\u8BA4\u9886\u9879\u76EE",{projectId:t.projectId,generation:t.generation,workspaceDir:n});let o;try{o=await this.doSync(this.clientConfig(),t.projectId,n)}catch(l){b.error(R,"\u5DE5\u4F5C\u533A\u540C\u6B65\u5931\u8D25\uFF0C\u4EA4\u8FD8\u79DF\u7EA6",{projectId:t.projectId,error:$(l)}),await this.postSafe(`/api/runner/workflows/${t.projectId}/release`,{generation:t.generation,reason:"workspace_sync_failed"});return}let i=(this.options.createSupervisor??nr)({projectId:t.projectId,workspaceDir:n,cliPath:this.options.cliPath,onRunEvent:c(l=>this.handleRunEvent(t.projectId,l),"onRunEvent"),onCrashLoop:c(()=>{this.releaseHolding(t.projectId,"engine_crash_loop")},"onCrashLoop")}),s=this.options.sendRunEvents?new ce({projectId:t.projectId,spoolDir:n,send:c(l=>this.options.sendRunEvents(t.projectId,l),"send")}):null;s?.start();let a={projectId:t.projectId,generation:t.generation,revision:o.revision,engine:i,spool:s,heartbeatTimer:null,busy:!1};this.holdings.set(t.projectId,a),i.start(),this.scheduleHeartbeat(a,(e??15)*1e3)}handleRunEvent(t,e){this.holdings.get(t)?.spool?.append(e),this.options.onRunEvent?.(t,e)}scheduleHeartbeat(t,e){this.running&&(t.heartbeatTimer&&this.clearTimer(t.heartbeatTimer),t.heartbeatTimer=this.setTimer(()=>{t.heartbeatTimer=null,this.heartbeatOnce(t)},e))}async heartbeatOnce(t){if(!this.running||t.busy||!this.holdings.has(t.projectId))return;let e=this.options.defaultHeartbeatMs??15e3;try{let n=await this.post(`/api/runner/workflows/${t.projectId}/heartbeat`,{generation:t.generation,workspaceRevision:t.revision,engineStatus:t.engine.status,...t.spool?{lastEventSeq:t.spool.lastSeq}:{}}),o=typeof n.nextIntervalSeconds=="number"&&n.nextIntervalSeconds>0?n.nextIntervalSeconds*1e3:e;if(t.spool&&typeof n.lastEventSeq=="number"&&t.spool.replayFrom(n.lastEventSeq),n.action==="stop"){b.info(R,"\u5FC3\u8DF3\u4E0B\u53D1 stop\uFF0C\u505C\u6B62\u5F15\u64CE",{projectId:t.projectId}),await this.releaseHolding(t.projectId,"heartbeat_stop");return}if(n.action==="resync"){await this.resyncHolding(t)&&this.scheduleHeartbeat(t,o);return}t.engine.markHealthy(),this.scheduleHeartbeat(t,o)}catch(n){b.warn(R,"\u5FC3\u8DF3\u5931\u8D25\uFF08\u4FDD\u6301\u5F15\u64CE\u8FD0\u884C\uFF0C\u7B49\u5F85\u6062\u590D\u6216\u79DF\u7EA6\u8FC7\u671F\uFF09",{projectId:t.projectId,error:$(n)}),this.scheduleHeartbeat(t,Math.min(e,5e3))}}async resyncHolding(t){if(t.busy)return!0;t.busy=!0;let e=Lt.join(this.options.workspaceRoot,"projects",t.projectId);try{b.info(R,"\u5DE5\u4F5C\u533A\u9700\u91CD\u540C\u6B65\uFF0C\u91CD\u542F\u5F15\u64CE",{projectId:t.projectId}),await t.engine.stop();let n=await this.doSync(this.clientConfig(),t.projectId,e);t.revision=n.revision,t.engine.start()}catch(n){return b.error(R,"\u91CD\u540C\u6B65\u5931\u8D25\uFF0C\u4EA4\u8FD8\u79DF\u7EA6",{projectId:t.projectId,error:$(n)}),t.busy=!1,await this.releaseHolding(t.projectId,"resync_failed"),!1}return t.busy=!1,!0}async releaseHolding(t,e){let n=this.holdings.get(t);n&&(this.holdings.delete(t),n.heartbeatTimer&&(this.clearTimer(n.heartbeatTimer),n.heartbeatTimer=null),await n.engine.stop().catch(o=>{b.warn(R,"\u505C\u6B62\u5F15\u64CE\u5F02\u5E38",{projectId:t,error:$(o)})}),await n.spool?.stop().catch(()=>{}),await this.postSafe(`/api/runner/workflows/${t}/release`,{generation:n.generation,reason:e}),b.info(R,"\u5DF2\u8BA9\u51FA\u79DF\u7EA6",{projectId:t,reason:e}),this.running&&this.scheduleNextPoll(this.options.defaultPollMs??1e4))}clientConfig(){return{gatewayUrl:this.options.gatewayUrl,machineKey:this.options.machineKey,...this.options.fetchImpl?{fetchImpl:this.options.fetchImpl}:{}}}async post(t,e){let o=await(this.options.fetchImpl??fetch)(`${this.options.gatewayUrl.replace(/\/+$/,"")}${t}`,{method:"POST",headers:{authorization:`Bearer ${this.options.machineKey}`,"content-type":"application/json"},body:JSON.stringify(e??{})});if(!o.ok){let i=await o.text().catch(()=>"");throw new Error(`runner API ${t} \u5931\u8D25: HTTP ${o.status} ${i.slice(0,200)}`)}return await o.json()}async postSafe(t,e){try{await this.post(t,e)}catch(n){b.warn(R,"\u6536\u5C3E\u8BF7\u6C42\u5931\u8D25\uFF08\u79DF\u7EA6\u5C06\u7531\u670D\u52A1\u7AEF\u8FC7\u671F\u56DE\u6536\uFF09",{pathname:t,error:$(n)})}}};function nr(r){return new ie({projectId:r.projectId,workspaceDir:r.workspaceDir,cliPath:r.cliPath,...r.onRunEvent?{onRunEvent:r.onRunEvent}:{},...r.onCrashLoop?{onCrashLoop:c(()=>r.onCrashLoop(),"onCrashLoop")}:{}})}c(nr,"defaultSupervisorFactory");function $(r){return r instanceof Error?r.message:String(r)}c($,"describeError");import{spawn as rr}from"child_process";import{existsSync as ir}from"fs";import J from"path";import{fileURLToPath as sr}from"url";import{appendFileSync as ma,statSync as da,renameSync as ua,mkdirSync as ga,existsSync as fa}from"fs";import or from"path";var ya=10*1024*1024;function H(r){return or.join(X(r),"daemon.log")}c(H,"logFilePath");var ue=J.dirname(sr(import.meta.url));function $e(){let r=[J.resolve(ue,"..","..","bin","aitable-workflow.mjs"),J.resolve(ue,"..","bin","aitable-workflow.mjs"),J.resolve(ue,"..","..","dist","cli.js"),J.resolve(ue,"cli.js")];return r.find(t=>ir(t))??r[0]}c($e,"resolveDaemonEntry");var ar=$e();async function V(r){await qe(r.agentId);let t=["relay"];r.serverUrl&&t.push("--server-url",r.serverUrl),r.token&&t.push("--token",r.token),r.key&&t.push("--key",r.key),r.name&&t.push("--name",r.name),r.workspaceRoot&&t.push("--workspace-root",r.workspaceRoot),r.machineId&&t.push("--machine-id",r.machineId),r.maxTasks&&t.push("--max-tasks",String(r.maxTasks));let e=await import("fs").then(s=>{let a=H(r.agentId);return s.openSync(a,"a")}),n=rr(process.execPath,[ar,...t],{detached:!0,stdio:["ignore",e,e],env:{...process.env}});try{let{closeSync:s}=await import("fs");s(e)}catch{}n.unref();let{writeFile:o}=await import("fs/promises"),{pidFilePath:i}=await import("./pid-file-KT5KHCKU.js");return n.pid&&await o(i(r.agentId),String(n.pid),"utf8"),{pid:n.pid??0}}c(V,"startDaemon");async function ge(r,t=5e3){let e=await ke(r);if(e===null||!W(e))return await Q(r),!1;try{process.kill(e,"SIGTERM")}catch{return await Q(r),!1}let n=Date.now()+t;for(;Date.now()<n&&W(e);)await new Promise(o=>setTimeout(o,200));if(W(e))try{process.kill(e,"SIGKILL")}catch{}return await Q(r),!0}c(ge,"stopDaemon");async function q(r){let t=await ke(r),e=t!==null&&W(t),n=null;if(e&&t!==null)try{let{readFile:o}=await import("fs/promises"),i=await o(`/proc/${t}/stat`,"utf8"),s=parseInt(i.split(" ")[21]??"0",10),a=await o("/proc/uptime","utf8"),m=parseFloat(a.split(" ")[0]??"0")-s/100;n=Math.round(m*1e3)}catch{}return{agentId:r,running:e,pid:e?t:null,uptimeMs:n,logFile:H(r)}}c(q,"getDaemonStatus");function wr(r){return r.replace(/\/+$/,"").replace(/^ws/,"http")}c(wr,"toHttpBase");var y="relay:daemon",Ft=["aitable"],yr="dws";function vr(r,t=Ft){if(!Array.isArray(r)||r.length===0)return{ok:!1,reason:"dws args must be a non-empty array"};for(let n of r){if(typeof n!="string")return{ok:!1,reason:"dws args must all be strings"};if(n.length===0)return{ok:!1,reason:"dws args must not contain empty tokens"};if(/[\u0000-\u001f]/.test(n))return{ok:!1,reason:"dws args must not contain control characters"}}let e=r[0];return e.startsWith("-")?{ok:!1,reason:"first dws arg must be a subcommand, not a flag"}:t.length>0&&!t.includes(e)?{ok:!1,reason:`dws command "${e}" is not allowed`}:{ok:!0}}c(vr,"validateDwsArgs");function kr(r){return fr(r,["--version"],hr({timeoutMs:5e3})).ok}c(kr,"detectDwsAvailable");var Pe=class{static{c(this,"RelayDaemon")}config;allowedDwsCommands;conn;runAgent;createDwsClient;detectAgents;detectDws;hostname;osString;onPermanentReject;artifactUploader;grantTimeoutMs;pendingGrants=new Map;maxTasks;inflight=0;taskQueue=[];runnerLoop;machineId;constructor(t,e={}){this.config={...t,dwsBin:t.dwsBin??yr},this.machineId=t.machineId,this.allowedDwsCommands=t.allowedDwsCommands??Ft,this.runAgent=e.runAgent??dr,this.createDwsClient=e.createDwsClient??((o,i)=>new ur({bin:o,timeoutMs:i})),this.detectAgents=e.detectAgents??(()=>mr()),this.detectDws=e.detectDws??(o=>kr(o)),this.hostname=e.hostname??(()=>B.hostname()),this.osString=e.osString??(()=>`${B.platform()} ${B.arch()}`),this.onPermanentReject=e.onPermanentReject,this.artifactUploader=e.artifactUploader??St,this.grantTimeoutMs=e.grantTimeoutMs??3e4,this.maxTasks=Math.max(1,Math.floor(t.maxTasks??1));let n=e.createConnection??(o=>new re(o));this.conn=n({serverUrl:this.config.serverUrl,key:this.config.key,token:this.config.token,onMessage:c(o=>this.handleMessage(o),"onMessage"),onOpen:c(()=>this.handleOpen(),"onOpen"),onPermanentReject:c(o=>this.handlePermanentReject(o),"onPermanentReject")}),this.runnerLoop=this.buildRunnerLoop(e)}buildRunnerLoop(t){let e=Math.max(0,Math.floor(this.config.maxWorkflows??3));if(e===0)return null;let n=this.config.key??this.config.token;if(!n)return w.warn(y,"\u65E0 machine key/owner-token\uFF0C\u8DF3\u8FC7 RunnerLoop\uFF08run \u9636\u6BB5\u4E0D\u8BA4\u9886\u9879\u76EE\uFF09"),null;let o={gatewayUrl:wr(this.config.serverUrl),machineKey:n,workspaceRoot:this.config.workspaceRoot,cliPath:$e(),maxWorkflows:e,sendRunEvents:c((i,s)=>this.sendRunEvents(i,s),"sendRunEvents")};return(t.createRunnerLoop??(i=>new de(i)))(o)}sendRunEvents(t,e){e.length!==0&&this.conn.send({type:"run:events",projectId:t,entries:e})}start(){w.info(y,"starting",{serverUrl:this.config.serverUrl,workspaceRoot:this.config.workspaceRoot}),this.config.name||w.warn(y,"\u672A\u6307\u5B9A --name\uFF0C\u5C06\u4F7F\u7528\u4E3B\u673A\u540D\u4F5C\u4E3A\u673A\u5668\u6CE8\u518C\u540D\uFF1B\u591A\u673A\u573A\u666F\u4E0B hostname \u82E5\u91CD\u590D\u4F1A\u5BFC\u81F4\u8FDE\u63A5\u4E92\u76F8\u9876\u66FF\uFF0C\u5EFA\u8BAE\u663E\u5F0F\u6307\u5B9A --name",{hostname:this.hostname()}),this.conn.connect(),this.runnerLoop?.start()}stop(){return w.info(y,"stopping"),this.conn.close(),this.runnerLoop?this.runnerLoop.stop().catch(t=>{w.warn(y,"runner loop \u505C\u6B62\u5F02\u5E38",{error:t instanceof Error?t.message:String(t)})}):Promise.resolve()}buildReady(){let e={type:"ready",runtimes:Array.from(new Set(this.detectAgents().map(n=>n.type))),hasDws:this.detectDws(this.config.dwsBin),hostname:this.hostname(),os:this.osString()};return this.machineId&&(e.machineId=this.machineId),this.config.name&&(e.name=this.config.name),this.config.displayName&&(e.displayName=this.config.displayName),this.config.description&&(e.description=this.config.description),this.maxTasks>1&&(e.maxTasks=this.maxTasks),e}handleOpen(){let t=this.buildReady();w.info(y,"connected; sending ready",{runtimes:t.runtimes,hasDws:t.hasDws}),this.conn.send(t)}handlePermanentReject(t){w.error(y,"permanently rejected by gateway",{...t}),this.onPermanentReject?.(t)}handleMessage(t){switch(t.type){case"run:agent":this.enqueueTask(()=>this.handleRunAgent(t));break;case"run:dws":this.enqueueTask(()=>this.handleRunDws(t));break;case"upload:grant":this.resolveGrant(t);break;case"wf:available":this.runnerLoop?.onWakeup();break;case"ready:ack":t.machineId&&(this.machineId=t.machineId,w.info(y,"machine id assigned",{machineId:t.machineId}));break;default:break}}enqueueTask(t){let e=c(()=>{this.inflight+=1,t().finally(()=>{this.inflight-=1;let n=this.taskQueue.shift();n&&n()})},"exec");this.inflight<this.maxTasks?e():this.taskQueue.push(e)}async handleRunAgent(t){let{requestId:e}=t;w.info(y,"run:agent received",{requestId:e,projectId:t.projectId,agent:t.agent});try{let n=this.resolveWorkDir(t.projectId,t.workDir);await cr(n,{recursive:!0});let o=this.rewritePromptWorkDir(t.prompt,t.workDir,n),i={agent:t.agent,workDir:n,onEvent:c(l=>this.conn.send({type:"event",requestId:e,event:l}),"onEvent")};t.sessionId&&(i.sessionId=t.sessionId),t.permissionMode&&(i.adapterOptions={permissionMode:t.permissionMode}),t.timeoutMs!==void 0?i.timeoutMs=t.timeoutMs:this.config.agentTimeoutMs!=null&&(i.timeoutMs=this.config.agentTimeoutMs);let s=await this.runAgent(o,i),a;try{a=await this.collectAndUploadArtifacts(e,t.projectId,n)}catch(l){let p=l instanceof Error?l.message:String(l);w.error(y,"artifact upload failed",{requestId:e,error:p}),this.conn.send({type:"error",requestId:e,code:"artifact_upload_failed",message:p});return}this.conn.send({type:"result",requestId:e,ok:!0,response:s.response,sessionId:s.sessionId,...a?{artifacts:a}:{}}),w.info(y,"run:agent done",{requestId:e,sessionId:s.sessionId,artifacts:a?a.files.length:0})}catch(n){let o=n instanceof Error?n.message:String(n);w.error(y,"run:agent failed",{requestId:e,error:o}),this.conn.send({type:"error",requestId:e,code:"agent_failed",message:o})}}async collectAndUploadArtifacts(t,e,n){let o=await At(n);if(o.length===0)return;this.conn.send({type:"upload:request",requestId:t,projectId:e,files:o.map(a=>({path:a.relPath,size:a.size,sha256:a.sha256}))});let i=await this.awaitGrant(t);if(!i)throw new Error("upload:grant \u7B49\u5F85\u8D85\u65F6");if(i.grants.length===0){w.warn(y,"upload:grant \u65E0\u6388\u6743\u9879\uFF08gateway \u672A\u914D\u7F6E store \u6216\u5168\u88AB\u62D2\uFF09",{requestId:t,rejected:(i.rejected??[]).length});return}let s=[];for(let a of i.grants){let l=o.find(m=>m.relPath===a.path);if(!l)continue;let p=await lr(l.absPath);await this.artifactUploader.upload(a.url,p,a.headers),s.push({path:a.path,key:a.key,sha256:l.sha256,size:l.size})}return{store:"oss",files:s}}awaitGrant(t){return new Promise(e=>{let n=setTimeout(()=>{this.pendingGrants.delete(t),e(void 0)},this.grantTimeoutMs);n.unref?.(),this.pendingGrants.set(t,o=>{clearTimeout(n),e(o)})})}resolveGrant(t){let e=this.pendingGrants.get(t.requestId);e&&(this.pendingGrants.delete(t.requestId),e(t))}async handleRunDws(t){let{requestId:e}=t,n=vr(t.args,this.allowedDwsCommands);if(!n.ok){w.warn(y,"run:dws rejected",{requestId:e,reason:n.reason}),this.conn.send({type:"error",requestId:e,code:"dws_rejected",message:n.reason});return}w.info(y,"run:dws received",{requestId:e,command:t.args[0]});try{let i=await this.createDwsClient(this.config.dwsBin,t.timeoutMs).runJson(t.args,t.timeoutMs!=null?{timeoutMs:t.timeoutMs}:void 0);this.conn.send({type:"result",requestId:e,ok:!0,response:JSON.stringify(i)}),w.info(y,"run:dws done",{requestId:e})}catch(o){let i=o instanceof Error?o.message:String(o);w.error(y,"run:dws failed",{requestId:e,error:i}),this.conn.send({type:"error",requestId:e,code:"dws_failed",message:i})}}resolveWorkDir(t,e){if(e&&e.trim()!=="")if(M.isAbsolute(e))w.warn(y,"\u5FFD\u7565\u670D\u52A1\u7AEF\u4E0B\u53D1\u7684\u7EDD\u5BF9\u8DEF\u5F84 workDir\uFF0C\u56DE\u9000\u5230 workspaceRoot/projectId",{workDir:e,projectId:t});else return Mt(this.config.workspaceRoot,e,{allowRoot:!1});return Mt(this.config.workspaceRoot,Bt(t,{label:"projectId"}),{allowRoot:!1})}rewritePromptWorkDir(t,e,n){let o=e?.trim();return!o||!M.isAbsolute(o)||o===n?t:t.split(o).join(n)}};function je(r,t){let e,n=r?.trim();if(n)e=M.isAbsolute(n)?M.resolve(n):M.resolve(B.homedir(),n);else{let o=t?.trim()?t.trim():"default";e=M.join(B.homedir(),".aitable-workflow","workspaces",Bt(o,{label:"agentId"}))}return pr(e,{recursive:!0}),e}c(je,"resolveWorkspaceRoot");function br(r,t=process.env){let e=r.serverUrl??t.AITABLE_RELAY_SERVER_URL,n=r.key??t.AITABLE_RELAY_BOOTSTRAP_KEY,o=r.token??t.AITABLE_RELAY_TOKEN,i=r.workspaceRoot??t.AITABLE_RELAY_WORKSPACE_ROOT,s=r.machineId??t.AITABLE_RELAY_MACHINE_ID,a=r.name??t.AITABLE_RELAY_NAME,l=r.desc??t.AITABLE_RELAY_DESC,p=r.maxTasks??t.AITABLE_RELAY_MAX_TASKS,m=r.maxWorkflows??t.AITABLE_RELAY_MAX_WORKFLOWS,u=[];if(e||u.push("--server-url (\u6216 AITABLE_RELAY_SERVER_URL)"),!n&&!o&&u.push("--key/--token (\u6216 AITABLE_RELAY_BOOTSTRAP_KEY/AITABLE_RELAY_TOKEN)"),u.length>0)throw new Error(`relay \u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${u.join(", ")}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
`),p={
|
|
34
|
-
|
|
507
|
+
${s?`
|
|
508
|
+
${s}`:""}`}c(vo,"mergeEnvContent");function wo(o){return o===""||/[\s#'"`\\]/.test(o)?`"${o.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n")}"`:o}c(wo,"quoteEnvValue");async function Kt(o,e){let t=await fo(o,"utf8").catch(()=>""),n=vo(t,e);if(n===t||n===""&&t==="")return!1;let r=`${o}.aitable-sync-tmp`;return await ho(r,n,{encoding:"utf8",mode:384}),await mo(r,384).catch(()=>{}),await go(r,o),!0}c(Kt,"mergeEnvFile");var Eo="workspace-sync",fe=".workspace-meta.json";function So(o){return yo("sha256").update(o).digest("hex")}c(So,"sha256Hex");async function Me(o,e){let n=await(o.fetchImpl??fetch)(`${o.gatewayUrl.replace(/\/+$/,"")}${e}`,{headers:{authorization:`Bearer ${o.machineKey}`}});if(!n.ok){let r=await n.text().catch(()=>"");throw new Error(`runner API ${e} \u5931\u8D25: HTTP ${n.status} ${r.slice(0,200)}`)}return n}c(Me,"apiGet");async function Io(o){try{let e=await ko(me.join(o,fe),"utf8"),t=JSON.parse(e);return t&&typeof t.projectId=="string"?t:null}catch{return null}}c(Io,"readWorkspaceMeta");function Be(o,e){return Ao(o,e,{allowRoot:!1})}c(Be,"resolveTracked");async function To(o,e){let t=Be(o,e.path);await De(me.dirname(t),{recursive:!0});let n=`${t}.aitable-sync-tmp`;await Xt(n,e.content,"utf8"),await bo(n,t)}c(To,"writeTracked");async function Zt(o,e,t){let n=await Io(t);if(n&&n.projectId!==e)throw new Error(`\u5DE5\u4F5C\u533A\u76EE\u5F55\u5F52\u5C5E\u4E0D\u7B26: \u76EE\u5F55\u8BB0\u5F55 projectId=${n.projectId}\uFF0C\u8BF7\u6C42\u540C\u6B65 ${e}\uFF08${t}\uFF09`);let s=await(await Me(o,`/api/runner/workspace/${e}`)).json(),i=0,a=0,l="up-to-date",d=n?.trackedManifest??{};if(!n||n.revision!==s.revision){l="synced";let R=await Me(o,`/api/runner/workspace/${e}/bundle`),S=Co(Buffer.from(await R.arrayBuffer()));if(S.projectId!==e)throw new Error(`\u5FEB\u7167\u5305\u5F52\u5C5E\u4E0D\u7B26: \u5305\u5185 projectId=${S.projectId}\uFF0C\u671F\u671B ${e}`);S.revision!==s.revision&&(s.revision=S.revision),await De(t,{recursive:!0});let E={};for(let g of S.files)E[g.path]=So(g.content);for(let g of S.files)Be(t,g.path);let H=n?.trackedManifest??{};for(let g of S.files)H[g.path]!==E[g.path]&&(await To(t,g),i+=1);for(let g of Object.keys(H))if(E[g]===void 0){let h;try{h=Be(t,g)}catch(Ee){xo.warn(Eo,"\u8DF3\u8FC7\u8D8A\u754C\u7684\u65E7 manifest \u6761\u76EE",{projectId:e,path:g,error:Ee instanceof Error?Ee.message:String(Ee)});continue}await Ro(h,{force:!0}).catch(()=>{}),a+=1}d=E}let u=await(await Me(o,`/api/runner/workspace/${e}/credentials`)).json();await De(t,{recursive:!0});let m=await Kt(me.join(t,".env"),u.credentials??{}),f={projectId:e,revision:s.revision,syncedAt:new Date().toISOString(),trackedManifest:d};return await Xt(me.join(t,fe),`${JSON.stringify(f,null,2)}
|
|
509
|
+
`,"utf8"),{projectId:e,revision:s.revision,action:l,written:i,deleted:a,envUpdated:m}}c(Zt,"syncWorkspace");var z="runner-gc";async function en(o){let e=0,t;try{t=await Fe(o,{withFileTypes:!0})}catch{return 0}for(let n of t){let r=N.join(o,n.name);if(!n.isSymbolicLink()){if(n.isDirectory()){e+=await en(r);continue}e+=await ge(r).then(s=>s.size).catch(()=>0)}}return e}c(en,"dirSize");async function _o(o){let e=N.join(o,"projects"),t;try{t=await Fe(e,{withFileTypes:!0})}catch{return[]}let n=[];for(let r of t){if(!r.isDirectory())continue;let s=N.join(e,r.name),i=await ge(N.join(s,fe)).then(l=>l.mtimeMs).catch(()=>null),a=await ge(s).then(l=>l.mtimeMs).catch(()=>0);n.push({projectId:r.name,dir:s,lastTouchedMs:i??a,sizeBytes:await en(s)})}return n}c(_o,"scanProjects");async function Qt(o,e){let t=N.join(o,"traces"),n;try{n=await Fe(t,{withFileTypes:!0})}catch{return 0}let r=[];for(let a of n){if(!a.isFile())continue;let l=N.join(t,a.name),d=await ge(l).catch(()=>null);d&&r.push({full:l,size:d.size,mtimeMs:d.mtimeMs})}let s=r.reduce((a,l)=>a+l.size,0);if(s<=e)return 0;r.sort((a,l)=>a.mtimeMs-l.mtimeMs);let i=0;for(let a of r){if(s<=e)break;await He(a.full,{force:!0}).catch(()=>{}),s-=a.size,i+=a.size}return i}c(Qt,"pruneTraces");async function tn(o){let e=(o.now??Date.now)(),t=(o.ttlDays??14)*24*60*60*1e3,n=o.tracesMaxBytes??500*1024*1024,r=o.maxDiskBytes??20*1024*1024*1024,s=new Set(o.activeProjectIds),i=await _o(o.workspaceRoot),a=[],l=0;for(let m of i){if(s.has(m.projectId)){l+=await Qt(m.dir,n);continue}if(e-m.lastTouchedMs>=t){await He(m.dir,{recursive:!0,force:!0}).catch(f=>{q.warn(z,"\u9879\u76EE\u76EE\u5F55\u56DE\u6536\u5931\u8D25",{projectId:m.projectId,error:f instanceof Error?f.message:String(f)})}),a.push(m.projectId),q.info(z,"\u56DE\u6536\u8FC7\u671F\u9879\u76EE\u76EE\u5F55",{projectId:m.projectId,idleDays:Math.floor((e-m.lastTouchedMs)/864e5)});continue}l+=await Qt(m.dir,n)}let d=i.filter(m=>!a.includes(m.projectId)),p=d.reduce((m,f)=>m+f.sizeBytes,0)-l,u=!1;if(p>r){u=!0,q.warn(z,"\u5DE5\u4F5C\u533A\u8D85\u78C1\u76D8\u6C34\u4F4D\uFF0C\u5F00\u59CB\u56DE\u6536\u6700\u4E45\u672A\u8BA4\u9886\u9879\u76EE",{totalBytes:p,maxDiskBytes:r});let m=d.filter(f=>!s.has(f.projectId)).sort((f,R)=>f.lastTouchedMs-R.lastTouchedMs);for(let f of m){if(p<=r)break;await He(f.dir,{recursive:!0,force:!0}).catch(()=>{}),a.push(f.projectId),p-=f.sizeBytes,q.warn(z,"\u6C34\u4F4D\u56DE\u6536\u9879\u76EE\u76EE\u5F55",{projectId:f.projectId,freedBytes:f.sizeBytes})}p>r&&q.error(z,"\u56DE\u6536\u540E\u4ECD\u8D85\u78C1\u76D8\u6C34\u4F4D\uFF08\u6D3B\u8DC3\u9879\u76EE\u5360\u7528\uFF09\uFF0C\u9700\u4EBA\u5DE5\u4ECB\u5165",{totalBytes:p,maxDiskBytes:r})}return{removedProjects:a,tracesFreedBytes:l,diskPressure:u,totalBytes:Math.max(0,p)}}c(tn,"runGc");var A="runner-loop";function Po(o){return!(typeof o=="object"&&o!==null&&o.type==="run.agent_event")}c(Po,"shouldUplinkRunEvent");var he=class{static{c(this,"RunnerLoop")}options;maxWorkflows;setTimer;clearTimer;doSync;holdings=new Map;pollTimer=null;gcTimer=null;running=!1;claiming=!1;constructor(e){this.options=e,this.maxWorkflows=Math.max(1,Math.floor(e.maxWorkflows??3)),this.setTimer=e.setTimeoutImpl??((t,n)=>setTimeout(t,n)),this.clearTimer=e.clearTimeoutImpl??(t=>clearTimeout(t)),this.doSync=e.syncImpl??Zt}get held(){return[...this.holdings.values()].map(e=>({projectId:e.projectId,generation:e.generation,revision:e.revision,engine:e.engine.status}))}get freeSlots(){return Math.max(0,this.maxWorkflows-this.holdings.size)}start(){this.running||(this.running=!0,x.info(A,"runner loop \u542F\u52A8",{maxWorkflows:this.maxWorkflows,workspaceRoot:this.options.workspaceRoot}),this.claimOnce(),this.scheduleGc(0))}async stop(){this.running=!1,this.pollTimer&&(this.clearTimer(this.pollTimer),this.pollTimer=null),this.gcTimer&&(this.clearTimer(this.gcTimer),this.gcTimer=null),await Promise.all([...this.holdings.keys()].map(e=>this.releaseHolding(e,"daemon_shutdown")))}scheduleGc(e){let t=this.options.gcIntervalMs??864e5;!this.running||t<=0||(this.gcTimer&&this.clearTimer(this.gcTimer),this.gcTimer=this.setTimer(()=>{this.gcTimer=null,this.gcOnce().finally(()=>this.scheduleGc(t))},e))}async gcOnce(){try{let e=await(this.options.gcImpl??tn)({workspaceRoot:this.options.workspaceRoot,activeProjectIds:[...this.holdings.keys()],...this.options.gcOptions??{}});(e.removedProjects.length>0||e.tracesFreedBytes>0)&&x.info(A,"\u672C\u673A\u56DE\u6536\u5B8C\u6210",{removed:e.removedProjects.length,tracesFreedBytes:e.tracesFreedBytes,totalBytes:e.totalBytes})}catch(e){x.warn(A,"\u672C\u673A\u56DE\u6536\u5931\u8D25",{error:j(e)})}}onWakeup(){this.running&&this.claimOnce()}async claimOnce(){if(!this.running||this.claiming)return;this.claiming=!0;let e=this.options.defaultPollMs??1e4;try{let t=this.freeSlots;if(t>0){let n=await this.post("/api/runner/workflows/claim",{capacity:t});typeof n.nextPollAfterMs=="number"&&n.nextPollAfterMs>0&&(e=n.nextPollAfterMs);for(let r of n.grants??[])await this.acceptGrant(r,n.heartbeatIntervalSeconds)}}catch(t){x.warn(A,"claim \u5931\u8D25\uFF08\u9000\u907F\u540E\u91CD\u8BD5\uFF09",{error:j(t)}),e=Math.max(e,5e3)}finally{this.claiming=!1,this.scheduleNextPoll(e)}}scheduleNextPoll(e){this.running&&(this.pollTimer&&this.clearTimer(this.pollTimer),this.pollTimer=this.setTimer(()=>{this.pollTimer=null,this.claimOnce()},e))}async acceptGrant(e,t){if(this.holdings.has(e.projectId))return;let n=nn.join(this.options.workspaceRoot,"projects",e.projectId);x.info(A,"\u8BA4\u9886\u9879\u76EE",{projectId:e.projectId,generation:e.generation,workspaceDir:n});let r;try{r=await this.doSync(this.clientConfig(),e.projectId,n)}catch(l){x.error(A,"\u5DE5\u4F5C\u533A\u540C\u6B65\u5931\u8D25\uFF0C\u4EA4\u8FD8\u79DF\u7EA6",{projectId:e.projectId,error:j(l)}),await this.postSafe(`/api/runner/workflows/${e.projectId}/release`,{generation:e.generation,reason:"workspace_sync_failed"});return}let s=(this.options.createSupervisor??$o)({projectId:e.projectId,workspaceDir:n,cliPath:this.options.cliPath,onRunEvent:c(l=>this.handleRunEvent(e.projectId,l),"onRunEvent"),onCrashLoop:c(()=>{this.releaseHolding(e.projectId,"engine_crash_loop")},"onCrashLoop")}),i=this.options.sendRunEvents?new ue({projectId:e.projectId,spoolDir:n,send:c(l=>this.options.sendRunEvents(e.projectId,l),"send")}):null;i?.start();let a={projectId:e.projectId,generation:e.generation,revision:r.revision,engine:s,spool:i,heartbeatTimer:null,busy:!1};this.holdings.set(e.projectId,a),s.start(),this.scheduleHeartbeat(a,(t??15)*1e3)}handleRunEvent(e,t){Po(t)&&this.holdings.get(e)?.spool?.append(t),this.options.onRunEvent?.(e,t)}scheduleHeartbeat(e,t){this.running&&(e.heartbeatTimer&&this.clearTimer(e.heartbeatTimer),e.heartbeatTimer=this.setTimer(()=>{e.heartbeatTimer=null,this.heartbeatOnce(e)},t))}async heartbeatOnce(e){if(!this.running||e.busy||!this.holdings.has(e.projectId))return;let t=this.options.defaultHeartbeatMs??15e3;try{let n=await this.post(`/api/runner/workflows/${e.projectId}/heartbeat`,{generation:e.generation,workspaceRevision:e.revision,engineStatus:e.engine.status,...e.spool?{lastEventSeq:e.spool.lastSeq}:{}}),r=typeof n.nextIntervalSeconds=="number"&&n.nextIntervalSeconds>0?n.nextIntervalSeconds*1e3:t;if(e.spool&&typeof n.lastEventSeq=="number"&&e.spool.replayFrom(n.lastEventSeq),n.action==="stop"){x.info(A,"\u5FC3\u8DF3\u4E0B\u53D1 stop\uFF0C\u505C\u6B62\u5F15\u64CE",{projectId:e.projectId}),await this.releaseHolding(e.projectId,"heartbeat_stop");return}if(n.action==="resync"){await this.resyncHolding(e)&&this.scheduleHeartbeat(e,r);return}e.engine.markHealthy(),this.scheduleHeartbeat(e,r)}catch(n){x.warn(A,"\u5FC3\u8DF3\u5931\u8D25\uFF08\u4FDD\u6301\u5F15\u64CE\u8FD0\u884C\uFF0C\u7B49\u5F85\u6062\u590D\u6216\u79DF\u7EA6\u8FC7\u671F\uFF09",{projectId:e.projectId,error:j(n)}),this.scheduleHeartbeat(e,Math.min(t,5e3))}}async resyncHolding(e){if(e.busy)return!0;e.busy=!0;let t=nn.join(this.options.workspaceRoot,"projects",e.projectId);try{x.info(A,"\u5DE5\u4F5C\u533A\u9700\u91CD\u540C\u6B65\uFF0C\u91CD\u542F\u5F15\u64CE",{projectId:e.projectId}),await e.engine.stop();let n=await this.doSync(this.clientConfig(),e.projectId,t);e.revision=n.revision,e.engine.start()}catch(n){return x.error(A,"\u91CD\u540C\u6B65\u5931\u8D25\uFF0C\u4EA4\u8FD8\u79DF\u7EA6",{projectId:e.projectId,error:j(n)}),e.busy=!1,await this.releaseHolding(e.projectId,"resync_failed"),!1}return e.busy=!1,!0}async releaseHolding(e,t){let n=this.holdings.get(e);n&&(this.holdings.delete(e),n.heartbeatTimer&&(this.clearTimer(n.heartbeatTimer),n.heartbeatTimer=null),await n.engine.stop().catch(r=>{x.warn(A,"\u505C\u6B62\u5F15\u64CE\u5F02\u5E38",{projectId:e,error:j(r)})}),await n.spool?.stop().catch(()=>{}),await this.postSafe(`/api/runner/workflows/${e}/release`,{generation:n.generation,reason:t}),x.info(A,"\u5DF2\u8BA9\u51FA\u79DF\u7EA6",{projectId:e,reason:t}),this.running&&this.scheduleNextPoll(this.options.defaultPollMs??1e4))}clientConfig(){return{gatewayUrl:this.options.gatewayUrl,machineKey:this.options.machineKey,...this.options.fetchImpl?{fetchImpl:this.options.fetchImpl}:{}}}async post(e,t){let r=await(this.options.fetchImpl??fetch)(`${this.options.gatewayUrl.replace(/\/+$/,"")}${e}`,{method:"POST",headers:{authorization:`Bearer ${this.options.machineKey}`,"content-type":"application/json"},body:JSON.stringify(t??{})});if(!r.ok){let s=await r.text().catch(()=>"");throw new Error(`runner API ${e} \u5931\u8D25: HTTP ${r.status} ${s.slice(0,200)}`)}return await r.json()}async postSafe(e,t){try{await this.post(e,t)}catch(n){x.warn(A,"\u6536\u5C3E\u8BF7\u6C42\u5931\u8D25\uFF08\u79DF\u7EA6\u5C06\u7531\u670D\u52A1\u7AEF\u8FC7\u671F\u56DE\u6536\uFF09",{pathname:e,error:j(n)})}}};function $o(o){return new le({projectId:o.projectId,workspaceDir:o.workspaceDir,cliPath:o.cliPath,...o.onRunEvent?{onRunEvent:o.onRunEvent}:{},...o.onCrashLoop?{onCrashLoop:c(()=>o.onCrashLoop(),"onCrashLoop")}:{}})}c($o,"defaultSupervisorFactory");function j(o){return o instanceof Error?o.message:String(o)}c(j,"describeError");import{spawn as Oo}from"child_process";import{existsSync as jo}from"fs";import Y from"path";import{fileURLToPath as Mo}from"url";import{appendFileSync as fc,statSync as gc,renameSync as hc,mkdirSync as vc,existsSync as wc}from"fs";import Lo from"path";var bc=10*1024*1024;function J(o){return Lo.join(Q(o),"daemon.log")}c(J,"logFilePath");var ve=Y.dirname(Mo(import.meta.url));function Ne(){let o=[Y.resolve(ve,"..","..","bin","aitable-workflow.mjs"),Y.resolve(ve,"..","bin","aitable-workflow.mjs"),Y.resolve(ve,"..","..","dist","cli.js"),Y.resolve(ve,"cli.js")];return o.find(e=>jo(e))??o[0]}c(Ne,"resolveDaemonEntry");var Do=Ne();async function V(o){await ct(o.agentId);let e=["relay"];o.serverUrl&&e.push("--server-url",o.serverUrl),o.token&&e.push("--token",o.token),o.key&&e.push("--key",o.key),o.name&&e.push("--name",o.name),o.workspaceRoot&&e.push("--workspace-root",o.workspaceRoot),o.machineId&&e.push("--machine-id",o.machineId),o.maxTasks&&e.push("--max-tasks",String(o.maxTasks));let t=await import("fs").then(i=>{let a=J(o.agentId);return i.openSync(a,"a")}),n=Oo(process.execPath,[Do,...e],{detached:!0,stdio:["ignore",t,t],env:{...process.env}});try{let{closeSync:i}=await import("fs");i(t)}catch{}n.unref();let{writeFile:r}=await import("fs/promises"),{pidFilePath:s}=await import("./pid-file-KT5KHCKU.js");return n.pid&&await r(s(o.agentId),String(n.pid),"utf8"),{pid:n.pid??0}}c(V,"startDaemon");async function we(o,e=5e3){let t=await Se(o);if(t===null||!G(t))return await ee(o),!1;try{process.kill(t,"SIGTERM")}catch{return await ee(o),!1}let n=Date.now()+e;for(;Date.now()<n&&G(t);)await new Promise(r=>setTimeout(r,200));if(G(t))try{process.kill(t,"SIGKILL")}catch{}return await ee(o),!0}c(we,"stopDaemon");async function K(o){let e=await Se(o),t=e!==null&&G(e),n=null;if(t&&e!==null)try{let{readFile:r}=await import("fs/promises"),s=await r(`/proc/${e}/stat`,"utf8"),i=parseInt(s.split(" ")[21]??"0",10),a=await r("/proc/uptime","utf8"),p=parseFloat(a.split(" ")[0]??"0")-i/100;n=Math.round(p*1e3)}catch{}return{agentId:o,running:t,pid:t?e:null,uptimeMs:n,logFile:J(o)}}c(K,"getDaemonStatus");function es(o){return o.replace(/\/+$/,"").replace(/^ws/,"http")}c(es,"toHttpBase");var b="relay:daemon",be="relay:trace",an=["aitable"],ts="dws",ns=20,rs=500,os=2e4,on=8e3,Ue="127.0.0.1",ss=200,is=15e3,We=class{static{c(this,"AgentTraceRingBuffer")}maxRuns;maxEventsPerRun;now;runs=new Map;order=[];listeners=new Map;constructor(e={}){this.maxRuns=Math.max(1,Math.floor(e.maxRuns??ns)),this.maxEventsPerRun=Math.max(1,Math.floor(e.maxEventsPerRun??rs)),this.now=e.now??(()=>new Date().toISOString())}subscribeRun(e,t){let n=this.listeners.get(e);return n||(n=new Set,this.listeners.set(e,n)),n.add(t),()=>{let r=this.listeners.get(e);r&&(r.delete(t),r.size===0&&this.listeners.delete(e))}}notify(e){let t=this.listeners.get(e);if(!(!t||t.size===0))for(let n of[...t])try{n()}catch{}}startRun(e){this.runs.delete(e.requestId);let t=this.order.indexOf(e.requestId);if(t>=0&&this.order.splice(t,1),this.order.length>=this.maxRuns){let n=this.order.shift();n&&(this.runs.delete(n),this.notify(n))}this.order.push(e.requestId),this.runs.set(e.requestId,{...e,startedAt:this.now(),status:"running",events:[],eventCount:0,droppedEvents:0})}appendEvent(e,t){let n=this.runs.get(e);if(n){for(n.eventCount+=1,n.events.push(ln(t));n.events.length>this.maxEventsPerRun;)n.events.shift(),n.droppedEvents+=1;this.notify(e)}}finishRun(e,t){let n=this.runs.get(e);n&&(n.status=t.status,n.endedAt=this.now(),t.error&&(n.error=ze(t.error,on)),t.response&&(n.responsePreview=ze(t.response,on)),t.sessionId&&(n.sessionId=t.sessionId),this.notify(e))}listRuns(){return[...this.order].reverse().map(e=>this.runs.get(e)).filter(e=>!!e).map(e=>({...cn(e),eventBufferSize:e.events.length}))}getRun(e){let t=this.runs.get(e);return t?ls(t):void 0}},Ge=class{constructor(e,t){this.store=e;this.options=t;this.server=Ho((n,r)=>{this.handle(n,r).catch(s=>{let i=s instanceof Error?s.message:String(s);w.error(be,"trace http handler error",{error:i}),r.headersSent?r.end():v(r,500,{error:"internal_error"})})})}store;options;static{c(this,"AgentTraceHttpServer")}server;started=!1;start(){if(this.started)return Promise.resolve();let e=this.options.host??Ue;return new Promise((t,n)=>{let r=c(i=>{this.server.off("listening",s),n(i)},"onError"),s=c(()=>{this.server.off("error",r),this.started=!0,t()},"onListening");this.server.once("error",r),this.server.once("listening",s),this.server.listen(this.options.port,e)})}stop(){return this.started?new Promise((e,t)=>{this.server.close(n=>{if(n){t(n);return}this.started=!1,e()})}):Promise.resolve()}address(){let e=this.server.address();return!e||typeof e=="string"?null:{host:this.options.host??Ue,port:e.port}}async handle(e,t){let n=new URL(e.url??"/","http://127.0.0.1"),r=e.method??"GET";if(r==="GET"){await this.handleGet(n,t);return}if(r==="POST"){await this.handlePost(e,n,t);return}v(t,405,{error:"method_not_allowed"})}async handleGet(e,t){if(e.pathname==="/"||e.pathname==="/index.html"||e.pathname==="/assistant"||e.pathname==="/assistant/"){await this.serveAssistantFile(t,"index.html","text/html; charset=utf-8");return}if(e.pathname==="/classic"||e.pathname==="/classic/"){ye(t,200,"text/html; charset=utf-8",Bt);return}if(e.pathname==="/assets/workbench.css"){ye(t,200,"text/css; charset=utf-8",Ht);return}if(e.pathname==="/assets/workbench.js"){ye(t,200,"application/javascript; charset=utf-8",Ft);return}let n=/^\/assistant\/assets\/([A-Za-z0-9._-]+)$/.exec(e.pathname);if(n){let l=n[1]??"",d=l.endsWith(".css")?"text/css; charset=utf-8":l.endsWith(".js")?"application/javascript; charset=utf-8":"application/octet-stream";await this.serveAssistantFile(t,`assets/${l}`,d);return}if(e.pathname==="/health"){v(t,200,{ok:!0,chat:!!this.options.chat});return}if(e.pathname==="/api/chat/agents"){if(!this.options.chat){v(t,404,{error:"not_found"});return}v(t,200,{agents:this.options.chat.listAgents()});return}if(e.pathname==="/runs"){v(t,200,{runs:this.store.listRuns()});return}let r=/^\/runs\/([^/]+)\/events$/.exec(e.pathname);if(r){let l=decodeURIComponent(r[1]??""),d=this.store.getRun(l);if(!d){v(t,404,{error:"run_not_found"});return}v(t,200,{run:d,events:d.events});return}if(e.pathname==="/api/runs"){v(t,200,{runs:this.store.listRuns().map(ke)});return}let s=/^\/api\/runs\/([^/]+)$/.exec(e.pathname);if(s){let l=this.store.getRun(decodeURIComponent(s[1]??""));if(!l){v(t,404,{error:"run_not_found"});return}v(t,200,{run:ke(l)});return}let i=/^\/api\/runs\/([^/]+)\/events$/.exec(e.pathname);if(i){let l=this.store.getRun(decodeURIComponent(i[1]??""));if(!l){v(t,404,{error:"run_not_found"});return}let d=rn(l.events);v(t,200,{run:ke(l),groups:d,eventCount:l.eventCount,droppedEvents:l.droppedEvents});return}let a=/^\/api\/runs\/([^/]+)\/stream$/.exec(e.pathname);if(a){this.handleSse(t,decodeURIComponent(a[1]??""));return}v(t,404,{error:"not_found"})}async handlePost(e,t,n){let r=this.options.chat;if(!r){v(n,404,{error:"not_found"});return}let s=/^\/api\/chat\/([^/]+)\/stop$/.exec(t.pathname);if(s){let i=decodeURIComponent(s[1]??"");if(!r.stop(i)){v(n,404,{error:"no_active_chat"});return}v(n,200,{ok:!0,requestId:i});return}if(t.pathname==="/api/chat"){let i=await cs(e);if(!i.ok){v(n,i.status,{error:i.error});return}let a=i.value,l=r.start({requestId:typeof a.requestId=="string"?a.requestId:"",prompt:typeof a.prompt=="string"?a.prompt:"",...typeof a.agent=="string"?{agent:a.agent}:{},...typeof a.workDir=="string"?{workDir:a.workDir}:{},...typeof a.sessionId=="string"?{sessionId:a.sessionId}:{},...typeof a.timeoutMs=="number"?{timeoutMs:a.timeoutMs}:{}});if(!l.ok){v(n,l.status,{error:l.error});return}v(n,202,{accepted:!0,stream:`/api/runs/${encodeURIComponent(a.requestId??"")}/stream`});return}v(n,404,{error:"not_found"})}buildSnapshot(e){let t=this.store.getRun(e);return t?{run:ke(t),groups:rn(t.events)}:{run:null,groups:[]}}async serveAssistantFile(e,t,n){let r=this.resolveAssistantDir();if(r)try{let s=await sn(I.join(r,t));e.statusCode=200,e.setHeader("content-type",n),e.setHeader("cache-control","no-store"),e.end(s);return}catch{}ye(e,404,"text/plain; charset=utf-8","assistant UI \u672A\u6784\u5EFA\uFF1A\u5728 packages/cli \u4E0B\u6267\u884C pnpm run build\uFF08\u6216\u5355\u72EC\u6784\u5EFA assistant-ui \u5B50\u5305\uFF09\u540E\u91CD\u8BD5\u3002")}resolveAssistantDir(){if(this.options.assistantDir)return this.options.assistantDir;let e=[new URL("./assistant/",import.meta.url),new URL("../../dist/assistant/",import.meta.url)];for(let t of e){let n=Bo(t);try{if(qo(I.join(n,"index.html")))return n}catch{}}return null}handleSse(e,t){if(!this.store.getRun(t)){v(e,404,{error:"run_not_found"});return}e.statusCode=200,e.setHeader("content-type","text/event-stream; charset=utf-8"),e.setHeader("cache-control","no-cache, no-transform"),e.setHeader("connection","keep-alive"),e.setHeader("x-accel-buffering","no"),e.write(`retry: 3000
|
|
510
|
+
|
|
511
|
+
`);let n=!1,r=null,s=c((m,f)=>{e.write(`event: ${m}
|
|
512
|
+
data: ${JSON.stringify(f)}
|
|
513
|
+
|
|
514
|
+
`)},"writeFrame"),i=c(()=>{n||(n=!0,r&&clearTimeout(r),clearInterval(p),d(),e.end())},"cleanup"),a=c(()=>{if(r=null,n)return;let m=this.buildSnapshot(t);if(!m.run){s("finish",{run:null,groups:[]}),i();return}s("update",m),m.run.status!=="running"&&(s("finish",m),i())},"flush"),l=c(()=>{n||r||(r=setTimeout(a,ss))},"schedule"),d=this.store.subscribeRun(t,l),p=setInterval(()=>{n||e.write(`: ping
|
|
515
|
+
|
|
516
|
+
`)},is);p.unref?.(),e.on("close",i);let u=this.buildSnapshot(t);s("snapshot",u),(!u.run||u.run.status!=="running")&&(s("finish",u),i())}};function ye(o,e,t,n){o.statusCode=e,o.setHeader("content-type",t),o.setHeader("cache-control","no-store"),o.end(n)}c(ye,"sendTraceText");function ke(o){let{events:e,eventBufferSize:t,...n}=o;return{...n,id:o.requestId,source:o.source??"server_workflow"}}c(ke,"toWorkbenchRunSummary");function v(o,e,t){o.statusCode=e,o.setHeader("content-type","application/json; charset=utf-8"),o.end(JSON.stringify(t))}c(v,"sendTraceJson");var as=64e3;async function cs(o){let e=[],t=0;for await(let s of o){let i=Buffer.isBuffer(s)?s:Buffer.from(s);if(t+=i.length,t>as)return{ok:!1,status:413,error:"request_body_too_large"};e.push(i)}let n=Buffer.concat(e).toString("utf8").trim();if(n==="")return{ok:!1,status:400,error:"request_body_required"};let r;try{r=JSON.parse(n)}catch{return{ok:!1,status:400,error:"invalid_json"}}return typeof r!="object"||r===null||Array.isArray(r)?{ok:!1,status:400,error:"request_body_must_be_object"}:{ok:!0,value:r}}c(cs,"readJsonBody");function ls(o){return{...cn(o),events:o.events.map(e=>ln(e))}}c(ls,"cloneTraceRun");function cn(o){let{events:e,...t}=o;return{...t}}c(cn,"cloneRunWithoutEvents");function ln(o){return qe(o)}c(ln,"cloneTraceEvent");function qe(o){if(typeof o=="string")return ze(o,os);if(Array.isArray(o))return o.map(e=>qe(e));if(o&&typeof o=="object"){let e={};for(let[t,n]of Object.entries(o))e[t]=qe(n);return e}return o}c(qe,"clipTraceValue");function ze(o,e){return o.length<=e?o:`${o.slice(0,e)}... [truncated ${o.length-e} chars]`}c(ze,"clipTraceText");function ds(o){if(typeof o!="object"||o===null)return null;let e=o,t=typeof e.itemId=="string"?e.itemId:null,n=typeof e.stepId=="string"?e.stepId:null;if(!t||!n)return null;switch(e.type){case"step.started":return{op:"start",itemId:t,stepId:n};case"run.agent_event":{let r=typeof e.text=="string"?e.text:void 0,s=typeof e.tool=="string"?e.tool:void 0,i=typeof e.args=="string"?e.args:void 0,a=null;return e.kind==="text"?a={type:"text",content:r}:e.kind==="thinking"?a={type:"thinking",content:r}:e.kind==="tool_use"?a={type:"tool_use",toolName:s,toolInput:i}:e.kind==="tool_result"?a={type:"tool_result",content:r}:e.kind==="result"&&(a={type:"result",content:r}),a?{op:"event",itemId:t,stepId:n,event:a}:null}case"step.succeeded":return{op:"finish",itemId:t,stepId:n,status:"succeeded"};case"step.failed":return{op:"finish",itemId:t,stepId:n,status:"failed",error:typeof e.error=="string"?e.error:void 0};case"record.blocked":return{op:"finish",itemId:t,stepId:n,status:"failed",error:typeof e.reason=="string"?e.reason:void 0};default:return null}}c(ds,"toRunnerTraceProjection");function ps(o,e=an){if(!Array.isArray(o)||o.length===0)return{ok:!1,reason:"dws args must be a non-empty array"};for(let n of o){if(typeof n!="string")return{ok:!1,reason:"dws args must all be strings"};if(n.length===0)return{ok:!1,reason:"dws args must not contain empty tokens"};if(/[\u0000-\u001f]/.test(n))return{ok:!1,reason:"dws args must not contain control characters"}}let t=o[0];return t.startsWith("-")?{ok:!1,reason:"first dws arg must be a subcommand, not a flag"}:e.length>0&&!e.includes(t)?{ok:!1,reason:`dws command "${t}" is not allowed`}:{ok:!0}}c(ps,"validateDwsArgs");function us(o){return Xo(o,["--version"],Zo({timeoutMs:5e3})).ok}c(us,"detectDwsAvailable");var Je=class{static{c(this,"RelayDaemon")}config;allowedDwsCommands;conn;runAgent;createDwsClient;detectAgents;detectDws;hostname;osString;onPermanentReject;artifactUploader;grantTimeoutMs;pendingGrants=new Map;maxTasks;inflight=0;taskQueue=[];runnerLoop;traceStore;traceHttpServer;chatManager;machineId;constructor(e,t={}){this.config={...e,dwsBin:e.dwsBin??ts},this.machineId=e.machineId,this.allowedDwsCommands=e.allowedDwsCommands??an,this.runAgent=t.runAgent??Jo,this.createDwsClient=t.createDwsClient??((r,s)=>new Yo({bin:r,timeoutMs:s})),this.detectAgents=t.detectAgents??(()=>zo()),this.detectDws=t.detectDws??(r=>us(r)),this.hostname=t.hostname??(()=>M.hostname()),this.osString=t.osString??(()=>`${M.platform()} ${M.arch()}`),this.onPermanentReject=t.onPermanentReject,this.artifactUploader=t.artifactUploader??qt,this.grantTimeoutMs=t.grantTimeoutMs??3e4,this.maxTasks=Math.max(1,Math.floor(e.maxTasks??1)),this.traceStore=t.traceStore??new We({maxRuns:e.traceRunBufferSize,maxEventsPerRun:e.traceEventBufferSize}),this.chatManager=e.traceChat&&e.traceHttpPort!=null?new ae({workspaceRoot:this.config.workspaceRoot,store:this.traceStore,runAgent:this.runAgent,detectAgents:this.detectAgents,enqueue:c(r=>this.enqueueTask(r),"enqueue"),defaultTimeoutMs:e.agentTimeoutMs}):null,this.traceHttpServer=e.traceHttpPort!=null?new Ge(this.traceStore,{host:e.traceHttpHost??Ue,port:e.traceHttpPort,...this.chatManager?{chat:this.chatManager}:{}}):null;let n=t.createConnection??(r=>new ce(r));this.conn=n({serverUrl:this.config.serverUrl,key:this.config.key,token:this.config.token,onMessage:c(r=>this.handleMessage(r),"onMessage"),onOpen:c(()=>this.handleOpen(),"onOpen"),onPermanentReject:c(r=>this.handlePermanentReject(r),"onPermanentReject")}),this.runnerLoop=this.buildRunnerLoop(t)}buildRunnerLoop(e){let t=Math.max(0,Math.floor(this.config.maxWorkflows??3));if(t===0)return null;let n=this.config.key??this.config.token;if(!n)return w.warn(b,"\u65E0 machine key/owner-token\uFF0C\u8DF3\u8FC7 RunnerLoop\uFF08run \u9636\u6BB5\u4E0D\u8BA4\u9886\u9879\u76EE\uFF09"),null;let r={gatewayUrl:es(this.config.serverUrl),machineKey:n,workspaceRoot:this.config.workspaceRoot,cliPath:Ne(),maxWorkflows:t,sendRunEvents:c((s,i)=>this.sendRunEvents(s,i),"sendRunEvents"),onRunEvent:c((s,i)=>this.recordRunnerTrace(s,i),"onRunEvent")};return(e.createRunnerLoop??(s=>new he(s)))(r)}recordRunnerTrace(e,t){let n=ds(t);if(!n)return;let r=`run:${e}:${n.itemId}:${n.stepId}`;if(n.op==="start"){this.traceStore.getRun(r)||this.traceStore.startRun({requestId:r,projectId:e,agent:"engine",workDir:this.config.workspaceRoot??e});return}if(n.op==="event"){this.traceStore.getRun(r)||this.traceStore.startRun({requestId:r,projectId:e,agent:"engine",workDir:this.config.workspaceRoot??e}),this.traceStore.appendEvent(r,n.event);return}this.traceStore.finishRun(r,{status:n.status,...n.error?{error:n.error}:{}})}sendRunEvents(e,t){t.length!==0&&this.conn.send({type:"run:events",projectId:e,entries:t})}start(){w.info(b,"starting",{serverUrl:this.config.serverUrl,workspaceRoot:this.config.workspaceRoot}),this.config.name||w.warn(b,"\u672A\u6307\u5B9A --name\uFF0C\u5C06\u4F7F\u7528\u4E3B\u673A\u540D\u4F5C\u4E3A\u673A\u5668\u6CE8\u518C\u540D\uFF1B\u591A\u673A\u573A\u666F\u4E0B hostname \u82E5\u91CD\u590D\u4F1A\u5BFC\u81F4\u8FDE\u63A5\u4E92\u76F8\u9876\u66FF\uFF0C\u5EFA\u8BAE\u663E\u5F0F\u6307\u5B9A --name",{hostname:this.hostname()}),this.startTraceHttpServer(),this.conn.connect(),this.runnerLoop?.start()}stop(){w.info(b,"stopping"),this.conn.close();let e=[];return this.runnerLoop&&e.push(this.runnerLoop.stop().catch(t=>{w.warn(b,"runner loop \u505C\u6B62\u5F02\u5E38",{error:t instanceof Error?t.message:String(t)})})),this.traceHttpServer&&e.push(this.traceHttpServer.stop().catch(t=>{w.warn(be,"trace http \u505C\u6B62\u5F02\u5E38",{error:t instanceof Error?t.message:String(t)})})),Promise.all(e).then(()=>{})}startTraceHttpServer(){this.traceHttpServer&&this.traceHttpServer.start().then(()=>{let e=this.traceHttpServer?.address();e&&w.info(be,"trace http listening",{url:`http://${e.host}:${e.port}`})}).catch(e=>{w.warn(be,"trace http \u542F\u52A8\u5931\u8D25\uFF0C\u672C\u5730\u4E8B\u4EF6\u4ECD\u4FDD\u7559\u5728\u5185\u5B58\u4F46\u65E0\u6CD5 HTTP \u67E5\u770B",{error:e instanceof Error?e.message:String(e)})})}buildReady(){let t={type:"ready",runtimes:Array.from(new Set(this.detectAgents().map(n=>n.type))),hasDws:this.detectDws(this.config.dwsBin),hostname:this.hostname(),os:this.osString()};return this.machineId&&(t.machineId=this.machineId),this.config.name&&(t.name=this.config.name),this.config.displayName&&(t.displayName=this.config.displayName),this.config.description&&(t.description=this.config.description),this.maxTasks>1&&(t.maxTasks=this.maxTasks),t}handleOpen(){let e=this.buildReady();w.info(b,"connected; sending ready",{runtimes:e.runtimes,hasDws:e.hasDws}),this.conn.send(e)}handlePermanentReject(e){w.error(b,"permanently rejected by gateway",{...e}),this.onPermanentReject?.(e)}handleMessage(e){switch(e.type){case"run:agent":this.enqueueTask(()=>this.handleRunAgent(e));break;case"run:dws":this.enqueueTask(()=>this.handleRunDws(e));break;case"upload:grant":this.resolveGrant(e);break;case"wf:available":this.runnerLoop?.onWakeup();break;case"ready:ack":e.machineId&&(this.machineId=e.machineId,w.info(b,"machine id assigned",{machineId:e.machineId}));break;default:break}}enqueueTask(e){let t=c(()=>{this.inflight+=1,e().finally(()=>{this.inflight-=1;let n=this.taskQueue.shift();n&&n()})},"exec");this.inflight<this.maxTasks?t():this.taskQueue.push(t)}async handleRunAgent(e){let{requestId:t}=e;w.info(b,"run:agent received",{requestId:t,projectId:e.projectId,agent:e.agent});try{let n=this.resolveWorkDir(e.projectId,e.workDir);this.traceStore.startRun({requestId:t,projectId:e.projectId,agent:e.agent,workDir:n}),await Fo(n,{recursive:!0});let r=this.rewritePromptWorkDir(e.prompt,e.workDir,n),s={agent:e.agent,workDir:n,onEvent:c(l=>{this.traceStore.appendEvent(t,l),this.conn.send({type:"event",requestId:t,event:l})},"onEvent")};e.sessionId&&(s.sessionId=e.sessionId),e.permissionMode&&(s.adapterOptions={permissionMode:e.permissionMode}),e.timeoutMs!==void 0?s.timeoutMs=e.timeoutMs:this.config.agentTimeoutMs!=null&&(s.timeoutMs=this.config.agentTimeoutMs);let i=await this.runAgent(r,s),a;try{a=await this.collectAndUploadArtifacts(t,e.projectId,n)}catch(l){let d=l instanceof Error?l.message:String(l);w.error(b,"artifact upload failed",{requestId:t,error:d}),this.traceStore.finishRun(t,{status:"failed",error:d,sessionId:i.sessionId}),this.conn.send({type:"error",requestId:t,code:"artifact_upload_failed",message:d});return}this.traceStore.finishRun(t,{status:"succeeded",response:i.response,sessionId:i.sessionId}),this.conn.send({type:"result",requestId:t,ok:!0,response:i.response,sessionId:i.sessionId,...a?{artifacts:a}:{}}),w.info(b,"run:agent done",{requestId:t,sessionId:i.sessionId,artifacts:a?a.files.length:0})}catch(n){let r=n instanceof Error?n.message:String(n);w.error(b,"run:agent failed",{requestId:t,error:r}),this.traceStore.finishRun(t,{status:"failed",error:r}),this.conn.send({type:"error",requestId:t,code:"agent_failed",message:r})}}async collectAndUploadArtifacts(e,t,n){let r=await zt(n);if(r.length===0)return;this.conn.send({type:"upload:request",requestId:e,projectId:t,files:r.map(a=>({path:a.relPath,size:a.size,sha256:a.sha256}))});let s=await this.awaitGrant(e);if(!s)throw new Error("upload:grant \u7B49\u5F85\u8D85\u65F6");if(s.grants.length===0){w.warn(b,"upload:grant \u65E0\u6388\u6743\u9879\uFF08gateway \u672A\u914D\u7F6E store \u6216\u5168\u88AB\u62D2\uFF09",{requestId:e,rejected:(s.rejected??[]).length});return}let i=[];for(let a of s.grants){let l=r.find(p=>p.relPath===a.path);if(!l)continue;let d=await sn(l.absPath);await this.artifactUploader.upload(a.url,d,a.headers),i.push({path:a.path,key:a.key,sha256:l.sha256,size:l.size})}return{store:"oss",files:i}}awaitGrant(e){return new Promise(t=>{let n=setTimeout(()=>{this.pendingGrants.delete(e),t(void 0)},this.grantTimeoutMs);n.unref?.(),this.pendingGrants.set(e,r=>{clearTimeout(n),t(r)})})}resolveGrant(e){let t=this.pendingGrants.get(e.requestId);t&&(this.pendingGrants.delete(e.requestId),t(e))}async handleRunDws(e){let{requestId:t}=e,n=ps(e.args,this.allowedDwsCommands);if(!n.ok){w.warn(b,"run:dws rejected",{requestId:t,reason:n.reason}),this.conn.send({type:"error",requestId:t,code:"dws_rejected",message:n.reason});return}w.info(b,"run:dws received",{requestId:t,command:e.args[0]});let r=e.args,s;try{let i=await this.materializeInlineFiles(e.args,e.inlineFiles);r=i.args,s=i.tmpDir;let l=await this.createDwsClient(this.config.dwsBin,e.timeoutMs).runJson(r,e.timeoutMs!=null?{timeoutMs:e.timeoutMs}:void 0);this.conn.send({type:"result",requestId:t,ok:!0,response:JSON.stringify(l)}),w.info(b,"run:dws done",{requestId:t})}catch(i){let a=i instanceof Error?i.message:String(i);w.error(b,"run:dws failed",{requestId:t,error:a}),this.conn.send({type:"error",requestId:t,code:"dws_failed",message:a})}finally{s&&await Wo(s,{recursive:!0,force:!0}).catch(()=>{})}}async materializeInlineFiles(e,t){let n=t?Object.entries(t):[];if(n.length===0)return{args:e};let r=await No(I.join(M.tmpdir(),"aitable-dws-records-")),s=e,i=0;for(let[a,l]of n){let d=I.join(r,`records-${i++}.json`);await Uo(d,l,"utf8"),s=Qo(s,a,d)}return{args:s,tmpDir:r}}resolveWorkDir(e,t){return ie(this.config.workspaceRoot,e,t)}rewritePromptWorkDir(e,t,n){let r=t?.trim();return!r||!I.isAbsolute(r)||r===n?e:e.split(r).join(n)}};function Ye(o,e){let t,n=o?.trim();if(n)t=I.isAbsolute(n)?I.resolve(n):I.resolve(M.homedir(),n);else{let r=e?.trim()?e.trim():"default";t=I.join(M.homedir(),".aitable-workflow","workspaces",Ko(r,{label:"agentId"}))}return Go(t,{recursive:!0}),t}c(Ye,"resolveWorkspaceRoot");function ms(o,e=process.env){let t=o.serverUrl??e.AITABLE_RELAY_SERVER_URL,n=o.key??e.AITABLE_RELAY_BOOTSTRAP_KEY,r=o.token??e.AITABLE_RELAY_TOKEN,s=o.workspaceRoot??e.AITABLE_RELAY_WORKSPACE_ROOT,i=o.machineId??e.AITABLE_RELAY_MACHINE_ID,a=o.name??e.AITABLE_RELAY_NAME,l=o.desc??e.AITABLE_RELAY_DESC,d=o.maxTasks??e.AITABLE_RELAY_MAX_TASKS,p=o.maxWorkflows??e.AITABLE_RELAY_MAX_WORKFLOWS,u=o.traceHttpPort??e.AITABLE_RELAY_TRACE_HTTP_PORT,m=o.traceHttpHost??e.AITABLE_RELAY_TRACE_HTTP_HOST,f=o.traceBufferSize??e.AITABLE_RELAY_TRACE_BUFFER_SIZE,R=o.traceEventsPerRun??e.AITABLE_RELAY_TRACE_EVENTS_PER_RUN,S=o.traceChat??e.AITABLE_RELAY_TRACE_CHAT,E=[];if(t||E.push("--server-url (\u6216 AITABLE_RELAY_SERVER_URL)"),!n&&!r&&E.push("--key/--token (\u6216 AITABLE_RELAY_BOOTSTRAP_KEY/AITABLE_RELAY_TOKEN)"),E.length>0)throw new Error(`relay \u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${E.join(", ")}
|
|
517
|
+
\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 \`aitable-workflow connect\` \u6CE8\u518C\u540E\u53EF\u7701\u7565\u8FD9\u4E9B\u53C2\u6570`);let H=a??M.hostname()??"default",g={serverUrl:t,workspaceRoot:Ye(s,H)};if(r?g.token=r:n&&(g.key=n),i&&(g.machineId=i),a&&(g.name=a,g.displayName=a),l&&(g.description=l),d!=null&&d!==""){let h=Math.floor(Number(d));Number.isFinite(h)&&h>=1&&(g.maxTasks=h)}if(p!=null&&p!==""){let h=Math.floor(Number(p));Number.isFinite(h)&&h>=0&&(g.maxWorkflows=h)}if(u!=null&&u!==""){let h=Math.floor(Number(u));Number.isFinite(h)&&h>=0&&(g.traceHttpPort=h)}if(m?.trim()&&(g.traceHttpHost=m.trim()),f!=null&&f!==""){let h=Math.floor(Number(f));Number.isFinite(h)&&h>=1&&(g.traceRunBufferSize=h)}if(R!=null&&R!==""){let h=Math.floor(Number(R));Number.isFinite(h)&&h>=1&&(g.traceEventBufferSize=h)}return fs(S)&&(g.traceChat=!0),g}c(ms,"resolveRelayCliConfig");function fs(o){return typeof o=="boolean"?o:typeof o!="string"?!1:["1","true","yes","on"].includes(o.trim().toLowerCase())}c(fs,"isTruthyFlag");async function U(o,e=process.env){let t=null;try{t=await Vo()}catch{t=null}let n={serverUrl:o.serverUrl??e.AITABLE_RELAY_SERVER_URL??t?.serverUrl,key:o.key??e.AITABLE_RELAY_BOOTSTRAP_KEY??t?.key,token:o.token??e.AITABLE_RELAY_TOKEN??t?.token,name:o.name??e.AITABLE_RELAY_NAME??t?.name,desc:o.desc??e.AITABLE_RELAY_DESC,workspaceRoot:o.workspaceRoot??e.AITABLE_RELAY_WORKSPACE_ROOT??t?.workspaceRoot,machineId:o.machineId??e.AITABLE_RELAY_MACHINE_ID??t?.machineId,maxTasks:o.maxTasks??e.AITABLE_RELAY_MAX_TASKS,maxWorkflows:o.maxWorkflows??e.AITABLE_RELAY_MAX_WORKFLOWS,traceHttpPort:o.traceHttpPort??e.AITABLE_RELAY_TRACE_HTTP_PORT,traceHttpHost:o.traceHttpHost??e.AITABLE_RELAY_TRACE_HTTP_HOST,traceBufferSize:o.traceBufferSize??e.AITABLE_RELAY_TRACE_BUFFER_SIZE,traceEventsPerRun:o.traceEventsPerRun??e.AITABLE_RELAY_TRACE_EVENTS_PER_RUN,traceChat:o.traceChat??e.AITABLE_RELAY_TRACE_CHAT};return ms(n,e)}c(U,"resolveDaemonConfig");async function Re(o){let e=await U(o),t=new Je(e,{onPermanentReject:c(()=>{process.exit(1)},"onPermanentReject")}),n=!1,r=c(()=>{n&&(w.warn(b,"\u518D\u6B21\u6536\u5230\u9000\u51FA\u4FE1\u53F7\uFF0C\u5F3A\u5236\u9000\u51FA"),process.exit(1)),n=!0,t.stop().catch(()=>{}).finally(()=>process.exit(0))},"shutdown");return process.on("SIGINT",r),process.on("SIGTERM",r),t.start(),t}c(Re,"runRelayDaemon");import{readFile as gs,writeFile as Kc,mkdir as Xc}from"fs/promises";import hs from"path";var dn={connectionState:"disconnected",lastHeartbeatAt:null,machineId:null,serverUrl:"",runningTasks:0,queuedTasks:0,lastDisconnectReason:null,updatedAt:new Date().toISOString()};function vs(o){return hs.join(Q(o),"state.json")}c(vs,"stateFilePath");async function Ce(o){try{let e=await gs(vs(o),"utf8");return{...dn,...JSON.parse(e)}}catch{return{...dn}}}c(Ce,"readState");import{execSync as X}from"child_process";import{writeFile as ws,rm as ys,mkdir as ks,access as bs}from"fs/promises";import _ from"path";import pn from"os";import{assertPortableId as Rs,readCredentials as Cs}from"aitable-workflow-core";var xs="com.alibaba.aitable-workflow.daemon",Ve="\u8BF7\u5148\u5168\u5C40\u5B89\u88C5\uFF1Anpm i -g @ali/aitable-workflow";function Z(o){return`${xs}.${Rs(o,{label:"agentId"})}`}c(Z,"plistLabel");function Ke(o){return _.join(pn.homedir(),"Library","LaunchAgents",`${Z(o)}.plist`)}c(Ke,"plistPath");function D(){return process.platform==="darwin"}c(D,"isMacOS");function un(){try{return X("which aitable-workflow",{encoding:"utf8"}).trim()||null}catch{return null}}c(un,"resolveGlobalCliEntry");function mn(o){if(!o||!o.trim())throw new Error(`\u672A\u627E\u5230\u5168\u5C40\u5B89\u88C5\u7684 aitable-workflow CLI \u5165\u53E3\uFF0C\u65E0\u6CD5\u914D\u7F6E\u5F00\u673A\u81EA\u542F\u3002
|
|
518
|
+
\u{1F4A1} ${Ve}`);if(o.includes("/_npx/")||o.includes(`${_.sep}_npx${_.sep}`))throw new Error(`\u68C0\u6D4B\u5230 CLI \u5165\u53E3\u4F4D\u4E8E npx \u4E34\u65F6\u7F13\u5B58\uFF0C\u5F00\u673A\u81EA\u542F\u4F1A\u5931\u6548\uFF1A${o}
|
|
519
|
+
\u{1F4A1} ${Ve}`);if(!_.isAbsolute(o))throw new Error(`CLI \u5165\u53E3\u4E0D\u662F\u7A33\u5B9A\u7684\u5168\u5C40\u7EDD\u5BF9\u8DEF\u5F84\uFF1A${o}
|
|
520
|
+
\u{1F4A1} ${Ve}`)}c(mn,"assertStableCliEntry");async function As(o){let e={};e.AITABLE_RELAY_NAME=o;let t;try{let n=await Cs();t=n.agents.find(r=>r.name===o)??n.agents.find(r=>r.name===n.activeAgent)??void 0}catch{t=void 0}return t&&(t.serverUrl&&(e.AITABLE_RELAY_SERVER_URL=t.serverUrl),t.token&&(e.AITABLE_RELAY_TOKEN=t.token),t.workspaceRoot&&(e.AITABLE_RELAY_WORKSPACE_ROOT=t.workspaceRoot)),e}c(As,"buildRelayEnv");function Es(o,e){let t=Z(o),n=e?.cliEntry??un();mn(n);let r=["relay"];e?.maxTasks&&r.push("--max-tasks",String(e.maxTasks));let s=_.join(pn.homedir(),".aitable-workflow","daemons",o),i=_.join(s,"launchd.log"),a=_.join(s,"launchd.err.log"),l=[n,...r].map(u=>` <string>${W(u)}</string>`).join(`
|
|
521
|
+
`),d={PATH:process.env.PATH??"/usr/local/bin:/usr/bin:/bin",...e?.relayEnv??{}},p=Object.entries(d).map(([u,m])=>` <key>${W(u)}</key>
|
|
522
|
+
<string>${W(m)}</string>`).join(`
|
|
35
523
|
`);return`<?xml version="1.0" encoding="UTF-8"?>
|
|
36
524
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
37
525
|
<plist version="1.0">
|
|
38
526
|
<dict>
|
|
39
527
|
<key>Label</key>
|
|
40
|
-
<string>${
|
|
528
|
+
<string>${W(t)}</string>
|
|
41
529
|
<key>ProgramArguments</key>
|
|
42
530
|
<array>
|
|
43
531
|
${l}
|
|
44
532
|
</array>
|
|
45
533
|
<key>EnvironmentVariables</key>
|
|
46
534
|
<dict>
|
|
47
|
-
${
|
|
535
|
+
${p}
|
|
48
536
|
</dict>
|
|
49
537
|
<key>KeepAlive</key>
|
|
50
538
|
<true/>
|
|
51
539
|
<key>RunAtLoad</key>
|
|
52
540
|
<true/>
|
|
53
541
|
<key>StandardOutPath</key>
|
|
54
|
-
<string>${
|
|
542
|
+
<string>${W(i)}</string>
|
|
55
543
|
<key>StandardErrorPath</key>
|
|
56
|
-
<string>${
|
|
544
|
+
<string>${W(a)}</string>
|
|
57
545
|
</dict>
|
|
58
546
|
</plist>
|
|
59
|
-
`}c(
|
|
60
|
-
Agent: ${
|
|
61
|
-
--- Configuration ---`),console.log(`Server: ${
|
|
62
|
-
`);console.log(
|
|
63
|
-
`))}let l=a.length;
|
|
64
|
-
`);console.log(l.slice(-
|
|
65
|
-
`))}}catch(
|
|
66
|
-
Agent: ${n.agentId}`),console.log(`Installed: ${
|
|
547
|
+
`}c(Es,"generatePlist");function W(o){return o.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}c(W,"escapeXml");function xe(){let o=process.getuid?.();if(o===void 0)throw new Error("\u65E0\u6CD5\u83B7\u53D6\u7528\u6237 UID\uFF08\u4EC5\u652F\u6301 macOS/Linux\uFF09");return o}c(xe,"getUid");async function fn(o,e){if(!D())throw new Error("\u5F00\u673A\u81EA\u542F\u5F53\u524D\u4EC5\u652F\u6301 macOS");let t=un();mn(t);let n=await As(o),r=Ke(o),s=Z(o);try{X(`launchctl bootout gui/${xe()}/${s} 2>/dev/null`,{encoding:"utf8"})}catch{}await ks(_.dirname(r),{recursive:!0});let i=Es(o,{maxTasks:e?.maxTasks,relayEnv:n,cliEntry:t});await ws(r,i,"utf8"),X(`launchctl bootstrap gui/${xe()} ${r}`,{encoding:"utf8"})}c(fn,"enableAutostart");async function gn(o){if(!D())throw new Error("\u5F00\u673A\u81EA\u542F\u5F53\u524D\u4EC5\u652F\u6301 macOS");let e=Z(o),t=Ke(o);try{X(`launchctl bootout gui/${xe()}/${e} 2>/dev/null`,{encoding:"utf8"})}catch{}await ys(t,{force:!0})}c(gn,"disableAutostart");async function Xe(o){if(!D())throw new Error("\u5F00\u673A\u81EA\u542F\u5F53\u524D\u4EC5\u652F\u6301 macOS");let e=Z(o),t=Ke(o),n=!1;try{await bs(t),n=!0}catch{n=!1}let r=!1,s=!1,i=null;try{let a=X(`launchctl print gui/${xe()}/${e} 2>/dev/null`,{encoding:"utf8"});r=!0;let l=a.match(/pid\s*=\s*(\d+)/);l&&(i=parseInt(l[1],10),s=!0)}catch{r=!1}return{installed:n,loaded:r,running:s,pid:i}}c(Xe,"getAutostartStatus");import{watchFile as Is,statSync as Ts,openSync as _s,readSync as Ps,closeSync as $s}from"fs";import{readFile as vn}from"fs/promises";function wn(o,e){let t=o.command("daemon").description("\u540E\u53F0 relay daemon \u751F\u547D\u5468\u671F\u7BA1\u7406");t.command("start").description("\u4EE5\u540E\u53F0\u8FDB\u7A0B\u542F\u52A8 relay daemon").option("--agent <name>","Agent \u540D\u79F0\uFF08\u9ED8\u8BA4\u4F7F\u7528 activeAgent\uFF09").option("--server-url <url>","Gateway \u5730\u5740").option("--token <ownerToken>","owner-token").option("--key <machineKey>","per-machine key\uFF08sk_machine_*\uFF09").option("--workspace-root <dir>","\u5DE5\u4F5C\u533A\u6839\u76EE\u5F55").option("--max-tasks <n>","\u5E76\u53D1\u4E0A\u9650","1").action(async n=>{try{let r=n.agent;if(!r){let a=await B();if(!a)throw new Error("\u672A\u6307\u5B9A --agent \u4E14\u65E0\u6D3B\u8DC3 Agent\u3002\u4F7F\u7528 `aitable-workflow connect` \u6CE8\u518C\u6216 `--agent <name>` \u6307\u5B9A\u3002");r=a.name}let s=await U({serverUrl:n.serverUrl,token:n.token,key:n.key,workspaceRoot:n.workspaceRoot,name:r,maxTasks:n.maxTasks}),i=await V({agentId:r,serverUrl:s.serverUrl,token:s.token,key:s.key,name:s.name??r,workspaceRoot:s.workspaceRoot,machineId:s.machineId,maxTasks:s.maxTasks});console.log("\u2705 Daemon \u5DF2\u542F\u52A8"),console.log(` Agent: ${r}`),console.log(` PID: ${i.pid}`),console.log(` Log: ~/.aitable-workflow/daemons/${r}/daemon.log`)}catch(r){T.error("cli","start \u5931\u8D25",{error:r instanceof Error?r.message:String(r)}),process.exit(1)}}),t.command("stop").description("\u505C\u6B62\u540E\u53F0 daemon").option("--agent <name>","Agent \u540D\u79F0").option("--all","\u505C\u6B62\u6240\u6709 daemon").action(async n=>{try{if(n.all){let r=await hn(),s=0;for(let i of r)await we(i.name)&&s++;console.log(`\u2705 \u5DF2\u505C\u6B62 ${s} \u4E2A daemon`)}else{let r=n.agent;if(!r){let i=await B();if(!i)throw new Error("\u672A\u6307\u5B9A --agent \u4E14\u65E0\u6D3B\u8DC3 Agent");r=i.name}let s=await we(r);console.log(s?`\u2705 Daemon "${r}" \u5DF2\u505C\u6B62`:`\u26A0\uFE0F Daemon "${r}" \u672A\u5728\u8FD0\u884C`)}}catch(r){T.error("cli","stop \u5931\u8D25",{error:r instanceof Error?r.message:String(r)}),process.exit(1)}}),t.command("restart").description("\u91CD\u542F\u540E\u53F0 daemon").option("--agent <name>","Agent \u540D\u79F0").option("--max-tasks <n>","\u5E76\u53D1\u4E0A\u9650","1").action(async n=>{try{let r=n.agent;if(!r){let a=await B();if(!a)throw new Error("\u672A\u6307\u5B9A --agent \u4E14\u65E0\u6D3B\u8DC3 Agent");r=a.name}console.log(`\u{1F504} \u6B63\u5728\u91CD\u542F "${r}"...`),await we(r);let s=await U({name:r,maxTasks:n.maxTasks}),i=await V({agentId:r,serverUrl:s.serverUrl,token:s.token,key:s.key,name:s.name??r,workspaceRoot:s.workspaceRoot,machineId:s.machineId,maxTasks:s.maxTasks});console.log(`\u2705 Daemon \u5DF2\u91CD\u542F (PID: ${i.pid})`)}catch(r){T.error("cli","restart \u5931\u8D25",{error:r instanceof Error?r.message:String(r)}),process.exit(1)}}),t.command("status").description("\u67E5\u770B daemon \u72B6\u6001").option("--agent <name>","Agent \u540D\u79F0").option("-v, --verbose","\u5C55\u793A\u5B8C\u6574\u914D\u7F6E").action(async n=>{try{let r=n.agent;if(!r){let a=await B();if(!a){console.log("\u65E0\u6D3B\u8DC3 Agent");return}r=a.name}let s=await K(r),i=await B();if(console.log(`
|
|
548
|
+
Agent: ${s.agentId}`),console.log(`Running: ${s.running?"\u2705 yes":"\u274C no"}`),s.pid&&console.log(`PID: ${s.pid}`),s.uptimeMs!==null){let a=Math.floor(s.uptimeMs/1e3),l=Math.floor(a/60),d=Math.floor(l/60);console.log(`Uptime: ${d}h ${l%60}m ${a%60}s`)}console.log(`Log file: ${s.logFile}`),n.verbose&&i&&(console.log(`
|
|
549
|
+
--- Configuration ---`),console.log(`Server: ${i.serverUrl}`),console.log(`Token: ${Ss(i.token)}`),i.machineId&&console.log(`MachineID: ${i.machineId}`),i.workspaceRoot&&console.log(`Workspace: ${i.workspaceRoot}`)),console.log("")}catch(r){T.error("cli","status \u5931\u8D25",{error:r instanceof Error?r.message:String(r)}),process.exit(1)}}),t.command("logs").description("\u67E5\u770B daemon \u65E5\u5FD7").option("--agent <name>","Agent \u540D\u79F0").option("-f, --follow","\u6301\u7EED\u8DDF\u8E2A\u65E5\u5FD7\u8F93\u51FA").option("-n <lines>","\u663E\u793A\u6700\u8FD1 N \u884C","50").action(async n=>{try{let r=n.agent;if(!r){let a=await B();if(!a)throw new Error("\u672A\u6307\u5B9A --agent \u4E14\u65E0\u6D3B\u8DC3 Agent");r=a.name}let s=J(r),i=parseInt(n.n,10)||50;if(n.follow){let a=await vn(s,"utf8").catch(()=>"");if(a){let d=a.trimEnd().split(`
|
|
550
|
+
`);console.log(d.slice(-i).join(`
|
|
551
|
+
`))}let l=a.length;Is(s,{interval:500},()=>{try{let d=Ts(s);if(d.size>l){let p=_s(s,"r"),u=Buffer.alloc(d.size-l);Ps(p,u,0,u.length,l),$s(p),process.stdout.write(u.toString("utf8")),l=d.size}}catch{}})}else{let a=await vn(s,"utf8").catch(()=>"");if(!a){console.log(`\u6682\u65E0\u65E5\u5FD7 (${s})`);return}let l=a.trimEnd().split(`
|
|
552
|
+
`);console.log(l.slice(-i).join(`
|
|
553
|
+
`))}}catch(r){T.error("cli","logs \u5931\u8D25",{error:r instanceof Error?r.message:String(r)}),process.exit(1)}}),t.command("autostart").description("macOS \u5F00\u673A\u81EA\u542F\u7BA1\u7406").addCommand(new Ze("enable").description("\u542F\u7528 macOS \u767B\u5F55\u81EA\u542F\u52A8").requiredOption("--agent-id <id>","Agent ID / \u540D\u79F0").option("--max-tasks <n>","\u5E76\u53D1\u4E0A\u9650").action(async n=>{try{D()||(console.error("\u274C \u5F00\u673A\u81EA\u542F\u5F53\u524D\u4EC5\u652F\u6301 macOS"),process.exit(1)),await fn(n.agentId,{maxTasks:n.maxTasks?parseInt(n.maxTasks,10):void 0}),console.log("\u2705 \u81EA\u542F\u52A8\u5DF2\u542F\u7528"),console.log(` Agent: ${n.agentId}`),console.log(` Plist: ~/Library/LaunchAgents/com.alibaba.aitable-workflow.daemon.${n.agentId}.plist`)}catch(r){T.error("cli","autostart enable \u5931\u8D25",{error:r instanceof Error?r.message:String(r)}),process.exit(1)}})).addCommand(new Ze("disable").description("\u5173\u95ED macOS \u767B\u5F55\u81EA\u542F\u52A8").requiredOption("--agent-id <id>","Agent ID / \u540D\u79F0").action(async n=>{try{D()||(console.error("\u274C \u5F00\u673A\u81EA\u542F\u5F53\u524D\u4EC5\u652F\u6301 macOS"),process.exit(1)),await gn(n.agentId),console.log(`\u2705 \u81EA\u542F\u52A8\u5DF2\u5173\u95ED (${n.agentId})`)}catch(r){T.error("cli","autostart disable \u5931\u8D25",{error:r instanceof Error?r.message:String(r)}),process.exit(1)}})).addCommand(new Ze("status").description("\u67E5\u770B macOS \u81EA\u542F\u52A8\u72B6\u6001").option("--agent-id <id>","Agent ID / \u540D\u79F0\uFF08\u4E0D\u6307\u5B9A\u5219\u5217\u51FA\u6240\u6709\uFF09").action(async n=>{try{if(D()||(console.error("\u274C \u5F00\u673A\u81EA\u542F\u5F53\u524D\u4EC5\u652F\u6301 macOS"),process.exit(1)),n.agentId){let r=await Xe(n.agentId);console.log(`
|
|
554
|
+
Agent: ${n.agentId}`),console.log(`Installed: ${r.installed?"yes":"no"}`),console.log(`Loaded: ${r.loaded?"yes":"no"}`),console.log(`Running: ${r.running?`yes (PID: ${r.pid})`:"no"}`),console.log("")}else{let r=await hn();if(r.length===0){console.log("\u65E0\u5DF2\u6CE8\u518C\u7684 Agent");return}for(let s of r){let i=await Xe(s.name),a=i.running?`running (PID: ${i.pid})`:i.loaded?"loaded":i.installed?"installed":"not installed";console.log(` ${s.name}: ${a}`)}}}catch(r){T.error("cli","autostart status \u5931\u8D25",{error:r instanceof Error?r.message:String(r)}),process.exit(1)}}))}c(wn,"registerDaemonCommands");function yn(o,e){o.command("heartbeat").description("\u5411\u670D\u52A1\u7AEF\u53D1\u9001\u5FC3\u8DF3\u5E76\u8FD4\u56DE\u4EFB\u52A1\u5206\u914D\u60C5\u51B5").action(async()=>{try{let t=await B();if(!t)throw new Error("\u65E0\u6D3B\u8DC3 Agent");if(!(await K(t.name)).running){console.log("\u26A0\uFE0F Daemon \u672A\u5728\u8FD0\u884C\u3002\u4F7F\u7528 `aitable-workflow daemon start` \u542F\u52A8\u3002");return}let r=await Ce(t.name);console.log("\u2705 Heartbeat OK"),console.log(` Agent: ${t.name}`),console.log(` Connection: ${r.connectionState}`),console.log(` Running: ${r.runningTasks} tasks`),console.log(` Queued: ${r.queuedTasks} tasks`),r.lastHeartbeatAt&&console.log(` Last HB: ${r.lastHeartbeatAt}`)}catch(t){T.error("cli","heartbeat \u5931\u8D25",{error:t instanceof Error?t.message:String(t)}),process.exit(1)}})}c(yn,"registerHeartbeatCommand");import{logger as Ls,saveCredential as Os,findConflictingCredential as js,maskSecret as Ms}from"aitable-workflow-core";function kn(o,e){o.command("connect").description("\u4E00\u952E\u6CE8\u518C + \u4FDD\u5B58\u51ED\u8BC1 + \u540E\u53F0\u542F\u52A8 daemon\uFF08\u5BF9\u6807 Harness connect\uFF09").requiredOption("--server-url <url>","Gateway / \u5E73\u53F0\u5730\u5740").option("--token <ownerToken>","owner-token\uFF08\u81EA\u6CE8\u518C\uFF0C\u4E0E --key \u4E8C\u9009\u4E00\uFF09").option("--key <machineKey>","per-machine key\uFF08sk_machine_*\uFF0C\u4E0E --token \u4E8C\u9009\u4E00\uFF09").requiredOption("--name <name>","Agent \u540D\u79F0").option("--workspace-root <dir>","\u5DE5\u4F5C\u533A\u6839\u76EE\u5F55\uFF08\u53EF\u9009\uFF09").option("--no-start","\u53EA\u6CE8\u518C\u4E0D\u542F\u52A8 daemon").option("--foreground","\u6CE8\u518C\u540E\u5728\u524D\u53F0\u8FD0\u884C relay\uFF08\u963B\u585E\u7EC8\u7AEF\uFF0C\u4FBF\u4E8E\u8C03\u8BD5\uFF09").option("--force","\u8986\u76D6\u540C\u540D\u4F46\u7F51\u5173\u4E0D\u540C\u7684\u5DF2\u6709\u51ED\u8BC1").action(async t=>{try{if(!t.token&&!t.key)throw new Error("\u5FC5\u987B\u63D0\u4F9B --token\uFF08owner-token\uFF09\u6216 --key\uFF08per-machine key\uFF0Csk_machine_*\uFF09\u5176\u4E2D\u4E4B\u4E00\u3002");if(!t.force){let l=await js(t.name,t.serverUrl);l&&(console.error(`\u26A0\uFE0F \u62D2\u7EDD\u8986\u76D6\uFF1AAgent \u540D\u79F0 "${t.name}" \u5DF2\u7ED1\u5B9A\u5230\u53E6\u4E00\u4E2A\u7F51\u5173\u3002`),console.error(` \u65E7\u7F51\u5173: ${l.serverUrl}`),console.error(` \u65B0\u7F51\u5173: ${t.serverUrl}`),console.error(" \u7EE7\u7EED\u5C06\u8986\u76D6\u672C\u673A\u8BE5\u51ED\u8BC1\uFF0C\u4E14\u65E7\u7F51\u5173\u7684 daemon \u65E0\u6CD5\u4E0E\u65B0\u7684\u5171\u5B58\uFF08PID \u4E92\u65A5\uFF09\u3002"),console.error(" \u8BF7\u9009\u62E9\u5176\u4E00\uFF1A"),console.error(" 1) \u6362\u4E00\u4E2A --name\uFF08\u591A\u7F51\u5173\u5EFA\u8BAE\u6BCF\u4E2A\u7F51\u5173\u7528\u4E0D\u540C\u540D\u79F0\uFF09"),console.error(" 2) \u786E\u5B9E\u8981\u6539\u7ED1\uFF0C\u52A0 --force \u5F3A\u5236\u8986\u76D6"),process.exit(1))}let n=t.workspaceRoot?Ye(t.workspaceRoot,t.name):void 0,r={name:t.name,serverUrl:t.serverUrl,token:t.token??"",key:t.key,workspaceRoot:n,createdAt:new Date().toISOString()};if(await Os(r),console.log(`\u2705 Agent "${t.name}" \u5DF2\u6CE8\u518C\u5E76\u4FDD\u5B58\u51ED\u8BC1`),console.log(` Server: ${t.serverUrl}`),console.log(` ${t.token?"Token":"Key"}: ${Ms(t.token??t.key??"")}`),n&&console.log(` Workspace: ${n}`),console.log(" \u51ED\u8BC1\u6587\u4EF6: ~/.aitable-workflow/credentials.json"),!t.start){t.foreground&&console.log(`
|
|
67
555
|
\u{1F4A1} --no-start \u4E0E --foreground \u540C\u65F6\u6307\u5B9A\uFF0C\u6309 --no-start \u4F18\u5148\uFF1A\u4EC5\u6CE8\u518C\u4E0D\u542F\u52A8\u3002`),console.log(`
|
|
68
|
-
\u{1F4A1} \u542F\u52A8 daemon: aitable-workflow daemon start \u6216 aitable-workflow relay`);return}if(
|
|
69
|
-
\u{1F680} \u524D\u53F0\u542F\u52A8 relay\uFF08Ctrl-C \u9000\u51FA\uFF09...`),await
|
|
70
|
-
\u{1F680} Daemon \u5DF2\u540E\u53F0\u542F\u52A8`),console.log(` Agent: ${
|
|
71
|
-
\u{1F4CB} \u5E38\u7528\u547D\u4EE4\uFF1A`),console.log(` \u67E5\u770B\u72B6\u6001: aitable-workflow daemon status --agent ${
|
|
72
|
-
\u5DF2\u4FDD\u5B58 ${n.length} \u4E2A Agent\uFF08\u6D3B\u8DC3: ${
|
|
73
|
-
`);for(let
|
|
556
|
+
\u{1F4A1} \u542F\u52A8 daemon: aitable-workflow daemon start \u6216 aitable-workflow relay`);return}if(t.foreground){console.log(`
|
|
557
|
+
\u{1F680} \u524D\u53F0\u542F\u52A8 relay\uFF08Ctrl-C \u9000\u51FA\uFF09...`),await Re({serverUrl:t.serverUrl,token:t.token,key:t.key,name:t.name,workspaceRoot:n});return}let s=t.name,i=await U({serverUrl:t.serverUrl,token:t.token,key:t.key,workspaceRoot:t.workspaceRoot,name:s}),a=await V({agentId:s,serverUrl:i.serverUrl,token:i.token,key:i.key,name:i.name??s,workspaceRoot:i.workspaceRoot,machineId:i.machineId,maxTasks:i.maxTasks});console.log(`
|
|
558
|
+
\u{1F680} Daemon \u5DF2\u540E\u53F0\u542F\u52A8`),console.log(` Agent: ${s}`),console.log(` PID: ${a.pid}`),console.log(` Log: ~/.aitable-workflow/daemons/${s}/daemon.log`),console.log(`
|
|
559
|
+
\u{1F4CB} \u5E38\u7528\u547D\u4EE4\uFF1A`),console.log(` \u67E5\u770B\u72B6\u6001: aitable-workflow daemon status --agent ${s}`),console.log(` \u8DDF\u8E2A\u65E5\u5FD7: aitable-workflow daemon logs -f --agent ${s}`),console.log(` \u505C\u6B62: aitable-workflow daemon stop --agent ${s}`),console.log(` \u91CD\u542F: aitable-workflow daemon restart --agent ${s}`),console.log(" \u5217\u51FA Agent: aitable-workflow agent list"),console.log(" \u5207\u6362 Agent: aitable-workflow agent use <name>"),console.log(` \u5F00\u673A\u81EA\u542F: aitable-workflow daemon autostart enable --agent-id ${s}`)}catch(n){Ls.error("cli","connect \u5931\u8D25",{error:n instanceof Error?n.message:String(n)}),process.exit(1)}})}c(kn,"registerConnectCommand");import{logger as Ae,listCredentials as Ds,setActiveAgent as Bs,getActiveCredential as bn,readCredentials as Hs,maskSecret as Rn}from"aitable-workflow-core";function Cn(o,e){let t=o.command("agent").description("Agent \u51ED\u8BC1\u7BA1\u7406");t.command("list").description("\u5217\u51FA\u6240\u6709\u5DF2\u4FDD\u5B58\u7684 Agent \u51ED\u8BC1").action(async()=>{try{let n=await Ds();if(n.length===0){console.log("\u6682\u65E0\u5DF2\u4FDD\u5B58\u7684 Agent\u3002\u4F7F\u7528 `aitable-workflow connect` \u6CE8\u518C\u3002");return}let r=await Hs();console.log(`
|
|
560
|
+
\u5DF2\u4FDD\u5B58 ${n.length} \u4E2A Agent\uFF08\u6D3B\u8DC3: ${r.activeAgent??"\u65E0"}\uFF09:
|
|
561
|
+
`);for(let s of n){let i=s.name===r.activeAgent?" \u2190 active":"";console.log(` \u2022 ${s.name}${i}`),console.log(` Server: ${s.serverUrl}`),console.log(` Token: ${Rn(s.token)}`),s.machineId&&console.log(` MachineID: ${s.machineId}`),s.workspaceRoot&&console.log(` Workspace: ${s.workspaceRoot}`),console.log(` Created: ${s.createdAt}`)}console.log("")}catch(n){Ae.error("cli","agent list \u5931\u8D25",{error:n instanceof Error?n.message:String(n)}),process.exit(1)}}),t.command("use <name>").description("\u5207\u6362\u6D3B\u8DC3 Agent").action(async n=>{try{let r=await Bs(n);console.log(`\u2705 \u5DF2\u5207\u6362\u5230 Agent "${r.activeAgent}"`)}catch(r){Ae.error("cli","agent use \u5931\u8D25",{error:r instanceof Error?r.message:String(r)}),process.exit(1)}}),t.command("whoami").description("\u663E\u793A\u5F53\u524D\u6D3B\u8DC3 Agent").action(async()=>{try{let n=await bn();if(!n){console.log("\u5F53\u524D\u65E0\u6D3B\u8DC3 Agent\u3002\u4F7F\u7528 `aitable-workflow connect` \u6CE8\u518C\u6216 `aitable-workflow agent use <name>` \u5207\u6362\u3002");return}console.log(`Agent: ${n.name}`),console.log(`Server: ${n.serverUrl}`),console.log(`Token: ${Rn(n.token)}`),n.machineId&&console.log(`MachineID: ${n.machineId}`),n.workspaceRoot&&console.log(`Workspace: ${n.workspaceRoot}`)}catch(n){Ae.error("cli","agent whoami \u5931\u8D25",{error:n instanceof Error?n.message:String(n)}),process.exit(1)}}),t.command("status").description("\u67E5\u770B Agent \u8FDE\u63A5\u72B6\u6001\u4E0E\u8FD0\u884C\u65F6\u4FE1\u606F").option("--json","JSON \u683C\u5F0F\u8F93\u51FA").action(async n=>{try{let r=await bn();if(!r){console.log("\u65E0\u6D3B\u8DC3 Agent\u3002\u4F7F\u7528 `aitable-workflow connect` \u6CE8\u518C\u3002");return}let s=await K(r.name),i=await Ce(r.name),a={agent:r.name,serverUrl:r.serverUrl,connectionState:s.running?i.connectionState:"stopped",machineId:i.machineId??r.machineId??null,lastHeartbeatAt:i.lastHeartbeatAt,runningTasks:i.runningTasks,queuedTasks:i.queuedTasks,lastDisconnectReason:i.lastDisconnectReason,pid:s.pid};if(n.json){process.stdout.write(JSON.stringify(a,null,2)+`
|
|
74
562
|
`);return}let l=a.connectionState==="connected"?"\u{1F7E2}":a.connectionState==="reconnecting"?"\u{1F7E1}":"\u{1F534}";console.log(`
|
|
75
|
-
${l} Agent: ${a.agent}`),console.log(` Server: ${a.serverUrl}`),console.log(` Connection: ${a.connectionState}`),a.machineId&&console.log(` MachineID: ${a.machineId}`),a.lastHeartbeatAt&&console.log(` Last HB: ${a.lastHeartbeatAt}`),
|
|
563
|
+
${l} Agent: ${a.agent}`),console.log(` Server: ${a.serverUrl}`),console.log(` Connection: ${a.connectionState}`),a.machineId&&console.log(` MachineID: ${a.machineId}`),a.lastHeartbeatAt&&console.log(` Last HB: ${a.lastHeartbeatAt}`),s.running&&(console.log(` PID: ${a.pid}`),console.log(` Tasks: ${a.runningTasks} running, ${a.queuedTasks} queued`)),a.lastDisconnectReason&&console.log(` Last Error: ${a.lastDisconnectReason}`),console.log("")}catch(r){Ae.error("cli","agent status \u5931\u8D25",{error:r instanceof Error?r.message:String(r)}),process.exit(1)}})}c(Cn,"registerAgentCommands");import{logger as Fs}from"aitable-workflow-core";function xn(o,e){o.command("relay").description("\u4EE5\u672C\u673A relay \u5B88\u62A4\u8EAB\u4EFD\u53CD\u8FDE RelayGateway\uFF0C\u6309\u9700\u5728\u672C\u673A\u6267\u884C Agent/dws \u4EFB\u52A1").option("--server-url <url>","Gateway \u5730\u5740\uFF08\u4E5F\u53EF\u7528 AITABLE_RELAY_SERVER_URL\uFF09").option("--key <machineKey>","per-machine key\uFF08sk_machine_*\uFF09").option("--token <ownerToken>","owner-token \u81EA\u6CE8\u518C\uFF08\u4E5F\u53EF\u7528 AITABLE_RELAY_TOKEN\uFF1B\u4F18\u5148\u4E8E --key\uFF09").option("--name <name>","\u81EA\u6CE8\u518C\u673A\u5668\u540D\uFF08\u53EF\u9009\uFF0C\u7F3A\u7701\u81EA\u52A8\u4F7F\u7528\u4E3B\u673A\u540D\uFF1Bowner+name \u5E42\u7B49\u952E\uFF0C\u591A\u673A\u573A\u666F\u5EFA\u8BAE\u663E\u5F0F\u6307\u5B9A\u4EE5\u907F\u514D hostname \u51B2\u7A81\u4E92\u76F8\u9876\u8FDE\u63A5\uFF1B\u4E5F\u53EF\u7528 AITABLE_RELAY_NAME\uFF09").option("--desc <description>","\u81EA\u6CE8\u518C\u673A\u5668\u63CF\u8FF0\uFF08\u4E5F\u53EF\u7528 AITABLE_RELAY_DESC\uFF09").option("--workspace-root <dir>","\u5DE5\u4F5C\u533A\u6839\u76EE\u5F55\uFF08\u4E5F\u53EF\u7528 AITABLE_RELAY_WORKSPACE_ROOT\uFF09").option("--machine-id <id>","\u7A33\u5B9A\u673A\u5668\u8EAB\u4EFD\uFF08\u4E5F\u53EF\u7528 AITABLE_RELAY_MACHINE_ID\uFF09").option("--max-tasks <n>","\u672C\u673A\u5E76\u53D1\u6267\u884C\u4E0A\u9650\uFF0C\u9ED8\u8BA4 1\uFF08\u4E5F\u53EF\u7528 AITABLE_RELAY_MAX_TASKS\uFF09").option("--max-workflows <n>","\u672C\u673A\u53EF\u540C\u65F6\u8FD0\u884C\u7684\u5DE5\u4F5C\u6D41\u5F15\u64CE\u6570\uFF0C\u9ED8\u8BA4 3\uFF1B0 = \u4E0D\u8BA4\u9886\u5DE5\u4F5C\u6D41\uFF08\u4E5F\u53EF\u7528 AITABLE_RELAY_MAX_WORKFLOWS\uFF09").option("--trace-http-port <port>","\u542F\u7528\u672C\u5730\u53EA\u8BFB trace HTTP \u670D\u52A1\u7AEF\u53E3\uFF08\u4E5F\u53EF\u7528 AITABLE_RELAY_TRACE_HTTP_PORT\uFF09").option("--trace-http-host <host>","\u672C\u5730 trace HTTP \u76D1\u542C\u5730\u5740\uFF0C\u9ED8\u8BA4 127.0.0.1\uFF08\u4E5F\u53EF\u7528 AITABLE_RELAY_TRACE_HTTP_HOST\uFF09").option("--trace-buffer-size <n>","\u672C\u5730 trace \u4FDD\u7559\u6700\u8FD1 run \u6570\uFF0C\u9ED8\u8BA4 20\uFF08\u4E5F\u53EF\u7528 AITABLE_RELAY_TRACE_BUFFER_SIZE\uFF09").option("--trace-events-per-run <n>","\u6BCF\u4E2A run \u4FDD\u7559\u6700\u8FD1 agent event \u6570\uFF0C\u9ED8\u8BA4 500\uFF08\u4E5F\u53EF\u7528 AITABLE_RELAY_TRACE_EVENTS_PER_RUN\uFF09").option("--trace-chat","\u5728\u672C\u673A trace HTTP \u670D\u52A1\u4E0A\u5F00\u542F Local Chat \u5199\u63A5\u53E3\uFF08Task D\uFF0C\u9ED8\u8BA4\u5173\uFF1B\u4E5F\u53EF\u7528 AITABLE_RELAY_TRACE_CHAT=1\uFF09").action(t=>{try{Re(t)}catch(n){Fs.error("cli","relay \u542F\u52A8\u5931\u8D25",{error:n instanceof Error?n.message:String(n)}),process.exit(1)}})}c(xn,"registerRelayCommand");import{loadSettings as An,loadWorkflowTemplate as Ns,checkWorkflowRecipes as Us,Tracer as Ws}from"aitable-workflow-core";import Gs from"path";function En(o,e){o.command("inspect [recordId]").description("\u67E5\u770B\u5DE5\u5355\u6267\u884C trace\uFF1B\u6216\u7528 --recipes / --validate \u67E5\u770B\u6821\u9A8C recipe schema \u4E0E workflow \u5BF9\u9F50").option("-c, --config <path>","\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84",e.defaultConfig).option("-s, --step <stepId>","\u67E5\u770B\u7279\u5B9A\u6B65\u9AA4").option("-l, --latest","\u67E5\u770B\u6700\u8FD1\u6267\u884C").option("-n, --limit <number>","\u6700\u591A\u663E\u793A\u6761\u6570","10").option("--recipes","\u5217\u51FA\u5404\u6B65\u9AA4 recipe \u7684 input / output / config schema\u4E0E step \u914D\u7F6E").option("--validate","\u6821\u9A8C step.config / input_mapping / output_mapping \u662F\u5426\u7B26\u5408 recipe schema").option("-w, --workflow <id>","\u591A\u5DE5\u4F5C\u6D41\u6A21\u5F0F\uFF1A\u6307\u5B9A\u5DE5\u4F5C\u6D41 ID\uFF08\u7F3A\u7701\u53D6\u7B2C\u4E00\u4E2A\uFF09").action(async(t,n)=>{try{if(n.recipes||n.validate){await qs(n);return}let r=await An(n.config),s=Gs.resolve(r.configDir,r.agent.trace_dir),i=new Ws(s),a=parseInt(n.limit,10)||10,l;if(n.latest||!t){if(l=await i.getLatestTraces(a),l.length===0){console.log("\u26A0\uFE0F \u6682\u65E0 trace \u8BB0\u5F55\u3002\u8FD0\u884C `run` \u547D\u4EE4\u540E\u518D\u67E5\u770B\u3002");return}console.log(`
|
|
76
564
|
\u{1F4C4} \u6700\u8FD1 ${l.length} \u6761\u6267\u884C\u8BB0\u5F55:
|
|
77
|
-
`)}else{if(l=await
|
|
78
|
-
\u{1F4C4} \u5DE5\u5355 ${
|
|
79
|
-
`)}for(let
|
|
80
|
-
\u{1F4CB} \u5DE5\u4F5C\u6D41\u300C${n.meta.name}\u300D(${
|
|
81
|
-
`);for(let
|
|
82
|
-
\u2705 \u5DE5\u4F5C\u6D41\u300C${n.meta.name}\u300D(${
|
|
83
|
-
`);else{let
|
|
84
|
-
\u6821\u9A8C\u7ED3\u679C\uFF1A${
|
|
85
|
-
`);for(let l of
|
|
86
|
-
\u2705 \u7FA4 ${
|
|
87
|
-
\u2139\uFE0F \u7FA4 ${
|
|
88
|
-
\u2139\uFE0F \u7FA4 ${
|
|
89
|
-
\u2705 \u51ED\u636E\u5DF2\u7ED1\u5B9A\uFF08bound \u76F8\uFF09\u3002`),console.log(` appKey=${
|
|
565
|
+
`)}else{if(l=await i.getTraces(t),l.length===0){console.log(`\u26A0\uFE0F \u672A\u627E\u5230\u5DE5\u5355 ${t} \u7684 trace \u8BB0\u5F55\u3002`);return}n.step&&(l=l.filter(d=>d.step_id===n.step)),console.log(`
|
|
566
|
+
\u{1F4C4} \u5DE5\u5355 ${t} \u7684\u6267\u884C\u5386\u53F2 (${l.length} \u6B65):
|
|
567
|
+
`)}for(let d of l){let p=d.status==="success"?"\u2705":d.status==="failed"?"\u274C":"\u23F8\uFE0F",u=(d.duration_ms/1e3).toFixed(1);console.log(`${p} [${d.step_id}] ${d.step_name} \u2014 ${u}s \u2014 ${d.status.toUpperCase()}`);for(let[m,f]of d.llm_calls.entries()){let R=m===d.llm_calls.length-1,S=R?" \u2514\u2500":" \u251C\u2500",E=R?" ":" \u2502 ",H=(f.duration_ms/1e3).toFixed(1);console.log(`${S} LLM: ${f.model} (${H}s)`),console.log(`${E}Input: ${f.prompt_summary.slice(0,80)}${f.prompt_summary.length>80?"...":""}`),console.log(`${E}Output: ${f.response_summary.slice(0,100)}${f.response_summary.length>100?"...":""}`)}if(Object.keys(d.outputs).length>0){let m=Object.entries(d.outputs).map(([f,R])=>`${f}=${typeof R=="string"?R.slice(0,50):JSON.stringify(R)}`).join(", ");console.log(` \u2514\u2500 Outputs: ${m}`)}d.error&&console.log(` \u2514\u2500 Error: ${d.error}`),console.log()}}catch(r){console.error(`\u2717 inspect \u5931\u8D25: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}})}c(En,"registerInspectCommand");async function qs(o){let e=await An(o.config),t=o.workflow?e.workflowEntries.find(i=>i.id===o.workflow):e.workflowEntries[0];t||(console.error(`\u2717 \u672A\u627E\u5230\u5DE5\u4F5C\u6D41\u300C${o.workflow}\u300D\u3002\u53EF\u7528\uFF1A${e.workflowEntries.map(i=>i.id).join(", ")}`),process.exit(1));let n=await Ns(t.templatePath,{envSource:e.envSource}),{issues:r,rows:s}=await Us(t.recipeDir,n);if(o.recipes){console.log(`
|
|
568
|
+
\u{1F4CB} \u5DE5\u4F5C\u6D41\u300C${n.meta.name}\u300D(${t.id}) \u7684 recipe schema:
|
|
569
|
+
`);for(let i of s){let a=i.configSummary.length>0?i.configSummary.join(", "):"(none)",l=i.loaded?"":" \u26A0 \u52A0\u8F7D\u5931\u8D25";console.log(` [${i.stepId} \u2192 ${i.recipeId}]${l}`),console.log(` config: ${a}`),console.log()}}if(o.validate)if(r.length===0)console.log(`
|
|
570
|
+
\u2705 \u5DE5\u4F5C\u6D41\u300C${n.meta.name}\u300D(${t.id}) \u5168\u90E8\u6B65\u9AA4\u6821\u9A8C\u901A\u8FC7
|
|
571
|
+
`);else{let i=r.filter(l=>l.level==="error"),a=r.filter(l=>l.level==="warn");console.log(`
|
|
572
|
+
\u6821\u9A8C\u7ED3\u679C\uFF1A${i.length} \u4E2A\u9519\u8BEF\uFF0C${a.length} \u4E2A\u8B66\u544A
|
|
573
|
+
`);for(let l of r){let d=l.level==="error"?"\u274C":"\u26A0\uFE0F ";console.log(` ${d} [${l.stepId} \u2192 ${l.recipeId}] ${l.message}`)}console.log(),i.length>0&&process.exit(1)}}c(qs,"runRecipeInspect");import{runKbCompileCommand as zs,runKbUpdateCommand as Js,runKbStatusCommand as Ys,runKbIngestCommand as Vs,runKbCleanupCommand as Ks}from"aitable-workflow-core";function Sn(o,e){let t=o.command("kb").description("\u77E5\u8BC6\u5E93(LLM-Wiki)\u7F16\u8BD1\u4E0E\u72B6\u6001\u7BA1\u7406");t.command("compile [collections...]").description("\u7F16\u8BD1\u77E5\u8BC6\u5E93\u4E3A wiki\uFF08\u4E0D\u6307\u5B9A collection \u65F6\u7F16\u8BD1\u89D2\u8272\u58F0\u660E\u7684\u5168\u90E8\uFF09").option("-c, --config <path>","\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84",e.defaultConfig).option("--full","\u5F3A\u5236\u5168\u91CF\u91CD\u7F16\u8BD1").action(async(n,r)=>{try{await zs(n,r)}catch(s){console.error(`\u2717 kb compile \u5931\u8D25: ${s instanceof Error?s.message:String(s)}`),process.exit(1)}}),t.command("update [collections...]").description("\u6E90\u6587\u6863\u53D8\u66F4\u540E\u89E6\u53D1\u589E\u91CF\u7F16\u8BD1\uFF08\u672A\u53D8\u66F4\u5219\u8DF3\u8FC7\uFF09").option("-c, --config <path>","\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84",e.defaultConfig).action(async(n,r)=>{try{await Js(n,r)}catch(s){console.error(`\u2717 kb update \u5931\u8D25: ${s instanceof Error?s.message:String(s)}`),process.exit(1)}}),t.command("status [collections...]").description("\u67E5\u770B\u77E5\u8BC6\u5E93\u7F16\u8BD1\u72B6\u6001\uFF08\u7F16\u8BD1\u4E2D/\u5B8C\u6210/\u5931\u8D25 + \u6E90\u662F\u5426\u5DF2\u53D8\u66F4\uFF09").option("-c, --config <path>","\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84",e.defaultConfig).action(async(n,r)=>{try{await Ys(n,r)}catch(s){console.error(`\u2717 kb status \u5931\u8D25: ${s instanceof Error?s.message:String(s)}`),process.exit(1)}}),t.command("ingest <url-or-path>").description("\u5BFC\u5165\u6587\u6863\u5230 wiki \u76EE\u5F55\uFF08\u652F\u6301\u9489\u9489 URL \u6216\u672C\u5730\u8DEF\u5F84\uFF0Cdocx/pdf \u81EA\u52A8\u8F6C md\uFF09").option("-o, --output <dir>","\u8F93\u51FA\u76EE\u5F55\uFF08\u9ED8\u8BA4 ./wiki\uFF09").option("-t, --type <type>","\u6E90\u7C7B\u578B: dingtalk-doc\uFF08\u4E0D\u4F20\u5219\u81EA\u52A8\u8BC6\u522B\uFF09").option("--flat","\u4E0D\u4FDD\u7559\u8FDC\u7AEF\u76EE\u5F55\u7ED3\u6784\uFF08\u6240\u6709\u6587\u6863\u5E73\u94FA\u5230\u8F93\u51FA\u76EE\u5F55\uFF09").option("--force","\u5F3A\u5236\u91CD\u65B0\u62C9\u53D6\u6240\u6709\u6587\u6863\uFF08\u5FFD\u7565\u589E\u91CF\u5224\u65AD\uFF09").option("--compile","\u5BFC\u5165\u540E\u81EA\u52A8\u89E6\u53D1 kb compile").option("-c, --config <path>","\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84",e.defaultConfig).option("--timeout <ms>","\u5355\u6587\u6863\u8BF7\u6C42\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09").action(async(n,r)=>{try{await Vs(n,r)}catch(s){console.error(`\u2717 kb ingest \u5931\u8D25: ${s instanceof Error?s.message:String(s)}`),process.exit(1)}}),t.command("cleanup <collection>").description("\u6E05\u7406\u77E5\u8BC6\u5E93\u4E2D\u7684\u5B64\u513F\u6587\u7AE0\uFF08\u6E90\u884C\u5DF2\u5220\u4F46 articles/ \u8FD8\u5728\uFF09").option("-c, --config <path>","\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84",e.defaultConfig).action(async(n,r)=>{try{await Ks(n,r)}catch(s){console.error(`\u2717 kb cleanup \u5931\u8D25: ${s instanceof Error?s.message:String(s)}`),process.exit(1)}})}c(Sn,"registerKbCommands");import et from"path";import{BotProvisioner as Xs,BotProvisionError as Pn,DwsDevRunner as tt,buildBotApprovalReportLines as Zs,defaultProvisionStatePath as nt,groupEntriesOf as Qs,loadProvisionState as $n,resolveConfigPath as rt,validateProvisionName as ei}from"aitable-workflow-core";import{logger as In}from"aitable-workflow-core";function Tn(o){for(let e of o){let t=e.title?`\u300C${e.title}\u300D${e.openConversationId}`:e.openConversationId;e.outcome==="added"?console.log(`
|
|
574
|
+
\u2705 \u7FA4 ${t}\uFF1A\u672C\u6B21\u5DF2\u771F\u5B9E\u8C03\u7528 add-bot \u5165\u7FA4${e.robotName?`\uFF08\u673A\u5668\u4EBA\u663E\u793A\u540D=${e.robotName}\uFF09`:""}\u3002`):e.source==="server"?console.log(`
|
|
575
|
+
\u2139\uFE0F \u7FA4 ${t}\uFF1A\u670D\u52A1\u7AEF\u786E\u8BA4\u8BE5\u7FA4\u5DF2\u5B89\u88C5\u6B64\u673A\u5668\u4EBA\uFF08500043\uFF09\uFF0C\u89C6\u540C\u5165\u7FA4\u6210\u529F\u3002`):(console.log(`
|
|
576
|
+
\u2139\uFE0F \u7FA4 ${t}\uFF1A\u5DF2\u5728\u7FA4\u53F0\u8D26\uFF08addedAt=${e.addedAt??"?"}\uFF09\uFF0C\u672C\u6B21\u672A\u53D1\u8D77\u4EFB\u4F55 API \u8C03\u7528\u3002`),console.log(" \u6CE8\u610F\uFF1A\u82E5\u673A\u5668\u4EBA\u66FE\u88AB\u624B\u52A8\u79FB\u51FA\u7FA4\uFF0C\u91CD\u8DD1\u672C\u547D\u4EE4\u4E0D\u4F1A\u91CD\u65B0\u6DFB\u52A0\uFF1B\u4EE5\u7FA4\u8BBE\u7F6E\u9875\u6216\u7FA4\u91CC @ \u5B9E\u6D4B\u4E3A\u51C6\u3002"))}}c(Tn,"printGroupOutcomes");function Ln(o,e,t={}){let n=t.exit??(s=>process.exit(s)),r=o.command("bot").description("\u9489\u9489\u673A\u5668\u4EBA provisioning\uFF08\u5EFA\u53F7 / \u51ED\u636E\u7ED1\u5B9A / \u53D1\u5E03\u5BA1\u6279 / \u62C9\u7FA4\uFF09");r.command("provision").description("\u786E\u5B9A\u6027\u5EFA\u53F7\u5E76\u7ED1\u5B9A\u51ED\u636E\uFF08\u5E42\u7B49\u3001\u53EF\u65AD\u70B9\u7EED\u8DD1\uFF1B--publish/--group \u8D70\u4EBA\u5BA1\u4E0E\u62C9\u7FA4\u76F8\uFF09").requiredOption("--name <name>","\u5E94\u7528\u540D\uFF08\u4F01\u4E1A\u5185\u552F\u4E00\uFF0C2-20 \u5B57\uFF09").option("--robot-name <robotName>","\u673A\u5668\u4EBA\u663E\u793A\u540D\uFF08\u7F3A\u7701\u540C --name\uFF09").option("--desc <desc>","\u5E94\u7528\u63CF\u8FF0\uFF08\u2264200 \u5B57\uFF09").option("--group <group>","\u62C9\u7FA4\u76EE\u6807\uFF1AopenConversationId \u6216\u7FA4\u540D\uFF0C\u9017\u53F7\u5206\u9694\u591A\u7FA4\uFF08\u9700\u5DF2\u5B8C\u6210 publish \u76F8\uFF1B\u5DF2\u5728\u7FA4\u53F0\u8D26\u7684\u7FA4\u96F6\u8C03\u7528\u8DF3\u8FC7\uFF09").option("--publish","\u8FDB\u5165\u53D1\u5E03\u76F8\uFF08\u771F\u5B9E\u6253\u6270\u7BA1\u7406\u5458\u5BA1\u6279\uFF0C\u9700\u914D\u5408 --approver-user-id \u786E\u8BA4\uFF09").option("--approver-user-id <userId>","\u5BA1\u6279\u4EBA userId\uFF08\u5019\u9009\u7531 check-approval \u5217\u51FA\uFF1B\u4EBA\u5BA1\u95E8\u4E0D\u5F97\u9759\u9ED8\u4EE3\u9009\uFF09").option("--state-file <path>","\u72B6\u6001\u6587\u4EF6\u8DEF\u5F84\uFF08\u7F3A\u7701 <configDir>/.aitable/provision-state.json\uFF09").option("-c, --config <path>","\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\uFF08\u7528\u4E8E\u5B9A\u4F4D configDir\uFF09",e.defaultConfig).option("--yes","\u4E0E dws \u8BED\u4E49\u5BF9\u9F50\uFF1A\u8DF3\u8FC7\u786E\u8BA4\uFF08provision \u5168\u7A0B\u975E\u4EA4\u4E92\uFF0C\u5199\u64CD\u4F5C\u5DF2\u5E26 --yes\uFF09").action(async s=>{try{let i=await ti(s,e,t);i!==0&&n(i)}catch(i){Qe(i),n(1)}}),r.command("status").description("\u67E5\u770B provision \u76F8\u4F4D / \u53D1\u5E03\u5BA1\u6279\u72B6\u6001 / \u5BA1\u6279\u4EBA\u5019\u9009\u4E0E\u50AC\u529E\u547D\u4EE4\u6A21\u677F").option("--state-file <path>","\u72B6\u6001\u6587\u4EF6\u8DEF\u5F84\uFF08\u7F3A\u7701 <configDir>/.aitable/provision-state.json\uFF09").option("-c, --config <path>","\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\uFF08\u7528\u4E8E\u5B9A\u4F4D configDir\uFF09",e.defaultConfig).option("--refresh","\u5B9E\u65F6\u67E5\u8BE2 dws\uFF08version status + check-approval\uFF09\uFF0C\u800C\u975E\u53EA\u8BFB\u72B6\u6001\u6587\u4EF6").action(async s=>{try{let i=await ri(s,e,t);i!==0&&n(i)}catch(i){Qe(i),n(1)}});for(let[s,i]of[["disable","\u505C\u7528"],["enable","\u542F\u7528"]])r.command(s).description(`${i}\u673A\u5668\u4EBA\u80FD\u529B\u6216\u6574\u4E2A\u5E94\u7528\uFF08\u53EF\u9006\uFF1B--scope app \u4F5C\u7528\u4E8E\u6574\u4E2A\u5E94\u7528\uFF09`).option("--scope <scope>","\u4F5C\u7528\u8303\u56F4\uFF1Arobot\uFF08\u9ED8\u8BA4\uFF0C\u4EC5\u673A\u5668\u4EBA\u80FD\u529B\uFF09| app\uFF08\u6574\u4E2A\u5E94\u7528\uFF09","robot").option("--unified-app-id <id>","\u76EE\u6807\u5E94\u7528 unifiedAppId\uFF08\u7F3A\u7701\u4ECE\u72B6\u6001\u6587\u4EF6\u8BFB\uFF09").option("--state-file <path>","\u72B6\u6001\u6587\u4EF6\u8DEF\u5F84\uFF08\u7F3A\u7701 <configDir>/.aitable/provision-state.json\uFF09").option("-c, --config <path>","\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\uFF08\u7528\u4E8E\u5B9A\u4F4D configDir\uFF09",e.defaultConfig).action(async a=>{try{let l=await oi(s,a,e,t);l!==0&&n(l)}catch(l){Qe(l),n(1)}})}c(Ln,"registerBotCommands");async function ti(o,e,t){let n=ei(o.name);if(n)return console.error(`\u274C ${n}`),1;let r=et.dirname(await rt(o.config??e.defaultConfig)),s=o.stateFile??nt(r);o.publish&&!o.approverUserId&&console.log("\u2139 --publish \u672A\u6307\u5B9A --approver-user-id\uFF1A\u82E5\u7EC4\u7EC7\u5BA1\u6279\u7B56\u7565\u9700\u9009\u4EBA\uFF0C\u5C06\u5217\u51FA\u5019\u9009\u540E\u505C\u4E0B\uFF0C\u7531\u4F60\u663E\u5F0F\u786E\u8BA4\u3002");let i=t.createProvisioner?.()??new Xs({runner:new tt}),a={name:o.name,robotName:o.robotName,desc:o.desc,stateFile:s,publish:o.publish,approverUserId:o.approverUserId,group:o.group};console.log(`\u{1F916} \u5F00\u59CB provision\u300C${o.name}\u300D\uFF08\u72B6\u6001\u6587\u4EF6: ${s}\uFF09`);let l=await i.provision(a);return ni(l,{stateFile:s})}c(ti,"runProvision");function ni(o,e){switch(o.status){case"bound":{console.log(`
|
|
577
|
+
\u2705 \u51ED\u636E\u5DF2\u7ED1\u5B9A\uFF08bound \u76F8\uFF09\u3002`),console.log(` appKey=${o.state.clientId??"?"}`),console.log(` AppSecret \u4E0D\u56DE\u663E\uFF0C\u590D\u53D6: dws dev app credentials get --unified-app-id ${o.state.unifiedAppId??"<unifiedAppId>"}`),console.log(" \u51ED\u636E\u843D\u6CD5\u4E8C\u9009\u4E00\uFF08\u4E0D\u8981\u4E24\u5904\u90FD\u5199\uFF09\uFF1A"),console.log(" \xB7 \u5355\u4E00\u673A\u5668\u4EBA \u2192 \u5199\u5165 `.env`\uFF0C\u914D\u7F6E\u91CC\u7528 `${env.X}` \u5F15\u7528\uFF1B"),console.log(" \xB7 \u591A\u7FA4/\u591A\u673A\u5668\u4EBA/\u9700\u8FD0\u8425\u81EA\u7EF4\u62A4 \u2192 \u5199\u5165 AI \u8868\u683C\u7FA4\u914D\u7F6E\u8868\uFF0C\u7531 config-sync \u53D1\u5E03\u6210 `globalVar.robot_creds`\u3002"),console.log(" \u72B6\u6001\u6587\u4EF6:",e.stateFile),console.log("\n\u26A0\uFE0F Stream \u5355\u6D3E\u53D1\u4E92\u65A5\uFF1A\u52FF\u5BF9\u540C\u4E00\u673A\u5668\u4EBA\u540C\u65F6\u8FD0\u884C `dws dev connect`\uFF0C\u5426\u5219\u6D88\u606F\u53EA\u6D3E\u53D1\u5176\u4E00\u3002"),console.log("\u{1F4A1} \u771F\u5B9E\u7528\u6237\u6D41\u91CF\uFF08\u7FA4\u91CC @bot / \u5355\u804A\u53D1\u73B0\uFF09\u9700\u516C\u5F00\u53D1\u5E03\uFF1A`aitable-workflow bot provision --name <\u540C\u540D> --publish`");break}case"publish_pending":{console.log(`
|
|
90
578
|
\u23F3 \u53D1\u5E03\u5DF2\u63D0\u4EA4\uFF0C\u7B49\u5F85\u7BA1\u7406\u5458\u5BA1\u6279\uFF08publish_pending \u76F8\uFF09\u3002`),console.log(" \u67E5\u770B\u8FDB\u5EA6\u4E0E\u50AC\u529E: aitable-workflow bot status --refresh");break}case"published":{console.log(`
|
|
91
|
-
\u2705 \u5DF2\u53D1\u5E03\uFF08published \u76F8\uFF09\u2014\u2014\u771F\u5B9E\u7528\u6237\u6D41\u91CF\u53EF\u7528\u3002`),console.log("\u{1F4A1} \u62C9\u7FA4: `aitable-workflow bot provision --name <\u540C\u540D> --group <openConversationId|\u7FA4\u540D>`\uFF08\u591A\u7FA4\u9017\u53F7\u5206\u9694\uFF09");break}case"grouped":{if(
|
|
92
|
-
\u2705 grouped \u76F8\uFF1A\u7FA4\u53F0\u8D26\u5DF2\u6709 ${
|
|
93
|
-
\u26D4 \u516C\u5F00\u53D1\u5E03\u9700\u771F\u4EBA\u5BA1\u6279\uFF0C\u4E14\u672C\u7EC4\u7EC7\u7B56\u7565\u8981\u6C42\u663E\u5F0F\u9009\u5BA1\u6279\u4EBA\uFF08\u4EBA\u5BA1\u95E8\u4E0D\u5F97\u9759\u9ED8\u4EE3\u9009\uFF09\u3002`),console.error(" \u5BA1\u6279\u4EBA\u5019\u9009\uFF08\u6765\u81EA check-approval\uFF09:");for(let
|
|
94
|
-
\u274C provision \u5931\u8D25: ${
|
|
579
|
+
\u2705 \u5DF2\u53D1\u5E03\uFF08published \u76F8\uFF09\u2014\u2014\u771F\u5B9E\u7528\u6237\u6D41\u91CF\u53EF\u7528\u3002`),console.log("\u{1F4A1} \u62C9\u7FA4: `aitable-workflow bot provision --name <\u540C\u540D> --group <openConversationId|\u7FA4\u540D>`\uFF08\u591A\u7FA4\u9017\u53F7\u5206\u9694\uFF09");break}case"grouped":{if(o.groups.length===0){let t=Object.keys(Qs(o.state)).length;console.log(`
|
|
580
|
+
\u2705 grouped \u76F8\uFF1A\u7FA4\u53F0\u8D26\u5DF2\u6709 ${t} \u4E2A\u7FA4\u3002\u672C\u6B21\u672A\u4F20 --group\uFF0C\u672A\u53D1\u8D77\u4EFB\u4F55\u62C9\u7FA4\u8C03\u7528\u3002`);break}Tn(o.groups),console.log("\u{1F4A1} add-bot \u7684 success \u53EA\u662F\u53D7\u7406\u4FE1\u53F7\uFF08dws \u65E0\u5728\u7FA4\u5217\u8868\u67E5\u8BE2\u63A5\u53E3\uFF09\uFF1A\u8BF7\u5230\u7FA4\u8BBE\u7F6E\u6838\u5BF9\u673A\u5668\u4EBA\u5728\u7FA4\u3002");break}case"approver_required":{console.error(`
|
|
581
|
+
\u26D4 \u516C\u5F00\u53D1\u5E03\u9700\u771F\u4EBA\u5BA1\u6279\uFF0C\u4E14\u672C\u7EC4\u7EC7\u7B56\u7565\u8981\u6C42\u663E\u5F0F\u9009\u5BA1\u6279\u4EBA\uFF08\u4EBA\u5BA1\u95E8\u4E0D\u5F97\u9759\u9ED8\u4EE3\u9009\uFF09\u3002`),console.error(" \u5BA1\u6279\u4EBA\u5019\u9009\uFF08\u6765\u81EA check-approval\uFF09:");for(let t of o.candidates)console.error(` - ${t.name??"(\u672A\u77E5)"} userId=${t.userId}${t.mainAdmin?"\uFF08\u4E3B\u7BA1\u7406\u5458\uFF09":""}`);return console.error(" \u786E\u8BA4\u540E\u91CD\u8DD1: aitable-workflow bot provision --name <\u540C\u540D> --publish --approver-user-id <userId>"),2}case"failed":return o.groups&&o.groups.length>0&&Tn(o.groups),console.error(`
|
|
582
|
+
\u274C provision \u5931\u8D25: ${o.message}`),console.error(" \uFF08\u72B6\u6001\u6587\u4EF6\u5DF2\u4FDD\u7559\u8FDB\u5EA6\uFF0C\u4FEE\u590D\u540E\u53EF\u65AD\u70B9\u7EED\u8DD1: \u91CD\u8DD1\u540C\u4E00\u547D\u4EE4\uFF09"),1}return 0}c(ni,"printProvisionResult");async function ri(o,e,t){let n=et.dirname(await rt(o.config??e.defaultConfig)),r=o.stateFile??nt(n),s=await $n(r),i,a=null,l=null;if(o.refresh&&s?.unifiedAppId&&s.versionId){let p=t.createRunner?.()??new tt;try{i=(await p.versionStatus(s.unifiedAppId,s.versionId)).versionStatus}catch(u){l=_n(u)}if(!l)try{a=await p.checkApproval(s.unifiedAppId,s.versionId)}catch(u){l=_n(u)}}let d=Zs({state:s,versionStatus:i,approval:a,error:l});return console.log(d.map(p=>` ${p}`).join(`
|
|
95
583
|
`)),console.log(`
|
|
96
|
-
\u72B6\u6001\u6587\u4EF6: ${
|
|
97
|
-
\u2705 \u5DF2${
|
|
98
|
-
\u274C ${
|
|
99
|
-
\u274C ${
|
|
584
|
+
\u72B6\u6001\u6587\u4EF6: ${r}`),s&&!o.refresh&&(s.phase==="publish_pending"||s.phase==="version_created")&&console.log(" \u63D0\u793A: \u52A0 --refresh \u5B9E\u65F6\u67E5\u8BE2\u5BA1\u6279\u72B6\u6001\u4E0E\u5019\u9009\u3002"),s?0:1}c(ri,"runStatus");function _n(o){return o instanceof Pn?`${o.message}\uFF08${o.guidance}\uFF09`:o instanceof Error?o.message:String(o)}c(_n,"describeError");async function oi(o,e,t,n){let r=e.scope??"robot";if(r!=="robot"&&r!=="app")return console.error(`\u274C --scope \u53EA\u652F\u6301 robot | app\uFF0C\u6536\u5230: ${r}`),1;let s=e.unifiedAppId?.trim();if(!s){let p=et.dirname(await rt(e.config??t.defaultConfig)),u=e.stateFile??nt(p);if(s=(await $n(u))?.unifiedAppId??void 0,!s)return console.error(`\u274C \u65E0\u6CD5\u786E\u5B9A\u76EE\u6807\u5E94\u7528\uFF1A\u72B6\u6001\u6587\u4EF6\u65E0 unifiedAppId\uFF08${u}\uFF09\uFF0C\u8BF7\u7528 --unified-app-id \u663E\u5F0F\u6307\u5B9A\u3002`),1}let i=o==="disable"?"\u505C\u7528":"\u542F\u7528",a=n.createRunner?.()??new tt,l=r==="app"?"\u6574\u4E2A\u5E94\u7528":"\u673A\u5668\u4EBA\u80FD\u529B";return console.log(`\u{1F916} ${i}${l}\uFF08unifiedAppId=${s}\uFF09`),r==="app"&&o==="disable"&&console.log("\u2139 --scope app \u4F1A\u505C\u7528\u6574\u4E2A\u5E94\u7528\uFF08\u673A\u5668\u4EBA/\u7F51\u9875\u5E94\u7528\u7B49\u5168\u90E8\u4E0D\u53EF\u7528\uFF09\uFF1B\u53EA\u60F3\u505C\u673A\u5668\u4EBA\u7528\u9ED8\u8BA4 --scope robot\u3002"),await{disable:{robot:a.disableRobot.bind(a),app:a.disableApp.bind(a)},enable:{robot:a.enableRobot.bind(a),app:a.enableApp.bind(a)}}[o][r](s),console.log(`
|
|
585
|
+
\u2705 \u5DF2${i}${l}\u3002`),o==="disable"&&(console.log(` \u6062\u590D: ${r==="app"?"aitable-workflow bot enable --scope app":"aitable-workflow bot enable"}\uFF08\u542F\u505C\u53EF\u9006\uFF1B.env \u51ED\u636E\u4E0E\u72B6\u6001\u6587\u4EF6\u4E0D\u53D7\u5F71\u54CD\uFF09`),console.log(" \u26A0\uFE0F \u505C\u7528\u540E Stream \u5EFA\u8054/\u6D88\u606F\u6536\u53D1\u4F1A\u5931\u8D25\uFF1B\u8FD0\u884C\u4E2D\u7684\u5F15\u64CE\u4F1A\u6301\u7EED\u62A5\u9519\u76F4\u5230\u6062\u590D\u3002")),0}c(oi,"runToggle");function Qe(o){if(o instanceof Pn)In.error("cli","bot \u547D\u4EE4\u5931\u8D25",{kind:o.kind}),console.error(`
|
|
586
|
+
\u274C ${o.message}`),console.error(` \u21B3 ${o.guidance}`);else{let e=o instanceof Error?o.message:String(o);In.error("cli","bot \u547D\u4EE4\u5931\u8D25",{error:e}),console.error(`
|
|
587
|
+
\u274C ${e}`)}}c(Qe,"failWithDiagnostics");var Dn=Mn.dirname(ci(import.meta.url));jn({override:!1,quiet:!0});jn({path:Mn.resolve(Dn,"..",".env"),override:!1,quiet:!0});var Bn=dt(),ot=Ie(Bn),li=pt(Bn);ai({version:ot});var y=new si().name("aitable-workflow").description("\u901A\u7528\u4E1A\u52A1\u6D41\u7A0B\u5F15\u64CE \u2014 \u914D\u7F6E\u9A71\u52A8\u7684 AI \u8868\u683C\u5DE5\u4F5C\u6D41\u81EA\u52A8\u5316").version(ot).enablePositionalOptions().option("-d, --debug","\u8F93\u51FA debug \u7EA7\u522B\u65E5\u5FD7\uFF08\u542B recipe \u5185\u90E8 log\uFF09\uFF1B\u9700\u5199\u5728\u547D\u4EE4\u540D\u4E4B\u524D").hook("preAction",(o,e)=>{o.opts().debug?On.setLevel("debug"):(e.name()==="config"||e.parent?.name()==="config")&&On.setLevel("warn")}).hook("preAction",async(o,e)=>{e.name()!=="init"&&await ii()}),k={cliDir:Dn,version:ot,packageVersions:li,defaultConfig:ut};mt(y,k);ft(y,k);gt(y,k);wt(y,k);bt(y,k);Ct(y,k);It(y,k);$t(y,k);st(y,k);Lt(y,k);Ot(y,k);jt(y,k);Dt(y,k);wn(y,k);kn(y,k);Cn(y,k);yn(y,k);xn(y,k);En(y,k);Sn(y,k);Ln(y,k);await y.parseAsync();
|