aws-runtime-bridge 1.9.171 → 1.9.175
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +171 -0
- package/dist/adapter/AcodeSdkAdapter.d.ts +11 -13
- package/dist/adapter/AcodeSdkAdapter.js +3 -3
- package/dist/adapter/ClaudeSdkAdapter.d.ts +2 -0
- package/dist/adapter/ClaudeSdkAdapter.js +3 -3
- package/dist/adapter/types.d.ts +6 -7
- package/dist/index.js +1 -1
- package/dist/routes/bridge-temp-files.d.ts +1 -0
- package/dist/routes/bridge-temp-files.js +2 -0
- package/dist/routes/dashboard.js +35 -5
- package/dist/routes/file-browser.d.ts +4 -10
- package/dist/routes/file-browser.js +1 -1
- package/dist/routes/git.d.ts +42 -0
- package/dist/routes/git.js +34 -34
- package/dist/routes/sessions.js +1 -1
- package/dist/routes/tech-stack.d.ts +2 -0
- package/dist/routes/tech-stack.js +2 -0
- package/dist/routes/terminal.d.ts +8 -0
- package/dist/routes/terminal.js +27 -27
- package/dist/services/agent-pty-manager.d.ts +2 -0
- package/dist/services/agent-pty-manager.js +5 -4
- package/dist/services/agent-startup-memory.js +4 -4
- package/dist/services/bridge-temp-files.d.ts +36 -0
- package/dist/services/bridge-temp-files.js +2 -0
- package/dist/services/fileSnapshotStore.d.ts +9 -0
- package/dist/services/fileSnapshotStore.js +1 -1
- package/dist/services/gitignore.d.ts +12 -0
- package/dist/services/gitignore.js +2 -0
- package/dist/services/log-retention.js +1 -1
- package/dist/services/open-doc-events.d.ts +21 -0
- package/dist/services/open-doc-events.js +2 -0
- package/dist/services/open-doc-registry.d.ts +24 -0
- package/dist/services/open-doc-registry.js +2 -0
- package/dist/services/request-invalid-dump.js +1 -1
- package/dist/services/runtime-resources-snapshot.js +2 -2
- package/dist/services/session-output.d.ts +2 -0
- package/dist/services/session-output.js +2 -2
- package/dist/services/snapshot-retention.d.ts +7 -0
- package/dist/services/snapshot-retention.js +2 -0
- package/dist/services/tech-stack-scanner.d.ts +31 -0
- package/dist/services/tech-stack-scanner.js +2 -0
- package/dist/services/tunnel-client.d.ts +42 -0
- package/dist/services/tunnel-client.js +1 -1
- package/dist/services/workspaceTaskChangeWatcher.js +2 -2
- package/package/acode/dist/__tests__/summary-request-helper.d.ts +2 -0
- package/package/acode/dist/__tests__/summary-request-helper.js +2 -0
- package/package/acode/dist/ask-user-question-tool.d.ts +11 -1
- package/package/acode/dist/ask-user-question-tool.js +3 -3
- package/package/acode/dist/built-in-file-tools.js +2 -2
- package/package/acode/dist/cache-control.d.ts +26 -0
- package/package/acode/dist/cache-control.js +2 -0
- package/package/acode/dist/compaction.d.ts +174 -32
- package/package/acode/dist/compaction.js +22 -6
- package/package/acode/dist/microcompact.d.ts +57 -0
- package/package/acode/dist/microcompact.js +2 -0
- package/package/acode/dist/runtime-environment.js +1 -1
- package/package/acode/dist/runtime.d.ts +17 -4
- package/package/acode/dist/runtime.js +50 -40
- package/package/acode/dist/token-estimator.d.ts +15 -0
- package/package/acode/dist/token-estimator.js +2 -0
- package/package/acode/dist/types.d.ts +14 -1
- package/package/aws-client-agent-mcp/dist/ability-market-tools.js +1 -1
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts +15 -2
- package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +5 -0
- package/package/aws-client-agent-mcp/dist/mcp-server.js +25 -23
- package/package/aws-client-agent-mcp/dist/mcp-tools.js +7 -7
- package/package/aws-client-agent-mcp/dist/memory-store.d.ts +21 -2
- package/package/aws-client-agent-mcp/dist/memory-store.js +27 -2
- package/package/aws-client-agent-mcp/dist/memory-tools.js +13 -9
- package/package/aws-client-agent-mcp/dist/server-memory-store.d.ts +1 -1
- package/package/aws-client-agent-mcp/dist/server-memory-store.js +1 -1
- package/package/aws-client-agent-mcp/dist/types.d.ts +51 -0
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import c from"node:fs/promises";import o from"node:path";import{getAutoRegisterConfigFilePath as N,getBridgeDataHome as
|
|
1
|
+
import c from"node:fs/promises";import o from"node:path";import{getAutoRegisterConfigFilePath as N,getBridgeDataHome as S,getRuntimeHomeDir as I}from"../config.js";import{createLogger as x}from"../utils/logger.js";import{sweepExpiredSnapshots as b}from"./fileSnapshotStore.js";import{getSnapshotRetentionDays as M,setSnapshotRetentionDays as O}from"./snapshot-retention.js";const w=x("log-retention"),m=7,j=7,_=6*60*60*1e3,$="Instance-ai-configuration-debug.log";let r=m,l=null,d=!1,y=!1,h=!1;function A(t,e){h||(h=!0,w.warn(`${t}${e instanceof Error?`: ${e.message}`:""}`))}function E(t){if(t==null||t===""||typeof t=="boolean")return m;const e=Number(t);return!Number.isFinite(e)||e<=0?m:Math.min(Math.floor(e),j)}function q(t){const e=E(t);return y=!0,e!==r&&(r=e,F()),r}function K(){return r}function Q(){r=m}function Z(){r=m,y=!1,l&&(clearInterval(l),l=null),d=!1,h=!1}function W(){const t=o.join(S(),"log");return{logDir:t,agentLogDir:o.join(t,"agent"),instanceAiDebugLogPath:o.join(z(),$)}}function z(){return String(process.env.AWS_TEST_HOME||"").trim()||String(process.env.AWS_RUNTIME_HOME_DIR||"").trim()||I()}async function D(t,e,i){try{const n=await c.stat(t);return n.mtimeMs>=e?!1:(await c.unlink(t),i.removedFiles+=1,i.bytesFreed+=n.size,!0)}catch(n){return n.code!=="ENOENT"&&(i.failures+=1,A("[log-retention] \u5220\u9664\u8FC7\u671F\u65E5\u5FD7\u5931\u8D25",n)),!1}}async function G(t,e,i){let n=o.normalize(t);const s=o.normalize(e);for(;n.startsWith(s)&&n!==s;){try{await c.rmdir(n),i.removedDirs+=1}catch{return}n=o.dirname(n)}}async function H(t,e,i){let n;try{n=await c.readdir(t)}catch{return}for(const s of n)!s.startsWith("lifecycle-")||!s.endsWith(".jsonl")||await D(o.join(t,s),e,i)}async function B(t,e,i){const n=o.join(t,"aws-mcp-node");let s;try{s=(await c.readdir(n,{withFileTypes:!0})).filter(u=>u.isDirectory()).map(u=>o.join(n,u.name))}catch{return}for(const g of s){let u;try{u=(await c.readdir(g,{withFileTypes:!0})).filter(a=>a.isDirectory()).map(a=>o.join(g,a.name))}catch{continue}for(const f of u){let a;try{a=(await c.readdir(f,{withFileTypes:!0})).filter(p=>p.isFile()).map(p=>o.join(f,p.name))}catch{continue}let L=!0;for(const T of a)await D(T,e,i)||(L=!1);L&&a.length>0&&await G(f,n,i)}let v;try{v=(await c.readdir(g,{withFileTypes:!0})).filter(a=>a.isFile()).map(a=>o.join(g,a.name))}catch{continue}for(const f of v)await D(f,e,i)}}async function P(t,e,i){await D(t,e,i)}function F(){const t=async()=>{const e={retentionDays:r,removedFiles:0,removedDirs:0,failures:0,bytesFreed:0},i=Date.now()-r*24*60*60*1e3,n=W();try{await H(n.logDir,i,e),await B(n.agentLogDir,i,e),await P(n.instanceAiDebugLogPath,i,e)}catch(s){A("[log-retention] \u6E05\u7406\u8FC7\u671F\u65E5\u5FD7\u51FA\u9519",s)}return await b(M()),(e.removedFiles>0||e.removedDirs>0)&&w.info(`[log-retention] \u6E05\u7406\u5B8C\u6210\uFF1A\u5220\u9664 ${e.removedFiles} \u4E2A\u6587\u4EF6 / ${e.removedDirs} \u4E2A\u76EE\u5F55\uFF0C\u91CA\u653E ${(e.bytesFreed/1024/1024).toFixed(1)} MB\uFF08\u4FDD\u7559 ${r} \u5929\uFF09`),e};return d||(d=!0,R=t().finally(()=>{d=!1})),R}let R=Promise.resolve({retentionDays:r,removedFiles:0,removedDirs:0,failures:0,bytesFreed:0});function ee(){if(l)return;const t=String(process.env.AWS_BRIDGE_LOG_RETENTION_DAYS||"").trim();t&&(r=E(t),y=!0),l=setInterval(()=>{F()},_),U().finally(()=>{F(),w.info(`[log-retention] \u65E5\u5FD7\u4FDD\u7559\u7B56\u7565\u5DF2\u542F\u52A8\uFF1A\u4FDD\u7559 ${r} \u5929\uFF0C\u6BCF ${_/36e5}h \u6E05\u7406\u4E00\u6B21`)})}async function U(){try{const t=await c.readFile(N(),"utf-8"),e=JSON.parse(t);e.logRetentionDays!==void 0&&!y&&(r=E(e.logRetentionDays)),e.snapshotRetentionDays!==void 0&&O(e.snapshotRetentionDays,!0)}catch{}}function te(){l&&(clearInterval(l),l=null)}export{m as DEFAULT_LOG_RETENTION_DAYS,K as getLogRetentionDays,W as getLogRetentionTargets,E as normalizeLogRetentionDays,Q as resetLogRetentionDaysForTest,q as setLogRetentionDays,ee as startLogRetention,te as stopLogRetention,Z as stopLogRetentionForTest,F as sweepExpiredLogs};
|
|
2
2
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
import type { OpenDocKind } from "./open-doc-registry.js";
|
|
3
|
+
|
|
4
|
+
export type OpenDocEvent = {
|
|
5
|
+
action: "open";
|
|
6
|
+
kind: OpenDocKind;
|
|
7
|
+
docId: string;
|
|
8
|
+
name: string;
|
|
9
|
+
detail?: string;
|
|
10
|
+
} | {
|
|
11
|
+
action: "close";
|
|
12
|
+
kind: OpenDocKind;
|
|
13
|
+
} | {
|
|
14
|
+
action: "delete";
|
|
15
|
+
kind: OpenDocKind;
|
|
16
|
+
docId: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export declare function normalizeSemanticToolName(raw: string | undefined): string;
|
|
20
|
+
|
|
21
|
+
export declare function resolveOpenDocEvent(toolName: string | undefined, args: Record<string, unknown> | undefined, result: unknown): OpenDocEvent | null;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const d={pencil_open_document:"pencil",pencil_close_document:"pencil",pencil_delete_document:"pencil",draw_open_document:"draw",draw_close_document:"draw",draw_delete_document:"draw",office_open_document:"office",office_close_document:"office",office_delete_document:"office"};function s(t){let e=String(t??"").trim().toLowerCase();if(!e)return"";const n=e.lastIndexOf("/");return n>=0&&(e=e.slice(n+1)),e.includes("__")&&(e=e.split("__").pop()??e),e}function p(t,e){if(t!=="call_tool"||!e)return null;const n=e.name;if(typeof n!="string"||!n.trim())return null;const r=e.arguments&&typeof e.arguments=="object"&&!Array.isArray(e.arguments)?e.arguments:{};return{innerName:s(n),innerArgs:r}}function a(t){const e=String(t??"").trim().replace(/\\/g,"/"),n=e.lastIndexOf("/");return n>=0?e.slice(n+1):e}function _(t){if(t&&typeof t=="object"&&!Array.isArray(t))return t;if(typeof t!="string")return null;try{const e=JSON.parse(t);return!e||typeof e!="object"||Array.isArray(e)?null:e}catch{return null}}function g(t,e,n){let r=s(t),c=e;if(r==="call_tool"){const u=p(r,e);if(!u)return null;r=u.innerName,c=u.innerArgs}const o=d[r];if(!o)return null;if(r.endsWith("_close_document"))return{action:"close",kind:o};const i=_(n),f=typeof i?.docId=="string"?i.docId.trim():typeof c?.docId=="string"?c.docId.trim():"";if(r.endsWith("_delete_document"))return f?{action:"delete",kind:o,docId:f}:null;if(!i||i.ok===!1)return null;const l=y(r,o,i,c);if(!l)return null;const m=o==="office"&&typeof i.kind=="string"&&i.kind.trim()?i.kind.trim():void 0;return{action:"open",kind:o,docId:f,name:l,...m?{detail:m}:{}}}function y(t,e,n,r){if(e!=="office"){const f=typeof n.name=="string"?n.name.trim():"";return f||(typeof r?.name=="string"?r.name.trim():"")}const c=typeof n.fileName=="string"?n.fileName.trim():"";if(c)return c;const o=typeof n.file=="string"?n.file.trim():"";if(o)return a(o);const i=typeof r?.file=="string"?r.file.trim():"";return i?a(i):""}export{s as normalizeSemanticToolName,g as resolveOpenDocEvent};
|
|
2
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
export type OpenDocKind = "pencil" | "draw" | "office";
|
|
4
|
+
|
|
5
|
+
export interface OpenDocEntry {
|
|
6
|
+
|
|
7
|
+
kind: OpenDocKind;
|
|
8
|
+
|
|
9
|
+
docId: string;
|
|
10
|
+
|
|
11
|
+
name: string;
|
|
12
|
+
|
|
13
|
+
detail?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export declare function recordOpenDocument(agentId: string | undefined, entry: OpenDocEntry): void;
|
|
17
|
+
|
|
18
|
+
export declare function closeOpenDocument(agentId: string | undefined, kind: OpenDocKind): void;
|
|
19
|
+
|
|
20
|
+
export declare function removeOpenDocument(agentId: string | undefined, kind: OpenDocKind, docId: string): void;
|
|
21
|
+
|
|
22
|
+
export declare function listOpenDocuments(agentId: string | undefined): OpenDocEntry[];
|
|
23
|
+
|
|
24
|
+
export declare function clearOpenDocuments(agentId: string | undefined): void;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const o=new Map;function s(r,t){const e=String(r??"").trim();if(!e||!t.name.trim())return;let n=o.get(e);n||(n=new Map,o.set(e,n)),n.set(t.kind,{...t,docId:t.docId.trim(),name:t.name.trim()})}function f(r,t){const e=String(r??"").trim();e&&o.get(e)?.delete(t)}function g(r,t,e){const n=String(r??"").trim();if(!n)return;const c=e.trim();if(!c)return;const i=o.get(n)?.get(t);i&&i.docId&&i.docId===c&&o.get(n)?.delete(t)}function m(r){const t=String(r??"").trim();if(!t)return[];const e=o.get(t);if(!e)return[];const n=["pencil","draw","office"],c=[];for(const i of n){const u=e.get(i);u&&c.push(u)}return c}function d(r){const t=String(r??"").trim();t&&o.delete(t)}export{d as clearOpenDocuments,f as closeOpenDocument,m as listOpenDocuments,s as recordOpenDocument,g as removeOpenDocument};
|
|
2
|
+
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createHash as T}from"node:crypto";import i from"node:fs/promises";import d from"node:path";import{getBridgeDataHome as v}from"../config.js";const p="acode-request-invalid-",I=20,h=10*6e4,_=8e3,w=2*1024*1024,u=800;let m=!1;const g=new Map;function C(){g.clear(),m=!1}function S(){return d.join(v(),"log")}function D(e){return T("sha1").update(e).digest("hex").slice(0,16)}function E(e){return new Date(e).toISOString().replace(/[:.]/g,"-")}function x(e){if(!Array.isArray(e))return{conversation:[],truncated:!1};try{if(JSON.stringify(e).length<=w)return{conversation:e,truncated:!1}}catch{}return{conversation:e.map(n=>{if(!n||typeof n!="object")return{value:String(n).slice(0,u)};const r=n,t=r.content;let o;if(typeof t=="string")o=t.slice(0,u);else if(t==null)o=t;else try{o=JSON.stringify(t).slice(0,u)}catch{o="[unserializable]"}return{role:r.role,tool_call_id:r.tool_call_id,tool_calls:Array.isArray(r.tool_calls)?r.tool_calls.map(c=>{const s=c;return{id:s?.id,type:s?.type,name:s?.name??s?.function?.name}}):void 0,contentPreview:o}}),truncated:!0}}async function O(e){try{const n=(await i.readdir(e)).filter(t=>t.startsWith(p)&&t.endsWith(".json")).sort(),r=n.length-I;if(r<=0)return;await Promise.all(n.slice(0,r).map(t=>i.rm(d.join(e,t),{force:!0})))}catch{}}async function M(e){const a=S(),n=D(e.errorText),r=Date.now(),t=g.get(e.sessionId);if(t&&t.fingerprint===n&&r-t.at<h)return t.file;const{conversation:o,truncated:c}=x(e.conversation),s=`${p}${E(r)}-${e.sessionId.slice(0,8)}.json`,l=d.join(a,s),y={timestamp:new Date(r).toISOString(),kind:"provider-request-invalid",sessionId:e.sessionId,agentId:e.agentId,model:e.model,attempt:e.attempt,errorText:e.errorText.slice(0,_),errorTextTruncated:e.errorText.length>_,messageCount:Array.isArray(e.conversation)?e.conversation.length:0,conversationTruncated:c,conversation:o,...e.extra?{extra:e.extra}:{}};try{return await i.mkdir(a,{recursive:!0}),await i.writeFile(l,JSON.stringify(y,null,2),"utf8"),g.set(e.sessionId,{fingerprint:n,file:l,at:r}),await O(a),l}catch(f){return m||(m=!0,console.warn(`[request-invalid-dump] \u4E0A\u4E0B\u6587\u5FEB\u7167\u5199\u5165\u5931\u8D25\uFF0C\u540E\u7EED\u5FEB\u7167\u5C06\u88AB\u4E22\u5F03: ${f instanceof Error?f.message:String(f)}`)),null}}export{M as dumpInvalidProviderRequest,S as getInvalidRequestDumpDir,C as resetInvalidRequestDumpStateForTest};
|
|
1
|
+
import{createHash as T}from"node:crypto";import i from"node:fs/promises";import d from"node:path";import{getBridgeDataHome as v}from"../config.js";const p="acode-request-invalid-",I=20,h=10*6e4,_=8e3,w=2*1024*1024,u=800;let m=!1;const g=new Map;function C(){g.clear(),m=!1}function S(){return d.join(v(),"log")}function D(e){return T("sha1").update(e).digest("hex").slice(0,16)}function E(e){return new Date(e).toISOString().replace(/[:.]/g,"-")}function x(e){if(!Array.isArray(e))return{conversation:[],truncated:!1};try{if(JSON.stringify(e).length<=w)return{conversation:e,truncated:!1}}catch{}return{conversation:e.map(n=>{if(!n||typeof n!="object")return{value:String(n).slice(0,u)};const r=n,t=r.content;let o;if(typeof t=="string")o=t.slice(0,u);else if(t==null)o=t;else try{o=JSON.stringify(t).slice(0,u)}catch{o="[unserializable]"}return{role:r.role,tool_call_id:r.tool_call_id,tool_calls:Array.isArray(r.tool_calls)?r.tool_calls.map(c=>{const s=c;return{id:s?.id,type:s?.type,name:s?.name??s?.function?.name}}):void 0,contentPreview:o}}),truncated:!0}}async function O(e){try{const n=(await i.readdir(e)).filter(t=>t.startsWith(p)&&t.endsWith(".json")).sort(),r=n.length-I;if(r<=0)return;await Promise.all(n.slice(0,r).map(t=>i.rm(d.join(e,t),{force:!0})))}catch{}}async function M(e){const a=S(),n=D(e.errorText),r=Date.now(),t=g.get(e.sessionId);if(t&&t.fingerprint===n&&r-t.at<h)return t.file;const{conversation:o,truncated:c}=x(e.conversation),s=`${p}${E(r)}-${e.sessionId.slice(0,8)}-${n.slice(0,8)}.json`,l=d.join(a,s),y={timestamp:new Date(r).toISOString(),kind:"provider-request-invalid",sessionId:e.sessionId,agentId:e.agentId,model:e.model,attempt:e.attempt,errorText:e.errorText.slice(0,_),errorTextTruncated:e.errorText.length>_,messageCount:Array.isArray(e.conversation)?e.conversation.length:0,conversationTruncated:c,conversation:o,...e.extra?{extra:e.extra}:{}};try{return await i.mkdir(a,{recursive:!0}),await i.writeFile(l,JSON.stringify(y,null,2),"utf8"),g.set(e.sessionId,{fingerprint:n,file:l,at:r}),await O(a),l}catch(f){return m||(m=!0,console.warn(`[request-invalid-dump] \u4E0A\u4E0B\u6587\u5FEB\u7167\u5199\u5165\u5931\u8D25\uFF0C\u540E\u7EED\u5FEB\u7167\u5C06\u88AB\u4E22\u5F03: ${f instanceof Error?f.message:String(f)}`)),null}}export{M as dumpInvalidProviderRequest,S as getInvalidRequestDumpDir,C as resetInvalidRequestDumpStateForTest};
|
|
2
2
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import
|
|
2
|
-
`)}async function
|
|
1
|
+
import m from"axios";import{getBrowserPool as f}from"../browser/browser-pool.js";import{resolveSchedulerBaseUrl as p}from"../config.js";import{ptySessions as g}from"../routes/pty.js";import{createLogger as $}from"../utils/logger.js";import{getAcodeBgManager as h}from"./acode-bg-manager.js";import{agentPtyManager as w}from"./agent-pty-manager.js";import{listOpenDocuments as b}from"./open-doc-registry.js";import{getRuntimeAccessToken as l}from"./runtime-binding.js";import{subAgentManager as k}from"./sub-agent-manager-instance.js";const i=$("runtime-resources"),S=3e3,a=20,y={pencil:"open pencil canvas",draw:"open draw diagram",office:"open office document"};function c(t,e){const n=String(t??"").replace(/\s+/g," ").trim();return n.length>e?`${n.slice(0,e)}\u2026`:n}function D(t){if(typeof t!="number"||!Number.isFinite(t)||t<=0)return"";const e=new Date(t),n=r=>String(r).padStart(2,"0");return`${n(e.getHours())}:${n(e.getMinutes())}`}async function v(t){try{const e=await h();return e?.listTasksWithReconcile?(await e.listTasksWithReconcile(t,"running")).filter(r=>r.status==="running").slice(0,a).map(r=>{const o=D(r.startedAt),s=r.description?c(r.description,60):c(r.commandPreview||r.command,80);return{kind:"background commands",text:`${r.taskId} \`${s}\`${o?` (since ${o})`:""}`}}):[]}catch(e){return i.warn(`collect background commands failed: ${e?.message}`),[]}}function x(t){try{const e=[];let n=[];try{n=w.listWaitingForInput(t)}catch(o){i.warn(`collect terminals waiting-input failed: ${o?.message}`)}const r=new Set(n);for(const o of g.values()){if(o.ownerUserId!==t||o.status!=="running")continue;if(e.length>=a)break;const s=c(o.title||o.shell,60),d=r.has(o.id)?"running, waiting for input":"running";e.push({kind:"terminals",text:`${o.id} ${s} (${d})`})}return e}catch(e){return i.warn(`collect terminals failed: ${e?.message}`),[]}}function A(t){try{return k.listActiveByParent(t).slice(0,a).map(n=>({kind:"sub-agents",text:`${n.subId} ${n.subagentType} "${c(n.description,60)}" (running)`}))}catch(e){return i.warn(`collect sub-agents failed: ${e?.message}`),[]}}function T(t){try{return f().listSessions(t).slice(0,a).map(n=>{const r=c(n.title||n.browserId,40),o=c(n.currentUrl,80);return{kind:"browsers",text:`${c(n.browserId,40)} "${r}"${o?` ${o}`:""}`}})}catch(e){return i.warn(`collect browsers failed: ${e?.message}`),[]}}function M(t){try{return b(t).map(e=>{const n=e.docId?`${e.docId} `:"",r=e.detail?` (${e.detail})`:"";return{kind:y[e.kind],text:`${n}${e.name}${r}`}})}catch(e){return i.warn(`collect open documents failed: ${e?.message}`),[]}}function u(t,e){if(!Array.isArray(e))return[];const n=[];for(const r of e){if(n.length>=a)break;const o=c(String(r?.name??r?.docId??""),60);if(!o)continue;const s=String(r?.permission??"").trim();n.push({kind:t,text:`${o}${s?` (${s})`:""}`})}return n}async function R(t){try{const{url:e}=p();if(!e)return[];const n=l(e)||l();if(!n)return[];const o=(await m.get(`${e}/api/runtime/agent-resources`,{params:{agentId:t},headers:{"X-Runtime-Token":n},timeout:S})).data??{};return[...u("office docs",o.officeDocs),...u("pencil docs",o.pencilDocs),...u("draw docs",o.drawDocs)]}catch(e){return i.warn(`collect java docs failed (office/pencil/draw omitted): agentId=${t}, error=${e?.message}`),[]}}function _(t){const e=new Map;for(const r of t){const o=e.get(r.kind);o?o.push(r.text):e.set(r.kind,[r.text])}const n=["[Runtime resources \u2014 live snapshot taken after context compaction.]","These already exist and are still running/available. Reuse them instead of creating duplicates","(do not start another dev server, open another browser, or redraw an existing document).","Details (output, page content, document body) are not included \u2014 query them when needed."];for(const[r,o]of e)n.push(`- ${r} (${o.length}): ${o.join("; ")}`);return n.join(`
|
|
2
|
+
`)}async function W(t){if(!t)return null;try{const[e,n]=await Promise.all([v(t),R(t)]),r=[...e,...x(t),...A(t),...T(t),...M(t),...n];if(r.length===0)return null;const o=_(r);return i.debug(`snapshot built for agentId=${t}: ${r.length} entries (${[...new Set(r.map(s=>s.kind))].join(", ")})`),o}catch(e){return i.warn(`build snapshot failed: ${e?.message}`),null}}export{W as buildRuntimeResourcesSnapshot};
|
|
3
3
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import h from"axios";import{resolveSchedulerBaseUrlFrom as H}from"../config.js";import{requestRuntimeAccessTokenRefreshForServer as
|
|
2
|
-
${r.slice(-E)}`:r,a={category:"output",agentId:t,sessionId:c,output:n,seq:e,sourceEventType:i?.sourceEventType,logLevel:i?.logLevel,logCategory:i?.logCategory};B.appendOrMerge(a,p=>{const l=p.data;if(l.category!=="output"||l.sessionId!==c||l.sourceEventType!==i?.sourceEventType||Date.now()-p.timestamp>1e4)return!1;const d=(l.output||"").length,T=(a.output||"").length;return d+T<=E},(p,l)=>{const d=p.output||"",T=l.output||"";return d.includes(T)?p:{...p,output:`${d}${T}`}});const k=S.appendOrMergeOutput(t,a);$(t,k,o)}}async function V(t,r,c,e,i){const o=y(e),u={agentId:t,sessionId:r,questions:c,...i?{toolCallId:i}:{}};try{const s=m(e,o);if(!s)return;await h.post(`${o}/api/runtime/callback/question`,u,{headers:s})}catch(s){if(w(s)===401&&await R(o)){const a=m(x(e),o);if(a)try{await h.post(`${o}/api/runtime/callback/question`,u,{headers:a});return}catch{}}}finally{const s={category:"question",agentId:t,sessionId:r,...i?{toolCallId:i}:{},questions:c};B.append(s);const n=S.append(t,s);$(t,n,e)}}async function Y(t,r,c,e){const i=y(e),o={agentId:t,sessionId:r,...c};try{const u=m(e,i);if(!u)return;await h.post(`${i}/api/runtime/callback/tool-auth`,o,{headers:u})}catch(u){if(w(u)===401&&await R(i)){const n=m(x(e),i);if(n)try{await h.post(`${i}/api/runtime/callback/tool-auth`,o,{headers:n});return}catch{}}}}async function Z(t){const r=y();try{const c=m(void 0,r);if(!c)return;await h.post(`${r}/api/runtime/callback/file-changed`,t,{headers:c})}catch(c){if(w(c)===401&&await R(r)){const i=m(void 0,r);if(i)try{await h.post(`${r}/api/runtime/callback/file-changed`,t,{headers:i});return}catch{}}}finally{const c={category:"file_changed",agentId:"",sessionId:null,workspacePath:t.workspacePath,filePath:t.filePath,eventType:t.eventType,size:t.size};B.append(c)}}function I(t,r){const c=U.get(t);if(!c||!r)return;const e=`${c.outputBuffer}${r}`;if(e.length<=M){c.outputBuffer=e;return}const o=`\r
|
|
1
|
+
import h from"axios";import{resolveSchedulerBaseUrlFrom as H}from"../config.js";import{requestRuntimeAccessTokenRefreshForServer as P}from"../services/auto-register.js";import{logger as f}from"../utils/logger.js";import{agentEventStore as S}from"./agent-event-store.js";import{scheduleEventPush as $}from"./event-delta-pusher.js";import{RingBuffer as C}from"./ring-buffer.js";import{getRuntimeAccessToken as _}from"./runtime-binding.js";const B=new C(2e3);function m(t,r=y(t)){const c=t?.runtimeAccessToken||_(r)||_();return c?{"X-Runtime-Token":c}:void 0}function x(t){if(t)return{schedulerBaseUrl:t.schedulerBaseUrl}}function y(t){return H(t?.schedulerBaseUrl).url}const O=100;function w(t){if(typeof t!="object"||t===null)return;const r=t.response;if(typeof r!="object"||r===null)return;const c=r.status;return typeof c=="number"?c:void 0}let L=null;async function R(t){if(L)return L;L=(async()=>{try{const r=await P(t);return r.success&&r.runtimeAccessToken?(f.info("[session-output] Runtime token refreshed after 401"),!0):(f.warn("[session-output] Runtime token refresh failed",{error:r.error}),!1)}catch(r){return f.warn("[session-output] Runtime token refresh threw",{error:r}),!1}})();try{return await L}finally{L=null}}const E=8e3,M=64*1024,g=32*1024,A=15e3,U=new Map;async function J(t,r,c,e,i,o,u,s){const n={agentId:t,sessionId:r,status:c};u!==void 0&&(n.timestamp=u),e&&(e.actionType&&(n.actionType=e.actionType),e.actionLabel&&(n.actionLabel=e.actionLabel),e.actionDetail&&(n.actionDetail=e.actionDetail),e.actionInput&&(n.actionInput=e.actionInput),e.actionResult&&(n.actionResult=e.actionResult),e.actionError&&(n.actionError=e.actionError),e.actionId&&(n.actionId=e.actionId),e.parentId&&(n.parentId=e.parentId),e.batchId&&(n.batchId=e.batchId),e.batchMetrics&&(n.batchMetrics=e.batchMetrics)),i&&(n.inputTokens=i.inputTokens,n.outputTokens=i.outputTokens,i.contextLimit&&(n.contextLimit=i.contextLimit),i.maxOutput&&(n.maxOutput=i.maxOutput),i.inputLimit&&(n.inputLimit=i.inputLimit),i.compactionThreshold&&(n.compactionThreshold=i.compactionThreshold),i.cacheHitTokens!==void 0&&(n.cacheHitTokens=i.cacheHitTokens),i.cacheMissTokens!==void 0&&(n.cacheMissTokens=i.cacheMissTokens)),s&&(n.sourceEventType=s),process.env.ACODE_TOKEN_DEBUG==="1"&&(n.inputTokens!==void 0||n.outputTokens!==void 0||n.cacheHitTokens!==void 0||n.cacheMissTokens!==void 0)&&console.log(`[TokenDebug][SendStatus] status=${c} inputTokens=${n.inputTokens??"(none)"} outputTokens=${n.outputTokens??"(none)"} cacheHitTokens=${n.cacheHitTokens??"(none)"} cacheMissTokens=${n.cacheMissTokens??"(none)"} contextLimit=${n.contextLimit??"(none)"} actionType=${n.actionType??"(none)"}`);const a=y(o),k=m(o,a);if(!k){f.warn("Skip runtime status callback because runtime token is missing",{agentId:t,sessionId:r,status:c,schedulerBaseUrl:a});return}const p=e?.actionType==="context_compaction";p&&f.info("[compaction-diag] sendStatus enter",{agentId:t,sessionId:r,status:c,actionId:e?.actionId,parentId:e?.parentId,actionLabel:e?.actionLabel});try{const l=await h.post(`${a}/api/runtime/callback/status`,n,{headers:k,timeout:15e3});if(p){const d=l?.data;f.info("[compaction-diag] sendStatus success",{agentId:t,actionId:e?.actionId,actionLabel:e?.actionLabel,httpStatus:l?.status,ignored:d?.ignored,responseBody:d})}return l}catch(l){if(w(l)===401&&await R(a)){const T=m(x(o),a);if(T)try{const b=await h.post(`${a}/api/runtime/callback/status`,n,{headers:T,timeout:15e3});if(p){const v=b?.data;f.info("[compaction-diag] sendStatus retry success",{agentId:t,actionId:e?.actionId,actionLabel:e?.actionLabel,httpStatus:b?.status,ignored:v?.ignored})}return b}catch(b){f.warn("Runtime status callback retry failed after token refresh",{agentId:t,sessionId:r,status:c,error:b});return}}f.warn("Runtime status callback failed",{agentId:t,sessionId:r,status:c,schedulerBaseUrl:a,error:l});return}finally{const l={category:"status",agentId:t,sessionId:r,status:c,actionType:e?.actionType,actionLabel:e?.actionLabel,actionDetail:e?.actionDetail,actionInput:e?.actionInput,actionResult:e?.actionResult,actionError:e?.actionError,actionId:e?.actionId,parentId:e?.parentId,batchId:e?.batchId,batchMetrics:e?.batchMetrics,inputTokens:i?.inputTokens,outputTokens:i?.outputTokens,cacheHitTokens:i?.cacheHitTokens,cacheMissTokens:i?.cacheMissTokens,sourceEventType:s};B.append(l);const d=S.append(t,l);$(t,d,o)}}async function D(t,r,c,e,i,o,u){const s=y(o);try{const n=m(o,s);if(!n){f.warn("Skip runtime output callback because runtime token is missing",{agentId:t,sessionId:c,schedulerBaseUrl:s});return}const a={headers:n,timeout:A};u&&(a.signal=u),await h.post(`${s}/api/runtime/callback/output`,{agentId:t,output:r,sessionId:c,seq:e,...i},a)}catch(n){if(u?.aborted||n?.name==="AbortError"||n?.code==="ERR_CANCELED")throw n;if(w(n)===401&&await R(s)){const k=m(x(o),s);if(k)try{const p={headers:k,timeout:A};u&&(p.signal=u),await h.post(`${s}/api/runtime/callback/output`,{agentId:t,output:r,sessionId:c,seq:e,...i},p);return}catch{}}throw f.warn("Runtime output callback failed",{agentId:t,sessionId:c,error:n}),n}finally{if(!i?.skipLocalPersist){const n=r.length>E?`...(truncated)
|
|
2
|
+
${r.slice(-E)}`:r,a={category:"output",agentId:t,sessionId:c,output:n,seq:e,sourceEventType:i?.sourceEventType,logLevel:i?.logLevel,logCategory:i?.logCategory};B.appendOrMerge(a,p=>{const l=p.data;if(l.category!=="output"||l.sessionId!==c||l.sourceEventType!==i?.sourceEventType||Date.now()-p.timestamp>1e4)return!1;const d=(l.output||"").length,T=(a.output||"").length;return d+T<=E},(p,l)=>{const d=p.output||"",T=l.output||"";return d.includes(T)?p:{...p,output:`${d}${T}`}});const k=S.appendOrMergeOutput(t,a);$(t,k,o)}}}async function V(t,r,c,e,i){const o=y(e),u={agentId:t,sessionId:r,questions:c,...i?{toolCallId:i}:{}};try{const s=m(e,o);if(!s)return;await h.post(`${o}/api/runtime/callback/question`,u,{headers:s})}catch(s){if(w(s)===401&&await R(o)){const a=m(x(e),o);if(a)try{await h.post(`${o}/api/runtime/callback/question`,u,{headers:a});return}catch{}}}finally{const s={category:"question",agentId:t,sessionId:r,...i?{toolCallId:i}:{},questions:c};B.append(s);const n=S.append(t,s);$(t,n,e)}}async function Y(t,r,c,e){const i=y(e),o={agentId:t,sessionId:r,...c};try{const u=m(e,i);if(!u)return;await h.post(`${i}/api/runtime/callback/tool-auth`,o,{headers:u})}catch(u){if(w(u)===401&&await R(i)){const n=m(x(e),i);if(n)try{await h.post(`${i}/api/runtime/callback/tool-auth`,o,{headers:n});return}catch{}}}}async function Z(t){const r=y();try{const c=m(void 0,r);if(!c)return;await h.post(`${r}/api/runtime/callback/file-changed`,t,{headers:c})}catch(c){if(w(c)===401&&await R(r)){const i=m(void 0,r);if(i)try{await h.post(`${r}/api/runtime/callback/file-changed`,t,{headers:i});return}catch{}}}finally{const c={category:"file_changed",agentId:"",sessionId:null,workspacePath:t.workspacePath,filePath:t.filePath,eventType:t.eventType,size:t.size};B.append(c)}}function I(t,r){const c=U.get(t);if(!c||!r)return;const e=`${c.outputBuffer}${r}`;if(e.length<=M){c.outputBuffer=e;return}const o=`\r
|
|
3
3
|
[AgentsWorkStudio: omitted ${e.length-M} chars of old terminal output]\r
|
|
4
4
|
`,u=Math.max(0,M-o.length);c.outputBuffer=`${o}${e.slice(-u)}`}function F(t){const r=U.get(t);r&&(r.flushTimer||(r.flushTimer=setTimeout(()=>{r.flushTimer=null,q(t).catch(()=>{})},O)))}async function q(t){const r=U.get(t);if(!r||r.flushInFlight||!r.outputBuffer)return;const c=r.outputBuffer.slice(0,g);r.outputBuffer=r.outputBuffer.slice(g);const e=(async()=>{const i=r.seq+1;r.seq=i,await D(r.agentId,c,t,i),U.get(t)?.outputBuffer&&F(t)})();r.flushInFlight=e;try{await e}finally{const i=U.get(t);i&&(i.flushInFlight=null)}}export{I as appendSessionOutput,B as bridgeEventBuffer,q as flushSessionOutput,F as scheduleOutputFlush,Z as sendFileChanged,D as sendOutput,V as sendQuestionRequest,J as sendStatus,Y as sendToolAuthRequest,U as sessions};
|
|
5
5
|
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const u=3650;let t=null,l=!1;function i(e,o=!1){if(o&&l)return;if(o||(l=!0),e==null||e===""){t=null;return}if(typeof e=="boolean"){t=null;return}const n=Number(e);if(!Number.isFinite(n)||n<=0){t=null;return}t=Math.min(Math.floor(n),3650)}function r(){return t}function s(){t=null,l=!1}export{r as getSnapshotRetentionDays,s as resetSnapshotRetentionForTest,i as setSnapshotRetentionDays};
|
|
2
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
export type LaunchStackType = "generic" | "java" | "python" | "node" | "go" | "php";
|
|
4
|
+
export interface TechStackCandidate {
|
|
5
|
+
|
|
6
|
+
id: string;
|
|
7
|
+
|
|
8
|
+
name: string;
|
|
9
|
+
type: LaunchStackType;
|
|
10
|
+
|
|
11
|
+
command: string;
|
|
12
|
+
|
|
13
|
+
cwd: string;
|
|
14
|
+
|
|
15
|
+
relativeCwd: string;
|
|
16
|
+
|
|
17
|
+
stack: string;
|
|
18
|
+
|
|
19
|
+
markers: string[];
|
|
20
|
+
confidence: "high" | "medium" | "low";
|
|
21
|
+
}
|
|
22
|
+
export interface TechStackScanResult {
|
|
23
|
+
workspacePath: string;
|
|
24
|
+
|
|
25
|
+
scannedDirs: number;
|
|
26
|
+
|
|
27
|
+
truncated: boolean;
|
|
28
|
+
candidates: TechStackCandidate[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export declare function scanTechStack(workspacePath: string): Promise<TechStackScanResult>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import N from"node:crypto";import{promises as k}from"node:fs";import d from"node:path";import{createLogger as R}from"../utils/logger.js";import{isIgnoredByGitIgnore as A,loadGitIgnoreRules as B}from"./gitignore.js";const w=R("tech-stack-scanner"),E=64*1024,T=4e3,C=2e3,F=5,M=new Set([".git",".svn",".hg",".idea",".vscode","node_modules","bower_components","vendor","target","dist","build","out","bin","obj",".gradle",".venv","venv","env","__pycache__",".mypy_cache",".pytest_cache",".next",".nuxt",".svelte-kit",".turbo",".cache","coverage"]);function q(e,n){return e==="."?n:`${e}/${n}`}async function g(e){try{const n=await k.open(e,"r");try{const t=await n.stat();if(!t.isFile())return null;const p=Math.min(t.size,E),o=Buffer.alloc(p);return await n.read(o,0,p,0),o.toString("utf8")}finally{await n.close()}}catch{return null}}async function D(e){try{return(await k.stat(e)).isFile()}catch{return!1}}function _(e){if(!e)return null;try{const n=JSON.parse(e);return n&&typeof n=="object"?n:null}catch{return null}}function L(e,n,t){return N.createHash("sha1").update(`${e}|${n}|${t}`).digest("hex").slice(0,12)}function I(e){return process.platform==="win32"?`${e}.cmd`:`./${e}`}function O(e,n,t){return n.has("mvnw")||n.has("mvnw.cmd")?`${I("mvnw")} ${t}`:`mvn ${t}`}function W(e,n){return e.has("gradlew")||e.has("gradlew.bat")?`${I("gradlew")} ${n}`:`gradle ${n}`}function G(e){if(!e)return"";const t=e.replace(/<parent>[\s\S]*?<\/parent>/gi,"").match(/<artifactId>\s*([^<\s]+)\s*<\/artifactId>/i);return t?t[1].trim():""}function J(e){if(!e)return"";const n=e.match(/rootProject\.name\s*=\s*['"]([^'"]+)['"]/);return n?n[1].trim():""}function X(e){if(!e)return"";const n=e.match(/\[package\][\s\S]*?(?=\n\[|$)/),p=(n?n[0]:e).match(/^\s*name\s*=\s*["']([^"']+)["']/m);return p?p[1].trim():""}function x(e){return d.basename(e)||"workspace"}function Y(e){return e.has("pnpm-lock.yaml")||e.has("pnpm-workspace.yaml")?{runner:"pnpm",runCommand:n=>`pnpm run ${n}`}:e.has("yarn.lock")?{runner:"yarn",runCommand:n=>`yarn run ${n}`}:e.has("bun.lockb")||e.has("bun.lock")?{runner:"bun",runCommand:n=>`bun run ${n}`}:{runner:"npm",runCommand:n=>`npm run ${n}`}}const K=["dev","develop","serve","start"];function z(e){for(const n of K)if(typeof e[n]=="string"&&e[n].trim())return n;return null}function H(e,n){return e.has("uv.lock")?"uv run ":n&&/\[tool\.poetry\]/i.test(n)?"poetry run ":""}function m(e){const{facts:n,stack:t,type:p,command:o,name:i,markers:h,confidence:f}=e;return{id:L(n.relativeDir,t,o),name:i||x(n.absoluteDir),type:p,command:o,cwd:n.absoluteDir,relativeCwd:n.relativeDir,stack:t,markers:h,confidence:f}}async function Q(e){const{absoluteDir:n,entryNames:t,subdirectories:p}=e,o=[],i=x(n);if(t.has("pom.xml")){const a=await g(d.join(n,"pom.xml")),s=G(a)||i,c=!!(a&&/spring-boot/i.test(a));o.push(m({facts:e,stack:c?"spring-boot":"maven",type:"java",command:O(n,t,c?"spring-boot:run":"-DskipTests package"),name:s,markers:["pom.xml"],confidence:c?"high":"medium"}))}else if(t.has("build.gradle")||t.has("build.gradle.kts")){const a=t.has("build.gradle.kts")?"build.gradle.kts":"build.gradle",s=await g(d.join(n,a)),c=J(s)||i,r=!!(s&&/org\.springframework\.boot/i.test(s));o.push(m({facts:e,stack:r?"spring-boot":"gradle",type:"java",command:W(t,r?"bootRun":"build"),name:c,markers:[a],confidence:r?"high":"medium"}))}if(t.has("package.json")){const a=_(await g(d.join(n,"package.json"))),s=a&&typeof a.scripts=="object"&&a.scripts!==null?a.scripts:{},c=z(s);if(c){const{runCommand:r}=Y(t),l=a&&typeof a.name=="string"?a.name.trim():"";o.push(m({facts:e,stack:"node",type:"node",command:r(c),name:l||i,markers:["package.json"],confidence:"high"}))}}if(t.has("manage.py"))o.push(m({facts:e,stack:"django",type:"python",command:"python manage.py runserver",name:`${i} (Django)`,markers:["manage.py"],confidence:"high"}));else if(t.has("pyproject.toml")||t.has("requirements.txt")||t.has("setup.py")){const a=t.has("pyproject.toml")?await g(d.join(n,"pyproject.toml")):null,s=H(t,a),c=t.has("pyproject.toml")?"pyproject.toml":t.has("requirements.txt")?"requirements.txt":"setup.py";!!(a&&/fastapi/i.test(a))&&t.has("main.py")?o.push(m({facts:e,stack:"fastapi",type:"python",command:`${s}uvicorn main:app --reload`,name:`${i} (FastAPI)`,markers:[c,"main.py"],confidence:"high"})):t.has("main.py")?o.push(m({facts:e,stack:"python",type:"python",command:`${s}python main.py`,name:i,markers:[c,"main.py"],confidence:"medium"})):t.has("app.py")&&o.push(m({facts:e,stack:"python",type:"python",command:`${s}python app.py`,name:i,markers:[c,"app.py"],confidence:"medium"}))}if(t.has("go.mod")){if(t.has("main.go"))o.push(m({facts:e,stack:"go",type:"go",command:"go run .",name:i,markers:["go.mod","main.go"],confidence:"high"}));else if(p.includes("cmd")){const a=d.join(n,"cmd");let s=[];try{s=await k.readdir(a,{withFileTypes:!0})}catch{s=[]}const c=s.filter(r=>r.isDirectory()).map(r=>r.name).sort().slice(0,F);for(const r of c)await D(d.join(a,r,"main.go"))&&o.push(m({facts:e,stack:"go",type:"go",command:`go run ./cmd/${r}`,name:`${i}/${r}`,markers:["go.mod",`cmd/${r}/main.go`],confidence:"high"}))}}if(t.has("composer.json")){const a=_(await g(d.join(n,"composer.json"))),s=a&&typeof a.name=="string"?a.name.trim():"";!!(a&&(/laravel\/framework/i.test(JSON.stringify(a.require??{}))||/laravel\/framework/i.test(JSON.stringify(a["require-dev"]??{}))))&&t.has("artisan")?o.push(m({facts:e,stack:"laravel",type:"php",command:"php artisan serve",name:s||i,markers:["composer.json","artisan"],confidence:"high"})):e.directoryNames.has("public")&&e.directoryNames.has("bin")?o.push(m({facts:e,stack:"symfony",type:"php",command:"php -S localhost:8000 -t public",name:s||i,markers:["composer.json"],confidence:"medium"})):t.has("index.php")&&o.push(m({facts:e,stack:"php",type:"php",command:"php -S localhost:8000",name:s||i,markers:["composer.json","index.php"],confidence:"medium"}))}else t.has("index.php")&&o.push(m({facts:e,stack:"php",type:"php",command:"php -S localhost:8000",name:i,markers:["index.php"],confidence:"low"}));if(t.has("Cargo.toml")){const a=await g(d.join(n,"Cargo.toml")),s=!!(a&&/^\s*\[package\]/m.test(a)),c=!!(a&&/^\s*\[\[bin\]\]/m.test(a)||await D(d.join(n,"src","main.rs")));if(s&&c){const r=X(a);o.push(m({facts:e,stack:"cargo",type:"generic",command:"cargo run",name:r||i,markers:["Cargo.toml"],confidence:"medium"}))}}const h=t.has("deno.json")?"deno.json":t.has("deno.jsonc")?"deno.jsonc":"";if(h){const a=await g(d.join(n,h));a&&/["']?start["']?\s*:/.test(a)&&o.push(m({facts:e,stack:"deno",type:"generic",command:"deno task start",name:i,markers:[h],confidence:"medium"}))}const f=["docker-compose.yml","docker-compose.yaml","compose.yml","compose.yaml"].find(a=>t.has(a));return f&&o.push(m({facts:e,stack:"docker-compose",type:"generic",command:"docker compose up",name:`${i} (compose)`,markers:[f],confidence:"medium"})),o}function U(e,n,t,p){return M.has(t.toLowerCase())?!0:p.length===0?!1:A(n,!0,p)}async function ae(e){const n=String(e||"").trim();if(!n)throw new Error("workspacePath is required");const t=d.resolve(n);if(!(await k.stat(t)).isDirectory())throw new Error(`Workspace path is not a directory: ${t}`);const o=await B(t),i=[];let h=0,f=!1;const a=[[t,"."]];for(;a.length>0;){if(h>=T){f=!0;break}const r=a.shift();if(!r)break;const[l,v]=r;h+=1;let y=[];try{y=await k.readdir(l,{withFileTypes:!0})}catch(u){w.warn(`[scan] readdir failed: dir=${l} error=${u.message}`);continue}y.length>C&&(f=!0,y=y.slice(0,C));const b=new Set,j=new Set,$=[];for(const u of y)if(u.isDirectory()){j.add(u.name);const S=q(v,u.name);if(U(t,S,u.name,o))continue;$.push(u.name),a.push([d.join(l,u.name),S])}else u.isFile()&&b.add(u.name);const P={absoluteDir:l,relativeDir:v,entryNames:b,directoryNames:j,subdirectories:$};try{i.push(...await Q(P))}catch(u){w.warn(`[scan] detect failed: dir=${l} error=${u.message}`)}}const s=new Set,c=i.filter(r=>s.has(r.id)?!1:(s.add(r.id),!0));return c.sort((r,l)=>r.relativeCwd!==l.relativeCwd?r.relativeCwd.localeCompare(l.relativeCwd):r.stack.localeCompare(l.stack)),w.info(`[scan] workspace=${t} dirs=${h} candidates=${c.length} truncated=${f}`),{workspacePath:t,scannedDirs:h,truncated:f,candidates:c}}export{ae as scanTechStack};
|
|
2
|
+
|
|
@@ -1,4 +1,36 @@
|
|
|
1
1
|
|
|
2
|
+
import WebSocket from "ws";
|
|
3
|
+
interface LocalStream {
|
|
4
|
+
ws: WebSocket;
|
|
5
|
+
|
|
6
|
+
pending: Array<{
|
|
7
|
+
data: Buffer;
|
|
8
|
+
bin: boolean;
|
|
9
|
+
}>;
|
|
10
|
+
}
|
|
11
|
+
interface TunnelState {
|
|
12
|
+
|
|
13
|
+
serverUrl: string;
|
|
14
|
+
instanceId: string;
|
|
15
|
+
ws?: WebSocket;
|
|
16
|
+
|
|
17
|
+
streams: Map<string, LocalStream>;
|
|
18
|
+
|
|
19
|
+
pendingReqChunks: Map<string, PendingRequestChunks>;
|
|
20
|
+
timer?: NodeJS.Timeout;
|
|
21
|
+
reconnectTimer?: NodeJS.Timeout;
|
|
22
|
+
|
|
23
|
+
reconnectAttempts?: number;
|
|
24
|
+
shuttingDown: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface PendingRequestChunks {
|
|
28
|
+
method: string;
|
|
29
|
+
path: string;
|
|
30
|
+
headers?: Record<string, string[]>;
|
|
31
|
+
parts: Buffer[];
|
|
32
|
+
timer: NodeJS.Timeout;
|
|
33
|
+
}
|
|
2
34
|
|
|
3
35
|
export declare function startTunnelClient(serverUrl: string, instanceId: string): void;
|
|
4
36
|
|
|
@@ -7,3 +39,13 @@ export declare function stopTunnelClient(): void;
|
|
|
7
39
|
export declare function stopTunnelClientForServer(serverUrl: string): void;
|
|
8
40
|
|
|
9
41
|
export declare function stopTunnelClientsExcept(serverUrls: string[]): void;
|
|
42
|
+
|
|
43
|
+
export declare const __tunnelClientTestHooks: {
|
|
44
|
+
createState(serverUrl?: string, instanceId?: string): TunnelState;
|
|
45
|
+
dispatch(state: TunnelState, msg: Record<string, unknown>): void;
|
|
46
|
+
|
|
47
|
+
pendingChunkIds(state: TunnelState): string[];
|
|
48
|
+
|
|
49
|
+
cleanup(state: TunnelState): void;
|
|
50
|
+
};
|
|
51
|
+
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
1
|
+
import O,{AxiosError as x}from"axios";import g from"ws";import{getActiveBridgeHttpPort as R}from"../config.js";import{logger as s}from"../utils/logger.js";import{loadConfigs as L,loadPrimaryLifecycleConfig as P}from"./auto-register.js";import{getRuntimeAccessToken as W,normalizeSchedulerBaseUrl as C}from"./runtime-binding.js";const $=15e3,G=5e3,H=3e4,A=.2,J=200,K=1*1024*1024,X=4001,Y=768*1024,j=384*1024,z=5*6e4,p=new Map;function F(e){const n=e.serverUrl,r=e.instanceId;if(!n||!r)return null;try{const t=new URL(n),o=t.protocol==="https:"?"wss:":"ws:",u=W(n),l=L().find(h=>C(h.serverUrl)===n)||P(),i=u||l.userKey;if(u?s.debug("[TunnelClient] \u4F7F\u7528 runtime access token \u8FDE\u63A5\u96A7\u9053"):l.userKey&&s.warn("[TunnelClient] getRuntimeAccessToken \u8FD4\u56DE\u7A7A\uFF0C\u56DE\u9000\u5230 userKey\uFF08\u975E runtime token\uFF0C\u9274\u6743\u53EF\u80FD\u5931\u8D25\uFF09: targetUrl=",n),!i)return s.warn("[TunnelClient] \u7F3A\u5C11 runtime token\uFF0C\u65E0\u6CD5\u5EFA\u7ACB\u96A7\u9053: targetUrl=",n),null;const f=new URLSearchParams({instanceId:r});return{url:`${o}//${t.host}/ws/bridge-tunnel?${f.toString()}`,token:i}}catch(t){return s.warn("[TunnelClient] \u65E0\u6CD5\u89E3\u6790 serverUrl:",String(t)),null}}function le(e,n){const r=C(e);if(!r){s.warn("[TunnelClient] serverUrl \u65E0\u6548\uFF0C\u65E0\u6CD5\u542F\u52A8\u96A7\u9053:",e);return}const t=p.get(r);t&&(t.shuttingDown=!0,S(t),p.delete(r));const o={serverUrl:r,instanceId:n,streams:new Map,pendingReqChunks:new Map,shuttingDown:!1};p.set(r,o),B(o)}function de(){for(const e of p.values())e.shuttingDown=!0,S(e);p.clear()}function fe(e){const n=C(e);if(!n)return;const r=p.get(n);r&&(r.shuttingDown=!0,S(r),p.delete(n),s.info(`[TunnelClient] tunnel stopped: ${n}`))}function ae(e){const n=new Set(e.map(r=>C(r)).filter(r=>!!r));for(const[r,t]of p.entries())n.has(r)||(s.info(`[TunnelClient] serverUrl \u5DF2\u4E0D\u5728\u914D\u7F6E\u4E2D\uFF0C\u505C\u6B62\u65E7\u96A7\u9053: ${r}`),t.shuttingDown=!0,S(t),p.delete(r))}function S(e){e.timer&&(clearInterval(e.timer),e.timer=void 0),e.reconnectTimer&&(clearTimeout(e.reconnectTimer),e.reconnectTimer=void 0);for(const[n,r]of e.streams.entries()){try{r.ws.close(1e3,"tunnel client stopped")}catch{}e.streams.delete(n)}if(e.ws){e.ws.removeAllListeners();try{e.ws.close(1e3,"tunnel client stopped")}catch{}e.ws=void 0}}function B(e){if(e.shuttingDown)return;const n=e.instanceId;if(!n)return;const r=F(e);if(!r){b(e);return}s.info("[TunnelClient] \u8FDE\u63A5\u96A7\u9053\u670D\u52A1\u7AEF:",r.url);const t=new g(r.url,{handshakeTimeout:15e3,headers:{"X-Runtime-Token":r.token}});e.ws=t,t.on("open",()=>{s.info("[TunnelClient] \u96A7\u9053\u8FDE\u63A5\u5DF2\u5EFA\u7ACB: server=",e.serverUrl,"instanceId=",n),e.reconnectTimer&&clearTimeout(e.reconnectTimer),e.reconnectTimer=void 0,e.reconnectAttempts=0,e.timer=setInterval(()=>{t.readyState===g.OPEN&&t.send(JSON.stringify({t:"ping"}))},$)}),t.on("unexpected-response",(o,u)=>{s.error("[TunnelClient] \u670D\u52A1\u7AEF\u62D2\u7EDD\u8FDE\u63A5\uFF08\u975E 101 \u54CD\u5E94\uFF09: server=",e.serverUrl,"statusCode=",u.statusCode,"statusMessage=",u.statusMessage)}),t.on("upgrade",o=>{s.debug("[TunnelClient] \u6536\u5230\u5347\u7EA7\u54CD\u5E94: statusCode=",o.statusCode)}),t.on("message",o=>{let u;typeof o=="string"?u=o:Buffer.isBuffer(o)?u=o.toString("utf-8"):u=Buffer.from(o).toString("utf-8");try{const l=JSON.parse(u);M(e,l)}catch(l){s.warn("[TunnelClient] \u89E3\u6790\u96A7\u9053\u6D88\u606F\u5931\u8D25:",String(l))}}),t.on("close",(o,u)=>{if(s.warn("[TunnelClient] \u96A7\u9053\u8FDE\u63A5\u5173\u95ED: server=",e.serverUrl,"code=",o,"reason=",String(u)),k(e),o===X){s.warn("[TunnelClient] \u9274\u6743\u5931\u8D25\uFF084001\uFF09\uFF0C\u505C\u6B62\u81EA\u52A8\u91CD\u8FDE\uFF1B\u5F85\u91CD\u65B0\u6CE8\u518C\u540E\u518D\u542F\u52A8\u96A7\u9053: server=",e.serverUrl);return}b(e)}),t.on("error",o=>{s.warn("[TunnelClient] \u96A7\u9053\u8FDE\u63A5\u9519\u8BEF: server=",e.serverUrl,"err=",o.message,"code=",o.code),k(e),b(e)})}function k(e){e.timer&&(clearInterval(e.timer),e.timer=void 0);for(const[n,r]of e.streams.entries()){try{r.ws.close(1011,"tunnel disconnected")}catch{}e.streams.delete(n)}for(const n of Array.from(e.pendingReqChunks.keys()))E(e,n);e.ws=void 0}function b(e){if(e.shuttingDown||e.reconnectTimer)return;const n=(e.reconnectAttempts??0)+1;e.reconnectAttempts=n;const r=Math.min(G*Math.pow(2,n-1),H),t=1-A+Math.random()*A*2,o=Math.round(r*t);s.debug("[TunnelClient] \u8BA1\u5212\u91CD\u8FDE: server=",e.serverUrl,"attempt=",n,"delayMs=",o),e.reconnectTimer=setTimeout(()=>{e.reconnectTimer=void 0,B(e)},o)}function M(e,n){switch(n.t){case"req":n.chunked?V(e,n):U(e,n);break;case"reqchunk":Q(e,n);break;case"reqend":Z(e,n);break;case"wsopen":ee(e,n);break;case"wsmsg":ne(e,n);break;case"wsclose":re(e,n);break;case"ping":d(e,{t:"pong"});break;case"pong":break;default:s.debug("[TunnelClient] \u672A\u77E5\u6D88\u606F\u7C7B\u578B: t=",n.t)}}function V(e,n){E(e,n.id);const r=setTimeout(()=>{s.warn("[TunnelClient] \u8BF7\u6C42\u4F53\u62C6\u5E27\u8D85\u65F6\uFF0C\u4E22\u5F03\u534A\u5305:",n.id),e.pendingReqChunks.delete(n.id)},z);r.unref?.(),e.pendingReqChunks.set(n.id,{method:n.method||"GET",path:n.path||"/",headers:n.headers,parts:[],timer:r})}function Q(e,n){const r=e.pendingReqChunks.get(n.id);if(!r){s.debug("[TunnelClient] \u6536\u5230\u65E0\u4E3B reqchunk\uFF0C\u5DF2\u5FFD\u7565:",n.id);return}n.d&&r.parts.push(Buffer.from(n.d,"base64"))}async function Z(e,n){const r=e.pendingReqChunks.get(n.id);if(!r){s.debug("[TunnelClient] \u6536\u5230\u65E0\u4E3B reqend\uFF0C\u5DF2\u5FFD\u7565:",n.id);return}E(e,n.id);const t=Buffer.concat(r.parts);await U(e,{t:"req",id:n.id,method:r.method,path:r.path,headers:r.headers,body:t.length>0?t.toString("base64"):null})}function E(e,n){const r=e.pendingReqChunks.get(n);r&&(clearTimeout(r.timer),e.pendingReqChunks.delete(n))}async function U(e,n){const r=n.id,t=n.method||"GET",o=n.path||"/",u=`http://127.0.0.1:${R()}${o}`;try{const l=n.body?Buffer.from(n.body,"base64"):void 0,i={};if(n.headers)for(const[a,c]of Object.entries(n.headers))c&&c.length>0&&(i[a]=c[0]);i["x-bridge-tunnel-source"]=e.serverUrl;const f=await O.request({url:u,method:t,headers:i,data:l,timeout:0,responseType:"stream",validateStatus:()=>!0}),h={};for(const[a,c]of Object.entries(f.headers))c!==void 0&&(h[a]=Array.isArray(c)?c:[String(c)]);const v=f.data,I=String(h["content-type"]?.[0]||"").toLowerCase().includes("text/event-stream"),m=[];let w=0,T=!1,y=!1;try{if(v)for await(const a of v){const c=Buffer.isBuffer(a)?a:Buffer.from(a);if(c.length!==0){if(T){if(!_(e,r,c))return}else if(I){if(T=!0,y=!0,!d(e,{t:"res",id:r,status:f.status,headers:h,body:null,chunked:!0})||!_(e,r,c))return}else if(m.push(c),w+=c.length,w>Y){if(T=!0,y=!0,!d(e,{t:"res",id:r,status:f.status,headers:h,body:null,chunked:!0}))return;for(const D of m)if(!_(e,r,D))return;m.length=0,w=0}}}}catch(a){const c=a instanceof Error?a.message:String(a);s.warn("[TunnelClient] \u672C\u5730\u6D41\u8BFB\u53D6\u4E2D\u65AD:",t,o,"->",c),y?d(e,{t:"resend",id:r,error:c}):d(e,{t:"res",id:r,status:502,headers:{"content-type":["text/plain; charset=utf-8"]},body:Buffer.from(c).toString("base64")});return}if(T){d(e,{t:"resend",id:r});return}const N=w>0?Buffer.concat(m).toString("base64"):"";d(e,{t:"res",id:r,status:f.status,headers:h,body:N||null})}catch(l){const i=l instanceof x?l.message:String(l);s.warn("[TunnelClient] \u672C\u5730\u8F6C\u53D1\u5931\u8D25:",t,o,"->",i),d(e,{t:"res",id:r,status:502,headers:{"content-type":["text/plain; charset=utf-8"]},body:Buffer.from(i).toString("base64")})}}function _(e,n,r){let t=0;for(;t<r.length;){const o=r.subarray(t,t+j);if(!d(e,{t:"reschunk",id:n,d:o.toString("base64")}))return!1;t+=o.length}return!0}function ee(e,n){const r=n.id,t=n.path||"/",o=`ws://127.0.0.1:${R()}${t}`;let u;try{u=new g(o,{handshakeTimeout:1e4})}catch(i){s.warn("[TunnelClient] \u672C\u5730 WS \u8FDE\u63A5\u5931\u8D25:",String(i)),d(e,{t:"wsclose",id:r,code:1011,reason:"local ws connect failed"});return}const l={ws:u,pending:[]};e.streams.set(r,l),u.on("open",()=>{for(const i of l.pending)q(l,i.data,i.bin);l.pending=[],d(e,{t:"wsopened",id:r})}),u.on("message",(i,f)=>{const h=Buffer.isBuffer(i)?i:Buffer.from(i);f&&e.ws&&e.ws.bufferedAmount>K||d(e,{t:"wsmsg",id:r,bin:f,d:h.toString("base64")})}),u.on("close",(i,f)=>{e.streams.delete(r),d(e,{t:"wsclose",id:r,code:i,reason:String(f)})}),u.on("error",i=>{s.warn("[TunnelClient] \u672C\u5730 WS \u9519\u8BEF: id=",r,"err=",i.message),e.streams.delete(r);try{u.close(1011,i.message)}catch{}d(e,{t:"wsclose",id:r,code:1011,reason:i.message})})}function q(e,n,r){r?e.ws.send(n):e.ws.send(n.toString("utf-8"))}function ne(e,n){const r=e.streams.get(n.id);if(!r)return;const t=n.d?Buffer.from(n.d,"base64"):Buffer.alloc(0);if(r.ws.readyState!==g.OPEN){r.pending.length>=J&&(r.pending.shift(),s.warn("[TunnelClient] \u672C\u5730 WS \u672A\u5C31\u7EEA\uFF0C\u6392\u961F\u6D88\u606F\u8D85\u4E0A\u9650\uFF0C\u4E22\u5F03\u6700\u65E7\u4E00\u6761: id=",n.id)),r.pending.push({data:t,bin:!!n.bin});return}q(r,t,!!n.bin)}function re(e,n){const r=e.streams.get(n.id);if(r){e.streams.delete(n.id);try{r.ws.close(n.code??1e3,n.reason||"")}catch{}}}function d(e,n){if(!e.ws||e.ws.readyState!==g.OPEN)return!1;try{return e.ws.send(JSON.stringify(n)),!0}catch(r){return s.warn("[TunnelClient] sendJson \u5931\u8D25:",String(r)),!1}}const he={createState(e="http://server.test",n="test-instance"){return{serverUrl:e,instanceId:n,streams:new Map,pendingReqChunks:new Map,shuttingDown:!1}},dispatch(e,n){M(e,n)},pendingChunkIds(e){return Array.from(e.pendingReqChunks.keys())},cleanup(e){k(e)}};export{he as __tunnelClientTestHooks,le as startTunnelClient,de as stopTunnelClient,fe as stopTunnelClientForServer,ae as stopTunnelClientsExcept};
|
|
2
2
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{createHash as
|
|
1
|
+
import{createHash as E}from"node:crypto";import{promises as r}from"node:fs";import c from"node:path";import X from"axios";import*as J from"diff";import{resolveSchedulerBaseUrl as V,getRuntimeHomeDir as C}from"../config.js";import{createLogger as Z}from"../utils/logger.js";import{getChangeCacheRetentionDays as $,setChangeCacheRetentionDays as q}from"./change-cache-retention.js";import{getSnapshotRetentionDays as T,setSnapshotRetentionDays as Q}from"./snapshot-retention.js";import{sweepExpiredSnapshots as Y}from"./fileSnapshotStore.js";import{getRuntimeAccessToken as L}from"./runtime-binding.js";const h=Z("workspace-task-change-watcher"),ee=10*1024*1024,te=".agentswork/change-cache",m="change-cache",ne=60*60*1e3,ae=24*60*60*1e3;let l=null,b=!1,y="",p=null;const g=new Map,d=new Map;let R=!1;function me(e){l&&l.taskNodeId!==e.taskNodeId&&z().catch(()=>{}),l=e,h.info(`Task context set: agent=${e.agentId}, taskInstance=${e.taskInstanceId}, node=${e.taskNodeId}`)}function ye(){l&&(h.info(`Task context cleared: agent=${l.agentId}`),z().catch(()=>{})),l=null}function ke(){return l}function De(){return l!==null}async function Ie(e){const t=c.resolve(e.trim());try{if(!(await r.stat(t)).isDirectory())throw new Error(`Not a directory: ${t}`)}catch{throw new Error(`Workspace path does not exist or inaccessible: ${t}`)}if(p){try{p.close()}catch{}p=null}y=t,b=!0,h.info(`Workspace path set (fs.watch disabled, using tool interception only): ${y}`)}async function Ee(){if(b=!1,p){try{p.close()}catch{}p=null}g.clear(),d.clear(),y="",h.info("Workspace watch stopped")}function F(e,t,a){return E("sha256").update(`${e||"no-task"}:${t}:${a}`,"utf-8").digest("hex").slice(0,32)}function N(e){return E("sha256").update(c.resolve(e),"utf-8").digest("hex").slice(0,16)}function k(e){return c.join(C(),".aws-bridge",m,N(e))}function oe(e){return c.join(C(),m,N(e))}function W(e){return c.join(e,te)}const j=new Set;async function _(e){if(!j.has(e)){j.add(e);try{const t=W(e),a=k(e);await r.access(t),await r.mkdir(c.dirname(a),{recursive:!0}),await r.rename(t,a),h.info(`Migrated legacy change-cache: ${t} -> ${a}`)}catch{}}}async function v(e,t,a){if(a===null)return;await _(e);const o=k(e);await r.mkdir(o,{recursive:!0});const n=c.join(o,`${t}.before`);await r.writeFile(n,a,"utf-8"),B(),h.debug(`Saved beforeContent cache: ${n}`)}async function M(e,t,a,o){const n=J.createPatch("file",a,o);await _(e);const i=k(e);await r.mkdir(i,{recursive:!0});const f=c.join(i,`${t}.diff`);await r.writeFile(f,n,"utf-8"),B(),h.debug(`Saved diff cache: ${f}`)}async function U(e,t){const a=[c.join(k(e),t),c.join(oe(e),t),c.join(W(e),t)];for(const o of a)try{return await r.readFile(o,"utf-8")}catch{}return null}async function $e(e,t){return U(e,`${t}.before`)}async function Te(e,t){return U(e,`${t}.diff`)}let x=0,S=null,A=Promise.resolve();function P(){return A=A.then(()=>ie()),A}async function ie(){const e=$();if(!(e===null||e<=0))try{const t=[c.join(C(),".aws-bridge",m),c.join(C(),m)],a=Date.now()-e*24*60*60*1e3;let o=0;for(const n of t){let i=[];try{i=(await r.readdir(n)).filter(f=>!f.startsWith("."))}catch{continue}for(const f of i){const s=c.join(n,f);try{const u=await r.readdir(s);let w=!0;for(const I of u){if(!I.endsWith(".diff")&&!I.endsWith(".before")){w=!1;continue}const H=c.join(s,I);try{(await r.stat(H)).mtimeMs<a?(await r.unlink(H),o++):w=!1}catch{w=!1}}w&&await r.rmdir(s).catch(()=>{})}catch{}}}o>0&&h.info(`Change-cache TTL sweep: removed ${o} expired file(s), retentionDays=${e}`)}catch(t){h.warn(`Change-cache TTL sweep failed: ${t.message}`)}}function B(){const e=Date.now();e-x>=ne&&(x=e,P().catch(()=>{})),S||(S=setInterval(()=>{P().catch(()=>{})},ae),S.unref?.())}async function O(e){try{return(await r.stat(e)).size>ee?null:await r.readFile(e,"utf-8")}catch{return null}}function D(e){return e===null?null:E("sha256").update(e,"utf-8").digest("hex").slice(0,16)}async function se(e){const t=g.get(e);if(!t)return;g.delete(e),t.timer&&clearTimeout(t.timer);const a=l;if(!a){if(t.operation==="DELETE")d.delete(e);else{const u=await O(e);u!==null&&d.set(e,u)}return}const o=c.relative(a.workspacePath,e).replace(/\\/g,"/");if(o.startsWith(".."))return;let n=t.beforeContent,i=null;t.operation==="DELETE"?(n=n??d.get(e)??null,i=null):(i=await O(e),t.operation==="UPDATE"&&n===null&&(n=d.get(e)??null)),t.operation==="DELETE"?d.delete(e):d.set(e,i);const f=new Date().toISOString(),s=F(a.taskInstanceId,o,f);t.operation==="UPDATE"&&n!==null&&i!==null?await M(a.workspacePath,s,n,i):t.operation==="DELETE"&&await v(a.workspacePath,s,n),await K(a,{workspacePath:a.workspacePath,filePath:o,operation:t.operation,beforeContent:n,afterContent:i,beforeHash:D(n),afterHash:D(i),timestamp:f,reason:G(t.operation,n,i)},s)}async function K(e,t,a){try{const o=V().url,n=L(o)||L();if(!n){h.warn("Cannot send change record: no auth token");return}const i=JSON.stringify({toolRecorded:!0,cacheKey:a,timestamp:t.timestamp}),s=(await X.post(`${o}/api/runtime/callback/task-file-changed`,{agentId:e.agentId,taskInstanceId:e.taskInstanceId,taskNodeId:e.taskNodeId,tenantId:e.tenantId,operation:t.operation,targetType:"FILE",targetPath:t.filePath,beforeHash:t.beforeHash,afterHash:t.afterHash,metadata:i,reason:t.reason,workspacePath:e.workspacePath},{headers:{"X-Runtime-Token":n},timeout:1e4})).data;if(s?.ignored===!0?h.warn(`Change record ignored by server: ${t.filePath} (${t.operation}), reason: ${String(s.reason??"unknown")}`):h.info(`Change record sent: ${t.filePath} (${t.operation})`),s&&s.changeCacheRetentionDays!==void 0){const u=$();q(s.changeCacheRetentionDays),u!==$()&&(x=0,P().catch(()=>{}))}if(s&&s.snapshotRetentionDays!==void 0){const u=T();Q(s.snapshotRetentionDays),u!==T()&&Y(T()).catch(()=>{})}}catch(o){h.warn(`Failed to send change record: ${o.message}`)}}async function z(){if(R)return;R=!0;const e=Array.from(g.keys());for(const t of e)try{await se(t)}catch{}R=!1}function be(){return g.size}function Re(){return b&&p!==null}function ve(){return y}function G(e,t,a){const o=t?t.split(`
|
|
2
2
|
`).length:0,n=a?a.split(`
|
|
3
|
-
`).length:0;if(e==="CREATE")return`\u521B\u5EFA\u6587\u4EF6\uFF0C\u5171 ${n} \u884C`;if(e==="DELETE")return`\u5220\u9664\u6587\u4EF6\uFF0C\u539F ${o} \u884C`;if(o===n)return`\u4FEE\u6539\u6587\u4EF6\uFF08\u884C\u6570\u4E0D\u53D8\uFF0C${n} \u884C\uFF09`;const i=n-o;return`\u4FEE\u6539\u6587\u4EF6\uFF1A${o} \u884C -> ${n} \u884C\uFF08${i>0?"+":""}${i} \u884C\uFF09`}async function
|
|
3
|
+
`).length:0;if(e==="CREATE")return`\u521B\u5EFA\u6587\u4EF6\uFF0C\u5171 ${n} \u884C`;if(e==="DELETE")return`\u5220\u9664\u6587\u4EF6\uFF0C\u539F ${o} \u884C`;if(o===n)return`\u4FEE\u6539\u6587\u4EF6\uFF08\u884C\u6570\u4E0D\u53D8\uFF0C${n} \u884C\uFF09`;const i=n-o;return`\u4FEE\u6539\u6587\u4EF6\uFF1A${o} \u884C -> ${n} \u884C\uFF08${i>0?"+":""}${i} \u884C\uFF09`}async function xe(e){const t=l,a=e.agentId||t?.agentId,o=e.workspacePath||t?.workspacePath;if(!a||!o){h.warn(`Agent file change skipped (no identity): ${e.filePath} (${e.operation})`);return}h.info(`Recording agent file change: ${e.filePath} (${e.operation}), taskNode=${t?.taskNodeId??"(no task)"}`);const n=t??{agentId:a,taskInstanceId:"",taskNodeId:"",tenantId:"",workspacePath:o,projectId:""},i=new Date().toISOString(),f=F(n.taskInstanceId,e.filePath,i);e.operation==="UPDATE"&&e.beforeContent!==null&&e.afterContent!==null?(await M(n.workspacePath,f,e.beforeContent,e.afterContent),await v(n.workspacePath,f,e.beforeContent)):e.operation==="DELETE"&&await v(n.workspacePath,f,e.beforeContent);const s=e.reason?.trim()||G(e.operation,e.beforeContent,e.afterContent);await K(n,{workspacePath:n.workspacePath,filePath:e.filePath,operation:e.operation,beforeContent:e.beforeContent,afterContent:e.afterContent,beforeHash:D(e.beforeContent),afterHash:D(e.afterContent),timestamp:i,reason:s},f)}export{ye as clearTaskContext,be as getPendingChangeCountForTest,ke as getTaskContext,ve as getWorkspaceRoot,De as hasActiveTask,Re as isWatching,$e as readBeforeContentFromCache,Te as readDiffFromCache,xe as recordAgentFileChange,me as setTaskContext,Ie as startWatching,Ee as stopWatching,P as sweepExpiredChangeCache};
|
|
4
4
|
|
|
@@ -4,8 +4,16 @@ export interface AcodeAskUserQuestionDeps {
|
|
|
4
4
|
|
|
5
5
|
onQuestion(toolCallId: string, questions: AcodeQuestionItem[]): void;
|
|
6
6
|
|
|
7
|
-
waitForAnswer(toolCallId: string, contextVersion: number): Promise<
|
|
7
|
+
waitForAnswer(toolCallId: string, contextVersion: number): Promise<AcodeQuestionAnswerOutcome>;
|
|
8
8
|
}
|
|
9
|
+
|
|
10
|
+
export type AcodeQuestionAnswerOutcome = {
|
|
11
|
+
answers: Record<string, string>;
|
|
12
|
+
cancelled?: false;
|
|
13
|
+
} | {
|
|
14
|
+
cancelled: true;
|
|
15
|
+
reason?: string;
|
|
16
|
+
};
|
|
9
17
|
export interface AcodeQuestionOption {
|
|
10
18
|
label: string;
|
|
11
19
|
description?: string;
|
|
@@ -22,6 +30,8 @@ export interface AcodeAskUserQuestionResult {
|
|
|
22
30
|
tool: "ask_user_question";
|
|
23
31
|
answers: Record<string, string>;
|
|
24
32
|
summary: string;
|
|
33
|
+
cancelled?: boolean;
|
|
34
|
+
reason?: string;
|
|
25
35
|
}
|
|
26
36
|
|
|
27
37
|
export declare const ASK_USER_QUESTION_TOOL_NAME = "ask_user_question";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
2
|
-
`);function
|
|
3
|
-
`)}function
|
|
1
|
+
const u="ask_user_question",f=["\u5411\u7528\u6237\u63D0\u51FA\u95EE\u9898\uFF0C\u6536\u96C6\u66F4\u591A\u4FE1\u606F\u4E3A\u505A\u51B3\u7B56\u63D0\u4F9B\u66F4\u591A\u7684\u65B9\u5411\u9009\u62E9\uFF0C\u6BCF\u4E2A\u95EE\u9898\u4F1A\u81EA\u52A8\u8FFD\u52A0\u201C\u5176\u5B83\u201D\u9009\u9879\u4F9B\u7528\u6237\u81EA\u5B9A\u4E49\u8F93\u5165\u3002","\u591A\u4E2A\u95EE\u9898\u65F6\u4E0D\u5F97\u4F9D\u8D56\u524D\u9762\u95EE\u9898\u7684\u7B54\u6848\uFF0C\u82E5\u67D0\u95EE\u9898\u4F9D\u8D56\u53E6\u4E00\u95EE\u9898\u7684\u7B54\u6848\uFF0C\u5E94\u62C6\u6210\u591A\u8F6E\u5206\u522B\u8C03\u7528\u672C\u5DE5\u5177\u3002","\u63D0\u4EA4\u540E\u8FDB\u5165\u7528\u6237\u5BA1\u6279\uFF0C\u5BA1\u6279\u901A\u8FC7\u7684\u9879\u4F1A\u76F4\u63A5\u521B\u5EFA\uFF08\u7ED3\u679C\u968F\u5DE5\u5177\u8FD4\u56DE\uFF09\u3002","\u5982\u679C\u63A8\u8350\u67D0\u4E2A\u9009\u9879\uFF0C\u628A\u5B83\u653E\u5728\u7B2C\u4E00\u4F4D\u5E76\u5728 label \u672B\u5C3E\u52A0\u201C\uFF08\u63A8\u8350\uFF09\u201D\u3002"].join(`
|
|
2
|
+
`);function q(t,o){return{kind:"builtin",toolName:u,exposedName:u,concurrencyMode:"blocking",description:f,inputSchema:d(),async execute(n,e){const r=e?.toolCallId;if(!r)return{ok:!1,tool:u,error:"missing toolCallId in execution context"};const s=b(n.questions);if(s.length===0)return{ok:!1,tool:u,error:"questions must be a non-empty array"};t.onQuestion(r,s);const c=o();let i;try{i=await t.waitForAnswer(r,c)}catch(a){const m=a instanceof Error?a.message:String(a);return{ok:!1,tool:u,error:m}}if(i.cancelled){const a=i.reason?.trim();return{ok:!0,tool:u,answers:{},summary:y(a),cancelled:!0,...a?{reason:a}:{}}}const l=i.answers,p=h(s,l);return{ok:!0,tool:u,answers:l,summary:p}}}}function y(t){return t?`\u7528\u6237\u53D6\u6D88\u4E86\u672C\u6B21\u4F5C\u7B54\u3002\u539F\u56E0\uFF1A${t}`:"\u7528\u6237\u53D6\u6D88\u4E86\u672C\u6B21\u4F5C\u7B54\uFF0C\u672A\u63D0\u4F9B\u539F\u56E0\u3002"}function d(){return{type:"object",properties:{questions:{type:"array",description:"\u8981\u63D0\u95EE\u7684\u95EE\u9898\u5217\u8868\uFF08\u81F3\u5C11 1 \u4E2A\uFF0C\u6570\u91CF\u4E0D\u8BBE\u4E0A\u9650\uFF09\uFF1B\u591A\u4E2A\u95EE\u9898\u65F6\u5FC5\u987B\u76F8\u4E92\u72EC\u7ACB\u3001\u5E76\u5217\u63D0\u95EE\uFF0C\u540E\u7EED\u95EE\u9898\u4E0D\u5F97\u4F9D\u8D56\u524D\u9762\u95EE\u9898\u7684\u7B54\u6848\uFF0C\u6709\u4F9D\u8D56\u5173\u7CFB\u65F6\u5E94\u62C6\u6210\u591A\u6B21\u8C03\u7528",minItems:1,items:{type:"object",properties:{question:{type:"string",description:"\u5B8C\u6574\u95EE\u9898\u6587\u672C\uFF0C\u5EFA\u8BAE\u4EE5\u95EE\u53F7\u7ED3\u5C3E"},header:{type:"string",description:"\u226412 \u5B57\u7B26\u7684\u7B80\u77ED\u6807\u7B7E\uFF0C\u7528\u4E8E UI chip \u663E\u793A"},options:{type:"array",description:"2-4 \u4E2A\u4E92\u65A5\u9009\u9879\uFF08multiSelect=true \u65F6\u53EF\u4E0D\u4E92\u65A5\uFF09",minItems:2,maxItems:4,items:{type:"object",properties:{label:{type:"string",description:"1-5 \u8BCD\u7684\u7B80\u77ED\u6807\u7B7E"},description:{type:"string",description:"\u9009\u9879\u542B\u4E49\u6216\u6743\u8861\u8BF4\u660E"},requiresCustomInput:{type:"boolean",description:"\u9009\u4E2D\u6B64\u9879\u65F6 UI \u663E\u793A\u81EA\u5B9A\u4E49\u8F93\u5165\u6846"}},required:["label"]}},multiple:{type:"boolean",description:"\u662F\u5426\u5141\u8BB8\u591A\u9009\uFF1B\u9ED8\u8BA4 false"}},required:["question","options"]}},custom:{type:"boolean",description:"\u662F\u5426\u5141\u8BB8\u7528\u6237\u8865\u5145\u81EA\u5B9A\u4E49\u8F93\u5165\uFF1B\u9ED8\u8BA4 true"}},required:["questions"]}}function b(t){if(!Array.isArray(t)||t.length===0)return[];const o=[];for(const n of t){if(!n||typeof n!="object")continue;const e=n,r=typeof e.question=="string"?e.question.trim():"";if(!r)continue;const s=g(e.options);if(s.length<2)continue;const c=typeof e.header=="string"&&e.header.trim()?e.header.trim():void 0,i=e.multiple===!0||e.multiSelect===!0;o.push({question:r,header:c,options:s,multiple:i})}return o}function g(t){if(!Array.isArray(t))return[];const o=[];for(const n of t){if(typeof n=="string"){const i=n.trim();i&&o.push({label:i});continue}if(!n||typeof n!="object")continue;const e=n,r=typeof e.label=="string"?e.label.trim():typeof e.value=="string"?e.value.trim():typeof e.text=="string"?e.text.trim():"";if(!r)continue;const s=typeof e.description=="string"&&e.description.trim()?e.description.trim():void 0,c=e.requiresCustomInput===!0||e.requireCustomInput===!0||e.allowCustomInput===!0;if(o.push({label:r,...s?{description:s}:{},...c?{requiresCustomInput:c}:{}}),o.length>=4)break}return o}function h(t,o){const n=["\u7528\u6237\u5DF2\u56DE\u7B54\u4E86\u60A8\u7684\u95EE\u9898\uFF1A"];return t.forEach((e,r)=>{const s=String(r),c=o[s]||(e.header?o[e.header]:"")||o[e.question]||"\uFF08\u672A\u586B\u5199\uFF09",i=e.header||e.question;n.push(`\u2022 ${i}\uFF1A${c}`)}),n.join(`
|
|
3
|
+
`)}function j(t){if(!t||typeof t!="object")return!1;const o=t;return o.ok===!0&&o.tool===u&&typeof o.answers=="object"&&o.answers!==null&&typeof o.summary=="string"&&(o.cancelled===void 0||typeof o.cancelled=="boolean")}function x(t){const o={ok:!0,tool:u,answers:I(t.answers),summary:t.summary,...t.cancelled?{cancelled:!0}:{},...t.reason?{reason:t.reason}:{}};return JSON.stringify(o)}function I(t){const o={};for(const[n,e]of Object.entries(t))o[n]=e;return o}export{u as ASK_USER_QUESTION_TOOL_NAME,q as createAskUserQuestionTool,j as isAskUserQuestionResult,x as serializeAskUserQuestionResult};
|
|
4
4
|
|