feat(setup): per-checkout service name and docker image tag
Two NanoClaw installs on the same host used to fight over the shared `com.nanoclaw` launchd label / `nanoclaw.service` systemd unit and the `nanoclaw-agent:latest` docker tag — the second install silently rewrote the service pointer and rebuilt the image out from under the first. Introduces a deterministic per-checkout slug (sha1(projectRoot)[:8]) and namespaces everything off it: - Service: `com.nanoclaw-v2-<slug>` / `nanoclaw-v2-<slug>.service` - Image: `nanoclaw-agent-v2-<slug>:latest` (base), `nanoclaw-agent-v2-<slug>:<agentGroupId>` (per-group) New shared helpers: src/install-slug.ts (host) + setup/lib/install-slug.sh (bash). Both compute the same slug so verify/probe/add-*.sh/build.sh/container-runner all agree. Any v1 `com.nanoclaw` service left on the host stays untouched and can coexist. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import path from 'path';
|
||||
|
||||
import { getLaunchdLabel } from '../src/install-slug.js';
|
||||
|
||||
/**
|
||||
* Tests for service configuration generation.
|
||||
*
|
||||
@@ -14,12 +16,13 @@ function generatePlist(
|
||||
projectRoot: string,
|
||||
homeDir: string,
|
||||
): string {
|
||||
const label = getLaunchdLabel(projectRoot);
|
||||
return `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.nanoclaw</string>
|
||||
<string>${label}</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>${nodePath}</string>
|
||||
@@ -73,13 +76,11 @@ WantedBy=${isSystem ? 'multi-user.target' : 'default.target'}`;
|
||||
}
|
||||
|
||||
describe('plist generation', () => {
|
||||
it('contains the correct label', () => {
|
||||
const plist = generatePlist(
|
||||
'/usr/local/bin/node',
|
||||
'/home/user/nanoclaw',
|
||||
'/home/user',
|
||||
);
|
||||
expect(plist).toContain('<string>com.nanoclaw</string>');
|
||||
it('contains the slug-scoped label', () => {
|
||||
const projectRoot = '/home/user/nanoclaw';
|
||||
const plist = generatePlist('/usr/local/bin/node', projectRoot, '/home/user');
|
||||
expect(plist).toContain(`<string>${getLaunchdLabel(projectRoot)}</string>`);
|
||||
expect(plist).toMatch(/<string>com\.nanoclaw-v2-[0-9a-f]{8}<\/string>/);
|
||||
});
|
||||
|
||||
it('uses the correct node path', () => {
|
||||
|
||||
Reference in New Issue
Block a user