grok-dev 1.0.0-rc8 → 1.1.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.
Files changed (87) hide show
  1. package/.claude/worktrees/vigilant-johnson/.cursor/hooks/state/continual-learning.json +8 -0
  2. package/.claude/worktrees/vigilant-johnson/.cursor/rules/development-workflow.mdc +66 -0
  3. package/.claude/worktrees/vigilant-johnson/.cursor/rules/project-overview.mdc +66 -0
  4. package/.claude/worktrees/vigilant-johnson/.cursor/rules/react-ink-components.mdc +45 -0
  5. package/.claude/worktrees/vigilant-johnson/.cursor/rules/tools-and-agent.mdc +62 -0
  6. package/.claude/worktrees/vigilant-johnson/.cursor/rules/typescript-conventions.mdc +54 -0
  7. package/.claude/worktrees/vigilant-johnson/.husky/pre-commit +1 -0
  8. package/.claude/worktrees/vigilant-johnson/LICENSE +21 -0
  9. package/.claude/worktrees/vigilant-johnson/README.md +341 -0
  10. package/.claude/worktrees/vigilant-johnson/biome.json +51 -0
  11. package/.claude/worktrees/vigilant-johnson/package.json +74 -0
  12. package/.claude/worktrees/vigilant-johnson/telegram-pair-code.txt +0 -0
  13. package/.claude/worktrees/vigilant-johnson/vitest.config.ts +7 -0
  14. package/.grok/generated-media/image-2026-03-26T16-38-08-388Z.jpg +0 -0
  15. package/.grok/generated-media/video-2026-03-26T16-39-19-329Z.mp4 +0 -0
  16. package/.grok/settings.json +1 -1
  17. package/README.md +20 -2
  18. package/dist/agent/agent.d.ts +9 -1
  19. package/dist/agent/agent.js +704 -18
  20. package/dist/agent/agent.js.map +1 -1
  21. package/dist/agent/batch-mode.test.d.ts +1 -0
  22. package/dist/agent/batch-mode.test.js.map +1 -0
  23. package/dist/agent/delegations.d.ts +2 -0
  24. package/dist/agent/delegations.js +9 -1
  25. package/dist/agent/delegations.js.map +1 -1
  26. package/dist/agent/delegations.test.js.map +1 -1
  27. package/dist/grok/batch.d.ts +136 -0
  28. package/dist/grok/batch.js +204 -0
  29. package/dist/grok/batch.js.map +1 -0
  30. package/dist/grok/batch.test.d.ts +1 -0
  31. package/dist/grok/batch.test.js.map +1 -0
  32. package/dist/grok/tool-schemas.d.ts +3 -0
  33. package/dist/grok/tool-schemas.js +24 -0
  34. package/dist/grok/tool-schemas.js.map +1 -0
  35. package/dist/grok/tool-schemas.test.d.ts +1 -0
  36. package/dist/grok/tool-schemas.test.js.map +1 -0
  37. package/dist/grok/tools.js +3 -3
  38. package/dist/grok/tools.js.map +1 -1
  39. package/dist/grok/tools.test.js.map +1 -1
  40. package/dist/headless/output.d.ts +1 -0
  41. package/dist/headless/output.js +29 -4
  42. package/dist/headless/output.js.map +1 -1
  43. package/dist/index.js +24 -6
  44. package/dist/index.js.map +1 -1
  45. package/dist/tools/bash.d.ts +3 -1
  46. package/dist/tools/bash.js +101 -12
  47. package/dist/tools/bash.js.map +1 -1
  48. package/dist/tools/bash.test.js.map +1 -1
  49. package/dist/types/index.d.ts +18 -1
  50. package/dist/types/index.js.map +1 -1
  51. package/dist/ui/app.js +14 -0
  52. package/dist/ui/app.js.map +1 -1
  53. package/dist/ui/schedule-modal.js +2 -2
  54. package/dist/ui/schedule-modal.js.map +1 -1
  55. package/dist/utils/settings.d.ts +6 -0
  56. package/dist/utils/settings.js +9 -1
  57. package/dist/utils/settings.js.map +1 -1
  58. package/dist/utils/skills.d.ts +3 -2
  59. package/dist/utils/skills.js +27 -7
  60. package/dist/utils/skills.js.map +1 -1
  61. package/dist/utils/skills.test.d.ts +1 -0
  62. package/dist/utils/skills.test.js.map +1 -0
  63. package/dist/utils/subagents-settings.test.js.map +1 -1
  64. package/dist/verify/checkpoint.d.ts +11 -0
  65. package/dist/verify/checkpoint.js +158 -0
  66. package/dist/verify/checkpoint.js.map +1 -0
  67. package/dist/verify/checkpoint.test.d.ts +1 -0
  68. package/dist/verify/checkpoint.test.js.map +1 -0
  69. package/dist/verify/entrypoint.d.ts +34 -0
  70. package/dist/verify/entrypoint.js +642 -0
  71. package/dist/verify/entrypoint.js.map +1 -0
  72. package/dist/verify/entrypoint.test.d.ts +1 -0
  73. package/dist/verify/entrypoint.test.js.map +1 -0
  74. package/package.json +2 -1
  75. package/tmp/.grok/verify-artifacts/screenshot-1774806349456.png +0 -0
  76. package/tmp/.grok/verify-artifacts/verify-smoke.webm +0 -0
  77. package/tmp/README.md +36 -0
  78. package/tmp/eslint.config.mjs +18 -0
  79. package/tmp/next.config.ts +7 -0
  80. package/tmp/package.json +34 -0
  81. package/tmp/postcss.config.mjs +7 -0
  82. package/tmp/public/file.svg +1 -0
  83. package/tmp/public/globe.svg +1 -0
  84. package/tmp/public/next.svg +1 -0
  85. package/tmp/public/vercel.svg +1 -0
  86. package/tmp/public/window.svg +1 -0
  87. package/tmp/large_class.py +0 -633
