diff --git a/cli/src/__tests__/service-health-check.test.ts b/cli/src/__tests__/service-health-check.test.ts index accb8775369..0703e3e3f07 100644 --- a/cli/src/__tests__/service-health-check.test.ts +++ b/cli/src/__tests__/service-health-check.test.ts @@ -3,7 +3,9 @@ import os from "node:os"; import path from "node:path"; import { describe, expect, it, vi } from "vitest"; import { serviceHealthChecks } from "../checks/service-health-check.js"; +import { resolveRestartExpectedVersion } from "../commands/service.js"; import type { PaperclipConfig } from "../config/schema.js"; +import { packageVersion } from "../version.js"; const config = { server: { host: "127.0.0.1", port: 3100 }, @@ -38,6 +40,11 @@ function managerFixture(active = true) { } describe("service health doctor checks", () => { + it("uses the bare package version when restart health has no prior server version", () => { + expect(resolveRestartExpectedVersion(null)).toBe(packageVersion); + expect(resolveRestartExpectedVersion("1.2.3")).toBe("1.2.3"); + }); + it("passes for a current, active, healthy service", async () => { const manager = managerFixture(); const results = await serviceHealthChecks(config, { diff --git a/cli/src/commands/service.ts b/cli/src/commands/service.ts index 1613019e856..e9312b4f8e6 100644 --- a/cli/src/commands/service.ts +++ b/cli/src/commands/service.ts @@ -2,7 +2,7 @@ import fs from "node:fs/promises"; import path from "node:path"; import * as p from "@clack/prompts"; import type { Command } from "commander"; -import { cliVersion } from "../version.js"; +import { packageVersion } from "../version.js"; import { readConfig, resolveConfigPath } from "../config/store.js"; import { resolvePaperclipHomeDir, resolvePaperclipInstanceId } from "../config/home.js"; import { detectServiceManager, type ServiceManager, type ServiceStatus } from "../services/service-manager.js"; @@ -53,6 +53,10 @@ async function waitForHealth(instanceId: string, expectedVersion: string | null, throw new Error(`Paperclip service did not become healthy${expectedVersion ? ` at version ${expectedVersion}` : ""}: ${last.error ?? `reported ${last.serverVersion ?? "no version"}`}`); } +export function resolveRestartExpectedVersion(serverVersion: string | null): string { + return serverVersion ?? packageVersion; +} + async function writeHotRestartIntent(status: ServiceStatus, instanceId: string, drainRequired: boolean): Promise<{ requestedAt: string; previousVersion: string }> { if (!status.pid) throw new Error(`Cannot restart ${status.serviceName}: supervisor did not report a server pid.`); const health = await probeHealth(instanceId); @@ -68,7 +72,7 @@ async function writeHotRestartIntent(status: ServiceStatus, instanceId: string, drainRequired, requestedByRunId: process.env.PAPERCLIP_RUN_ID?.trim() || null, }, null, 2)}\n`, "utf8"); - return { requestedAt, previousVersion: health.serverVersion ?? cliVersion }; + return { requestedAt, previousVersion: resolveRestartExpectedVersion(health.serverVersion) }; } async function waitForRestartReport(requestedAt: string, timeoutMs = 10_000): Promise { diff --git a/cli/src/version.ts b/cli/src/version.ts index 077e9e4e582..8f3632f44c3 100644 --- a/cli/src/version.ts +++ b/cli/src/version.ts @@ -12,7 +12,7 @@ type PackageJson = { const require = createRequire(import.meta.url); const pkg = require("../package.json") as PackageJson; -const packageVersion = pkg.version ?? "0.0.0"; +export const packageVersion = pkg.version ?? "0.0.0"; export function resolveCliVersion(executablePath = process.argv[1]): string { try { diff --git a/scripts/install.sh b/scripts/install.sh index 87d96253d35..9c7a5c41b0d 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -335,12 +335,7 @@ fi INSTALL_ARGS=(install) [ "$CANARY" = "1" ] && INSTALL_ARGS+=(--canary) [ -n "$VERSION" ] && INSTALL_ARGS+=(--version "$VERSION") -[ -n "$REF" ] && INSTALL_ARGS+=(--ref "$REF") -[ -n "$REPO" ] && INSTALL_ARGS+=(--repo "$REPO") -[ "$NO_PROMPT" = "1" ] && INSTALL_ARGS+=(--no-prompt) -[ "$INSTALL_SERVICE" = "1" ] && INSTALL_ARGS+=(--install-service) -[ "$DRY_RUN" = "1" ] && INSTALL_ARGS+=(--dry-run) -[ "$VERBOSE" = "1" ] && INSTALL_ARGS+=(--verbose) +[ "$NO_PROMPT" = "1" ] && INSTALL_ARGS+=(--yes) log "Delegating to the Paperclip CLI" print_command npx --yes "$PACKAGE_SPEC" "${INSTALL_ARGS[@]}" diff --git a/scripts/test-install-sh-docker.sh b/scripts/test-install-sh-docker.sh index b010e84e8d1..648bbee58c8 100755 --- a/scripts/test-install-sh-docker.sh +++ b/scripts/test-install-sh-docker.sh @@ -50,6 +50,16 @@ assert_line() { } } +assert_no_line() { + local file="$1" + local unexpected="$2" + if grep -Fx -- "$unexpected" "$file" >/dev/null; then + printf 'Did not expect %q in %s\n' "$unexpected" "$file" >&2 + cat "$file" >&2 + exit 1 + fi +} + echo "==> shellcheck" run_shellcheck @@ -57,16 +67,16 @@ echo "==> existing Node" run_with_node with-node bash /paperclip-scripts/install.sh --no-onboard assert_line "$RESULTS_DIR/with-node.args" "paperclipai@latest" assert_line "$RESULTS_DIR/with-node.args" "install" -assert_line "$RESULTS_DIR/with-node.args" "--no-prompt" +assert_line "$RESULTS_DIR/with-node.args" "--yes" echo "==> --ref master" run_with_node ref-master bash /paperclip-scripts/install.sh --ref master --no-onboard -assert_line "$RESULTS_DIR/ref-master.args" "--ref" -assert_line "$RESULTS_DIR/ref-master.args" "master" +assert_no_line "$RESULTS_DIR/ref-master.args" "--ref" +assert_no_line "$RESULTS_DIR/ref-master.args" "master" echo "==> piped --no-prompt" run_with_node piped bash -c 'cat /paperclip-scripts/install.sh | bash -s -- --no-prompt --no-onboard' -assert_line "$RESULTS_DIR/piped.args" "--no-prompt" +assert_line "$RESULTS_DIR/piped.args" "--yes" echo "==> environment twins" docker run --rm \ @@ -83,9 +93,9 @@ docker run --rm \ assert_line "$RESULTS_DIR/env.args" "paperclipai@2026.722.0" assert_line "$RESULTS_DIR/env.args" "--version" assert_line "$RESULTS_DIR/env.args" "2026.722.0" -assert_line "$RESULTS_DIR/env.args" "--repo" -assert_line "$RESULTS_DIR/env.args" "example/paperclip" -assert_line "$RESULTS_DIR/env.args" "--install-service" +assert_no_line "$RESULTS_DIR/env.args" "--repo" +assert_no_line "$RESULTS_DIR/env.args" "example/paperclip" +assert_no_line "$RESULTS_DIR/env.args" "--install-service" echo "==> no Node, apt bootstrap" docker run --rm \