chore: checkpoint before performance tuning
This commit is contained in:
+118
-3
@@ -2,7 +2,8 @@ import { spawn } from "node:child_process";
|
||||
import { type UniDeskConfig } from "./config";
|
||||
import { type DebugDispatchCommand, isDebugDispatchCommand } from "./debug";
|
||||
import { summarizeMicroserviceProxyResponse } from "./microservices";
|
||||
import { parseSshArgs } from "./ssh";
|
||||
import { isSshSkillDiscoveryArgs, parseSshArgs } from "./ssh";
|
||||
import { codexOutputQueryAsync, codexTaskQueryAsync } from "./codex-queue";
|
||||
|
||||
export interface RemoteCliOptions {
|
||||
host: string | null;
|
||||
@@ -236,6 +237,95 @@ function jsonOption(args: string[], name: string): Record<string, unknown> | und
|
||||
return parsed as Record<string, unknown>;
|
||||
}
|
||||
|
||||
const compactSkillDiscoverPython = String.raw`import os,json,socket,platform,getpass
|
||||
from pathlib import Path as P
|
||||
S=os.getenv('S','all');L=int(os.getenv('L','0'));D=int(os.getenv('D','4'));skip={'node_modules','.git','.state','logs','references','__pycache__'}
|
||||
def isw():
|
||||
try:r=P('/proc/sys/kernel/osrelease').read_text(errors='ignore').lower()
|
||||
except Exception:r=''
|
||||
return 'microsoft' in r or 'wsl' in r or 'WSL_INTEROP' in os.environ
|
||||
def wp(p):
|
||||
s=str(p)
|
||||
return s[5].upper()+':\\'+s[7:].replace('/','\\') if s.startswith('/mnt/') and len(s)>6 and s[5].isalpha() and s[6]=='/' else None
|
||||
def md(f):
|
||||
n=f.parent.name;d=''
|
||||
try:ls=f.read_text(errors='replace')[:8192].splitlines()
|
||||
except Exception:ls=[]
|
||||
if ls and ls[0].strip()=='---':
|
||||
for l in ls[1:]:
|
||||
if l.strip()=='---':break
|
||||
if ':' in l:
|
||||
k,v=l.split(':',1);k=k.strip().lower();v=v.strip().strip('"\' ')
|
||||
if k=='name' and v:n=v
|
||||
if k=='description' and v:d=v
|
||||
if not d:
|
||||
for l in ls:
|
||||
x=l.strip()
|
||||
if x and not x.startswith('---') and not x.startswith('#'):
|
||||
d=x;break
|
||||
return n,d
|
||||
def scan(sc,root):
|
||||
rec={'scope':sc,'path':str(root),'windowsPath':wp(root),'exists':False,'skillCount':0,'error':None};out=[]
|
||||
try:rec['exists']=root.exists()
|
||||
except Exception as e:rec['error']=str(e)
|
||||
if not rec['exists']:return rec,out
|
||||
try:
|
||||
for f in root.rglob('SKILL.md'):
|
||||
rel=f.relative_to(root).parts[:-1]
|
||||
if not rel or len(rel)>D or any(x in skip for x in rel):continue
|
||||
n,d=md(f);out.append({'scope':sc,'name':n,'description':d,'path':str(f.parent),'skillMd':str(f),'windowsPath':wp(f.parent),'root':str(root)})
|
||||
except Exception as e:rec['error']=str(e)
|
||||
rec['skillCount']=len(out);return rec,out
|
||||
roots=[];h=P.home()
|
||||
if S!='windows':roots += [('wsl',h/'.agents/skills'),('wsl',h/'.codex/skills'),('wsl',P('/root/.agents/skills')),('wsl',P('/root/.codex/skills'))]
|
||||
if S!='wsl' and isw():
|
||||
try:users=list(P('/mnt/c/Users').iterdir())
|
||||
except Exception:users=[]
|
||||
for u in users:
|
||||
if u.is_dir() and u.name.lower() not in {'all users','default','default user','public'}:roots += [('windows',u/'.agents/skills'),('windows',u/'.codex/skills')]
|
||||
seen=set();rr=[];ss=[]
|
||||
for sc,r in roots:
|
||||
k=(sc,str(r))
|
||||
if k in seen:continue
|
||||
seen.add(k);a,b=scan(sc,r);rr.append(a);ss+=b
|
||||
ss.sort(key=lambda x:(0 if x['scope']=='wsl' else 1,x['name'].lower(),x['path']));tb=len(ss)
|
||||
if L>0:ss=ss[:L]
|
||||
c={'total':len(ss),'totalBeforeLimit':tb,'wsl':sum(1 for x in ss if x['scope']=='wsl'),'windows':sum(1 for x in ss if x['scope']=='windows')}
|
||||
print(json.dumps({'ok':True,'command':'unidesk ssh skills','node':{'hostname':socket.gethostname(),'user':getpass.getuser(),'home':str(P.home()),'platform':platform.platform(),'isWsl':isw()},'counts':c,'roots':rr,'skills':ss},ensure_ascii=False,indent=2))`;
|
||||
|
||||
function remoteFrontendSkillDiscoverCommand(args: string[]): string {
|
||||
let scope = "all";
|
||||
let limit = 0;
|
||||
let maxDepth = 4;
|
||||
const start = args[0] === "skill" ? 2 : 1;
|
||||
for (let index = start; index < args.length; index += 1) {
|
||||
const arg = args[index] ?? "";
|
||||
const next = args[index + 1];
|
||||
if (arg === "--scope") {
|
||||
if (next !== "all" && next !== "wsl" && next !== "windows") throw new Error("ssh skills --scope must be one of: all, wsl, windows");
|
||||
scope = next;
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
if (arg === "--limit") {
|
||||
const value = Number(next);
|
||||
if (!Number.isInteger(value) || value < 0) throw new Error("ssh skills --limit must be >= 0");
|
||||
limit = value;
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
if (arg === "--max-depth") {
|
||||
const value = Number(next);
|
||||
if (!Number.isInteger(value) || value <= 0) throw new Error("ssh skills --max-depth must be positive");
|
||||
maxDepth = value;
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
throw new Error(`remote frontend ssh skills does not support option: ${arg}`);
|
||||
}
|
||||
return `S=${shellQuote(scope)} L=${shellQuote(String(limit))} D=${shellQuote(String(maxDepth))} python3 -c ${shellQuote(compactSkillDiscoverPython)}`;
|
||||
}
|
||||
|
||||
function dispatchPayload(args: string[], command: DebugDispatchCommand): Record<string, unknown> {
|
||||
const explicit = jsonOption(args, "--payload-json") ?? {};
|
||||
if (command === "provider.upgrade") {
|
||||
@@ -378,6 +468,22 @@ async function remoteMicroservice(session: FrontendSession, args: string[]): Pro
|
||||
throw new Error("remote microservice command must be: microservice list | status <id> | health <id> | proxy <id> <path>");
|
||||
}
|
||||
|
||||
async function remoteCodexQueue(session: FrontendSession, args: string[]): Promise<unknown> {
|
||||
const action = args[1] ?? "task";
|
||||
if (action !== "task" && action !== "summary" && action !== "show" && action !== "output") {
|
||||
throw new Error("remote codex command must be: codex task <taskId> or codex output <taskId>");
|
||||
}
|
||||
const taskId = args[2];
|
||||
if (taskId === undefined || taskId.length === 0) throw new Error(`codex ${action} requires task id`);
|
||||
const fetcher = (path: string): Promise<FetchJsonResult> => frontendJson(session, path, undefined, 24_000);
|
||||
return {
|
||||
transport: "frontend",
|
||||
result: action === "output"
|
||||
? await codexOutputQueryAsync(taskId, args.slice(3), fetcher)
|
||||
: await codexTaskQueryAsync(taskId, args.slice(3), fetcher),
|
||||
};
|
||||
}
|
||||
|
||||
async function runRemoteSshOverFrontend(session: FrontendSession, providerId: string | undefined, args: string[]): Promise<number> {
|
||||
if (!providerId) throw new Error("remote ssh requires provider id, for example: bun scripts/cli.ts --main-server-ip 74.48.78.17 ssh D601 hostname");
|
||||
const parsed = parseSshArgs(args);
|
||||
@@ -389,12 +495,17 @@ async function runRemoteSshOverFrontend(session: FrontendSession, providerId: st
|
||||
process.stderr.write("remote frontend transport supports ssh remote commands only; pass a command such as: ssh D601 hostname\n");
|
||||
return 255;
|
||||
}
|
||||
if (args[0] === "glob") {
|
||||
process.stderr.write("remote frontend transport does not support the ssh glob helper because host.ssh exec has a short command-length limit; run it on the main server CLI instead\n");
|
||||
return 255;
|
||||
}
|
||||
const remoteCommand = isSshSkillDiscoveryArgs(args) ? remoteFrontendSkillDiscoverCommand(args) : parsed.remoteCommand;
|
||||
const dispatch = await frontendJson(session, "/api/dispatch", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
providerId,
|
||||
command: "host.ssh",
|
||||
payload: { source: "cli-remote-ssh", mode: "exec", command: parsed.remoteCommand, timeoutMs: 15000 },
|
||||
payload: { source: "cli-remote-ssh", mode: "exec", command: remoteCommand, timeoutMs: isSshSkillDiscoveryArgs(args) ? 30000 : 15000 },
|
||||
}),
|
||||
});
|
||||
const taskId = (dispatch as { body?: { taskId?: string } }).body?.taskId ?? "";
|
||||
@@ -427,7 +538,7 @@ async function runRemoteCliOverFrontend(options: RemoteCliOptions, config: UniDe
|
||||
emitRemoteJson(name, {
|
||||
transport: "frontend",
|
||||
baseUrl: session.baseUrl,
|
||||
commands: ["debug health", "debug dispatch", "debug task", "ssh <providerId> <command>", "microservice list", "microservice status <id>", "microservice health <id>", "microservice proxy <id> <path>"],
|
||||
commands: ["debug health", "debug dispatch", "debug task", "ssh <providerId> <command>", "ssh <providerId> skills", "microservice list", "microservice status <id>", "microservice health <id>", "microservice proxy <id> <path>", "codex task <taskId>"],
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
@@ -447,6 +558,10 @@ async function runRemoteCliOverFrontend(options: RemoteCliOptions, config: UniDe
|
||||
emitRemoteJson(name, await remoteMicroservice(session, args));
|
||||
return 0;
|
||||
}
|
||||
if (top === "codex") {
|
||||
emitRemoteJson(name, await remoteCodexQueue(session, args));
|
||||
return 0;
|
||||
}
|
||||
if (top === "ssh") {
|
||||
return await runRemoteSshOverFrontend(session, sub, args.slice(2));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user