@@ -0,0 +1,642 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import { mergeSandboxSettings } from "../utils/settings";
4
+ export const VERIFY_SUBAGENT_ID = "verify";
5
+ export const VERIFY_TASK_DESCRIPTION = "Run local verification";
6
+ function normalizeVerifyAppKind(value) {
7
+ return [
8
+ "nextjs",
9
+ "vite",
10
+ "astro",
11
+ "sveltekit",
12
+ "remix",
13
+ "cra",
14
+ "node",
15
+ "django",
16
+ "python",
17
+ "go",
18
+ "rust",
19
+ "maven",
20
+ "gradle",
21
+ "make",
22
+ "unknown",
23
+ ].includes(value)
24
+ ? value
25
+ : "unknown";
26
+ }
27
+ function fileExists(cwd, file) {
28
+ return fs.existsSync(path.join(cwd, file));
29
+ }
30
+ function readTextFile(cwd, file) {
31
+ try {
32
+ return fs.readFileSync(path.join(cwd, file), "utf8");
33
+ }
34
+ catch {
35
+ return null;
36
+ }
37
+ }
38
+ function parseHostPort(mapping) {
39
+ const match = mapping.trim().match(/^(\d+):(\d+)$/);
40
+ return match ? match[1] : null;
41
+ }
42
+ function readPackageJson(cwd) {
43
+ const raw = readTextFile(cwd, "package.json");
44
+ if (!raw)
45
+ return null;
46
+ try {
47
+ return JSON.parse(raw);
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ }
53
+ function detectPackageManager(cwd) {
54
+ const candidates = [
55
+ ["pnpm-lock.yaml", "pnpm"],
56
+ ["bun.lock", "bun"],
57
+ ["bun.lockb", "bun"],
58
+ ["yarn.lock", "yarn"],
59
+ ["package-lock.json", "npm"],
60
+ ["uv.lock", "uv"],
61
+ ["poetry.lock", "poetry"],
62
+ ["Pipfile.lock", "pipenv"],
63
+ ];
64
+ for (const [file, manager] of candidates) {
65
+ if (fileExists(cwd, file)) {
66
+ return manager;
67
+ }
68
+ }
69
+ return null;
70
+ }
71
+ function dedupe(values) {
72
+ return [...new Set(values.map((v) => v?.trim()).filter((v) => Boolean(v)))];
73
+ }
74
+ function defaultShellInit() {
75
+ return ["export DEBIAN_FRONTEND=noninteractive"];
76
+ }
77
+ function inferPortFromCommand(command) {
78
+ if (!command)
79
+ return undefined;
80
+ const flagMatch = command.match(/(?:--port|-p)\s+(\d{2,5})/);
81
+ if (flagMatch)
82
+ return flagMatch[1];
83
+ const envMatch = command.match(/\bPORT=(\d{2,5})\b/);
84
+ if (envMatch)
85
+ return envMatch[1];
86
+ return undefined;
87
+ }
88
+ function parseTargetNames(raw) {
89
+ return raw
90
+ .split(/\r?\n/)
91
+ .map((line) => line.match(/^([A-Za-z0-9_.-]+):(?:\s|$)/)?.[1])
92
+ .filter((target) => Boolean(target));
93
+ }
94
+ function detectMakeRecipe(cwd) {
95
+ const makefile = readTextFile(cwd, "Makefile");
96
+ if (!makefile)
97
+ return null;
98
+ const targets = parseTargetNames(makefile);
99
+ const has = (names) => names.find((name) => targets.includes(name));
100
+ const install = has(["install", "setup", "bootstrap"]);
101
+ const build = has(["build", "compile"]);
102
+ const test = has(["test", "check"]);
103
+ const run = has(["run", "start", "serve", "dev"]);
104
+ return {
105
+ ecosystem: "make",
106
+ appKind: "make",
107
+ appLabel: "Makefile-driven project",
108
+ shellInitCommands: defaultShellInit(),
109
+ bootstrapCommands: [],
110
+ installCommands: install ? [`make ${install}`] : [],
111
+ buildCommands: build ? [`make ${build}`] : [],
112
+ testCommands: test ? [`make ${test}`] : [],
113
+ startCommand: run ? `make ${run}` : undefined,
114
+ smokeKind: "none",
115
+ evidence: ["Detected Makefile", `Targets: ${targets.join(", ") || "(none)"}`],
116
+ notes: [],
117
+ };
118
+ }
119
+ function detectNodeRecipe(cwd, pkg, packageManager) {
120
+ const scripts = pkg.scripts ?? {};
121
+ const deps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) };
122
+ let appKind = "node";
123
+ let appLabel = "Node.js app";
124
+ let defaultPort;
125
+ if (deps.next) {
126
+ appKind = "nextjs";
127
+ appLabel = "Next.js";
128
+ defaultPort = "3000";
129
+ }
130
+ else if (deps["@sveltejs/kit"]) {
131
+ appKind = "sveltekit";
132
+ appLabel = "SvelteKit";
133
+ defaultPort = "5173";
134
+ }
135
+ else if (deps.astro) {
136
+ appKind = "astro";
137
+ appLabel = "Astro";
138
+ defaultPort = "4321";
139
+ }
140
+ else if (deps["@remix-run/dev"] || deps["@remix-run/react"]) {
141
+ appKind = "remix";
142
+ appLabel = "Remix";
143
+ defaultPort = "3000";
144
+ }
145
+ else if (deps["react-scripts"]) {
146
+ appKind = "cra";
147
+ appLabel = "Create React App";
148
+ defaultPort = "3000";
149
+ }
150
+ else if (deps.vite) {
151
+ appKind = "vite";
152
+ appLabel = "Vite";
153
+ defaultPort = "5173";
154
+ }
155
+ const install = packageManager
156
+ ? packageManager === "pnpm"
157
+ ? "pnpm install"
158
+ : packageManager === "bun"
159
+ ? "bun install"
160
+ : packageManager === "yarn"
161
+ ? "yarn install"
162
+ : "npm install"
163
+ : undefined;
164
+ const startCommand = scripts.dev ?? scripts.start;
165
+ const startPort = inferPortFromCommand(startCommand) ?? defaultPort;
166
+ const smokeKind = startCommand && startPort ? "http" : "none";
167
+ return {
168
+ ecosystem: "node",
169
+ appKind,
170
+ appLabel,
171
+ shellInitCommands: defaultShellInit(),
172
+ bootstrapCommands: [],
173
+ installCommands: dedupe([install]),
174
+ buildCommands: dedupe([scripts.build, scripts.typecheck].map((script) => script && pickPackageScript(packageManager, scripts, script))),
175
+ testCommands: dedupe(["test", "check", "lint"]
176
+ .filter((name) => scripts[name])
177
+ .map((name) => pickPackageScript(packageManager, scripts, scripts[name]))),
178
+ startCommand: startCommand ? pickPackageScript(packageManager, scripts, startCommand) : undefined,
179
+ startPort,
180
+ smokeKind,
181
+ evidence: [`Detected package.json`, `Scripts: ${Object.keys(scripts).join(", ") || "(none)"}`],
182
+ notes: [],
183
+ };
184
+ }
185
+ function pickPackageScript(packageManager, scripts, body) {
186
+ const entry = Object.entries(scripts).find(([, scriptBody]) => scriptBody === body)?.[0];
187
+ if (!entry)
188
+ return body;
189
+ const runner = packageManager === "pnpm"
190
+ ? "pnpm"
191
+ : packageManager === "bun"
192
+ ? "bun"
193
+ : packageManager === "yarn"
194
+ ? "yarn"
195
+ : "npm run";
196
+ return runner === "yarn" ? `yarn ${entry}` : runner === "bun" ? `bun run ${entry}` : `${runner} ${entry}`;
197
+ }
198
+ function detectPythonRecipe(cwd) {
199
+ const pyproject = readTextFile(cwd, "pyproject.toml");
200
+ const requirements = readTextFile(cwd, "requirements.txt");
201
+ const managePy = fileExists(cwd, "manage.py");
202
+ if (!pyproject && !requirements && !managePy && !fileExists(cwd, "setup.py")) {
203
+ return null;
204
+ }
205
+ const lower = `${pyproject ?? ""}\n${requirements ?? ""}`.toLowerCase();
206
+ const packageManager = detectPackageManager(cwd);
207
+ const isDjango = managePy || lower.includes("django");
208
+ const isFastApi = lower.includes("fastapi") || lower.includes("uvicorn");
209
+ let install = "pip install -r requirements.txt";
210
+ if (packageManager === "uv")
211
+ install = "uv sync";
212
+ else if (packageManager === "poetry")
213
+ install = "poetry install";
214
+ else if (packageManager === "pipenv")
215
+ install = "pipenv install";
216
+ else if (pyproject && !requirements)
217
+ install = "pip install -e .";
218
+ if (isDjango) {
219
+ return {
220
+ ecosystem: "python",
221
+ appKind: "django",
222
+ appLabel: "Django app",
223
+ shellInitCommands: defaultShellInit(),
224
+ bootstrapCommands: [],
225
+ installCommands: [install],
226
+ buildCommands: [],
227
+ testCommands: ["python manage.py test"],
228
+ startCommand: "python manage.py runserver 0.0.0.0:8000",
229
+ startPort: "8000",
230
+ smokeKind: "http",
231
+ evidence: ["Detected manage.py", pyproject ? "Detected pyproject.toml" : undefined].filter(Boolean),
232
+ notes: [],
233
+ };
234
+ }
235
+ if (isFastApi) {
236
+ const appModule = fileExists(cwd, "main.py") ? "main:app" : fileExists(cwd, "app.py") ? "app:app" : "main:app";
237
+ return {
238
+ ecosystem: "python",
239
+ appKind: "python",
240
+ appLabel: "Python web app",
241
+ shellInitCommands: defaultShellInit(),
242
+ bootstrapCommands: [],
243
+ installCommands: [install],
244
+ buildCommands: [],
245
+ testCommands: fileExists(cwd, "tests") ? ["pytest"] : [],
246
+ startCommand: `uvicorn ${appModule} --host 0.0.0.0 --port 8000`,
247
+ startPort: "8000",
248
+ smokeKind: "http",
249
+ evidence: ["Detected Python project", "Detected FastAPI/Uvicorn dependency"],
250
+ notes: [],
251
+ };
252
+ }
253
+ return {
254
+ ecosystem: "python",
255
+ appKind: "python",
256
+ appLabel: "Python project",
257
+ shellInitCommands: defaultShellInit(),
258
+ bootstrapCommands: [],
259
+ installCommands: [install],
260
+ buildCommands: [],
261
+ testCommands: fileExists(cwd, "tests") ? ["pytest"] : ["python -m unittest discover"],
262
+ smokeKind: "none",
263
+ evidence: ["Detected Python project"],
264
+ notes: [],
265
+ };
266
+ }
267
+ function detectGoRecipe(cwd) {
268
+ if (!fileExists(cwd, "go.mod"))
269
+ return null;
270
+ return {
271
+ ecosystem: "go",
272
+ appKind: "go",
273
+ appLabel: "Go project",
274
+ shellInitCommands: defaultShellInit(),
275
+ bootstrapCommands: [],
276
+ installCommands: [],
277
+ buildCommands: ["go build ./..."],
278
+ testCommands: ["go test ./..."],
279
+ startCommand: fileExists(cwd, "main.go") ? "go run ." : undefined,
280
+ smokeKind: "none",
281
+ evidence: ["Detected go.mod"],
282
+ notes: [],
283
+ };
284
+ }
285
+ function detectRustRecipe(cwd) {
286
+ if (!fileExists(cwd, "Cargo.toml"))
287
+ return null;
288
+ return {
289
+ ecosystem: "rust",
290
+ appKind: "rust",
291
+ appLabel: "Rust project",
292
+ shellInitCommands: defaultShellInit(),
293
+ bootstrapCommands: [],
294
+ installCommands: [],
295
+ buildCommands: ["cargo build"],
296
+ testCommands: ["cargo test"],
297
+ startCommand: fileExists(cwd, path.join("src", "main.rs")) ? "cargo run" : undefined,
298
+ smokeKind: "none",
299
+ evidence: ["Detected Cargo.toml"],
300
+ notes: [],
301
+ };
302
+ }
303
+ function detectJavaRecipe(cwd) {
304
+ if (fileExists(cwd, "pom.xml")) {
305
+ return {
306
+ ecosystem: "java",
307
+ appKind: "maven",
308
+ appLabel: "Maven project",
309
+ shellInitCommands: defaultShellInit(),
310
+ bootstrapCommands: [],
311
+ installCommands: [],
312
+ buildCommands: ["mvn package"],
313
+ testCommands: ["mvn test"],
314
+ smokeKind: "none",
315
+ evidence: ["Detected pom.xml"],
316
+ notes: [],
317
+ };
318
+ }
319
+ if (fileExists(cwd, "build.gradle") || fileExists(cwd, "build.gradle.kts")) {
320
+ const gradle = fileExists(cwd, "gradlew") ? "./gradlew" : "gradle";
321
+ return {
322
+ ecosystem: "java",
323
+ appKind: "gradle",
324
+ appLabel: "Gradle project",
325
+ shellInitCommands: defaultShellInit(),
326
+ bootstrapCommands: [],
327
+ installCommands: [],
328
+ buildCommands: [`${gradle} build`],
329
+ testCommands: [`${gradle} test`],
330
+ smokeKind: "none",
331
+ evidence: ["Detected Gradle build file"],
332
+ notes: [],
333
+ };
334
+ }
335
+ return null;
336
+ }
337
+ function detectFallbackRecipe(cwd) {
338
+ const makeRecipe = detectMakeRecipe(cwd);
339
+ if (makeRecipe)
340
+ return makeRecipe;
341
+ return {
342
+ ecosystem: "unknown",
343
+ appKind: "unknown",
344
+ appLabel: "Unknown project type",
345
+ shellInitCommands: defaultShellInit(),
346
+ bootstrapCommands: [],
347
+ installCommands: [],
348
+ buildCommands: [],
349
+ testCommands: [],
350
+ smokeKind: "none",
351
+ evidence: ["No known app metadata detected"],
352
+ notes: ["The verify sub-agent should inspect the repo directly and derive commands from the codebase."],
353
+ };
354
+ }
355
+ function inferFallbackRecipe(cwd, pkg, packageManager) {
356
+ if (pkg)
357
+ return detectNodeRecipe(cwd, pkg, packageManager);
358
+ return (detectPythonRecipe(cwd) ??
359
+ detectGoRecipe(cwd) ??
360
+ detectRustRecipe(cwd) ??
361
+ detectJavaRecipe(cwd) ??
362
+ detectFallbackRecipe(cwd));
363
+ }
364
+ export function normalizeVerifyRecipe(value) {
365
+ if (!value || typeof value !== "object" || Array.isArray(value))
366
+ return null;
367
+ const raw = value;
368
+ const asStrings = (input) => Array.isArray(input)
369
+ ? input.filter((v) => typeof v === "string" && v.trim() !== "").map((v) => v.trim())
370
+ : [];
371
+ const ecosystem = typeof raw.ecosystem === "string" ? raw.ecosystem.trim() : "";
372
+ const appKind = typeof raw.appKind === "string" ? raw.appKind.trim() : "";
373
+ const appLabel = typeof raw.appLabel === "string" ? raw.appLabel.trim() : "";
374
+ const smokeKind = raw.smokeKind === "http" || raw.smokeKind === "cli" || raw.smokeKind === "none" ? raw.smokeKind : "none";
375
+ if (!ecosystem || !appKind || !appLabel)
376
+ return null;
377
+ return {
378
+ ecosystem,
379
+ appKind,
380
+ appLabel,
381
+ shellInitCommands: asStrings(raw.shellInitCommands),
382
+ bootstrapCommands: asStrings(raw.bootstrapCommands),
383
+ installCommands: asStrings(raw.installCommands),
384
+ buildCommands: asStrings(raw.buildCommands),
385
+ testCommands: asStrings(raw.testCommands),
386
+ startCommand: typeof raw.startCommand === "string" && raw.startCommand.trim() ? raw.startCommand.trim() : undefined,
387
+ startPort: typeof raw.startPort === "string" && raw.startPort.trim() ? raw.startPort.trim() : undefined,
388
+ smokeKind,
389
+ smokeTarget: typeof raw.smokeTarget === "string" && raw.smokeTarget.trim() ? raw.smokeTarget.trim() : undefined,
390
+ evidence: asStrings(raw.evidence),
391
+ notes: asStrings(raw.notes),
392
+ };
393
+ }
394
+ export function inferVerifySmokeUrl(settings) {
395
+ const ports = settings?.ports ?? [];
396
+ if (ports.length !== 1) {
397
+ return null;
398
+ }
399
+ const hostPort = parseHostPort(ports[0]);
400
+ return hostPort ? `http://127.0.0.1:${hostPort}` : null;
401
+ }
402
+ export function inferVerifyProjectProfile(cwd, baseSettings = {}, recipeOverride) {
403
+ const pkg = readPackageJson(cwd);
404
+ const packageManager = detectPackageManager(cwd);
405
+ const recipe = recipeOverride ?? inferFallbackRecipe(cwd, pkg, packageManager);
406
+ const inferredDefaults = recipe.smokeKind === "http" && recipe.startPort ? { ports: [`${recipe.startPort}:${recipe.startPort}`] } : {};
407
+ const sandboxSettings = mergeSandboxSettings(inferredDefaults, baseSettings);
408
+ const smokeUrl = inferVerifySmokeUrl(sandboxSettings);
409
+ const recipeWithRuntime = {
410
+ ...recipe,
411
+ smokeTarget: recipe.smokeKind === "http" ? (smokeUrl ?? recipe.smokeTarget) : undefined,
412
+ };
413
+ if (!fs.existsSync(path.join(cwd, "node_modules")) && recipeWithRuntime.ecosystem === "node") {
414
+ recipeWithRuntime.notes = dedupe([
415
+ ...recipeWithRuntime.notes,
416
+ "Host dependencies are not installed in node_modules. Verification may be limited unless a Shuru checkpoint already contains the needed runtime dependencies.",
417
+ ]);
418
+ }
419
+ return {
420
+ appKind: normalizeVerifyAppKind(recipeWithRuntime.appKind),
421
+ appLabel: recipeWithRuntime.appLabel,
422
+ packageManager,
423
+ availableScripts: Object.keys(pkg?.scripts ?? {}),
424
+ hasNodeModules: fs.existsSync(path.join(cwd, "node_modules")),
425
+ sandboxSettings,
426
+ recipe: recipeWithRuntime,
427
+ };
428
+ }
429
+ function buildBrowserGuidance(profile) {
430
+ if (profile.recipe.smokeKind === "http" && profile.recipe.smokeTarget) {
431
+ return [
432
+ `- REQUIRED: After the dev server is running, you MUST run browser smoke tests against ${profile.recipe.smokeTarget}.`,
433
+ "- The agent-browser command runs on the HOST, not inside the sandbox. It WILL work. Do not skip it or assume it is unavailable.",
434
+ "- Run this exact sequence using the bash tool:",
435
+ ` mkdir -p .grok/verify-artifacts && agent-browser record start .grok/verify-artifacts/verify-smoke.webm && agent-browser --screenshot-dir .grok/verify-artifacts open ${profile.recipe.smokeTarget} && agent-browser wait --load networkidle && agent-browser --screenshot-dir .grok/verify-artifacts screenshot && agent-browser get title && agent-browser record stop && agent-browser close`,
436
+ "- IMPORTANT: Use --screenshot-dir .grok/verify-artifacts to control where screenshots are saved. Do NOT pass a filename as a positional arg to the screenshot command.",
437
+ "- IMPORTANT: Use `agent-browser record start <path>` and `agent-browser record stop` to capture a video recording of the smoke test flow.",
438
+ "- If that command fails, report the exact error output. Do not preemptively skip browser checks.",
439
+ "- Include both the screenshot and video file paths from the output in the Evidence section.",
440
+ ];
441
+ }
442
+ if ((profile.sandboxSettings.ports?.length ?? 0) > 1) {
443
+ return [
444
+ "- Multiple forwarded ports are configured, so browser smoke testing is ambiguous.",
445
+ "- Skip browser checks unless the user clearly identifies which forwarded localhost URL to verify.",
446
+ ];
447
+ }
448
+ if (profile.recipe.smokeKind === "cli") {
449
+ return ["- This project appears to need CLI-style runtime validation rather than browser smoke testing."];
450
+ }
451
+ return [
452
+ "- No unambiguous forwarded localhost URL is configured, so browser smoke testing is optional and should usually be skipped.",
453
+ "- If the app can still be verified with bash-only checks, do that and explain why browser checks were skipped.",
454
+ ];
455
+ }
456
+ function formatRecipeCommands(title, commands) {
457
+ return commands.length > 0 ? `- ${title}: ${commands.join(" ; ")}` : `- ${title}: (none inferred)`;
458
+ }
459
+ function buildProjectContextLines(profile) {
460
+ const lines = [`- Detected app type: ${profile.appLabel}.`, `- Recipe ecosystem: ${profile.recipe.ecosystem}.`];
461
+ if (profile.packageManager) {
462
+ lines.push(`- Likely package manager: ${profile.packageManager}.`);
463
+ }
464
+ if (profile.availableScripts.length > 0) {
465
+ lines.push(`- Available package.json scripts: ${profile.availableScripts.join(", ")}.`);
466
+ }
467
+ lines.push(...profile.recipe.evidence.map((evidence) => `- Evidence: ${evidence}.`));
468
+ lines.push(formatRecipeCommands("Shell init", profile.recipe.shellInitCommands));
469
+ lines.push(formatRecipeCommands("Bootstrap commands", profile.recipe.bootstrapCommands));
470
+ lines.push(formatRecipeCommands("Install commands", profile.recipe.installCommands));
471
+ lines.push(formatRecipeCommands("Build commands", profile.recipe.buildCommands));
472
+ lines.push(formatRecipeCommands("Test commands", profile.recipe.testCommands));
473
+ lines.push(`- Start command: ${profile.recipe.startCommand ?? "(none inferred)"}.`);
474
+ if (profile.recipe.smokeTarget) {
475
+ lines.push(`- Smoke target: ${profile.recipe.smokeTarget}.`);
476
+ }
477
+ lines.push(...profile.recipe.notes.map((note) => `- Note: ${note}`));
478
+ return lines;
479
+ }
480
+ export function buildVerifyTaskPrompt(cwd, settings, recipeOverride) {
481
+ const profile = inferVerifyProjectProfile(cwd, settings, recipeOverride);
482
+ const checkpoint = profile.sandboxSettings.from?.trim();
483
+ const network = profile.sandboxSettings.allowNet
484
+ ? profile.sandboxSettings.allowedHosts?.length
485
+ ? `enabled but restricted to: ${profile.sandboxSettings.allowedHosts.join(", ")}`
486
+ : "enabled"
487
+ : "disabled";
488
+ return [
489
+ "Run a local verification pass for the current workspace.",
490
+ "",
491
+ "Goals:",
492
+ "- Prove the current changes work as well as possible in phase 1.",
493
+ "- First derive and sanity-check a runnable verification recipe from the repository.",
494
+ "- Then execute that recipe inside the active Shuru sandbox and report the result.",
495
+ "",
496
+ "Detected project context and inferred recipe:",
497
+ ...buildProjectContextLines(profile),
498
+ "",
499
+ "Environment:",
500
+ "- Sandbox mode should be Shuru with workspace mounted at /workspace.",
501
+ `- Network is ${network}.`,
502
+ checkpoint
503
+ ? `- Start from the configured Shuru checkpoint: ${checkpoint}.`
504
+ : "- No Shuru checkpoint is configured; use the current sandbox settings as-is.",
505
+ "- Shuru runs are ephemeral in this version. Shell-side workspace edits do not persist back to the host.",
506
+ "",
507
+ "Required workflow:",
508
+ "- Quickly inspect the code and config files to confirm or correct the inferred recipe before executing it.",
509
+ "- If the inferred recipe is wrong, say what you changed and why before proceeding.",
510
+ "- Prefer the recipe commands as the default execution plan.",
511
+ "- In verify mode, ephemeral dependency installs are allowed inside the sandbox.",
512
+ "- If the recipe needs install/setup work and no checkpoint already provides it, prefer chaining install + build/test/start in the same sandbox command so the installed dependencies remain available for that command.",
513
+ "- Use background bash only when a dev server or watcher must stay alive while you continue verifying.",
514
+ "- If an inferred install/setup step is blocked by sandbox persistence rules, explain the blocker clearly and continue with any valid non-setup checks.",
515
+ "- IMPORTANT: agent-browser commands run on the HOST, not inside the sandbox. They WILL work. Do not skip browser checks or assume agent-browser is unavailable. Just run the command via the bash tool.",
516
+ "- Always save a screenshot and include the screenshot file path in the final report so the user can verify visually.",
517
+ ...buildBrowserGuidance(profile),
518
+ "",
519
+ "Reporting requirements:",
520
+ "- Return a concise structured report with these sections:",
521
+ " Summary",
522
+ " Recipe",
523
+ " Environment",
524
+ " Commands Run",
525
+ " Browser Checks",
526
+ " Evidence",
527
+ " Results",
528
+ " Failures or Blockers",
529
+ " Residual Risk",
530
+ "- The Recipe section must say what recipe you used and whether you changed the inferred one.",
531
+ "- If you captured screenshots or other browser artifacts, include their exact workspace-relative file paths in the Evidence section.",
532
+ "- Use markdown links for screenshot paths when practical, otherwise include the plain relative paths.",
533
+ ].join("\n");
534
+ }
535
+ export function createVerifyTaskRequest(cwd, settings, recipeOverride) {
536
+ return {
537
+ agent: VERIFY_SUBAGENT_ID,
538
+ description: VERIFY_TASK_DESCRIPTION,
539
+ prompt: buildVerifyTaskPrompt(cwd, settings, recipeOverride),
540
+ };
541
+ }
542
+ export function buildVerifyDetectPrompt(cwd, settings) {
543
+ const fallbackProfile = inferVerifyProjectProfile(cwd, settings);
544
+ return [
545
+ "Inspect this repository and produce a structured verification recipe.",
546
+ "",
547
+ "Your job:",
548
+ "- Read the codebase, config files, and any relevant docs or AGENTS guidance.",
549
+ "- Infer how the project should be installed, built, tested, and started.",
550
+ "- Infer whether verification should use HTTP/browser smoke checks, CLI checks, or no runtime smoke step.",
551
+ "- Prefer concrete commands that are likely to work in a fresh Debian Linux environment.",
552
+ "- Use the fallback hints below only as clues, not as the final answer.",
553
+ "",
554
+ "IMPORTANT for shellInitCommands and bootstrapCommands:",
555
+ "- The sandbox is a fresh Debian Linux VM with almost nothing pre-installed.",
556
+ '- shellInitCommands run before every bash command. Use them for PATH exports (e.g. export PATH="$HOME/.bun/bin:$PATH").',
557
+ "- bootstrapCommands run once during checkpoint creation to install runtimes and tools.",
558
+ "- You MUST include bootstrap commands to install any runtime the project needs (e.g. bun, node, npm, python3, go, cargo, java).",
559
+ "- Example for a Bun + Next.js project: bootstrapCommands should install both bun AND node/npm, since Next.js calls npm internally.",
560
+ '- Example: ["apt-get update && apt-get install -y curl unzip ca-certificates && curl -fsSL https://bun.sh/install | bash", "apt-get install -y nodejs npm"]',
561
+ "",
562
+ "Fallback hints from static detection:",
563
+ ...buildProjectContextLines(fallbackProfile),
564
+ "",
565
+ "Return ONLY valid JSON with this exact shape:",
566
+ "{",
567
+ ' "ecosystem": string,',
568
+ ' "appKind": string,',
569
+ ' "appLabel": string,',
570
+ ' "shellInitCommands": string[],',
571
+ ' "bootstrapCommands": string[],',
572
+ ' "installCommands": string[],',
573
+ ' "buildCommands": string[],',
574
+ ' "testCommands": string[],',
575
+ ' "startCommand": string | undefined,',
576
+ ' "startPort": string | undefined,',
577
+ ' "smokeKind": "http" | "cli" | "none",',
578
+ ' "smokeTarget": string | undefined,',
579
+ ' "evidence": string[],',
580
+ ' "notes": string[]',
581
+ "}",
582
+ "",
583
+ "Rules:",
584
+ "- Do not wrap the JSON in markdown.",
585
+ "- Do not include explanatory prose outside the JSON.",
586
+ "- If you are uncertain, put that uncertainty into `notes` and `evidence`.",
587
+ ].join("\n");
588
+ }
589
+ export function createVerifyRuntimeConfig(cwd, baseSettings = {}, recipeOverride) {
590
+ const profile = inferVerifyProjectProfile(cwd, baseSettings, recipeOverride);
591
+ const sandboxSettings = {
592
+ ...profile.sandboxSettings,
593
+ allowNet: true,
594
+ allowedHosts: undefined,
595
+ allowEphemeralInstall: true,
596
+ hostBrowserCommandsOnHost: true,
597
+ };
598
+ sandboxSettings.shellInit = profile.recipe.shellInitCommands;
599
+ return {
600
+ sandboxMode: "shuru",
601
+ sandboxSettings,
602
+ taskRequest: createVerifyTaskRequest(cwd, sandboxSettings, profile.recipe),
603
+ profile: { ...profile, sandboxSettings },
604
+ };
605
+ }
606
+ export const VERIFY_PROMPT = [
607
+ "Verify this project locally. Follow these steps in order using the `task` tool:",
608
+ "",
609
+ "Step 1: Run the `verify-detect` sub-agent to inspect the repository and produce a verification recipe.",
610
+ "- agent: verify-detect",
611
+ '- description: "Detect verification recipe"',
612
+ "- The prompt should ask it to read config files, package manifests, scripts, and source layout, then return ONLY a JSON VerifyRecipe object.",
613
+ "- The JSON must include: ecosystem, appKind, appLabel, shellInitCommands, bootstrapCommands, installCommands, buildCommands, testCommands, startCommand, startPort, smokeKind, smokeTarget, evidence, notes.",
614
+ "",
615
+ "Step 2: Once you have the recipe JSON from step 1, run the `verify` sub-agent to execute it.",
616
+ "- agent: verify",
617
+ '- description: "Run local verification"',
618
+ "- You MUST include the complete recipe JSON from step 1 in the verify prompt.",
619
+ "- You MUST also include these execution instructions in the verify prompt:",
620
+ " - The verify agent runs inside a Shuru sandbox with full network access enabled.",
621
+ " - Ephemeral dependency installs are allowed inside the sandbox.",
622
+ " - agent-browser commands run on the HOST, not inside the sandbox. They WILL work.",
623
+ " - If the recipe has a startCommand and startPort, start the app in the background and run browser smoke tests with agent-browser against http://127.0.0.1:<startPort>.",
624
+ " - Use `agent-browser record start .grok/verify-artifacts/verify-smoke.webm` before opening the page and `agent-browser record stop` after to capture video.",
625
+ " - Use `agent-browser --screenshot-dir .grok/verify-artifacts screenshot` to capture screenshots.",
626
+ " - Produce a structured verification report with: Summary, Recipe, Environment, Commands Run, Browser Checks, Evidence (with file paths), Results, Failures or Blockers, Residual Risk.",
627
+ "",
628
+ "Important:",
629
+ "- Do NOT perform verification work yourself. Delegate each step to the respective sub-agent using the `task` tool.",
630
+ "- Run step 1 first, then step 2. Do not skip or combine them.",
631
+ "- After step 2 completes, relay the verification report back to the user.",
632
+ ].join("\n");
633
+ export function getVerifyCliError(options) {
634
+ if (options.hasPrompt) {
635
+ return "Cannot combine --verify with --prompt.";
636
+ }
637
+ if (options.hasMessageArgs) {
638
+ return "Cannot combine --verify with an opening message.";
639
+ }
640
+ return null;
641
+ }
642
+ //# sourceMappingURL=entrypoint.js.map