From 941b7e872d98ecdcffd5d12d6a249d842c3aafa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20TEKTA=C5=9E?= Date: Fri, 21 Aug 2026 09:21:53 +0300 Subject: [PATCH 1/4] refactor: extract goal prompt runtime --- src/source/runtime/goal-prompt.js | 53 +++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/source/runtime/goal-prompt.js diff --git a/src/source/runtime/goal-prompt.js b/src/source/runtime/goal-prompt.js new file mode 100644 index 00000000..1cd6bfaf --- /dev/null +++ b/src/source/runtime/goal-prompt.js @@ -0,0 +1,53 @@ +import path from "node:path" +import { DEFAULT_GOAL_MAX_NO_PROGRESS } from "../core/args.js" +import { readSmallTextFile } from "../core/process.js" + +const GOAL_PROMPT_PREFIX = "EXPERIMENTAL OPENCODE GOAL MODE ITERATION" + +export async function buildGoalPrompt(directory, job) { + const sections = [] + sections.push(`Working directory:\n${path.resolve(directory)}\nKeep every file operation inside this directory. Prefer workspace-relative paths such as \"src/index.js\"; never turn a relative path into a root path such as \"/src/index.js\".`) + const objective = String(job.action || "").trim() + if (objective) sections.push(`Goal objective:\n${objective}`) + if (job.goalFile) { + const text = await readSmallTextFile(path.resolve(directory, job.goalFile), 120_000) + if (text.trim()) sections.push(`Goal file ${job.goalFile}:\n${text.trim()}`) + else sections.push(`Goal file ${job.goalFile} was requested but could not be read. Continue from the inline goal objective.`) + } + if (job.promptFile) { + const text = await readSmallTextFile(path.resolve(directory, job.promptFile), 120_000) + if (text.trim()) sections.push(`Extra goal instructions from ${job.promptFile}:\n${text.trim()}`) + } + if (job.goalAcceptance?.length) sections.push("Acceptance criteria:\n" + job.goalAcceptance.map((item, index) => `${index + 1}. ${item}`).join("\n")) + if (job.goalChecks?.length) sections.push("Verification commands that define useful evidence:\n" + job.goalChecks.map((item, index) => `${index + 1}. ${item}`).join("\n")) + if (job.verifyCommand) sections.push(`Post-turn verify command configured by the loop: ${job.verifyCommand}`) + if (job.lastGoalChecks?.length) sections.push("Latest goal check results:\n" + job.lastGoalChecks.map((item) => `- ${item.command}: exit ${item.code}`).join("\n")) + if (job.lastVerifyFailure) sections.push("Previous verify/check failure summary:\n" + String(job.lastVerifyFailure).slice(0, 1600)) + if (job.goalCompletionRejectedReason) sections.push(`Previous completion attempt was rejected:\n${job.goalCompletionRejectedReason}`) + if ((job.maxNoProgress ?? DEFAULT_GOAL_MAX_NO_PROGRESS) > 0) sections.push(`No-progress guard:\n${job.noProgressCount || 0}/${job.maxNoProgress ?? DEFAULT_GOAL_MAX_NO_PROGRESS} recent turn(s) without recorded meaningful progress.`) + if (job.goalProgress?.length) sections.push("Recent goal progress:\n" + job.goalProgress.slice(-5).map((item) => `- ${item.time}: ${item.summary}`).join("\n")) + for (const file of job.includeFiles || []) { + const text = await readSmallTextFile(path.resolve(directory, file), 80_000) + if (text.trim()) sections.push(`Context from ${file}:\n${text.trim().slice(0, 20_000)}`) + } + + return `${GOAL_PROMPT_PREFIX}. + +You are pursuing an experimental persistent goal for this OpenCode session. This is not a timer loop and not a one-shot prompt. Keep working toward the goal until it is completed, blocked, paused, cleared, or stopped by safety limits. + +Rules: +- Work on the next smallest useful step toward the goal. +- Prefer direct code changes, tests, typechecks, builds, and evidence over discussion. +- Do not claim the goal is complete unless the acceptance criteria are satisfied and verification evidence supports it. +- If verification commands are configured, do not call opencode_loop_goal_complete until the latest relevant checks have passed unless the user explicitly overrides the goal. +- Completion evidence must be concrete: mention commands, files, checks, results, or code inspection details. +- When the goal is complete, call the tool opencode_loop_goal_complete with a summary and evidence. +- If you are truly blocked and need user input, call the tool opencode_loop_goal_blocked with the reason and what is needed. +- If you made meaningful progress but the goal is not complete, call the tool opencode_loop_goal_progress with the summary and next step. +- If you cannot make meaningful progress for this turn, call opencode_loop_goal_blocked instead of repeating the same attempt. +- Do not call completion tools just to be polite; only call them when the state is real. +- Do not ask the user questions unless blocked; make reasonable assumptions and continue. +- Follow safety rules: no destructive commands, force pushes, production deploys, production database resets, or deleting user data. + +${sections.join("\n\n---\n\n")}` +} From 2c399fb82750f6fb4bf17c6aa0a7e125d34856c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20TEKTA=C5=9E?= Date: Fri, 21 Aug 2026 09:22:08 +0300 Subject: [PATCH 2/4] refactor: extract goal report runtime --- src/source/runtime/goal-report.js | 52 +++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/source/runtime/goal-report.js diff --git a/src/source/runtime/goal-report.js b/src/source/runtime/goal-report.js new file mode 100644 index 00000000..a737f0f5 --- /dev/null +++ b/src/source/runtime/goal-report.js @@ -0,0 +1,52 @@ +import { promises as fs } from "node:fs" +import path from "node:path" +import { DEFAULT_GOAL_MAX_NO_PROGRESS, safeID } from "../core/args.js" +import { isGoalJob, goalStatusText } from "../core/jobs.js" +import { stateDir, ensureDir } from "../core/state.js" + +const GOAL_REPORT_DIR = "goals" + +export function goalReportPath(directory, sessionID, job) { + return path.join(stateDir(directory), GOAL_REPORT_DIR, `${safeID(sessionID)}-${safeID(job.name || job.id)}.md`) +} + +export function goalReportText(job) { + const lines = [] + lines.push(`# OpenCode Loop Goal Report`) + lines.push("") + lines.push(`Status: ${goalStatusText(job) || "unknown"}`) + lines.push(`Goal: ${job.action || job.goalFile || ""}`) + lines.push(`Created: ${job.createdAt || ""}`) + if (job.goalCompletedAt) lines.push(`Completed: ${new Date(job.goalCompletedAt).toISOString()}`) + if (job.goalBlockedAt) lines.push(`Blocked: ${new Date(job.goalBlockedAt).toISOString()}`) + if (job.lastUserInterruptAt) lines.push(`Paused by user message: ${new Date(job.lastUserInterruptAt).toISOString()}`) + if (job.goalNoProgressPausedAt) lines.push(`Paused by no-progress guard: ${new Date(job.goalNoProgressPausedAt).toISOString()}`) + if (job.runCount) lines.push(`Turns: ${job.runCount}`) + if ((job.maxNoProgress ?? DEFAULT_GOAL_MAX_NO_PROGRESS) > 0) lines.push(`No-progress: ${job.noProgressCount || 0}/${job.maxNoProgress ?? DEFAULT_GOAL_MAX_NO_PROGRESS}`) + lines.push("") + if (job.goalSummary) lines.push("## Summary", "", String(job.goalSummary), "") + if (job.goalEvidence) lines.push("## Evidence", "", String(job.goalEvidence), "") + if (job.goalBlockedReason) lines.push("## Blocked reason", "", String(job.goalBlockedReason), "") + if (job.goalCompletionRejectedReason) lines.push("## Last completion rejection", "", String(job.goalCompletionRejectedReason), "") + if (job.goalInterruptedReason) lines.push("## Interrupt", "", String(job.goalInterruptedReason), "") + if (job.goalNoProgressReason) lines.push("## No-progress guard", "", String(job.goalNoProgressReason), "") + if (job.goalAcceptance?.length) lines.push("## Acceptance criteria", "", ...job.goalAcceptance.map((item) => `- ${item}`), "") + if (job.lastGoalChecks?.length) { + lines.push("## Latest checks", "") + for (const item of job.lastGoalChecks) lines.push(`- ${item.command}: exit ${item.code}`) + lines.push("") + } + if (job.goalProgress?.length) { + lines.push("## Progress", "") + for (const item of job.goalProgress) lines.push(`- ${item.time}: ${item.summary}${item.next ? ` Next: ${item.next}` : ""}`) + lines.push("") + } + return lines.join("\n") +} + +export async function writeGoalReport(directory, sessionID, job) { + if (!isGoalJob(job)) return + const target = job.goalEvidenceFile ? path.resolve(directory, job.goalEvidenceFile) : goalReportPath(directory, sessionID, job) + await ensureDir(path.dirname(target)) + await fs.writeFile(target, goalReportText(job), "utf8") +} From 003e8b553da63abf61d7af4dd66cbe5218692446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20TEKTA=C5=9E?= Date: Fri, 21 Aug 2026 09:22:30 +0300 Subject: [PATCH 3/4] refactor: compose goal presentation runtimes --- src/source/runtime/goal-runtime.js | 110 +++-------------------------- 1 file changed, 8 insertions(+), 102 deletions(-) diff --git a/src/source/runtime/goal-runtime.js b/src/source/runtime/goal-runtime.js index c1f5ee85..0d739db3 100644 --- a/src/source/runtime/goal-runtime.js +++ b/src/source/runtime/goal-runtime.js @@ -1,105 +1,11 @@ -import { promises as fs } from "node:fs" -import path from "node:path" -import { DEFAULT_GOAL_MAX_NO_PROGRESS, now, safeID } from "../core/args.js" -import { matchJob, isGoalJob, goalStatusText } from "../core/jobs.js" -import { stateDir, ensureDir, readState, writeState } from "../core/state.js" -import { appendLoopLog, readSmallTextFile } from "../core/process.js" - -const GOAL_REPORT_DIR = "goals" -const GOAL_PROMPT_PREFIX = "EXPERIMENTAL OPENCODE GOAL MODE ITERATION" - -export async function buildGoalPrompt(directory, job) { - const sections = [] - sections.push(`Working directory:\n${path.resolve(directory)}\nKeep every file operation inside this directory. Prefer workspace-relative paths such as \"src/index.js\"; never turn a relative path into a root path such as \"/src/index.js\".`) - const objective = String(job.action || "").trim() - if (objective) sections.push(`Goal objective:\n${objective}`) - if (job.goalFile) { - const text = await readSmallTextFile(path.resolve(directory, job.goalFile), 120_000) - if (text.trim()) sections.push(`Goal file ${job.goalFile}:\n${text.trim()}`) - else sections.push(`Goal file ${job.goalFile} was requested but could not be read. Continue from the inline goal objective.`) - } - if (job.promptFile) { - const text = await readSmallTextFile(path.resolve(directory, job.promptFile), 120_000) - if (text.trim()) sections.push(`Extra goal instructions from ${job.promptFile}:\n${text.trim()}`) - } - if (job.goalAcceptance?.length) sections.push("Acceptance criteria:\n" + job.goalAcceptance.map((item, index) => `${index + 1}. ${item}`).join("\n")) - if (job.goalChecks?.length) sections.push("Verification commands that define useful evidence:\n" + job.goalChecks.map((item, index) => `${index + 1}. ${item}`).join("\n")) - if (job.verifyCommand) sections.push(`Post-turn verify command configured by the loop: ${job.verifyCommand}`) - if (job.lastGoalChecks?.length) sections.push("Latest goal check results:\n" + job.lastGoalChecks.map((item) => `- ${item.command}: exit ${item.code}`).join("\n")) - if (job.lastVerifyFailure) sections.push("Previous verify/check failure summary:\n" + String(job.lastVerifyFailure).slice(0, 1600)) - if (job.goalCompletionRejectedReason) sections.push(`Previous completion attempt was rejected:\n${job.goalCompletionRejectedReason}`) - if ((job.maxNoProgress ?? DEFAULT_GOAL_MAX_NO_PROGRESS) > 0) sections.push(`No-progress guard:\n${job.noProgressCount || 0}/${job.maxNoProgress ?? DEFAULT_GOAL_MAX_NO_PROGRESS} recent turn(s) without recorded meaningful progress.`) - if (job.goalProgress?.length) sections.push("Recent goal progress:\n" + job.goalProgress.slice(-5).map((item) => `- ${item.time}: ${item.summary}`).join("\n")) - for (const file of job.includeFiles || []) { - const text = await readSmallTextFile(path.resolve(directory, file), 80_000) - if (text.trim()) sections.push(`Context from ${file}:\n${text.trim().slice(0, 20_000)}`) - } - - return `${GOAL_PROMPT_PREFIX}. - -You are pursuing an experimental persistent goal for this OpenCode session. This is not a timer loop and not a one-shot prompt. Keep working toward the goal until it is completed, blocked, paused, cleared, or stopped by safety limits. - -Rules: -- Work on the next smallest useful step toward the goal. -- Prefer direct code changes, tests, typechecks, builds, and evidence over discussion. -- Do not claim the goal is complete unless the acceptance criteria are satisfied and verification evidence supports it. -- If verification commands are configured, do not call opencode_loop_goal_complete until the latest relevant checks have passed unless the user explicitly overrides the goal. -- Completion evidence must be concrete: mention commands, files, checks, results, or code inspection details. -- When the goal is complete, call the tool opencode_loop_goal_complete with a summary and evidence. -- If you are truly blocked and need user input, call the tool opencode_loop_goal_blocked with the reason and what is needed. -- If you made meaningful progress but the goal is not complete, call the tool opencode_loop_goal_progress with the summary and next step. -- If you cannot make meaningful progress for this turn, call opencode_loop_goal_blocked instead of repeating the same attempt. -- Do not call completion tools just to be polite; only call them when the state is real. -- Do not ask the user questions unless blocked; make reasonable assumptions and continue. -- Follow safety rules: no destructive commands, force pushes, production deploys, production database resets, or deleting user data. - -${sections.join("\n\n---\n\n")}` -} - -export function goalReportPath(directory, sessionID, job) { - return path.join(stateDir(directory), GOAL_REPORT_DIR, `${safeID(sessionID)}-${safeID(job.name || job.id)}.md`) -} - -export function goalReportText(job) { - const lines = [] - lines.push(`# OpenCode Loop Goal Report`) - lines.push("") - lines.push(`Status: ${goalStatusText(job) || "unknown"}`) - lines.push(`Goal: ${job.action || job.goalFile || ""}`) - lines.push(`Created: ${job.createdAt || ""}`) - if (job.goalCompletedAt) lines.push(`Completed: ${new Date(job.goalCompletedAt).toISOString()}`) - if (job.goalBlockedAt) lines.push(`Blocked: ${new Date(job.goalBlockedAt).toISOString()}`) - if (job.lastUserInterruptAt) lines.push(`Paused by user message: ${new Date(job.lastUserInterruptAt).toISOString()}`) - if (job.goalNoProgressPausedAt) lines.push(`Paused by no-progress guard: ${new Date(job.goalNoProgressPausedAt).toISOString()}`) - if (job.runCount) lines.push(`Turns: ${job.runCount}`) - if ((job.maxNoProgress ?? DEFAULT_GOAL_MAX_NO_PROGRESS) > 0) lines.push(`No-progress: ${job.noProgressCount || 0}/${job.maxNoProgress ?? DEFAULT_GOAL_MAX_NO_PROGRESS}`) - lines.push("") - if (job.goalSummary) lines.push("## Summary", "", String(job.goalSummary), "") - if (job.goalEvidence) lines.push("## Evidence", "", String(job.goalEvidence), "") - if (job.goalBlockedReason) lines.push("## Blocked reason", "", String(job.goalBlockedReason), "") - if (job.goalCompletionRejectedReason) lines.push("## Last completion rejection", "", String(job.goalCompletionRejectedReason), "") - if (job.goalInterruptedReason) lines.push("## Interrupt", "", String(job.goalInterruptedReason), "") - if (job.goalNoProgressReason) lines.push("## No-progress guard", "", String(job.goalNoProgressReason), "") - if (job.goalAcceptance?.length) lines.push("## Acceptance criteria", "", ...job.goalAcceptance.map((item) => `- ${item}`), "") - if (job.lastGoalChecks?.length) { - lines.push("## Latest checks", "") - for (const item of job.lastGoalChecks) lines.push(`- ${item.command}: exit ${item.code}`) - lines.push("") - } - if (job.goalProgress?.length) { - lines.push("## Progress", "") - for (const item of job.goalProgress) lines.push(`- ${item.time}: ${item.summary}${item.next ? ` Next: ${item.next}` : ""}`) - lines.push("") - } - return lines.join("\n") -} - -export async function writeGoalReport(directory, sessionID, job) { - if (!isGoalJob(job)) return - const target = job.goalEvidenceFile ? path.resolve(directory, job.goalEvidenceFile) : goalReportPath(directory, sessionID, job) - await ensureDir(path.dirname(target)) - await fs.writeFile(target, goalReportText(job), "utf8") -} +import { now } from "../core/args.js" +import { matchJob, isGoalJob } from "../core/jobs.js" +import { readState, writeState } from "../core/state.js" +import { appendLoopLog } from "../core/process.js" +import { writeGoalReport } from "./goal-report.js" + +export { buildGoalPrompt } from "./goal-prompt.js" +export { goalReportPath, goalReportText, writeGoalReport } from "./goal-report.js" export function pickGoalJob(state, target = "") { const goals = (state.jobs || []).filter(isGoalJob) From 2584da1a10e15df67b5690c08b7c817905b14ad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20TEKTA=C5=9E?= Date: Fri, 21 Aug 2026 09:22:57 +0300 Subject: [PATCH 4/4] test: syntax-check goal presentation runtimes --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 32f13cd8..9200508d 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "build:plugin": "bun build src/source/v1.js --outfile=src/index.js --target=bun --format=esm --external=@opencode-ai/plugin/tool", "build:plugin:npm": "npm run build:plugin", "prepack": "node --check src/index.js", - "check": "node --check src/source/v1.js && node --check src/source/core/args.js && node --check src/source/core/state.js && node --check src/source/core/jobs.js && node --check src/source/core/process.js && node --check src/source/opencode/sdk.js && node --check src/source/opencode/session-context.js && node --check src/source/opencode/command-router.js && node --check src/source/opencode/goal-commands.js && node --check src/source/opencode/loop-commands.js && node --check src/source/opencode/loop-registration.js && node --check src/source/runtime/session-activity.js && node --check src/source/runtime/session-status.js && node --check src/source/runtime/compaction.js && node --check src/source/runtime/action-dispatch.js && node --check src/source/runtime/run-finalization.js && node --check src/source/runtime/run-admission.js && node --check src/source/runtime/executor.js && node --check src/source/runtime/scheduler.js && node --check src/source/runtime/goal-runtime.js && node --check src/source/runtime/goal-policy.js && node --check src/source/runtime/goal-steering.js && node --check src/source/runtime/job-workspace.js && node --check src/source/opencode2/prompt-runtime.js && node --check src/source/opencode2/diagnostics.js && node --check src/source/opencode2/logging.js && node --check src/source/legacy-v1.js && node --check src/index.js && node --check scripts/install-node.mjs && node --check scripts/install-with-goals.mjs && node --check scripts/loopd.mjs && node --check scripts/install-test.mjs && node --check scripts/goal-companion-test.mjs && node --check scripts/loopd-test.mjs && node --check scripts/smoke-test.mjs && node --check scripts/host-adapter-contract-test.mjs && node --check scripts/command-router-test.mjs && node --check scripts/goal-command-handlers-test.mjs && node --check scripts/loop-command-handlers-test.mjs && node --check scripts/loop-registration-test.mjs && node --check scripts/session-activity-test.mjs && node --check scripts/session-status-test.mjs && node --check scripts/compaction-runtime-test.mjs && node --check scripts/executor-runtime-test.mjs && node --check scripts/scheduler-runtime-test.mjs && node --check scripts/goal-runtime-test.mjs && node --check scripts/goal-policy-test.mjs && node --check scripts/goal-steering-test.mjs && node --check scripts/job-workspace-test.mjs && node --check scripts/v2-prompt-runtime-test.mjs && node --check scripts/v2-prompt-interval-test.mjs && node --check scripts/v2-command-runtime-test.mjs && node --check scripts/v2-command-adapter-test.mjs && node --check scripts/v2-diagnostics-test.mjs && node --check scripts/v2-logging-test.mjs && node --check scripts/comprehensive-watchdog.mjs && node --check scripts/comprehensive-test.mjs && node --check scripts/host-loop-canary.mjs && node --check scripts/host-goal-steering-canary.mjs && node --check scripts/publish-workflow-test.mjs", + "check": "node --check src/source/v1.js && node --check src/source/core/args.js && node --check src/source/core/state.js && node --check src/source/core/jobs.js && node --check src/source/core/process.js && node --check src/source/opencode/sdk.js && node --check src/source/opencode/session-context.js && node --check src/source/opencode/command-router.js && node --check src/source/opencode/goal-commands.js && node --check src/source/opencode/loop-commands.js && node --check src/source/opencode/loop-registration.js && node --check src/source/runtime/session-activity.js && node --check src/source/runtime/session-status.js && node --check src/source/runtime/compaction.js && node --check src/source/runtime/action-dispatch.js && node --check src/source/runtime/run-finalization.js && node --check src/source/runtime/run-admission.js && node --check src/source/runtime/executor.js && node --check src/source/runtime/scheduler.js && node --check src/source/runtime/goal-prompt.js && node --check src/source/runtime/goal-report.js && node --check src/source/runtime/goal-runtime.js && node --check src/source/runtime/goal-policy.js && node --check src/source/runtime/goal-steering.js && node --check src/source/runtime/job-workspace.js && node --check src/source/opencode2/prompt-runtime.js && node --check src/source/opencode2/diagnostics.js && node --check src/source/opencode2/logging.js && node --check src/source/legacy-v1.js && node --check src/index.js && node --check scripts/install-node.mjs && node --check scripts/install-with-goals.mjs && node --check scripts/loopd.mjs && node --check scripts/install-test.mjs && node --check scripts/goal-companion-test.mjs && node --check scripts/loopd-test.mjs && node --check scripts/smoke-test.mjs && node --check scripts/host-adapter-contract-test.mjs && node --check scripts/command-router-test.mjs && node --check scripts/goal-command-handlers-test.mjs && node --check scripts/loop-command-handlers-test.mjs && node --check scripts/loop-registration-test.mjs && node --check scripts/session-activity-test.mjs && node --check scripts/session-status-test.mjs && node --check scripts/compaction-runtime-test.mjs && node --check scripts/executor-runtime-test.mjs && node --check scripts/scheduler-runtime-test.mjs && node --check scripts/goal-runtime-test.mjs && node --check scripts/goal-policy-test.mjs && node --check scripts/goal-steering-test.mjs && node --check scripts/job-workspace-test.mjs && node --check scripts/v2-prompt-runtime-test.mjs && node --check scripts/v2-prompt-interval-test.mjs && node --check scripts/v2-command-runtime-test.mjs && node --check scripts/v2-command-adapter-test.mjs && node --check scripts/v2-diagnostics-test.mjs && node --check scripts/v2-logging-test.mjs && node --check scripts/comprehensive-watchdog.mjs && node --check scripts/comprehensive-test.mjs && node --check scripts/host-loop-canary.mjs && node --check scripts/host-goal-steering-canary.mjs && node --check scripts/publish-workflow-test.mjs", "test": "node scripts/publish-workflow-test.mjs && node scripts/command-router-test.mjs && node scripts/goal-command-handlers-test.mjs && node scripts/loop-command-handlers-test.mjs && node scripts/loop-registration-test.mjs && node scripts/session-activity-test.mjs && node scripts/session-status-test.mjs && node scripts/compaction-runtime-test.mjs && node scripts/action-dispatch-test.mjs && node scripts/run-finalization-test.mjs && node scripts/run-admission-test.mjs && node scripts/executor-runtime-test.mjs && node scripts/scheduler-runtime-test.mjs && node scripts/goal-runtime-test.mjs && node scripts/goal-policy-test.mjs && node scripts/goal-steering-test.mjs && node scripts/job-workspace-test.mjs && node scripts/v2-prompt-runtime-test.mjs && node scripts/v2-prompt-interval-test.mjs && node scripts/v2-command-runtime-test.mjs && node scripts/v2-command-adapter-test.mjs && node scripts/v2-diagnostics-test.mjs && node scripts/v2-logging-test.mjs && node scripts/install-test.mjs && node scripts/goal-companion-test.mjs && node scripts/loopd-test.mjs && node scripts/smoke-test.mjs && node scripts/host-adapter-contract-test.mjs && node scripts/comprehensive-watchdog.mjs", "canary:host": "node scripts/host-loop-canary.mjs && node scripts/host-goal-steering-canary.mjs", "install:global": "node scripts/install-with-goals.mjs",