@agent-plan/core 0.2.19-next.24 → 0.2.19-next.25

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.
@@ -1,3 +1,4 @@
1
+ import { z } from "zod";
1
2
  import { type Feature, type FeaturesDocument, type Manifest, type Phase, type PlanWorkspace, type Project, type RequirementsDocument, type Requirement, type ActivityEntry, type ActivityLog, type CodebaseProfile, type ResumeFocus, type WorkDeviation } from "./schema.js";
2
3
  import { type ParentDisplay } from "./display-status.js";
3
4
  export interface PlanStoreErrorDetails {
@@ -24,6 +25,11 @@ export declare class PlanStoreError extends Error {
24
25
  }
25
26
  export declare function setWriteBusyHook(hook: ((busy: boolean) => void) | undefined): void;
26
27
  export declare function setWriteNotifyHook(hook: (() => void) | undefined): void;
28
+ /** Allocation registry is deliberately outside the versioned plan. Git worktrees
29
+ * share their common git dir, so reservations are serialized across branches
30
+ * without rewriting project.json or unrelated planner entities. */
31
+ declare const AllocationKindSchema: z.ZodEnum<["feature", "phase", "task"]>;
32
+ type AllocationKind = z.infer<typeof AllocationKindSchema>;
27
33
  export declare function withFeatureLock<T>(featureId: string, fn: () => Promise<T>): Promise<T>;
28
34
  /** Summary of a phase that has a non-empty pending handoff, for the
29
35
  * listHandoffs() API. Completed/canceled phases are never returned here. */
@@ -165,26 +171,28 @@ export declare class PlanStore {
165
171
  * Returns true if the file was (re)written. Safe to call on every load. */
166
172
  ensureGitignore(): Promise<boolean>;
167
173
  exists(): Promise<boolean>;
174
+ /** Read-only manifest load. Upgrading legacy `.local` state is explicit
175
+ * maintenance (`repair`), never an incidental side effect of opening a plan. */
168
176
  loadManifest(): Promise<Manifest>;
169
177
  loadProject(): Promise<Project>;
170
178
  /**
171
- * Allocate the next global sequence number for a feature/phase/task.
172
- * Reads the monotonic counter from project.json, increments it, persists,
173
- * and returns the allocated number. MUST be called within withFeatureLock
174
- * (adapters create entities inside a lock) so the counter is race-free.
175
- * The counter never reuses a number deletions leave gaps (by design:
176
- * stable references survive deletion).
179
+ * Reserve immutable human identifiers without touching tracked `project.json`.
180
+ * Worktrees in the same clone share `.git/agent-plan/allocations`, guarded by
181
+ * the same cross-process lock used for atomic writes. The registry reserves
182
+ * numbers/short IDs before an entity file is written, so parallel branches
183
+ * cannot allocate the same F/P/T or shortId. Existing entities are never
184
+ * rewritten; cross-clone coordination requires a shared allocator service.
177
185
  */
186
+ allocateEntityIdentity(kind: AllocationKind, entityId: string): Promise<{
187
+ number: number;
188
+ shortId: string;
189
+ }>;
190
+ /** Compatibility helpers. New callers should allocate the number and shortId
191
+ * together with allocateEntityIdentity so reservation cannot be split. */
178
192
  allocFeatureNumber(): Promise<number>;
179
193
  allocPhaseNumber(): Promise<number>;
180
194
  allocTaskNumber(): Promise<number>;
181
- /** Allocate a globally-unique sequence number. `atomicUpdateJson` already
182
- * serializes concurrent calls via `withWriteLock` on the project file, so
183
- * the read-modify-write is race-free in-process. The collision guard
184
- * additionally skips any candidate that already exists in the data (safety
185
- * net for cross-process races or manual edits) and persists the corrected
186
- * counter. */
187
- private allocSeqNumber;
195
+ private allocateLegacyNumber;
188
196
  loadPhase(phaseId: string): Promise<Phase>;
189
197
  /** Read raw feature files WITHOUT the derived `status` field. Used
190
198
  * internally so loadFeatures/loadAll can derive status from phases without
@@ -385,4 +393,5 @@ export declare class PlanStore {
385
393
  /** Update .local/timestamp.json to reflect a change. */
386
394
  private touchTimestamp;
387
395
  }
396
+ export {};
388
397
  //# sourceMappingURL=plan-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"plan-store.d.ts","sourceRoot":"","sources":["../src/plan-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plan-store.d.ts","sourceRoot":"","sources":["../src/plan-store.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { access, copyFile, mkdir, readdir, readFile, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
2
- import { basename, dirname, join } from "node:path";
2
+ import { basename, dirname, join, resolve } from "node:path";
3
+ import { randomUUID } from "node:crypto";
3
4
  import { z, ZodError } from "zod";
4
5
  /** Canonical `.planner/.gitignore` content (P042 spec): ignore the `.local/`
5
6
  * transient root, legacy `*.bak` crash backups, `*.tmp.*` atomic-write temp
@@ -71,8 +72,53 @@ export function setWriteNotifyHook(hook) {
71
72
  }
72
73
  const CROSS_PROCESS_LOCK_STALE_MS = 30_000;
73
74
  const CROSS_PROCESS_LOCK_RETRY_MS = 10;
75
+ /** Allocation registry is deliberately outside the versioned plan. Git worktrees
76
+ * share their common git dir, so reservations are serialized across branches
77
+ * without rewriting project.json or unrelated planner entities. */
78
+ const AllocationKindSchema = z.enum(["feature", "phase", "task"]);
79
+ const AllocationRegistrySchema = z.object({
80
+ version: z.literal(1),
81
+ projectId: z.string().min(1),
82
+ allocations: z.array(z.object({
83
+ kind: AllocationKindSchema,
84
+ entityId: z.string().min(1),
85
+ number: z.number().int().positive(),
86
+ shortId: z.string().regex(/^[A-Z2-9]{5}$/),
87
+ })).default([]),
88
+ });
89
+ async function gitCommonDirFor(planRoot) {
90
+ let current = resolve(planRoot);
91
+ for (;;) {
92
+ const dotGit = join(current, ".git");
93
+ try {
94
+ const info = await stat(dotGit);
95
+ if (info.isDirectory())
96
+ return dotGit;
97
+ const pointer = await readFile(dotGit, "utf8");
98
+ const match = pointer.match(/^gitdir:\s*(.+)\s*$/m);
99
+ if (!match?.[1])
100
+ return undefined;
101
+ const worktreeGitDir = resolve(current, match[1]);
102
+ const commonDirRef = await readFile(join(worktreeGitDir, "commondir"), "utf8").catch(() => "");
103
+ return commonDirRef.trim() ? resolve(worktreeGitDir, commonDirRef.trim()) : worktreeGitDir;
104
+ }
105
+ catch {
106
+ const parent = dirname(current);
107
+ if (parent === current)
108
+ return undefined;
109
+ current = parent;
110
+ }
111
+ }
112
+ }
113
+ async function writeRegistry(path, registry) {
114
+ await mkdir(dirname(path), { recursive: true });
115
+ const tmp = `${path}.tmp.${process.pid}.${Date.now()}`;
116
+ await writeFile(tmp, JSON.stringify(registry, null, 2), "utf8");
117
+ await rename(tmp, path);
118
+ }
74
119
  async function acquireCrossProcessLock(path) {
75
120
  const lockPath = `${path}.lock`;
121
+ await mkdir(dirname(lockPath), { recursive: true });
76
122
  for (;;) {
77
123
  try {
78
124
  await mkdir(lockPath);
@@ -850,79 +896,71 @@ export class PlanStore {
850
896
  }
851
897
  }
852
898
  // ── Loaders ──────────────────────────────────────────────────────────
899
+ /** Read-only manifest load. Upgrading legacy `.local` state is explicit
900
+ * maintenance (`repair`), never an incidental side effect of opening a plan. */
853
901
  async loadManifest() {
854
- // Ensure the .planner/.gitignore ignores transients (P042). Idempotent;
855
- // upgrades plans initialized before the .local/ move. Runs on every load.
856
- await this.ensureGitignore().catch(() => { });
857
902
  const manifest = await readJson(this.manifestPath(), ManifestSchema);
858
- try {
859
- const timestamp = await readJson(this.timestampPath(), z.object({ updatedAt: TimestampSchema }));
860
- manifest.updatedAt = timestamp.updatedAt;
861
- }
862
- catch {
863
- // Legacy plan without .local/timestamp.json: bootstrap from manifest.updatedAt
864
- // and create the timestamp file so subsequent writes stay in .local/.
865
- try {
866
- await mkdir(this.localRoot(), { recursive: true });
867
- await atomicWriteJson(this.timestampPath(), { updatedAt: manifest.updatedAt }, this.root);
868
- }
869
- catch {
870
- // ignore bootstrap failure
871
- }
872
- }
873
- return manifest;
903
+ const timestamp = await readJson(this.timestampPath(), z.object({ updatedAt: TimestampSchema })).catch(() => undefined);
904
+ return timestamp ? { ...manifest, updatedAt: timestamp.updatedAt } : manifest;
874
905
  }
875
906
  async loadProject() {
876
907
  return readJson(this.projectPath(), ProjectSchema);
877
908
  }
878
909
  /**
879
- * Allocate the next global sequence number for a feature/phase/task.
880
- * Reads the monotonic counter from project.json, increments it, persists,
881
- * and returns the allocated number. MUST be called within withFeatureLock
882
- * (adapters create entities inside a lock) so the counter is race-free.
883
- * The counter never reuses a number deletions leave gaps (by design:
884
- * stable references survive deletion).
910
+ * Reserve immutable human identifiers without touching tracked `project.json`.
911
+ * Worktrees in the same clone share `.git/agent-plan/allocations`, guarded by
912
+ * the same cross-process lock used for atomic writes. The registry reserves
913
+ * numbers/short IDs before an entity file is written, so parallel branches
914
+ * cannot allocate the same F/P/T or shortId. Existing entities are never
915
+ * rewritten; cross-clone coordination requires a shared allocator service.
885
916
  */
886
- async allocFeatureNumber() { return this.allocSeqNumber("nextFeatureNumber", "feature"); }
887
- async allocPhaseNumber() { return this.allocSeqNumber("nextPhaseNumber", "phase"); }
888
- async allocTaskNumber() { return this.allocSeqNumber("nextTaskNumber", "task"); }
889
- /** Allocate a globally-unique sequence number. `atomicUpdateJson` already
890
- * serializes concurrent calls via `withWriteLock` on the project file, so
891
- * the read-modify-write is race-free in-process. The collision guard
892
- * additionally skips any candidate that already exists in the data (safety
893
- * net for cross-process races or manual edits) and persists the corrected
894
- * counter. */
895
- async allocSeqNumber(key, kind) {
896
- // Load already-used numbers for this kind (best-effort read; the
897
- // atomicUpdateJson below is the authoritative write).
898
- const used = new Set();
899
- if (kind === "task") {
900
- const phases = await this.loadAllPhases();
901
- for (const p of phases)
902
- for (const t of p.tasks)
903
- used.add(t.number);
904
- }
905
- else if (kind === "phase") {
917
+ async allocateEntityIdentity(kind, entityId) {
918
+ const project = await this.loadProject();
919
+ const manifest = await this.loadManifest();
920
+ const commonGitDir = await gitCommonDirFor(this.root);
921
+ const registryPath = commonGitDir
922
+ ? join(commonGitDir, "agent-plan", "allocations", `${manifest.projectId}.json`)
923
+ : join(this.localRoot(), "allocations", `${manifest.projectId}.json`);
924
+ return withWriteLock(registryPath, async () => {
925
+ const registry = AllocationRegistrySchema.parse(await readFile(registryPath, "utf8")
926
+ .then(JSON.parse)
927
+ .catch(() => ({ version: 1, projectId: manifest.projectId, allocations: [] })));
928
+ if (registry.projectId !== manifest.projectId)
929
+ throw new PlanStoreError(`allocation registry project mismatch: ${registryPath}`);
930
+ const prior = registry.allocations.find((entry) => entry.kind === kind && entry.entityId === entityId);
931
+ if (prior)
932
+ return { number: prior.number, shortId: prior.shortId };
906
933
  const phases = await this.loadAllPhases();
907
- for (const p of phases)
908
- used.add(p.number);
909
- }
910
- else {
911
- const feats = await this.loadRawFeatures();
912
- for (const f of feats)
913
- used.add(f.number);
914
- }
915
- let allocated = 0;
916
- await this.updateProject((project) => {
917
- let candidate = project[key];
918
- // Collision guard: skip any candidate that already exists.
919
- while (used.has(candidate))
920
- candidate++;
921
- allocated = candidate;
922
- project[key] = candidate + 1;
923
- return project;
934
+ const features = (await this.loadFeatures()).features;
935
+ const canonical = kind === "feature"
936
+ ? features.map((feature) => ({ number: feature.number, shortId: feature.shortId }))
937
+ : kind === "phase"
938
+ ? phases.map((phase) => ({ number: phase.number, shortId: phase.shortId }))
939
+ : phases.flatMap((phase) => phase.tasks.map((task) => ({ number: task.number, shortId: task.shortId })));
940
+ const usedNumbers = new Set([...canonical.map((entry) => entry.number), ...registry.allocations.filter((entry) => entry.kind === kind).map((entry) => entry.number)]);
941
+ const counter = kind === "feature" ? project.nextFeatureNumber : kind === "phase" ? project.nextPhaseNumber : project.nextTaskNumber;
942
+ let number = Math.max(1, counter);
943
+ while (usedNumbers.has(number))
944
+ number += 1;
945
+ const allShortIds = new Set([
946
+ ...features.map((feature) => feature.shortId),
947
+ ...phases.flatMap((phase) => [phase.shortId, ...phase.tasks.map((task) => task.shortId)]),
948
+ ...registry.allocations.map((entry) => entry.shortId),
949
+ ].filter(Boolean));
950
+ const allocation = { kind, entityId, number, shortId: createShortId(allShortIds, `${kind}:${entityId}`) };
951
+ registry.allocations.push(allocation);
952
+ await writeRegistry(registryPath, registry);
953
+ return { number: allocation.number, shortId: allocation.shortId };
924
954
  });
925
- return allocated;
955
+ }
956
+ /** Compatibility helpers. New callers should allocate the number and shortId
957
+ * together with allocateEntityIdentity so reservation cannot be split. */
958
+ async allocFeatureNumber() { return this.allocateLegacyNumber("feature"); }
959
+ async allocPhaseNumber() { return this.allocateLegacyNumber("phase"); }
960
+ async allocTaskNumber() { return this.allocateLegacyNumber("task"); }
961
+ async allocateLegacyNumber(kind) {
962
+ const id = `legacy-${kind}-${randomUUID()}`;
963
+ return (await this.allocateEntityIdentity(kind, id)).number;
926
964
  }
927
965
  async loadPhase(phaseId) {
928
966
  const raw = await readJson(this.phasePath(phaseId), PhaseSchema);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-plan/core",
3
- "version": "0.2.19-next.24",
3
+ "version": "0.2.19-next.25",
4
4
  "private": false,
5
5
  "description": "Harness-agnostic core for Agent Plan: schemas, persistence, ordering, status rollups, and markdown rendering.",
6
6
  "license": "MIT",