@paperclipai/adapter-grok-local 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/format-event.d.ts +2 -0
- package/dist/cli/format-event.d.ts.map +1 -0
- package/dist/cli/format-event.js +55 -0
- package/dist/cli/format-event.js.map +1 -0
- package/dist/cli/format-event.test.d.ts +2 -0
- package/dist/cli/format-event.test.d.ts.map +1 -0
- package/dist/cli/format-event.test.js +19 -0
- package/dist/cli/format-event.test.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/server/execute.d.ts +3 -0
- package/dist/server/execute.d.ts.map +1 -0
- package/dist/server/execute.js +466 -0
- package/dist/server/execute.js.map +1 -0
- package/dist/server/execute.test.d.ts +2 -0
- package/dist/server/execute.test.d.ts.map +1 -0
- package/dist/server/execute.test.js +169 -0
- package/dist/server/execute.test.js.map +1 -0
- package/dist/server/index.d.ts +7 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +62 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/parse.d.ts +11 -0
- package/dist/server/parse.d.ts.map +1 -0
- package/dist/server/parse.js +75 -0
- package/dist/server/parse.js.map +1 -0
- package/dist/server/parse.test.d.ts +2 -0
- package/dist/server/parse.test.d.ts.map +1 -0
- package/dist/server/parse.test.js +34 -0
- package/dist/server/parse.test.js.map +1 -0
- package/dist/server/skills.d.ts +4 -0
- package/dist/server/skills.d.ts.map +1 -0
- package/dist/server/skills.js +62 -0
- package/dist/server/skills.js.map +1 -0
- package/dist/server/test.d.ts +9 -0
- package/dist/server/test.d.ts.map +1 -0
- package/dist/server/test.js +266 -0
- package/dist/server/test.js.map +1 -0
- package/dist/server/test.test.d.ts +2 -0
- package/dist/server/test.test.d.ts.map +1 -0
- package/dist/server/test.test.js +120 -0
- package/dist/server/test.test.js.map +1 -0
- package/dist/ui/build-config.d.ts +3 -0
- package/dist/ui/build-config.d.ts.map +1 -0
- package/dist/ui/build-config.js +81 -0
- package/dist/ui/build-config.js.map +1 -0
- package/dist/ui/build-config.test.d.ts +2 -0
- package/dist/ui/build-config.test.d.ts.map +1 -0
- package/dist/ui/build-config.test.js +26 -0
- package/dist/ui/build-config.test.js.map +1 -0
- package/dist/ui/index.d.ts +3 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +3 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/parse-stdout.d.ts +3 -0
- package/dist/ui/parse-stdout.d.ts.map +1 -0
- package/dist/ui/parse-stdout.js +54 -0
- package/dist/ui/parse-stdout.js.map +1 -0
- package/dist/ui/parse-stdout.test.d.ts +2 -0
- package/dist/ui/parse-stdout.test.d.ts.map +1 -0
- package/dist/ui/parse-stdout.test.js +25 -0
- package/dist/ui/parse-stdout.test.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-event.d.ts","sourceRoot":"","sources":["../../src/cli/format-event.ts"],"names":[],"mappings":"AAWA,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CA+CvE"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
2
|
+
function asRecord(value) {
|
|
3
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
4
|
+
return null;
|
|
5
|
+
return value;
|
|
6
|
+
}
|
|
7
|
+
function asString(value, fallback = "") {
|
|
8
|
+
return typeof value === "string" ? value : fallback;
|
|
9
|
+
}
|
|
10
|
+
export function printGrokStreamEvent(raw, _debug) {
|
|
11
|
+
const line = raw.trim();
|
|
12
|
+
if (!line)
|
|
13
|
+
return;
|
|
14
|
+
let parsed = null;
|
|
15
|
+
try {
|
|
16
|
+
parsed = JSON.parse(line);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
console.log(line);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const type = asString(parsed.type).trim();
|
|
23
|
+
if (type === "thought") {
|
|
24
|
+
const text = asString(parsed.data);
|
|
25
|
+
if (text)
|
|
26
|
+
console.log(pc.gray(`thinking: ${text}`));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (type === "text") {
|
|
30
|
+
const text = asString(parsed.data);
|
|
31
|
+
if (text)
|
|
32
|
+
console.log(pc.green(`assistant: ${text}`));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (type === "end") {
|
|
36
|
+
const stopReason = asString(parsed.stopReason);
|
|
37
|
+
const sessionId = asString(parsed.sessionId);
|
|
38
|
+
const details = [stopReason ? `stopReason=${stopReason}` : "", sessionId ? `session=${sessionId}` : ""]
|
|
39
|
+
.filter(Boolean)
|
|
40
|
+
.join(" ");
|
|
41
|
+
console.log(pc.blue(`Grok run completed${details ? ` (${details})` : ""}`));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (type === "error") {
|
|
45
|
+
const text = asString(parsed.data) ||
|
|
46
|
+
asString(parsed.message) ||
|
|
47
|
+
asString(parsed.error) ||
|
|
48
|
+
"Grok error";
|
|
49
|
+
console.log(pc.red(`error: ${text}`));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const payload = asRecord(parsed);
|
|
53
|
+
console.log(pc.gray(`event: ${type || "unknown"} ${payload ? JSON.stringify(payload) : line}`));
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=format-event.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-event.js","sourceRoot":"","sources":["../../src/cli/format-event.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-event.test.d.ts","sourceRoot":"","sources":["../../src/cli/format-event.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { printGrokStreamEvent } from "./format-event.js";
|
|
3
|
+
describe("printGrokStreamEvent", () => {
|
|
4
|
+
const spy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
5
|
+
afterEach(() => {
|
|
6
|
+
spy.mockClear();
|
|
7
|
+
});
|
|
8
|
+
it("prints thought/text/end events", () => {
|
|
9
|
+
printGrokStreamEvent(JSON.stringify({ type: "thought", data: "Plan" }), false);
|
|
10
|
+
printGrokStreamEvent(JSON.stringify({ type: "text", data: "hello" }), false);
|
|
11
|
+
printGrokStreamEvent(JSON.stringify({ type: "end", stopReason: "EndTurn", sessionId: "sess-1" }), false);
|
|
12
|
+
expect(spy.mock.calls.flat()).toEqual(expect.arrayContaining([
|
|
13
|
+
expect.stringContaining("thinking: Plan"),
|
|
14
|
+
expect.stringContaining("assistant: hello"),
|
|
15
|
+
expect.stringContaining("Grok run completed"),
|
|
16
|
+
]));
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
//# sourceMappingURL=format-event.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-event.test.js","sourceRoot":"","sources":["../../src/cli/format-event.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,MAAM,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAElE,SAAS,CAAC,GAAG,EAAE;QACb,GAAG,CAAC,SAAS,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,oBAAoB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;QAC/E,oBAAoB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;QAC7E,oBAAoB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;QAEzG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CACnC,MAAM,CAAC,eAAe,CAAC;YACrB,MAAM,CAAC,gBAAgB,CAAC,gBAAgB,CAAC;YACzC,MAAM,CAAC,gBAAgB,CAAC,kBAAkB,CAAC;YAC3C,MAAM,CAAC,gBAAgB,CAAC,oBAAoB,CAAC;SAC9C,CAAC,CACH,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const type = "grok_local";
|
|
2
|
+
export declare const label = "Grok Build (local)";
|
|
3
|
+
export declare const DEFAULT_GROK_LOCAL_MODEL = "grok-build";
|
|
4
|
+
export declare const models: {
|
|
5
|
+
id: string;
|
|
6
|
+
label: string;
|
|
7
|
+
}[];
|
|
8
|
+
export declare const agentConfigurationDoc = "# grok_local agent configuration\n\nAdapter: grok_local\n\nUse when:\n- You want Paperclip to run the native Grok Build CLI locally on the host machine\n- You want resumable Grok sessions across heartbeats via `--resume`\n- You want Paperclip-managed instructions and skills staged into the execution workspace using Grok's native discovery paths (`Agents.md` and `.claude/skills`)\n\nDon't use when:\n- You need a webhook-style external invocation (use http or openclaw_gateway)\n- You only need a one-shot script without an AI coding agent loop (use process)\n- Grok CLI is not installed or authenticated on the machine that runs Paperclip\n\nCore fields:\n- cwd (string, optional): default absolute working directory fallback for the agent process (created if missing when possible)\n- instructionsFilePath (string, optional): absolute path to a markdown instructions file. Paperclip stages it into the execution workspace as `Agents.md` when safe, otherwise falls back to `--rules @file`\n- promptTemplate (string, optional): run prompt template\n- model (string, optional): Grok model id. Defaults to grok-build.\n- permissionMode (string, optional): Grok permission mode. Defaults to `dontAsk`\n- reasoningEffort (string, optional): Grok reasoning effort passed via `--reasoning-effort`\n- maxTurns (number, optional): maximum agent turns for the run\n- command (string, optional): defaults to \"grok\"\n- extraArgs (string[], optional): additional CLI args\n- env (object, optional): KEY=VALUE environment variables\n\nOperational fields:\n- timeoutSec (number, optional): run timeout in seconds\n- graceSec (number, optional): SIGTERM grace period in seconds\n\nNotes:\n- Runs use `grok --single` with `--output-format streaming-json`.\n- Sessions resume with `--resume <sessionId>` when the saved session cwd matches the current cwd.\n- Paperclip stages desired runtime skills into `.claude/skills` inside the execution workspace so Grok discovers them as project skills.\n- Use `grok models` to inspect authentication and available models on the host.\n";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI,eAAe,CAAC;AACjC,eAAO,MAAM,KAAK,uBAAuB,CAAC;AAE1C,eAAO,MAAM,wBAAwB,eAAe,CAAC;AAErD,eAAO,MAAM,MAAM;;;GAElB,CAAC;AAEF,eAAO,MAAM,qBAAqB,ohEAmCjC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export const type = "grok_local";
|
|
2
|
+
export const label = "Grok Build (local)";
|
|
3
|
+
export const DEFAULT_GROK_LOCAL_MODEL = "grok-build";
|
|
4
|
+
export const models = [
|
|
5
|
+
{ id: DEFAULT_GROK_LOCAL_MODEL, label: DEFAULT_GROK_LOCAL_MODEL },
|
|
6
|
+
];
|
|
7
|
+
export const agentConfigurationDoc = `# grok_local agent configuration
|
|
8
|
+
|
|
9
|
+
Adapter: grok_local
|
|
10
|
+
|
|
11
|
+
Use when:
|
|
12
|
+
- You want Paperclip to run the native Grok Build CLI locally on the host machine
|
|
13
|
+
- You want resumable Grok sessions across heartbeats via \`--resume\`
|
|
14
|
+
- You want Paperclip-managed instructions and skills staged into the execution workspace using Grok's native discovery paths (\`Agents.md\` and \`.claude/skills\`)
|
|
15
|
+
|
|
16
|
+
Don't use when:
|
|
17
|
+
- You need a webhook-style external invocation (use http or openclaw_gateway)
|
|
18
|
+
- You only need a one-shot script without an AI coding agent loop (use process)
|
|
19
|
+
- Grok CLI is not installed or authenticated on the machine that runs Paperclip
|
|
20
|
+
|
|
21
|
+
Core fields:
|
|
22
|
+
- cwd (string, optional): default absolute working directory fallback for the agent process (created if missing when possible)
|
|
23
|
+
- instructionsFilePath (string, optional): absolute path to a markdown instructions file. Paperclip stages it into the execution workspace as \`Agents.md\` when safe, otherwise falls back to \`--rules @file\`
|
|
24
|
+
- promptTemplate (string, optional): run prompt template
|
|
25
|
+
- model (string, optional): Grok model id. Defaults to grok-build.
|
|
26
|
+
- permissionMode (string, optional): Grok permission mode. Defaults to \`dontAsk\`
|
|
27
|
+
- reasoningEffort (string, optional): Grok reasoning effort passed via \`--reasoning-effort\`
|
|
28
|
+
- maxTurns (number, optional): maximum agent turns for the run
|
|
29
|
+
- command (string, optional): defaults to "grok"
|
|
30
|
+
- extraArgs (string[], optional): additional CLI args
|
|
31
|
+
- env (object, optional): KEY=VALUE environment variables
|
|
32
|
+
|
|
33
|
+
Operational fields:
|
|
34
|
+
- timeoutSec (number, optional): run timeout in seconds
|
|
35
|
+
- graceSec (number, optional): SIGTERM grace period in seconds
|
|
36
|
+
|
|
37
|
+
Notes:
|
|
38
|
+
- Runs use \`grok --single\` with \`--output-format streaming-json\`.
|
|
39
|
+
- Sessions resume with \`--resume <sessionId>\` when the saved session cwd matches the current cwd.
|
|
40
|
+
- Paperclip stages desired runtime skills into \`.claude/skills\` inside the execution workspace so Grok discovers them as project skills.
|
|
41
|
+
- Use \`grok models\` to inspect authentication and available models on the host.
|
|
42
|
+
`;
|
|
43
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,IAAI,GAAG,YAAY,CAAC;AACjC,MAAM,CAAC,MAAM,KAAK,GAAG,oBAAoB,CAAC;AAE1C,MAAM,CAAC,MAAM,wBAAwB,GAAG,YAAY,CAAC;AAErD,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,EAAE,EAAE,EAAE,wBAAwB,EAAE,KAAK,EAAE,wBAAwB,EAAE;CAClE,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCpC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../src/server/execute.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AA2LlG,wBAAsB,OAAO,CAAC,GAAG,EAAE,uBAAuB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAwY3F"}
|
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { adapterExecutionTargetIsRemote, adapterExecutionTargetRemoteCwd, adapterExecutionTargetSessionIdentity, adapterExecutionTargetSessionMatches, describeAdapterExecutionTarget, ensureAdapterExecutionTargetCommandResolvable, ensureAdapterExecutionTargetRuntimeCommandInstalled, overrideAdapterExecutionTargetRemoteCwd, prepareAdapterExecutionTargetRuntime, readAdapterExecutionTarget, resolveAdapterExecutionTargetCommandForLogs, resolveAdapterExecutionTargetTimeoutSec, runAdapterExecutionTargetProcess, } from "@paperclipai/adapter-utils/execution-target";
|
|
5
|
+
import { asBoolean, asNumber, asString, asStringArray, buildInvocationEnvForLogs, buildPaperclipEnv, ensureAbsoluteDirectory, ensurePathInEnv, joinPromptSections, materializePaperclipSkillCopy, parseObject, readPaperclipIssueWorkModeFromContext, readPaperclipRuntimeSkillEntries, renderTemplate, renderPaperclipWakePrompt, resolvePaperclipDesiredSkillNames, stringifyPaperclipWakePayload, refreshPaperclipWorkspaceEnvForExecution, DEFAULT_PAPERCLIP_AGENT_PROMPT_TEMPLATE, } from "@paperclipai/adapter-utils/server-utils";
|
|
6
|
+
import { DEFAULT_GROK_LOCAL_MODEL } from "../index.js";
|
|
7
|
+
import { isGrokUnknownSessionError, parseGrokJsonl } from "./parse.js";
|
|
8
|
+
const __moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
function firstNonEmptyLine(text) {
|
|
10
|
+
return (text
|
|
11
|
+
.split(/\r?\n/)
|
|
12
|
+
.map((line) => line.trim())
|
|
13
|
+
.find(Boolean) ?? "");
|
|
14
|
+
}
|
|
15
|
+
function hasNonEmptyEnvValue(env, key) {
|
|
16
|
+
const raw = env[key];
|
|
17
|
+
return typeof raw === "string" && raw.trim().length > 0;
|
|
18
|
+
}
|
|
19
|
+
function renderPaperclipEnvNote(env) {
|
|
20
|
+
const paperclipKeys = Object.keys(env)
|
|
21
|
+
.filter((key) => key.startsWith("PAPERCLIP_"))
|
|
22
|
+
.sort();
|
|
23
|
+
if (paperclipKeys.length === 0)
|
|
24
|
+
return "";
|
|
25
|
+
return [
|
|
26
|
+
"Paperclip runtime note:",
|
|
27
|
+
`The following PAPERCLIP_* environment variables are available in this run: ${paperclipKeys.join(", ")}`,
|
|
28
|
+
"Do not assume these variables are missing without checking your shell environment.",
|
|
29
|
+
"",
|
|
30
|
+
"",
|
|
31
|
+
].join("\n");
|
|
32
|
+
}
|
|
33
|
+
function renderApiAccessNote(env) {
|
|
34
|
+
if (!hasNonEmptyEnvValue(env, "PAPERCLIP_API_URL") || !hasNonEmptyEnvValue(env, "PAPERCLIP_API_KEY"))
|
|
35
|
+
return "";
|
|
36
|
+
return [
|
|
37
|
+
"Paperclip API access note:",
|
|
38
|
+
"Use shell commands with curl to make Paperclip API requests when needed.",
|
|
39
|
+
"Include X-Paperclip-Run-Id on mutating requests.",
|
|
40
|
+
"",
|
|
41
|
+
"",
|
|
42
|
+
].join("\n");
|
|
43
|
+
}
|
|
44
|
+
async function pathExists(candidate) {
|
|
45
|
+
return fs.access(candidate).then(() => true).catch(() => false);
|
|
46
|
+
}
|
|
47
|
+
async function stageGrokProjectAssets(input) {
|
|
48
|
+
const cleanup = [];
|
|
49
|
+
const ensureCleanupDir = (candidate) => {
|
|
50
|
+
cleanup.push({ kind: "dir", path: candidate });
|
|
51
|
+
};
|
|
52
|
+
const ensureCleanupFile = (candidate) => {
|
|
53
|
+
cleanup.push({ kind: "file", path: candidate });
|
|
54
|
+
};
|
|
55
|
+
let stagedInstructionsPath = null;
|
|
56
|
+
let rulesFilePath = null;
|
|
57
|
+
let stagedSkillsCount = 0;
|
|
58
|
+
const instructionsTarget = path.join(input.cwd, "Agents.md");
|
|
59
|
+
if (input.instructionsFilePath) {
|
|
60
|
+
if (!await pathExists(instructionsTarget)) {
|
|
61
|
+
await fs.copyFile(input.instructionsFilePath, instructionsTarget);
|
|
62
|
+
ensureCleanupFile(instructionsTarget);
|
|
63
|
+
stagedInstructionsPath = instructionsTarget;
|
|
64
|
+
}
|
|
65
|
+
else if (path.resolve(instructionsTarget) !== path.resolve(input.instructionsFilePath)) {
|
|
66
|
+
rulesFilePath = input.instructionsFilePath;
|
|
67
|
+
await input.onLog("stdout", `[paperclip] Grok workspace already contains ${instructionsTarget}; using --rules @${input.instructionsFilePath} instead of overwriting it.\n`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
const canonicalAgents = path.join(input.cwd, "AGENTS.md");
|
|
72
|
+
if (!await pathExists(instructionsTarget) && await pathExists(canonicalAgents)) {
|
|
73
|
+
await fs.copyFile(canonicalAgents, instructionsTarget);
|
|
74
|
+
ensureCleanupFile(instructionsTarget);
|
|
75
|
+
stagedInstructionsPath = instructionsTarget;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const desiredSet = new Set(input.desiredSkillNames);
|
|
79
|
+
const selectedSkills = input.skillEntries.filter((entry) => desiredSet.has(entry.key));
|
|
80
|
+
if (selectedSkills.length > 0) {
|
|
81
|
+
const claudeDir = path.join(input.cwd, ".claude");
|
|
82
|
+
const skillsRoot = path.join(claudeDir, "skills");
|
|
83
|
+
if (!await pathExists(claudeDir)) {
|
|
84
|
+
await fs.mkdir(claudeDir, { recursive: true });
|
|
85
|
+
ensureCleanupDir(claudeDir);
|
|
86
|
+
}
|
|
87
|
+
if (!await pathExists(skillsRoot)) {
|
|
88
|
+
await fs.mkdir(skillsRoot, { recursive: true });
|
|
89
|
+
ensureCleanupDir(skillsRoot);
|
|
90
|
+
}
|
|
91
|
+
for (const skill of selectedSkills) {
|
|
92
|
+
const target = path.join(skillsRoot, skill.runtimeName);
|
|
93
|
+
if (await pathExists(target)) {
|
|
94
|
+
await input.onLog("stdout", `[paperclip] Grok skill target already exists at ${target}; leaving it unchanged.\n`);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
await materializePaperclipSkillCopy(skill.source, target);
|
|
98
|
+
ensureCleanupDir(target);
|
|
99
|
+
stagedSkillsCount += 1;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
stagedSkillsCount,
|
|
104
|
+
stagedInstructionsPath,
|
|
105
|
+
rulesFilePath,
|
|
106
|
+
cleanup: async () => {
|
|
107
|
+
for (const entry of [...cleanup].reverse()) {
|
|
108
|
+
if (entry.kind === "file") {
|
|
109
|
+
await fs.rm(entry.path, { force: true }).catch(() => undefined);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
await fs.rm(entry.path, { recursive: true, force: true }).catch(() => undefined);
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function resolveBillingType(env) {
|
|
118
|
+
return hasNonEmptyEnvValue(env, "XAI_API_KEY") ? "api" : "subscription";
|
|
119
|
+
}
|
|
120
|
+
export async function execute(ctx) {
|
|
121
|
+
const { runId, agent, runtime, config, context, onLog, onMeta, onSpawn, authToken } = ctx;
|
|
122
|
+
const executionTarget = readAdapterExecutionTarget({
|
|
123
|
+
executionTarget: ctx.executionTarget,
|
|
124
|
+
legacyRemoteExecution: ctx.executionTransport?.remoteExecution,
|
|
125
|
+
});
|
|
126
|
+
const executionTargetIsRemote = adapterExecutionTargetIsRemote(executionTarget);
|
|
127
|
+
const promptTemplate = asString(config.promptTemplate, DEFAULT_PAPERCLIP_AGENT_PROMPT_TEMPLATE);
|
|
128
|
+
const command = asString(config.command, "grok");
|
|
129
|
+
const model = asString(config.model, DEFAULT_GROK_LOCAL_MODEL).trim();
|
|
130
|
+
const permissionMode = asString(config.permissionMode, "dontAsk").trim() || "dontAsk";
|
|
131
|
+
const reasoningEffort = asString(config.reasoningEffort, "").trim();
|
|
132
|
+
const maxTurns = asNumber(config.maxTurns, 0);
|
|
133
|
+
const alwaysApprove = asBoolean(config.alwaysApprove, true);
|
|
134
|
+
const disableWebSearch = asBoolean(config.disableWebSearch, true);
|
|
135
|
+
const workspaceContext = parseObject(context.paperclipWorkspace);
|
|
136
|
+
const workspaceCwd = asString(workspaceContext.cwd, "");
|
|
137
|
+
const workspaceSource = asString(workspaceContext.source, "");
|
|
138
|
+
const workspaceId = asString(workspaceContext.workspaceId, "");
|
|
139
|
+
const workspaceRepoUrl = asString(workspaceContext.repoUrl, "");
|
|
140
|
+
const workspaceRepoRef = asString(workspaceContext.repoRef, "");
|
|
141
|
+
const agentHome = asString(workspaceContext.agentHome, "");
|
|
142
|
+
const workspaceHints = Array.isArray(context.paperclipWorkspaces)
|
|
143
|
+
? context.paperclipWorkspaces.filter((value) => typeof value === "object" && value !== null)
|
|
144
|
+
: [];
|
|
145
|
+
const configuredCwd = asString(config.cwd, "");
|
|
146
|
+
const useConfiguredInsteadOfAgentHome = workspaceSource === "agent_home" && configuredCwd.length > 0;
|
|
147
|
+
const effectiveWorkspaceCwd = useConfiguredInsteadOfAgentHome ? "" : workspaceCwd;
|
|
148
|
+
const cwd = effectiveWorkspaceCwd || configuredCwd || process.cwd();
|
|
149
|
+
let effectiveExecutionCwd = adapterExecutionTargetRemoteCwd(executionTarget, cwd);
|
|
150
|
+
await ensureAbsoluteDirectory(cwd, { createIfMissing: true });
|
|
151
|
+
const grokSkillEntries = await readPaperclipRuntimeSkillEntries(config, __moduleDir);
|
|
152
|
+
const desiredGrokSkillNames = resolvePaperclipDesiredSkillNames(config, grokSkillEntries);
|
|
153
|
+
const instructionsFilePath = asString(config.instructionsFilePath, "").trim();
|
|
154
|
+
const stagedAssets = await stageGrokProjectAssets({
|
|
155
|
+
cwd,
|
|
156
|
+
instructionsFilePath,
|
|
157
|
+
skillEntries: grokSkillEntries,
|
|
158
|
+
desiredSkillNames: desiredGrokSkillNames,
|
|
159
|
+
onLog,
|
|
160
|
+
});
|
|
161
|
+
let restoreRemoteWorkspace = null;
|
|
162
|
+
try {
|
|
163
|
+
const envConfig = parseObject(config.env);
|
|
164
|
+
const hasExplicitApiKey = typeof envConfig.PAPERCLIP_API_KEY === "string" && envConfig.PAPERCLIP_API_KEY.trim().length > 0;
|
|
165
|
+
const env = { ...buildPaperclipEnv(agent) };
|
|
166
|
+
env.PAPERCLIP_RUN_ID = runId;
|
|
167
|
+
const wakeTaskId = (typeof context.taskId === "string" && context.taskId.trim().length > 0 && context.taskId.trim()) ||
|
|
168
|
+
(typeof context.issueId === "string" && context.issueId.trim().length > 0 && context.issueId.trim()) ||
|
|
169
|
+
null;
|
|
170
|
+
const wakeReason = typeof context.wakeReason === "string" && context.wakeReason.trim().length > 0
|
|
171
|
+
? context.wakeReason.trim()
|
|
172
|
+
: null;
|
|
173
|
+
const wakeCommentId = (typeof context.wakeCommentId === "string" && context.wakeCommentId.trim().length > 0 && context.wakeCommentId.trim()) ||
|
|
174
|
+
(typeof context.commentId === "string" && context.commentId.trim().length > 0 && context.commentId.trim()) ||
|
|
175
|
+
null;
|
|
176
|
+
const approvalId = typeof context.approvalId === "string" && context.approvalId.trim().length > 0
|
|
177
|
+
? context.approvalId.trim()
|
|
178
|
+
: null;
|
|
179
|
+
const approvalStatus = typeof context.approvalStatus === "string" && context.approvalStatus.trim().length > 0
|
|
180
|
+
? context.approvalStatus.trim()
|
|
181
|
+
: null;
|
|
182
|
+
const linkedIssueIds = Array.isArray(context.issueIds)
|
|
183
|
+
? context.issueIds.filter((value) => typeof value === "string" && value.trim().length > 0)
|
|
184
|
+
: [];
|
|
185
|
+
const wakePayloadJson = stringifyPaperclipWakePayload(context.paperclipWake);
|
|
186
|
+
const issueWorkMode = readPaperclipIssueWorkModeFromContext(context);
|
|
187
|
+
if (wakeTaskId)
|
|
188
|
+
env.PAPERCLIP_TASK_ID = wakeTaskId;
|
|
189
|
+
if (issueWorkMode)
|
|
190
|
+
env.PAPERCLIP_ISSUE_WORK_MODE = issueWorkMode;
|
|
191
|
+
if (wakeReason)
|
|
192
|
+
env.PAPERCLIP_WAKE_REASON = wakeReason;
|
|
193
|
+
if (wakeCommentId)
|
|
194
|
+
env.PAPERCLIP_WAKE_COMMENT_ID = wakeCommentId;
|
|
195
|
+
if (approvalId)
|
|
196
|
+
env.PAPERCLIP_APPROVAL_ID = approvalId;
|
|
197
|
+
if (approvalStatus)
|
|
198
|
+
env.PAPERCLIP_APPROVAL_STATUS = approvalStatus;
|
|
199
|
+
if (linkedIssueIds.length > 0)
|
|
200
|
+
env.PAPERCLIP_LINKED_ISSUE_IDS = linkedIssueIds.join(",");
|
|
201
|
+
if (wakePayloadJson)
|
|
202
|
+
env.PAPERCLIP_WAKE_PAYLOAD_JSON = wakePayloadJson;
|
|
203
|
+
refreshPaperclipWorkspaceEnvForExecution({
|
|
204
|
+
env,
|
|
205
|
+
envConfig,
|
|
206
|
+
workspaceCwd: effectiveWorkspaceCwd,
|
|
207
|
+
workspaceSource,
|
|
208
|
+
workspaceId,
|
|
209
|
+
workspaceRepoUrl,
|
|
210
|
+
workspaceRepoRef,
|
|
211
|
+
workspaceHints,
|
|
212
|
+
agentHome,
|
|
213
|
+
executionTargetIsRemote,
|
|
214
|
+
executionCwd: effectiveExecutionCwd,
|
|
215
|
+
});
|
|
216
|
+
if (!hasExplicitApiKey && authToken) {
|
|
217
|
+
env.PAPERCLIP_API_KEY = authToken;
|
|
218
|
+
}
|
|
219
|
+
const timeoutSec = resolveAdapterExecutionTargetTimeoutSec(executionTarget, asNumber(config.timeoutSec, 0));
|
|
220
|
+
const graceSec = asNumber(config.graceSec, 20);
|
|
221
|
+
await ensureAdapterExecutionTargetRuntimeCommandInstalled({
|
|
222
|
+
runId,
|
|
223
|
+
target: executionTarget,
|
|
224
|
+
installCommand: ctx.runtimeCommandSpec?.installCommand,
|
|
225
|
+
detectCommand: ctx.runtimeCommandSpec?.detectCommand,
|
|
226
|
+
cwd,
|
|
227
|
+
env,
|
|
228
|
+
timeoutSec,
|
|
229
|
+
graceSec,
|
|
230
|
+
onLog,
|
|
231
|
+
});
|
|
232
|
+
if (executionTargetIsRemote) {
|
|
233
|
+
await onLog("stdout", `[paperclip] Syncing Grok workspace to ${describeAdapterExecutionTarget(executionTarget)}.\n`);
|
|
234
|
+
const preparedExecutionTargetRuntime = await prepareAdapterExecutionTargetRuntime({
|
|
235
|
+
runId,
|
|
236
|
+
target: executionTarget,
|
|
237
|
+
adapterKey: "grok",
|
|
238
|
+
workspaceLocalDir: cwd,
|
|
239
|
+
timeoutSec,
|
|
240
|
+
installCommand: ctx.runtimeCommandSpec?.installCommand ?? null,
|
|
241
|
+
detectCommand: ctx.runtimeCommandSpec?.detectCommand ?? command,
|
|
242
|
+
});
|
|
243
|
+
restoreRemoteWorkspace = () => preparedExecutionTargetRuntime.restoreWorkspace();
|
|
244
|
+
effectiveExecutionCwd = preparedExecutionTargetRuntime.workspaceRemoteDir ?? effectiveExecutionCwd;
|
|
245
|
+
refreshPaperclipWorkspaceEnvForExecution({
|
|
246
|
+
env,
|
|
247
|
+
envConfig,
|
|
248
|
+
workspaceCwd: effectiveWorkspaceCwd,
|
|
249
|
+
workspaceSource,
|
|
250
|
+
workspaceId,
|
|
251
|
+
workspaceRepoUrl,
|
|
252
|
+
workspaceRepoRef,
|
|
253
|
+
workspaceHints,
|
|
254
|
+
agentHome,
|
|
255
|
+
executionTargetIsRemote,
|
|
256
|
+
executionCwd: effectiveExecutionCwd,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
const runtimeExecutionTarget = overrideAdapterExecutionTargetRemoteCwd(executionTarget, effectiveExecutionCwd);
|
|
260
|
+
const effectiveEnv = Object.fromEntries(Object.entries({ ...process.env, ...env }).filter((entry) => typeof entry[1] === "string"));
|
|
261
|
+
const runtimeEnv = ensurePathInEnv(effectiveEnv);
|
|
262
|
+
await ensureAdapterExecutionTargetCommandResolvable(command, executionTarget, cwd, runtimeEnv, {
|
|
263
|
+
installCommand: ctx.runtimeCommandSpec?.installCommand ?? null,
|
|
264
|
+
timeoutSec,
|
|
265
|
+
});
|
|
266
|
+
const resolvedCommand = await resolveAdapterExecutionTargetCommandForLogs(command, executionTarget, cwd, runtimeEnv);
|
|
267
|
+
const loggedEnv = buildInvocationEnvForLogs(env, {
|
|
268
|
+
runtimeEnv,
|
|
269
|
+
includeRuntimeKeys: ["HOME"],
|
|
270
|
+
resolvedCommand,
|
|
271
|
+
});
|
|
272
|
+
const billingType = resolveBillingType(effectiveEnv);
|
|
273
|
+
const runtimeSessionParams = parseObject(runtime.sessionParams);
|
|
274
|
+
const runtimeSessionId = asString(runtimeSessionParams.sessionId, runtime.sessionId ?? "");
|
|
275
|
+
const runtimeSessionCwd = asString(runtimeSessionParams.cwd, "");
|
|
276
|
+
const runtimeRemoteExecution = parseObject(runtimeSessionParams.remoteExecution);
|
|
277
|
+
const canResumeSession = runtimeSessionId.length > 0 &&
|
|
278
|
+
(runtimeSessionCwd.length === 0 || path.resolve(runtimeSessionCwd) === path.resolve(effectiveExecutionCwd)) &&
|
|
279
|
+
adapterExecutionTargetSessionMatches(runtimeRemoteExecution, runtimeExecutionTarget);
|
|
280
|
+
const sessionId = canResumeSession ? runtimeSessionId : null;
|
|
281
|
+
if (executionTargetIsRemote && runtimeSessionId && !canResumeSession) {
|
|
282
|
+
await onLog("stdout", `[paperclip] Grok session "${runtimeSessionId}" does not match the current remote execution identity and will not be resumed in "${effectiveExecutionCwd}". Starting a fresh remote session.\n`);
|
|
283
|
+
}
|
|
284
|
+
else if (runtimeSessionId && !canResumeSession) {
|
|
285
|
+
await onLog("stdout", `[paperclip] Grok session "${runtimeSessionId}" was saved for cwd "${runtimeSessionCwd}" and will not be resumed in "${effectiveExecutionCwd}".\n`);
|
|
286
|
+
}
|
|
287
|
+
const commandNotes = (() => {
|
|
288
|
+
const notes = ["Prompt is passed to Grok via --single in headless mode."];
|
|
289
|
+
if (alwaysApprove)
|
|
290
|
+
notes.push("Added --always-approve for unattended execution.");
|
|
291
|
+
if (stagedAssets.stagedInstructionsPath) {
|
|
292
|
+
notes.push(`Staged project instructions at ${stagedAssets.stagedInstructionsPath} for native Grok discovery.`);
|
|
293
|
+
}
|
|
294
|
+
if (stagedAssets.rulesFilePath) {
|
|
295
|
+
notes.push(`Applied fallback instructions via --rules @${stagedAssets.rulesFilePath}.`);
|
|
296
|
+
}
|
|
297
|
+
if (stagedAssets.stagedSkillsCount > 0) {
|
|
298
|
+
notes.push(`Staged ${stagedAssets.stagedSkillsCount} Paperclip skill(s) into .claude/skills for native Grok discovery.`);
|
|
299
|
+
}
|
|
300
|
+
return notes;
|
|
301
|
+
})();
|
|
302
|
+
const templateData = {
|
|
303
|
+
agentId: agent.id,
|
|
304
|
+
companyId: agent.companyId,
|
|
305
|
+
runId,
|
|
306
|
+
company: { id: agent.companyId },
|
|
307
|
+
agent,
|
|
308
|
+
run: { id: runId, source: "on_demand" },
|
|
309
|
+
context,
|
|
310
|
+
};
|
|
311
|
+
const wakePrompt = renderPaperclipWakePrompt(context.paperclipWake, { resumedSession: Boolean(sessionId) });
|
|
312
|
+
const shouldUseResumeDeltaPrompt = Boolean(sessionId) && wakePrompt.length > 0;
|
|
313
|
+
const renderedPrompt = shouldUseResumeDeltaPrompt ? "" : renderTemplate(promptTemplate, templateData);
|
|
314
|
+
const sessionHandoffNote = asString(context.paperclipSessionHandoffMarkdown, "").trim();
|
|
315
|
+
const paperclipEnvNote = renderPaperclipEnvNote(env);
|
|
316
|
+
const apiAccessNote = renderApiAccessNote(env);
|
|
317
|
+
const prompt = joinPromptSections([
|
|
318
|
+
wakePrompt,
|
|
319
|
+
sessionHandoffNote,
|
|
320
|
+
paperclipEnvNote,
|
|
321
|
+
apiAccessNote,
|
|
322
|
+
renderedPrompt,
|
|
323
|
+
]);
|
|
324
|
+
const promptMetrics = {
|
|
325
|
+
promptChars: prompt.length,
|
|
326
|
+
wakePromptChars: wakePrompt.length,
|
|
327
|
+
sessionHandoffChars: sessionHandoffNote.length,
|
|
328
|
+
runtimeNoteChars: paperclipEnvNote.length + apiAccessNote.length,
|
|
329
|
+
heartbeatPromptChars: renderedPrompt.length,
|
|
330
|
+
};
|
|
331
|
+
const buildArgs = (resumeSessionId) => {
|
|
332
|
+
const args = ["--cwd", effectiveExecutionCwd, "--output-format", "streaming-json"];
|
|
333
|
+
if (resumeSessionId)
|
|
334
|
+
args.push("--resume", resumeSessionId);
|
|
335
|
+
if (model && model !== DEFAULT_GROK_LOCAL_MODEL)
|
|
336
|
+
args.push("--model", model);
|
|
337
|
+
if (reasoningEffort)
|
|
338
|
+
args.push("--reasoning-effort", reasoningEffort);
|
|
339
|
+
if (maxTurns > 0)
|
|
340
|
+
args.push("--max-turns", String(maxTurns));
|
|
341
|
+
if (permissionMode)
|
|
342
|
+
args.push("--permission-mode", permissionMode);
|
|
343
|
+
if (alwaysApprove)
|
|
344
|
+
args.push("--always-approve");
|
|
345
|
+
if (disableWebSearch)
|
|
346
|
+
args.push("--disable-web-search");
|
|
347
|
+
if (stagedAssets.rulesFilePath)
|
|
348
|
+
args.push("--rules", `@${stagedAssets.rulesFilePath}`);
|
|
349
|
+
const extraArgs = (() => {
|
|
350
|
+
const fromExtraArgs = asStringArray(config.extraArgs);
|
|
351
|
+
if (fromExtraArgs.length > 0)
|
|
352
|
+
return fromExtraArgs;
|
|
353
|
+
return asStringArray(config.args);
|
|
354
|
+
})();
|
|
355
|
+
if (extraArgs.length > 0)
|
|
356
|
+
args.push(...extraArgs);
|
|
357
|
+
args.push("--single", prompt);
|
|
358
|
+
return args;
|
|
359
|
+
};
|
|
360
|
+
const runAttempt = async (resumeSessionId) => {
|
|
361
|
+
const args = buildArgs(resumeSessionId);
|
|
362
|
+
if (onMeta) {
|
|
363
|
+
await onMeta({
|
|
364
|
+
adapterType: "grok_local",
|
|
365
|
+
command: resolvedCommand,
|
|
366
|
+
cwd: effectiveExecutionCwd,
|
|
367
|
+
commandNotes,
|
|
368
|
+
commandArgs: args.map((value, index) => (index === args.length - 1 ? `<prompt ${prompt.length} chars>` : value)),
|
|
369
|
+
env: loggedEnv,
|
|
370
|
+
prompt,
|
|
371
|
+
promptMetrics,
|
|
372
|
+
context,
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
const proc = await runAdapterExecutionTargetProcess(runId, runtimeExecutionTarget, command, args, {
|
|
376
|
+
cwd,
|
|
377
|
+
env,
|
|
378
|
+
timeoutSec,
|
|
379
|
+
graceSec,
|
|
380
|
+
onSpawn,
|
|
381
|
+
onLog,
|
|
382
|
+
});
|
|
383
|
+
return {
|
|
384
|
+
proc,
|
|
385
|
+
parsed: parseGrokJsonl(proc.stdout),
|
|
386
|
+
};
|
|
387
|
+
};
|
|
388
|
+
const toResult = (attempt, clearSessionOnMissingSession = false, isRetry = false) => {
|
|
389
|
+
if (attempt.proc.timedOut) {
|
|
390
|
+
return {
|
|
391
|
+
exitCode: attempt.proc.exitCode,
|
|
392
|
+
signal: attempt.proc.signal,
|
|
393
|
+
timedOut: true,
|
|
394
|
+
errorMessage: `Timed out after ${timeoutSec}s`,
|
|
395
|
+
clearSession: clearSessionOnMissingSession,
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
const failed = (attempt.proc.exitCode ?? 0) !== 0;
|
|
399
|
+
const parsedError = typeof attempt.parsed.errorMessage === "string" ? attempt.parsed.errorMessage.trim() : "";
|
|
400
|
+
const stderrLine = firstNonEmptyLine(attempt.proc.stderr);
|
|
401
|
+
const fallbackErrorMessage = parsedError ||
|
|
402
|
+
stderrLine ||
|
|
403
|
+
`Grok exited with code ${attempt.proc.exitCode ?? -1}`;
|
|
404
|
+
const canFallbackToRuntimeSession = !isRetry;
|
|
405
|
+
const resolvedSessionId = attempt.parsed.sessionId
|
|
406
|
+
?? (canFallbackToRuntimeSession ? (runtimeSessionId ?? runtime.sessionId ?? null) : null);
|
|
407
|
+
const resolvedSessionParams = resolvedSessionId
|
|
408
|
+
? {
|
|
409
|
+
sessionId: resolvedSessionId,
|
|
410
|
+
cwd: effectiveExecutionCwd,
|
|
411
|
+
...(workspaceId ? { workspaceId } : {}),
|
|
412
|
+
...(workspaceRepoUrl ? { repoUrl: workspaceRepoUrl } : {}),
|
|
413
|
+
...(workspaceRepoRef ? { repoRef: workspaceRepoRef } : {}),
|
|
414
|
+
...(executionTargetIsRemote
|
|
415
|
+
? {
|
|
416
|
+
remoteExecution: adapterExecutionTargetSessionIdentity(runtimeExecutionTarget),
|
|
417
|
+
}
|
|
418
|
+
: {}),
|
|
419
|
+
}
|
|
420
|
+
: null;
|
|
421
|
+
return {
|
|
422
|
+
exitCode: attempt.proc.exitCode,
|
|
423
|
+
signal: attempt.proc.signal,
|
|
424
|
+
timedOut: false,
|
|
425
|
+
errorMessage: failed ? fallbackErrorMessage : null,
|
|
426
|
+
usage: {
|
|
427
|
+
inputTokens: 0,
|
|
428
|
+
outputTokens: 0,
|
|
429
|
+
cachedInputTokens: 0,
|
|
430
|
+
},
|
|
431
|
+
sessionId: resolvedSessionId,
|
|
432
|
+
sessionParams: resolvedSessionParams,
|
|
433
|
+
sessionDisplayId: resolvedSessionId,
|
|
434
|
+
provider: "xai",
|
|
435
|
+
biller: billingType === "api" ? "xai" : "grok",
|
|
436
|
+
model,
|
|
437
|
+
billingType,
|
|
438
|
+
costUsd: null,
|
|
439
|
+
resultJson: {
|
|
440
|
+
stopReason: attempt.parsed.stopReason,
|
|
441
|
+
requestId: attempt.parsed.requestId,
|
|
442
|
+
...(failed ? { stderr: attempt.proc.stderr } : {}),
|
|
443
|
+
},
|
|
444
|
+
summary: attempt.parsed.summary,
|
|
445
|
+
clearSession: Boolean(clearSessionOnMissingSession && !resolvedSessionId),
|
|
446
|
+
};
|
|
447
|
+
};
|
|
448
|
+
const initial = await runAttempt(sessionId);
|
|
449
|
+
if (sessionId &&
|
|
450
|
+
!initial.proc.timedOut &&
|
|
451
|
+
(initial.proc.exitCode ?? 0) !== 0 &&
|
|
452
|
+
isGrokUnknownSessionError(initial.proc.stdout, initial.proc.stderr)) {
|
|
453
|
+
await onLog("stdout", `[paperclip] Grok resume session "${sessionId}" is unavailable; retrying with a fresh session.\n`);
|
|
454
|
+
const retry = await runAttempt(null);
|
|
455
|
+
return toResult(retry, true, true);
|
|
456
|
+
}
|
|
457
|
+
return toResult(initial);
|
|
458
|
+
}
|
|
459
|
+
finally {
|
|
460
|
+
await Promise.all([
|
|
461
|
+
restoreRemoteWorkspace?.(),
|
|
462
|
+
stagedAssets.cleanup(),
|
|
463
|
+
]);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
//# sourceMappingURL=execute.js.map
|