ghostrail 0.14.0 → 0.15.0
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/README.md +2 -2
- package/dist/board/server.d.ts +9 -2
- package/dist/board/server.d.ts.map +1 -1
- package/dist/board/server.js +10 -3
- package/dist/board/server.js.map +1 -1
- package/dist/cli/commands.d.ts +1 -1
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +149 -13
- package/dist/cli/commands.js.map +1 -1
- package/dist/commands/help.js +3 -3
- package/dist/commands/help.js.map +1 -1
- package/dist/config/load.d.ts.map +1 -1
- package/dist/config/load.js +7 -5
- package/dist/config/load.js.map +1 -1
- package/dist/config/schema.d.ts +15 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +5 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/dashboard/server.d.ts +2 -2
- package/dist/dashboard/server.d.ts.map +1 -1
- package/dist/dashboard/server.js +8 -4
- package/dist/dashboard/server.js.map +1 -1
- package/dist/factory/build.d.ts +22 -2
- package/dist/factory/build.d.ts.map +1 -1
- package/dist/factory/build.js +11 -6
- package/dist/factory/build.js.map +1 -1
- package/dist/factory/checkout.d.ts +41 -0
- package/dist/factory/checkout.d.ts.map +1 -0
- package/dist/factory/checkout.js +90 -0
- package/dist/factory/checkout.js.map +1 -0
- package/dist/factory/state.d.ts +85 -0
- package/dist/factory/state.d.ts.map +1 -0
- package/dist/factory/state.js +157 -0
- package/dist/factory/state.js.map +1 -0
- package/dist/global/index.d.ts +3 -1
- package/dist/global/index.d.ts.map +1 -1
- package/dist/global/index.js +3 -1
- package/dist/global/index.js.map +1 -1
- package/dist/global/registry.d.ts +38 -5
- package/dist/global/registry.d.ts.map +1 -1
- package/dist/global/registry.js +40 -14
- package/dist/global/registry.js.map +1 -1
- package/dist/global/repo-id.d.ts +50 -0
- package/dist/global/repo-id.d.ts.map +1 -0
- package/dist/global/repo-id.js +149 -0
- package/dist/global/repo-id.js.map +1 -0
- package/dist/global/state-dir.d.ts +32 -0
- package/dist/global/state-dir.d.ts.map +1 -0
- package/dist/global/state-dir.js +43 -0
- package/dist/global/state-dir.js.map +1 -0
- package/dist/global/store.d.ts +2 -0
- package/dist/global/store.d.ts.map +1 -1
- package/dist/global/store.js.map +1 -1
- package/dist/loop/advice.d.ts +11 -0
- package/dist/loop/advice.d.ts.map +1 -0
- package/dist/loop/advice.js +48 -0
- package/dist/loop/advice.js.map +1 -0
- package/dist/loop/control.d.ts +15 -1
- package/dist/loop/control.d.ts.map +1 -1
- package/dist/loop/control.js +8 -1
- package/dist/loop/control.js.map +1 -1
- package/dist/loop/index.d.ts +1 -0
- package/dist/loop/index.d.ts.map +1 -1
- package/dist/loop/index.js +1 -0
- package/dist/loop/index.js.map +1 -1
- package/dist/service/manager.d.ts +2 -0
- package/dist/service/manager.d.ts.map +1 -1
- package/dist/service/manager.js +2 -1
- package/dist/service/manager.js.map +1 -1
- package/dist/service/unit.d.ts +16 -7
- package/dist/service/unit.d.ts.map +1 -1
- package/dist/service/unit.js +11 -7
- package/dist/service/unit.js.map +1 -1
- package/dist/store/file-store.d.ts +5 -18
- package/dist/store/file-store.d.ts.map +1 -1
- package/dist/store/file-store.js +1 -1
- package/dist/store/file-store.js.map +1 -1
- package/dist/store/index.d.ts +2 -1
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js.map +1 -1
- package/dist/store/port.d.ts +53 -0
- package/dist/store/port.d.ts.map +1 -0
- package/dist/store/port.js +2 -0
- package/dist/store/port.js.map +1 -0
- package/package.json +1 -1
- package/skill/ghostrail/SKILL.md +2 -2
- package/templates/{code-local → code}/README.md +2 -2
- package/templates/{code-local → code}/ghostrail.toml +2 -2
- package/templates/{content-loop → content}/README.md +2 -2
- package/templates/{content-loop → content}/ghostrail.toml +1 -1
- /package/templates/{code-local → code}/prompts/resolve-issue.md +0 -0
- /package/templates/{code-local → code}/prompts/respond.md +0 -0
- /package/templates/{code-local → code}/prompts/triage.md +0 -0
- /package/templates/{content-loop → content}/prompts/draft.md +0 -0
- /package/templates/{content-loop → content}/prompts/respond.md +0 -0
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ A software factory is thin glue over three primitive layers: where work comes fr
|
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
22
|
npx ghostrail install # CLI + skill, then offers to set up your credentials
|
|
23
|
-
ghostrail init code
|
|
23
|
+
ghostrail init code # or: content
|
|
24
24
|
ghostrail run # one tick: claim, isolate, run, gate, open PRs
|
|
25
25
|
ghostrail respond # fold new human PR comments back into branches
|
|
26
26
|
ghostrail board # watch runs at http://127.0.0.1:5050/
|
|
@@ -211,7 +211,7 @@ later release can tell a file *you* edited apart from one the *template* changed
|
|
|
211
211
|
Commit that file with the repo.
|
|
212
212
|
|
|
213
213
|
```bash
|
|
214
|
-
ghostrail init code
|
|
214
|
+
ghostrail init code --diff # read-only: how do my files differ?
|
|
215
215
|
```
|
|
216
216
|
|
|
217
217
|
Each scaffolded file reports as up to date, locally customized, safe to take
|
package/dist/board/server.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type Server } from "node:http";
|
|
2
|
+
import type { RunControl } from "../loop/control.js";
|
|
2
3
|
import type { PrStatus } from "../publish/githost.js";
|
|
3
|
-
import type {
|
|
4
|
+
import type { RunStore } from "../store/port.js";
|
|
4
5
|
export type Route = {
|
|
5
6
|
kind: "page";
|
|
6
7
|
} | {
|
|
@@ -44,6 +45,12 @@ export interface BoardOptions {
|
|
|
44
45
|
allowNoToken?: boolean;
|
|
45
46
|
/** Optional live PR/CI status reader. Without it, `/api/runs/:id/pr-status` reports unavailable. */
|
|
46
47
|
gitHost?: PrStatusReader;
|
|
48
|
+
/**
|
|
49
|
+
* The run/pause flag. Without it, `/api/control` reports the ghostrail as
|
|
50
|
+
* running and refuses to change it: a board that cannot reach the flag should
|
|
51
|
+
* say so rather than claim a pause it did not perform.
|
|
52
|
+
*/
|
|
53
|
+
control?: RunControl;
|
|
47
54
|
}
|
|
48
55
|
/** True for an address only this machine can reach, where a token is optional. */
|
|
49
56
|
export declare function isLoopback(bind: string): boolean;
|
|
@@ -55,7 +62,7 @@ export declare function isLoopback(bind: string): boolean;
|
|
|
55
62
|
* token is configured (required whenever the bind is not loopback), every
|
|
56
63
|
* request must present it.
|
|
57
64
|
*/
|
|
58
|
-
export declare function createBoardServer(store:
|
|
65
|
+
export declare function createBoardServer(store: RunStore, options?: BoardOptions): Server;
|
|
59
66
|
/** A token that is absent, empty, or only whitespace is no token at all. */
|
|
60
67
|
/**
|
|
61
68
|
* An empty or whitespace-only token is no token.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/board/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,MAAM,EAAqC,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/board/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,MAAM,EAAqC,MAAM,WAAW,CAAC;AACjG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAa,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAI5D,MAAM,MAAM,KAAK,GACb;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC3B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC;AAEzB,qDAAqD;AACrD,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,CAmBlD;AAED,2FAA2F;AAC3F,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAClD;AAuBD,MAAM,WAAW,YAAY;IAC3B,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4FAA4F;IAC5F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oGAAoG;IACpG,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB;;;;OAIG;IACH,OAAO,CAAC,EAAE,UAAU,CAAC;CACtB;AAED,kFAAkF;AAClF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEhD;AAQD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,GAAE,YAAiB,GAAG,MAAM,CAqBrF;AAED,4EAA4E;AAC5E;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAG5E"}
|
package/dist/board/server.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { createServer } from "node:http";
|
|
2
|
-
import { readControl, writeControl } from "../loop/control.js";
|
|
3
2
|
import { PAGE_HTML } from "./page.js";
|
|
4
3
|
import { computeStats } from "./stats.js";
|
|
5
4
|
/** Map a request pathname to a board route. Pure. */
|
|
@@ -166,6 +165,10 @@ async function handle(store, options, req, res) {
|
|
|
166
165
|
sendJson(res, 200, computeStats(await store.listRuns()));
|
|
167
166
|
return;
|
|
168
167
|
case "control": {
|
|
168
|
+
// From the options this request was handed, not a closure: `handle` is a
|
|
169
|
+
// module-level function, and a free `control` here silently resolved to a
|
|
170
|
+
// global at compile time and threw at runtime.
|
|
171
|
+
const control = options.control;
|
|
169
172
|
if (req.method === "POST") {
|
|
170
173
|
let payload;
|
|
171
174
|
try {
|
|
@@ -182,9 +185,13 @@ async function handle(store, options, req, res) {
|
|
|
182
185
|
sendJson(res, 400, { error: "enabled must be a boolean" });
|
|
183
186
|
return;
|
|
184
187
|
}
|
|
185
|
-
|
|
188
|
+
if (control === undefined) {
|
|
189
|
+
sendJson(res, 503, { error: "this board cannot change the run flag" });
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
await control.write({ enabled });
|
|
186
193
|
}
|
|
187
|
-
sendJson(res, 200, await
|
|
194
|
+
sendJson(res, 200, control === undefined ? { enabled: true } : await control.read());
|
|
188
195
|
return;
|
|
189
196
|
}
|
|
190
197
|
case "artifact": {
|
package/dist/board/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/board/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0D,YAAY,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/board/server.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/commands.d.ts
CHANGED
|
@@ -84,7 +84,7 @@ export declare function cmdStop(argv: readonly string[], streams: CommandStreams
|
|
|
84
84
|
/** `ghostrail status`: what each ghostrail is doing, and what it should be doing. */
|
|
85
85
|
export declare function cmdStatus(argv: readonly string[], streams: CommandStreams, env?: CommandEnv, manager?: ServiceManager): Promise<number>;
|
|
86
86
|
/** The quickstart templates bundled with the package. */
|
|
87
|
-
export declare const TEMPLATES: readonly ["code
|
|
87
|
+
export declare const TEMPLATES: readonly ["code", "content"];
|
|
88
88
|
/**
|
|
89
89
|
* `ghostrail init <template> [--repo <path>] [--force|--diff|--update]`: scaffold
|
|
90
90
|
* `ghostrail.toml` and `prompts/` from a quickstart template. Safe for a fresh OR
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/commands.js
CHANGED
|
@@ -11,13 +11,17 @@ import { buildProposal, writeProfile } from "../claude-profile/index.js";
|
|
|
11
11
|
import { parseDuration } from "../config/duration.js";
|
|
12
12
|
import { parseConfig, parseMergedConfig } from "../config/load.js";
|
|
13
13
|
import { createDashboardServer } from "../dashboard/index.js";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
14
|
+
import { buildLoopDeps, buildRespondDeps, buildTriageDeps, repoGhRunner, resolveRepoSlug, } from "../factory/build.js";
|
|
15
|
+
import { describeMigration, migrateLegacyStore, resolveWorkRepo, stateDirFor, } from "../factory/state.js";
|
|
16
|
+
import { entryKey, findByKey, findByPath, upsert } from "../global/registry.js";
|
|
17
|
+
import { canonicalRepoId, localRepoId } from "../global/repo-id.js";
|
|
16
18
|
import { GlobalStore, resolveGlobalDir } from "../global/store.js";
|
|
17
19
|
import { DEFAULT_FACTORY_IMAGE, dockerBuildArgs, dockerDir, parseImageFlags, } from "../image/build.js";
|
|
18
20
|
import { extractPlaceholders, isClean, missingSignals, repoPathFor, } from "../init/drift.js";
|
|
19
21
|
import { classify, hashContent, mergeManifest, readManifest, writeManifest, } from "../init/template.js";
|
|
20
22
|
import { FileLock } from "../lock/file-lock.js";
|
|
23
|
+
import { concurrencyAdvice } from "../loop/advice.js";
|
|
24
|
+
import { fileControl } from "../loop/control.js";
|
|
21
25
|
import { readControl } from "../loop/control.js";
|
|
22
26
|
import { runTick } from "../loop/engine.js";
|
|
23
27
|
import { watchLoop } from "../loop/watch.js";
|
|
@@ -121,9 +125,21 @@ async function prepareLoop(flags, streams, env) {
|
|
|
121
125
|
}
|
|
122
126
|
const claudeProfileDir = await resolveClaudeProfile(env);
|
|
123
127
|
const repoSlug = await resolveRepoSlug(config, flags.repo);
|
|
124
|
-
const
|
|
128
|
+
const state = await prepareState(flags.repo, config, env, streams);
|
|
129
|
+
const work = await resolveWorkRepo({ repoPath: flags.repo, stateDir: state.dir, config, env });
|
|
130
|
+
if (work.note !== undefined)
|
|
131
|
+
streams.err(`${work.note}\n`);
|
|
132
|
+
const advice = concurrencyAdvice(config);
|
|
133
|
+
if (advice !== undefined)
|
|
134
|
+
streams.err(`${advice}\n`);
|
|
135
|
+
// One lock per repo, not per checkout. This is the line that stops two clones
|
|
136
|
+
// of one repo running overlapping ticks: while the store lived inside each
|
|
137
|
+
// checkout they took different locks and nothing serialized them.
|
|
138
|
+
const lock = new FileLock(join(state.dir, "lock"), config.guardrails.claimTtlMs);
|
|
125
139
|
const deps = buildLoopDeps(config, {
|
|
126
140
|
repoPath: flags.repo,
|
|
141
|
+
...(work.path === undefined ? {} : { workRepoPath: work.path }),
|
|
142
|
+
stateDir: state.dir,
|
|
127
143
|
linearApiKey,
|
|
128
144
|
lock,
|
|
129
145
|
globalStore,
|
|
@@ -131,7 +147,7 @@ async function prepareLoop(flags, streams, env) {
|
|
|
131
147
|
...(repoSlug === undefined ? {} : { repoSlug }),
|
|
132
148
|
logger: makeLogger(streams, secrets),
|
|
133
149
|
});
|
|
134
|
-
return { config, deps, secrets };
|
|
150
|
+
return { config, deps, secrets, stateDir: state.dir };
|
|
135
151
|
}
|
|
136
152
|
/** `ghostrail run`: drain eligible work once. */
|
|
137
153
|
export async function cmdRun(argv, streams, env = process.env, cwd = process.cwd()) {
|
|
@@ -188,7 +204,7 @@ export async function cmdWatch(argv, streams, env = process.env, cwd = process.c
|
|
|
188
204
|
process.once("SIGTERM", onSignal);
|
|
189
205
|
streams.err(`watching every ${watch.intervalLabel}; press Ctrl-C to stop\n`);
|
|
190
206
|
try {
|
|
191
|
-
const controlDir =
|
|
207
|
+
const controlDir = setup.stateDir;
|
|
192
208
|
const ticks = await watchLoop({
|
|
193
209
|
intervalMs: watch.intervalMs,
|
|
194
210
|
signal: controller.signal,
|
|
@@ -226,9 +242,20 @@ export async function cmdTriage(argv, streams, env = process.env, cwd = process.
|
|
|
226
242
|
return 1;
|
|
227
243
|
}
|
|
228
244
|
const claudeProfileDir = await resolveClaudeProfile(env);
|
|
229
|
-
const
|
|
245
|
+
const triageState = await prepareState(flags.repo, config, env, streams);
|
|
246
|
+
const triageWork = await resolveWorkRepo({
|
|
247
|
+
repoPath: flags.repo,
|
|
248
|
+
stateDir: triageState.dir,
|
|
249
|
+
config,
|
|
250
|
+
env,
|
|
251
|
+
});
|
|
252
|
+
if (triageWork.note !== undefined)
|
|
253
|
+
streams.err(`${triageWork.note}\n`);
|
|
254
|
+
const lock = new FileLock(join(triageState.dir, "lock"), config.guardrails.claimTtlMs);
|
|
230
255
|
const deps = buildTriageDeps(config, {
|
|
231
256
|
repoPath: flags.repo,
|
|
257
|
+
...(triageWork.path === undefined ? {} : { workRepoPath: triageWork.path }),
|
|
258
|
+
stateDir: triageState.dir,
|
|
232
259
|
linearApiKey,
|
|
233
260
|
lock,
|
|
234
261
|
globalStore,
|
|
@@ -254,8 +281,21 @@ export async function cmdRespond(argv, streams, env = process.env, cwd = process
|
|
|
254
281
|
.filter((login) => login.length > 0);
|
|
255
282
|
const claudeProfileDir = await resolveClaudeProfile(env);
|
|
256
283
|
const repoSlug = await resolveRepoSlug(config, flags.repo);
|
|
284
|
+
// Respond's watermarks live with the rest of the repo's state, so a pass run
|
|
285
|
+
// from one checkout does not answer comments another checkout already handled.
|
|
286
|
+
const respondState = await prepareState(flags.repo, config, env, streams);
|
|
287
|
+
const respondWork = await resolveWorkRepo({
|
|
288
|
+
repoPath: flags.repo,
|
|
289
|
+
stateDir: respondState.dir,
|
|
290
|
+
config,
|
|
291
|
+
env,
|
|
292
|
+
});
|
|
293
|
+
if (respondWork.note !== undefined)
|
|
294
|
+
streams.err(`${respondWork.note}\n`);
|
|
257
295
|
const { deps, config: respondConfig } = buildRespondDeps(config, {
|
|
258
296
|
repoPath: flags.repo,
|
|
297
|
+
...(respondWork.path === undefined ? {} : { workRepoPath: respondWork.path }),
|
|
298
|
+
stateDir: respondState.dir,
|
|
259
299
|
linearApiKey,
|
|
260
300
|
lock: { acquire: async () => true, release: async () => { } },
|
|
261
301
|
selfLogins,
|
|
@@ -331,13 +371,17 @@ export async function cmdBoard(argv, streams, env = process.env, cwd = process.c
|
|
|
331
371
|
if (unauthenticated && !isLoopback(flags.bind)) {
|
|
332
372
|
streams.err(`serving the board unauthenticated on ${flags.bind}: anyone who can reach this host can read your run history, issue titles, branch names, and gate output\n`);
|
|
333
373
|
}
|
|
334
|
-
|
|
374
|
+
// The config, not just the checkout's origin: a factory with `[factory].source`
|
|
375
|
+
// is keyed on that, so reading the origin alone would point the board at a
|
|
376
|
+
// different repo's history than the one the runs are written to.
|
|
377
|
+
const store = new FileStore((await stateDirFor(flags.repo, await configAt(flags.repo), env)).dir);
|
|
335
378
|
const gitHost = new GhHost(repoGhRunner(flags.repo), await resolveBoardRepoSlug(flags.repo));
|
|
336
379
|
let server;
|
|
337
380
|
try {
|
|
338
381
|
server = createBoardServer(store, {
|
|
339
382
|
bind: flags.bind,
|
|
340
383
|
gitHost,
|
|
384
|
+
control: fileControl(store.dir),
|
|
341
385
|
...(flags.token === undefined ? {} : { token: flags.token }),
|
|
342
386
|
...(unauthenticated ? { allowNoToken: true } : {}),
|
|
343
387
|
});
|
|
@@ -395,7 +439,7 @@ function dashboardDeps(env, manager) {
|
|
|
395
439
|
states: async (entries) => {
|
|
396
440
|
if ((await manager.kind()) !== "systemd")
|
|
397
441
|
return new Map();
|
|
398
|
-
const units = entries.map((e) => unitName(e.name, e
|
|
442
|
+
const units = entries.map((e) => unitName(e.name, entryKey(e)));
|
|
399
443
|
const byUnit = await manager.states(units);
|
|
400
444
|
// Keyed by path, since that is a ghostrail's identity everywhere else.
|
|
401
445
|
return new Map(entries.map((e, i) => [e.path, byUnit.get(units[i]) ?? "unknown"]));
|
|
@@ -589,6 +633,31 @@ function explainNoManager(kind, streams, interval) {
|
|
|
589
633
|
}
|
|
590
634
|
streams.err(`run a ghostrail by hand instead:\n cd <repo> && ghostrail watch --interval ${interval}\n`);
|
|
591
635
|
}
|
|
636
|
+
/**
|
|
637
|
+
* Stop and delete units this ghostrail owned under an earlier name.
|
|
638
|
+
*
|
|
639
|
+
* Two things move a unit's name: adopting a repo identity (the hash stops being
|
|
640
|
+
* of the checkout path) and renaming the ghostrail. Both leave an enabled unit
|
|
641
|
+
* behind that still points at the same repo, which is a second watcher for work
|
|
642
|
+
* only one should do. Best-effort: failing to tidy up must never stop `start`.
|
|
643
|
+
*/
|
|
644
|
+
async function retireStaleUnits(manager, entry, current, streams) {
|
|
645
|
+
const candidates = new Set([
|
|
646
|
+
unitName(entry.name, entry.path),
|
|
647
|
+
...(entry.repo === undefined ? [] : [unitName(entry.name, entry.repo)]),
|
|
648
|
+
]);
|
|
649
|
+
candidates.delete(current);
|
|
650
|
+
for (const stale of candidates) {
|
|
651
|
+
try {
|
|
652
|
+
await manager.disable(stale);
|
|
653
|
+
await manager.remove(stale);
|
|
654
|
+
}
|
|
655
|
+
catch {
|
|
656
|
+
// Tidying is a courtesy; the ghostrail still starts without it.
|
|
657
|
+
streams.err(` note ${entry.name}: could not remove the old unit ${stale}\n`);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
592
661
|
/**
|
|
593
662
|
* `ghostrail start`: choose which ghostrails should be running, record that in
|
|
594
663
|
* the registry, and make the services match.
|
|
@@ -640,7 +709,13 @@ export async function cmdStart(argv, streams, env = process.env, ask = askOnTerm
|
|
|
640
709
|
}
|
|
641
710
|
let failed = false;
|
|
642
711
|
for (const entry of updated) {
|
|
643
|
-
const unit = unitName(entry.name, entry
|
|
712
|
+
const unit = unitName(entry.name, entryKey(entry));
|
|
713
|
+
// A unit this ghostrail used to own. The name is a hash of the identity, so
|
|
714
|
+
// it changes when a path-keyed entry gains a repo identity, and again if
|
|
715
|
+
// the display name changes. Left alone, the old unit stays enabled and
|
|
716
|
+
// pointed at the same repo, so two watchers race exactly as they did before
|
|
717
|
+
// any of this. Retire it before installing the new one.
|
|
718
|
+
await retireStaleUnits(manager, entry, unit, streams);
|
|
644
719
|
if (!entry.watch) {
|
|
645
720
|
const error = await manager.disable(unit);
|
|
646
721
|
if (error === undefined)
|
|
@@ -652,8 +727,15 @@ export async function cmdStart(argv, streams, env = process.env, ask = askOnTerm
|
|
|
652
727
|
failed = true;
|
|
653
728
|
continue;
|
|
654
729
|
}
|
|
730
|
+
// Said here as well as at run time: this is where someone configures a
|
|
731
|
+
// ghostrail, and the moment they can still change their mind cheaply.
|
|
732
|
+
const startConfig = await configAt(entry.path);
|
|
733
|
+
const startAdvice = startConfig === undefined ? undefined : concurrencyAdvice(startConfig);
|
|
734
|
+
if (startAdvice !== undefined)
|
|
735
|
+
streams.err(` note ${entry.name}: ${startAdvice}\n`);
|
|
655
736
|
const spec = {
|
|
656
737
|
name: entry.name,
|
|
738
|
+
repo: entryKey(entry),
|
|
657
739
|
path: entry.path,
|
|
658
740
|
exec: ghostrailExecPath(),
|
|
659
741
|
interval: flags.interval,
|
|
@@ -754,7 +836,7 @@ export async function cmdStop(argv, streams, env = process.env, manager = system
|
|
|
754
836
|
streams.out("stopping; a ghostrail mid-tick finishes its run first, which can take minutes\n");
|
|
755
837
|
let failed = false;
|
|
756
838
|
for (const entry of targets) {
|
|
757
|
-
const error = await manager.disable(unitName(entry.name, entry
|
|
839
|
+
const error = await manager.disable(unitName(entry.name, entryKey(entry)));
|
|
758
840
|
if (error !== undefined) {
|
|
759
841
|
streams.err(` failed ${entry.name}: ${error}\n`);
|
|
760
842
|
failed = true;
|
|
@@ -786,7 +868,7 @@ export async function cmdStatus(argv, streams, env = process.env, manager = syst
|
|
|
786
868
|
if (entries.length === 0)
|
|
787
869
|
return 0;
|
|
788
870
|
const kind = await manager.kind();
|
|
789
|
-
const units = entries.map((e) => unitName(e.name, e
|
|
871
|
+
const units = entries.map((e) => unitName(e.name, entryKey(e)));
|
|
790
872
|
const states = kind === "systemd" ? await manager.states(units) : new Map();
|
|
791
873
|
const width = Math.max(...entries.map((e) => e.name.length));
|
|
792
874
|
for (const [i, entry] of entries.entries()) {
|
|
@@ -808,7 +890,7 @@ export async function cmdStatus(argv, streams, env = process.env, manager = syst
|
|
|
808
890
|
return 0;
|
|
809
891
|
}
|
|
810
892
|
/** The quickstart templates bundled with the package. */
|
|
811
|
-
export const TEMPLATES = ["code
|
|
893
|
+
export const TEMPLATES = ["code", "content"];
|
|
812
894
|
function templatesDir() {
|
|
813
895
|
return fileURLToPath(new URL("../../templates", import.meta.url));
|
|
814
896
|
}
|
|
@@ -934,6 +1016,48 @@ async function ghostrailName(repo) {
|
|
|
934
1016
|
* convenience, and aborting a good scaffold over an unwritable config dir would
|
|
935
1017
|
* be the worse trade.
|
|
936
1018
|
*/
|
|
1019
|
+
/**
|
|
1020
|
+
* The repo identity for a checkout: its `origin`, canonicalized, else its path.
|
|
1021
|
+
*
|
|
1022
|
+
* The path fallback is deliberate and visible (`local:` prefixed), not an
|
|
1023
|
+
* accident: a repo with no remote genuinely has no identity beyond where it
|
|
1024
|
+
* sits, and inventing one would be the bug this whole change exists to fix.
|
|
1025
|
+
*/
|
|
1026
|
+
async function resolveRepoId(path) {
|
|
1027
|
+
const origin = await spawnCollect(["git", "-C", path, "remote", "get-url", "origin"]);
|
|
1028
|
+
const canonical = origin.exitCode === 0 ? canonicalRepoId(origin.stdout) : undefined;
|
|
1029
|
+
return canonical ?? localRepoId(path);
|
|
1030
|
+
}
|
|
1031
|
+
/**
|
|
1032
|
+
* Resolve where this repo's state lives, carrying over a `.factory` from inside
|
|
1033
|
+
* the checkout if one is still there.
|
|
1034
|
+
*
|
|
1035
|
+
* Migration runs here rather than at install time because this is the first
|
|
1036
|
+
* moment a command knows which repo it is working on. It never fails the
|
|
1037
|
+
* command: a copy that could not happen is reported and the original is left
|
|
1038
|
+
* untouched, which is strictly better than refusing to run.
|
|
1039
|
+
*/
|
|
1040
|
+
/**
|
|
1041
|
+
* A repo's parsed config, or undefined when it has none or it does not parse.
|
|
1042
|
+
*
|
|
1043
|
+
* Best-effort on purpose: a command that only reads state (the board) should
|
|
1044
|
+
* still work against a repo whose config is mid-edit, falling back to keying on
|
|
1045
|
+
* the checkout's origin.
|
|
1046
|
+
*/
|
|
1047
|
+
async function configAt(repo) {
|
|
1048
|
+
const raw = await readIfPresent(join(repo, "ghostrail.toml"));
|
|
1049
|
+
if (raw === undefined)
|
|
1050
|
+
return undefined;
|
|
1051
|
+
const parsed = parseConfig(raw);
|
|
1052
|
+
return parsed.ok ? parsed.value : undefined;
|
|
1053
|
+
}
|
|
1054
|
+
async function prepareState(repo, config, env, streams) {
|
|
1055
|
+
const state = await stateDirFor(repo, config, env);
|
|
1056
|
+
const note = describeMigration(await migrateLegacyStore(state.legacy, state.dir));
|
|
1057
|
+
if (note !== undefined)
|
|
1058
|
+
streams.err(`${note}\n`);
|
|
1059
|
+
return { dir: state.dir, repoId: state.repoId };
|
|
1060
|
+
}
|
|
937
1061
|
async function registerGhostrail(repo, env, streams) {
|
|
938
1062
|
const store = globalStoreFor(env);
|
|
939
1063
|
const path = resolve(repo);
|
|
@@ -943,10 +1067,22 @@ async function registerGhostrail(repo, env, streams) {
|
|
|
943
1067
|
streams.err(`note: ${store.registryPath()} could not be parsed, so this ghostrail was not registered\n`);
|
|
944
1068
|
return;
|
|
945
1069
|
}
|
|
946
|
-
|
|
1070
|
+
const repoId = await resolveRepoId(path);
|
|
1071
|
+
const existing = findByKey(entries, repoId);
|
|
1072
|
+
if (existing !== undefined) {
|
|
1073
|
+
// A second checkout of a repo that already has a ghostrail. Adopt this
|
|
1074
|
+
// checkout as the hint and say so, rather than adding a second ghostrail
|
|
1075
|
+
// that would poll the same tracker query and race the first for its work.
|
|
1076
|
+
if (existing.path === path)
|
|
1077
|
+
return;
|
|
1078
|
+
await store.writeRegistry(upsert(entries, { ...existing, repo: repoId, path }));
|
|
1079
|
+
streams.out(`this repo already has the ghostrail "${existing.name}"; pointed it at this checkout\n` +
|
|
1080
|
+
` was: ${existing.path}\n now: ${path}\n`);
|
|
947
1081
|
return;
|
|
1082
|
+
}
|
|
948
1083
|
const entry = {
|
|
949
1084
|
name: await ghostrailName(repo),
|
|
1085
|
+
repo: repoId,
|
|
950
1086
|
path,
|
|
951
1087
|
added: new Date().toISOString().slice(0, 10),
|
|
952
1088
|
watch: true,
|