fix: preserve keil sidecars for caserun downloads
This commit is contained in:
@@ -38,11 +38,19 @@ test("hwlab-cli case prepare copies a case hwpod-spec into isolated run state",
|
||||
assert.match(runLocalSpec, /node-d601-f103-v2/u);
|
||||
assert.match(runLocalSpec, /path: "F:\\\\Work\\\\HWLAB-CASE-F103\\\\\.worktree\\\\caserun-run-test"/u);
|
||||
assert.equal(requests.length, 1);
|
||||
assert.equal(requests[0].body.ops.length, 3);
|
||||
assert.equal(requests[0].body.ops.length, 4);
|
||||
assert.equal(requests[0].body.ops[0].args.workspacePath, SUBJECT_REPO_LOCAL_PATH);
|
||||
assert.deepEqual(requests[0].body.ops[0].args.argv, ["cat-file", "-e", SUBJECT_COMMIT_ID]);
|
||||
assert.deepEqual(requests[0].body.ops[1].args.argv, ["worktree", "add", "--detach", "--force", ".worktree\\caserun-run-test", SUBJECT_COMMIT_ID]);
|
||||
assert.deepEqual(requests[0].body.ops[2].args.argv, ["-C", ".worktree\\caserun-run-test", "rev-parse", "HEAD"]);
|
||||
assert.equal(requests[0].body.ops[3].opId, "op_04_keil_sidecars");
|
||||
assert.equal(requests[0].body.ops[3].args.command, "node");
|
||||
const sidecarInput = JSON.parse(requests[0].body.ops[3].args.argv[2]);
|
||||
assert.equal(sidecarInput.sourceBase, "projects\\01_baseline\\Projects\\MDK-ARM\\atk_f103");
|
||||
assert.equal(sidecarInput.destinationBase, ".worktree\\caserun-run-test\\projects\\01_baseline\\Projects\\MDK-ARM\\atk_f103");
|
||||
assert.equal(requests[0].body.ops[3].args.commandBinding.sourceBase, "projects\\01_baseline\\Projects\\MDK-ARM\\atk_f103");
|
||||
assert.equal(requests[0].body.ops[3].args.commandBinding.destinationBase, ".worktree\\caserun-run-test\\projects\\01_baseline\\Projects\\MDK-ARM\\atk_f103");
|
||||
assert.equal(result.payload.subject.setup.keilSidecars.copied, 1);
|
||||
} finally {
|
||||
await rm(root, { recursive: true, force: true });
|
||||
}
|
||||
@@ -700,18 +708,20 @@ async function writeJsonFile(file: string, value: any) {
|
||||
}
|
||||
|
||||
function hwpodSpecText() {
|
||||
return "kind: Hwpod\nmetadata:\n name: d601-f103-v2\nspec:\n nodeBinding:\n nodeId: node-d601-f103-v2\n workspace:\n path: F:\\\\Work\\\\HWLAB-CASE-F103\n targetDevice:\n board: D601-F103-V2\n debugProbe:\n type: daplink\n ioProbe:\n uart:\n port: COM9\n";
|
||||
return "kind: Hwpod\nmetadata:\n name: d601-f103-v2\nspec:\n nodeBinding:\n nodeId: node-d601-f103-v2\n workspace:\n path: F:\\\\Work\\\\HWLAB-CASE-F103\n toolchain: keil-mdk\n keilProject: projects/01_baseline/Projects/MDK-ARM/atk_f103.uvprojx\n keilTarget: USART\n targetDevice:\n board: D601-F103-V2\n debugProbe:\n type: daplink\n programBackend: keil\n probeUid: 95FFF39D3DB47E0D\n ioProbe:\n uart:\n port: COM9\n";
|
||||
}
|
||||
|
||||
function subjectWorktreeFetch(requests: any[]) {
|
||||
return async (url: RequestInfo | URL, init?: RequestInit) => {
|
||||
const body = JSON.parse(String(init?.body ?? "{}"));
|
||||
requests.push({ url: String(url), body });
|
||||
return new Response(JSON.stringify({ body: { results: [
|
||||
{ ok: true, output: { exitCode: 0, stdout: "" } },
|
||||
{ ok: true, output: { exitCode: 0, stdout: "Preparing worktree\n" } },
|
||||
{ ok: true, output: { exitCode: 0, stdout: `${SUBJECT_COMMIT_ID}\n` } }
|
||||
] } }), { status: 200, headers: { "content-type": "application/json" } });
|
||||
const results = (body.ops ?? []).map((op: any, index: number) => {
|
||||
if (op.opId === "op_02_subject_worktree_add") return { ok: true, output: { exitCode: 0, stdout: "Preparing worktree\n" } };
|
||||
if (op.opId === "op_03_subject_worktree_head") return { ok: true, output: { exitCode: 0, stdout: `${SUBJECT_COMMIT_ID}\n` } };
|
||||
if (op.opId === "op_04_keil_sidecars") return { ok: true, output: { exitCode: 0, stdout: "caseRunKeilSidecars {\"copied\":1,\"sourceBase\":\"projects\\\\01_baseline\\\\Projects\\\\MDK-ARM\\\\atk_f103\",\"destinationBase\":\".worktree\\\\caserun-run-test\\\\projects\\\\01_baseline\\\\Projects\\\\MDK-ARM\\\\atk_f103\"}\n" } };
|
||||
return { ok: true, output: { exitCode: 0, stdout: index === 0 ? "" : "" } };
|
||||
});
|
||||
return new Response(JSON.stringify({ body: { results } }), { status: 200, headers: { "content-type": "application/json" } });
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+15
-10
@@ -106,16 +106,21 @@ test("hwpod-compiler-cli generates Keil build and download commands from structu
|
||||
|
||||
const download = await runHwpodCompilerCli(["compile", "--spec", specPath, "--intent", "debug.download"], { now: () => NOW });
|
||||
assert.equal(download.exitCode, 0);
|
||||
assert.deepEqual(download.payload.plan.ops.map((op: any) => op.op), ["cmd.run"]);
|
||||
assert.equal(download.payload.plan.ops[0].args.step, "keil-flash");
|
||||
assert.equal(download.payload.plan.ops[0].args.command, "py");
|
||||
assert.deepEqual(download.payload.plan.ops[0].args.argv.slice(0, 5), ["-3", "C:\\Users\\liang\\.agents\\skills\\keil\\keil-cli.py", "flash", "-p", "F:\\Work\\D601-HWLAB\\projects\\01_baseline\\Projects\\MDK-ARM\\atk_f103.uvprojx"]);
|
||||
assert.deepEqual(download.payload.plan.ops[0].args.argv.slice(-8), ["-m", "daplink", "--program-backend", "keil", "-u", "3FD750C63E342E24", "-t", "USART"]);
|
||||
assert.equal(download.payload.plan.ops[0].args.commandBinding.action, "download");
|
||||
assert.equal(download.payload.plan.ops[0].args.commandBinding.keilCommand, "flash");
|
||||
assert.equal(download.payload.plan.ops[0].args.commandBinding.programBackend, "keil");
|
||||
assert.equal(download.payload.plan.ops[0].args.commandBinding.autoBindUvoptx, false);
|
||||
assert.match(download.payload.plan.ops[0].args.commandLine, /^py -3 C:\\Users\\liang\\\.agents\\skills\\keil\\keil-cli\.py flash -p/u);
|
||||
assert.deepEqual(download.payload.plan.ops.map((op: any) => op.op), ["cmd.run", "cmd.run"]);
|
||||
assert.equal(download.payload.plan.ops[0].args.step, "keil-sidecar-diagnostics");
|
||||
assert.equal(download.payload.plan.ops[0].args.command, "node");
|
||||
assert.deepEqual(JSON.parse(download.payload.plan.ops[0].args.argv[2]), { primary: "F:\\Work\\D601-HWLAB\\projects\\01_baseline\\Projects\\MDK-ARM\\atk_f103.uvoptx", alternate: "F:\\Work\\D601-HWLAB\\projects\\01_baseline\\Projects\\MDK-ARM\\atk_f103.uvopt" });
|
||||
assert.equal(download.payload.plan.ops[0].args.commandBinding.primary, "F:\\Work\\D601-HWLAB\\projects\\01_baseline\\Projects\\MDK-ARM\\atk_f103.uvoptx");
|
||||
assert.equal(download.payload.plan.ops[0].args.commandBinding.alternate, "F:\\Work\\D601-HWLAB\\projects\\01_baseline\\Projects\\MDK-ARM\\atk_f103.uvopt");
|
||||
assert.equal(download.payload.plan.ops[1].args.step, "keil-flash");
|
||||
assert.equal(download.payload.plan.ops[1].args.command, "py");
|
||||
assert.deepEqual(download.payload.plan.ops[1].args.argv.slice(0, 5), ["-3", "C:\\Users\\liang\\.agents\\skills\\keil\\keil-cli.py", "flash", "-p", "F:\\Work\\D601-HWLAB\\projects\\01_baseline\\Projects\\MDK-ARM\\atk_f103.uvprojx"]);
|
||||
assert.deepEqual(download.payload.plan.ops[1].args.argv.slice(-8), ["-m", "daplink", "--program-backend", "keil", "-u", "3FD750C63E342E24", "-t", "USART"]);
|
||||
assert.equal(download.payload.plan.ops[1].args.commandBinding.action, "download");
|
||||
assert.equal(download.payload.plan.ops[1].args.commandBinding.keilCommand, "flash");
|
||||
assert.equal(download.payload.plan.ops[1].args.commandBinding.programBackend, "keil");
|
||||
assert.equal(download.payload.plan.ops[1].args.commandBinding.autoBindUvoptx, false);
|
||||
assert.match(download.payload.plan.ops[1].args.commandLine, /^py -3 C:\\Users\\liang\\\.agents\\skills\\keil\\keil-cli\.py flash -p/u);
|
||||
|
||||
const jobStatus = await runHwpodCli(["job", "status", "keil_job_123", "--spec", specPath, "--dry-run"], { now: () => NOW });
|
||||
assert.equal(jobStatus.exitCode, 0);
|
||||
|
||||
+118
-30
@@ -1346,6 +1346,35 @@ function subjectFromDefinition(definition: Record<string, unknown>) {
|
||||
async function requestSubjectWorktree(context: CaseContext, input: { caseId: string; runId: string; runDir: string; apiUrl: string; sourceSpecPath: string }, subject: { repoLocalPath: string; commitId: string; subdir: string }, worktreePath: string, relativeWorktreePath: string) {
|
||||
const document = await readHwpodSpec(input.sourceSpecPath);
|
||||
const hwpodId = text(document.metadata.name) || text(document.metadata.uid) || input.caseId;
|
||||
const sidecarOp = keilSidecarCopyOp(document, subject, hwpodId, relativeWorktreePath);
|
||||
const ops = [{
|
||||
opId: "op_01_subject_commit",
|
||||
op: "cmd.run",
|
||||
args: {
|
||||
hwpodId,
|
||||
workspacePath: subject.repoLocalPath,
|
||||
command: "git",
|
||||
argv: ["cat-file", "-e", subject.commitId]
|
||||
}
|
||||
}, {
|
||||
opId: "op_02_subject_worktree_add",
|
||||
op: "cmd.run",
|
||||
args: {
|
||||
hwpodId,
|
||||
workspacePath: subject.repoLocalPath,
|
||||
command: "git",
|
||||
argv: ["worktree", "add", "--detach", "--force", relativeWorktreePath, subject.commitId]
|
||||
}
|
||||
}, {
|
||||
opId: "op_03_subject_worktree_head",
|
||||
op: "cmd.run",
|
||||
args: {
|
||||
hwpodId,
|
||||
workspacePath: subject.repoLocalPath,
|
||||
command: "git",
|
||||
argv: ["-C", relativeWorktreePath, "rev-parse", "HEAD"]
|
||||
}
|
||||
}, ...(sidecarOp ? [sidecarOp] : [])];
|
||||
const plan = {
|
||||
contractVersion: "hwpod-node-ops-v1",
|
||||
planId: `case_subject_${randomUUID()}`,
|
||||
@@ -1353,34 +1382,7 @@ async function requestSubjectWorktree(context: CaseContext, input: { caseId: str
|
||||
nodeId: document.spec.nodeBinding.nodeId,
|
||||
intent: "cmd.run",
|
||||
source: { compiler: "hwlab-cli.case", specPath: input.sourceSpecPath, specAuthority: "case-registry" },
|
||||
ops: [{
|
||||
opId: "op_01_subject_commit",
|
||||
op: "cmd.run",
|
||||
args: {
|
||||
hwpodId,
|
||||
workspacePath: subject.repoLocalPath,
|
||||
command: "git",
|
||||
argv: ["cat-file", "-e", subject.commitId]
|
||||
}
|
||||
}, {
|
||||
opId: "op_02_subject_worktree_add",
|
||||
op: "cmd.run",
|
||||
args: {
|
||||
hwpodId,
|
||||
workspacePath: subject.repoLocalPath,
|
||||
command: "git",
|
||||
argv: ["worktree", "add", "--detach", "--force", relativeWorktreePath, subject.commitId]
|
||||
}
|
||||
}, {
|
||||
opId: "op_03_subject_worktree_head",
|
||||
op: "cmd.run",
|
||||
args: {
|
||||
hwpodId,
|
||||
workspacePath: subject.repoLocalPath,
|
||||
command: "git",
|
||||
argv: ["-C", relativeWorktreePath, "rev-parse", "HEAD"]
|
||||
}
|
||||
}]
|
||||
ops
|
||||
};
|
||||
const response = await context.fetchImpl(`${input.apiUrl}/v1/hwpod-node-ops`, {
|
||||
method: "POST",
|
||||
@@ -1393,7 +1395,7 @@ async function requestSubjectWorktree(context: CaseContext, input: { caseId: str
|
||||
if (!status.ok) {
|
||||
throw cliError("subject_worktree_prepare_failed", "failed to prepare isolated subject worktree on the HWPOD node", clean({ httpStatus: response.status, nodeId: document.spec.nodeBinding.nodeId, repoLocalPath: subject.repoLocalPath, commitId: subject.commitId, worktreePath, exitCode: status.exitCode, stdout: clipText(status.stdout), stderr: clipText(status.stderr), body: compactObject(body) }));
|
||||
}
|
||||
return clean({ httpStatus: response.status, planId: plan.planId, nodeId: document.spec.nodeBinding.nodeId, exitCode: status.exitCode, stdout: clipText(status.stdout), stderr: clipText(status.stderr) });
|
||||
return clean({ httpStatus: response.status, planId: plan.planId, nodeId: document.spec.nodeBinding.nodeId, exitCode: status.exitCode, stdout: clipText(status.stdout), stderr: clipText(status.stderr), keilSidecars: keilSidecarSummary(status.stdout) });
|
||||
}
|
||||
|
||||
function subjectWorktreeStatus(httpStatus: number, body: any, expected: { commitId: string; worktreePath: string }) {
|
||||
@@ -1403,11 +1405,97 @@ function subjectWorktreeStatus(httpStatus: number, body: any, expected: { commit
|
||||
const stdout = outputs.map((output: any) => text(output.stdout)).filter(Boolean).join("\n");
|
||||
const stderr = outputs.map((output: any) => text(output.stderr)).filter(Boolean).join("\n");
|
||||
const actualHead = text(outputs[2]?.stdout).split(/\r?\n/u)[0]?.toLowerCase() ?? "";
|
||||
const commandOk = httpStatus >= 200 && httpStatus < 300 && outputs.length === 3 && exitCodes.every((exitCode) => exitCode === 0);
|
||||
const commandOk = httpStatus >= 200 && httpStatus < 300 && outputs.length >= 3 && exitCodes.every((exitCode) => exitCode === 0);
|
||||
const ok = commandOk && actualHead === expected.commitId;
|
||||
return { ok, exitCode: exitCodes.find((exitCode) => exitCode !== 0) ?? exitCodes[exitCodes.length - 1], stdout, stderr, actualHead, actualWorktreePath: expected.worktreePath };
|
||||
}
|
||||
|
||||
function keilSidecarCopyOp(document: any, subject: { repoLocalPath: string }, hwpodId: string, relativeWorktreePath: string) {
|
||||
const project = subjectRelativeKeilProject(document, subject.repoLocalPath);
|
||||
if (!project) return null;
|
||||
const sourceBase = stripUvprojx(project).replace(/\//gu, "\\");
|
||||
const destinationBase = windowsJoin(relativeWorktreePath, sourceBase);
|
||||
return {
|
||||
opId: "op_04_keil_sidecars",
|
||||
op: "cmd.run",
|
||||
args: {
|
||||
hwpodId,
|
||||
workspacePath: subject.repoLocalPath,
|
||||
command: "node",
|
||||
argv: ["-e", keilSidecarCopyNodeScript(), JSON.stringify({ sourceBase, destinationBase })],
|
||||
commandBinding: {
|
||||
kind: "keil-mdk-sidecar-copy",
|
||||
source: "hwlab-cli.case.prepare",
|
||||
sourceBase,
|
||||
destinationBase,
|
||||
sidecars: [".uvoptx", ".uvopt"]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function subjectRelativeKeilProject(document: any, repoLocalPath: string) {
|
||||
const workspace = objectRecord(document.spec?.workspace);
|
||||
const projectWorkspace = objectRecord(document.spec?.projectWorkspace);
|
||||
const rawProject = text(workspace.keilProject ?? workspace.projectPath ?? workspace.project ?? projectWorkspace.projectPath);
|
||||
if (!rawProject || !/\.uvprojx$/iu.test(rawProject)) return "";
|
||||
if (!isAbsolutePathLike(rawProject)) return rawProject.replace(/^[\\/]+/u, "");
|
||||
const repo = repoLocalPath.replace(/[\\/]+$/u, "");
|
||||
const normalizedRepo = normalizeLocalPath(repo);
|
||||
const normalizedProject = normalizeLocalPath(rawProject);
|
||||
if (!normalizedProject.startsWith(`${normalizedRepo}/`)) return "";
|
||||
return rawProject.slice(repo.length).replace(/^[\\/]+/u, "");
|
||||
}
|
||||
|
||||
function stripUvprojx(value: string) {
|
||||
return value.replace(/\.uvprojx$/iu, "");
|
||||
}
|
||||
|
||||
function windowsJoin(parent: string, child: string) {
|
||||
const left = parent.replace(/[\\/]+$/u, "").replace(/\//gu, "\\");
|
||||
const right = child.replace(/^[\\/]+/u, "").replace(/\//gu, "\\");
|
||||
return `${left}\\${right}`;
|
||||
}
|
||||
|
||||
function keilSidecarCopyNodeScript() {
|
||||
return [
|
||||
"const fs=require('fs');",
|
||||
"const path=require('path');",
|
||||
"const input=JSON.parse(process.argv[1]||'{}');",
|
||||
"const sidecars=['.uvoptx','.uvopt'];",
|
||||
"const copiedFiles=[];",
|
||||
"const missing=[];",
|
||||
"for(const ext of sidecars){",
|
||||
"const source=String(input.sourceBase||'')+ext;",
|
||||
"const destination=String(input.destinationBase||'')+ext;",
|
||||
"if(fs.existsSync(source)){",
|
||||
"const dir=destination.includes('\\\\')?path.win32.dirname(destination):path.dirname(destination);",
|
||||
"fs.mkdirSync(dir,{recursive:true});",
|
||||
"fs.copyFileSync(source,destination);",
|
||||
"copiedFiles.push({ext,source,destination});",
|
||||
"}else{missing.push(source);}",
|
||||
"}",
|
||||
"console.log('caseRunKeilSidecars '+JSON.stringify({copied:copiedFiles.length,copiedFiles,missing,sourceBase:input.sourceBase,destinationBase:input.destinationBase}));"
|
||||
].join("");
|
||||
}
|
||||
|
||||
function keilSidecarSummary(stdout: string) {
|
||||
const line = stdout.split(/\r?\n/u).find((item) => item.includes("caseRunKeilSidecars"));
|
||||
if (!line) return null;
|
||||
const payload = line.replace(/^.*caseRunKeilSidecars\s*/u, "");
|
||||
const parsed = parseJsonMaybe(payload);
|
||||
if (parsed && typeof parsed === "object") return clean({ ...(parsed as Record<string, unknown>), line });
|
||||
return clean({ copied: numberOption(line.match(/copied=(\d+)/u)?.[1]), line });
|
||||
}
|
||||
|
||||
function objectRecord(value: unknown): Record<string, unknown> {
|
||||
return value && typeof value === "object" && !Array.isArray(value) ? value as Record<string, unknown> : {};
|
||||
}
|
||||
|
||||
function isAbsolutePathLike(value: string) {
|
||||
return /^[A-Za-z]:[\\/]/u.test(value) || value.startsWith("/") || value.startsWith("\\\\");
|
||||
}
|
||||
|
||||
function subjectRelativeWorktreePath(repoLocalPath: string, worktreePath: string) {
|
||||
const repo = repoLocalPath.replace(/[\\/]+$/u, "");
|
||||
const normalizedRepo = normalizeLocalPath(repo);
|
||||
|
||||
@@ -531,6 +531,7 @@ function debugDownloadOps(common: any, args: any, document: any) {
|
||||
op: "cmd.run",
|
||||
args: clean({
|
||||
...opArgs,
|
||||
commandBinding: entry.commandBinding ?? opArgs.commandBinding,
|
||||
command: entry.commandRun.command,
|
||||
argv: entry.commandRun.argv,
|
||||
commandLine: entry.command,
|
||||
@@ -605,6 +606,7 @@ function keilCommandForIntent(intent: "debug.build" | "debug.download", args: an
|
||||
const programBackend = text(args.programBackend ?? args.backend) || text(debugProbe.programBackend) || (text(debugProbe.adapter).toLowerCase() === "keil" ? "keil" : "keil");
|
||||
const probeName = text(args.probeName) || text(debugProbe.probeName) || text(debugProbe.name);
|
||||
const autoBindUvoptx = debugProbe.autoBindUvoptx === true || debugProbe.autoBindProbe === true;
|
||||
const sidecarDiagnostics = keilSidecarDiagnosticRun(project);
|
||||
const bindTokens = autoBindUvoptx && probeUid
|
||||
? [...commonTokens, "project", "probe-binding", "set", "-p", project, ...projectTargetOption(target), "--probe-uid", probeUid, ...probeNameOption(probeName)]
|
||||
: [];
|
||||
@@ -622,6 +624,7 @@ function keilCommandForIntent(intent: "debug.build" | "debug.download", args: an
|
||||
...(args.wait === true ? ["--wait"] : [])
|
||||
];
|
||||
const commandRuns = [
|
||||
sidecarDiagnostics,
|
||||
...(bindTokens.length > 0 ? [{ step: "keil-probe-binding", command: shellCommand(bindTokens), commandRun: commandRun(bindTokens) }] : []),
|
||||
{ step: "keil-flash", command: shellCommand(flashTokens), commandRun: commandRun(flashTokens) }
|
||||
];
|
||||
@@ -630,10 +633,29 @@ function keilCommandForIntent(intent: "debug.build" | "debug.download", args: an
|
||||
command: commandRuns.map((entry) => entry.command).join(" && "),
|
||||
commandRuns,
|
||||
timeoutMs,
|
||||
binding: clean({ kind: "keil-mdk", source: "hwpod-compiler.keil-mdk", action: "download", keilCommand: "flash", project, target, keilCliPath, pythonCommand, programmer, programBackend, probeUid, probeName, autoBindUvoptx: bindTokens.length > 0, wait: args.wait === true })
|
||||
binding: clean({ kind: "keil-mdk", source: "hwpod-compiler.keil-mdk", action: "download", keilCommand: "flash", project, target, keilCliPath, pythonCommand, programmer, programBackend, probeUid, probeName, autoBindUvoptx: bindTokens.length > 0, wait: args.wait === true, keilSidecars: sidecarDiagnostics.commandBinding })
|
||||
};
|
||||
}
|
||||
|
||||
function keilSidecarDiagnosticRun(project: string) {
|
||||
const base = project.replace(/\.uvprojx$/iu, "");
|
||||
const primary = `${base}.uvoptx`;
|
||||
const alternate = `${base}.uvopt`;
|
||||
const script = [
|
||||
"const fs=require('fs');",
|
||||
"const input=JSON.parse(process.argv[1]||'{}');",
|
||||
"const primary=String(input.primary||'');",
|
||||
"const alternate=String(input.alternate||'');",
|
||||
"let result;",
|
||||
"if(fs.existsSync(primary)){result={status:'present',primary};}",
|
||||
"else if(fs.existsSync(alternate)){result={status:'present',alternate};}",
|
||||
"else{result={status:'missing',primary,alternate,reason:'keil_uvoptx_binding_absent'};}",
|
||||
"console.log('hwpodKeilSidecar '+JSON.stringify(result));"
|
||||
].join("");
|
||||
const run = { command: "node", argv: ["-e", script, JSON.stringify({ primary, alternate })] };
|
||||
return { step: "keil-sidecar-diagnostics", command: shellCommand([run.command, ...run.argv]), commandRun: run, commandBinding: { primary, alternate } };
|
||||
}
|
||||
|
||||
function keilJobStatusCommand(args: any, document: any) {
|
||||
const workspace = objectValue(document.spec.workspace);
|
||||
const debugProbe = objectValue(document.spec.debugProbe);
|
||||
|
||||
Reference in New Issue
Block a user