@felixdotgo/aidlc-kit 0.1.1 → 0.3.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/DEVELOPMENT.md +14 -13
- package/README.md +37 -43
- package/dist/assets/.agents/aidlc/docker/Dockerfile.claude +7 -0
- package/dist/assets/.agents/aidlc/docker/Dockerfile.codex +9 -0
- package/dist/assets/.agents/aidlc/docker/Dockerfile.opencode +8 -0
- package/dist/assets/.agents/aidlc/orchestrator.md +2 -2
- package/dist/assets/.agents/aidlc/phase-clarify.md +1 -1
- package/dist/assets/.agents/aidlc/phase-plan.md +2 -2
- package/dist/assets/.agents/aidlc/schemas/config.schema.json +2 -1
- package/dist/assets/.agents/aidlc/schemas/state.schema.json +2 -0
- package/dist/assets/.agents/aidlc/scripts/lib/assignment-store.mjs +94 -48
- package/dist/assets/.agents/aidlc/scripts/lib/context-runtime.mjs +5 -4
- package/dist/assets/.agents/aidlc/scripts/lib/loop-authority.mjs +261 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-commit-message.mjs +45 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-daemon.mjs +206 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-drivers.mjs +100 -14
- package/dist/assets/.agents/aidlc/scripts/lib/loop-env.mjs +279 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-fleet-cli.mjs +105 -32
- package/dist/assets/.agents/aidlc/scripts/lib/loop-fleet-remote.mjs +17 -1
- package/dist/assets/.agents/aidlc/scripts/lib/loop-fleet-supervisor.mjs +24 -7
- package/dist/assets/.agents/aidlc/scripts/lib/loop-fleet.mjs +42 -16
- package/dist/assets/.agents/aidlc/scripts/lib/loop-git.mjs +20 -6
- package/dist/assets/.agents/aidlc/scripts/lib/loop-holder.mjs +376 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-intake.mjs +33 -7
- package/dist/assets/.agents/aidlc/scripts/lib/loop-lease.mjs +67 -61
- package/dist/assets/.agents/aidlc/scripts/lib/loop-leases.mjs +268 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-local-workers.mjs +116 -28
- package/dist/assets/.agents/aidlc/scripts/lib/loop-runtime.mjs +114 -12
- package/dist/assets/.agents/aidlc/scripts/lib/loop-stream.mjs +117 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-supervisor-local.mjs +16 -56
- package/dist/assets/.agents/aidlc/scripts/lib/loop-supervisor-run-local.mjs +149 -6
- package/dist/assets/.agents/aidlc/scripts/lib/loop-supervisor.mjs +9 -1
- package/dist/assets/.agents/aidlc/scripts/lib/loop-worker-docker.mjs +44 -6
- package/dist/assets/.agents/aidlc/scripts/lib/loop-worker-image.mjs +64 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-worker-log.mjs +158 -0
- package/dist/assets/.agents/aidlc/scripts/lib/repo-head.mjs +22 -0
- package/dist/assets/.agents/aidlc/scripts/lib/store.mjs +68 -2
- package/dist/assets/.agents/aidlc/scripts/lib/task-runtime-migrate.mjs +75 -0
- package/dist/assets/.agents/aidlc/scripts/lib/task-runtime.mjs +97 -0
- package/dist/assets/.agents/aidlc/scripts/loop-entry.mjs +168 -73
- package/dist/assets/.agents/aidlc/scripts/loop-gate.mjs +19 -7
- package/dist/assets/.agents/aidlc/scripts/loop.cmd +101 -0
- package/dist/assets/.agents/aidlc/scripts/loop.mjs +2 -1
- package/dist/assets/.agents/aidlc/scripts/loop.sh +71 -0
- package/dist/assets/.agents/aidlc/scripts/remote-state.mjs +10 -4
- package/dist/assets/.agents/aidlc/scripts/state.mjs +16 -8
- package/dist/assets/.agents/aidlc/templates/design.md +9 -0
- package/dist/assets/.agents/aidlc/templates/intent.md +4 -0
- package/dist/assets/.agents/aidlc/templates/workplan.md +1 -1
- package/dist/assets/.agents/skills/aidlc-plan/SKILL.md +1 -1
- package/dist/assets/ui/bulma.min.css +3 -0
- package/dist/assets/ui/changes.js +83 -0
- package/dist/assets/ui/common.js +664 -0
- package/dist/assets/ui/dashboard.css +636 -0
- package/dist/assets/ui/dashboard.js +77 -0
- package/dist/assets/ui/detail.js +159 -0
- package/dist/assets/ui/live-log.js +332 -0
- package/dist/services/aidlc-coordination/Dockerfile +11 -3
- package/dist/services/aidlc-coordination/compose.yaml +12 -0
- package/dist/services/aidlc-coordination/package-lock.json +3 -1
- package/dist/services/aidlc-coordination/package.json +9 -4
- package/dist/services/aidlc-coordination/src/lifecycle-core.mjs +68 -2
- package/dist/services/aidlc-coordination/src/repository.mjs +66 -0
- package/dist/services/aidlc-coordination/src/server.mjs +9 -3
- package/dist/services/aidlc-coordination/test/fleet.test.mjs +21 -0
- package/dist/services/aidlc-coordination/test/server-health-auth.test.mjs +67 -0
- package/dist/src/adapters.d.ts +0 -3
- package/dist/src/adapters.js +3 -5
- package/dist/src/cli/argv.d.ts +12 -0
- package/dist/src/cli/argv.js +68 -0
- package/dist/src/cli/commands.d.ts +8 -0
- package/dist/src/cli/commands.js +159 -0
- package/dist/src/cli/loop-launcher.d.ts +47 -0
- package/dist/src/cli/loop-launcher.js +322 -0
- package/dist/src/cli/options.d.ts +25 -0
- package/dist/src/cli/options.js +32 -0
- package/dist/src/cli/prompt.d.ts +9 -0
- package/dist/src/cli/prompt.js +66 -0
- package/dist/src/cli.js +28 -191
- package/dist/src/gate.js +3 -2
- package/dist/src/installer.d.ts +14 -7
- package/dist/src/installer.js +42 -143
- package/dist/src/legacy.js +1 -0
- package/dist/src/managed-content.d.ts +7 -0
- package/dist/src/managed-content.js +15 -4
- package/dist/src/managed-planning.d.ts +65 -0
- package/dist/src/managed-planning.js +219 -0
- package/dist/src/mcp-setup.js +3 -1
- package/dist/src/model/config-contracts.d.ts +65 -0
- package/dist/src/model/config-contracts.js +1 -0
- package/dist/src/model/install-contracts.d.ts +29 -0
- package/dist/src/model/install-contracts.js +1 -0
- package/dist/src/model/lifecycle-enums.d.ts +13 -0
- package/dist/src/model/lifecycle-enums.js +1 -0
- package/dist/src/model/loop.d.ts +20 -0
- package/dist/src/model/loop.js +1 -0
- package/dist/src/model/manifest.d.ts +16 -0
- package/dist/src/model/manifest.js +1 -0
- package/dist/src/model/records.d.ts +142 -0
- package/dist/src/model/records.js +1 -0
- package/dist/src/model.d.ts +11 -264
- package/dist/src/model.js +1 -1
- package/dist/src/profiles.d.ts +2 -0
- package/dist/src/profiles.js +53 -9
- package/dist/src/state/archive-record.d.ts +9 -0
- package/dist/src/state/archive-record.js +26 -0
- package/dist/src/state/commands.d.ts +18 -0
- package/dist/src/state/commands.js +27 -0
- package/dist/src/state/domain.d.ts +9 -0
- package/dist/src/state/domain.js +9 -0
- package/dist/src/state/guards.d.ts +7 -0
- package/dist/src/state/guards.js +17 -0
- package/dist/src/state/io.d.ts +10 -0
- package/dist/src/state/io.js +35 -0
- package/dist/src/state/items.d.ts +3 -4
- package/dist/src/state/items.js +58 -57
- package/dist/src/state/lessons.js +14 -7
- package/dist/src/state/lifecycle.js +2 -2
- package/dist/src/state/lock.js +7 -6
- package/dist/src/state/memory.js +24 -12
- package/dist/src/state/{archive.js → migrate.js} +7 -7
- package/dist/src/state/partition.d.ts +15 -0
- package/dist/src/state/partition.js +90 -0
- package/dist/src/state/paths.d.ts +11 -0
- package/dist/src/state/paths.js +12 -0
- package/dist/src/state/render.js +9 -6
- package/dist/src/state/store.js +9 -15
- package/dist/src/state/transitions.js +9 -7
- package/dist/src/state/validate.js +55 -7
- package/dist/src/state.d.ts +16 -11
- package/dist/src/state.js +16 -11
- package/dist/src/task-ui.d.ts +33 -0
- package/dist/src/task-ui.js +33 -0
- package/dist/src/ui/assets.d.ts +14 -0
- package/dist/src/ui/assets.js +45 -0
- package/dist/src/ui/changes.d.ts +83 -0
- package/dist/src/ui/changes.js +498 -0
- package/dist/src/ui/containers.d.ts +71 -0
- package/dist/src/ui/containers.js +214 -0
- package/dist/src/ui/daemon.d.ts +75 -0
- package/dist/src/ui/daemon.js +232 -0
- package/dist/src/ui/data.d.ts +42 -0
- package/dist/src/ui/data.js +89 -0
- package/dist/src/ui/docs.d.ts +13 -0
- package/dist/src/ui/docs.js +39 -0
- package/dist/src/ui/files.d.ts +3 -0
- package/dist/src/ui/files.js +20 -0
- package/dist/src/ui/http.d.ts +14 -0
- package/dist/src/ui/http.js +80 -0
- package/dist/src/ui/live.d.ts +5 -0
- package/dist/src/ui/live.js +43 -0
- package/dist/src/ui/markdown.d.ts +2 -0
- package/dist/src/ui/markdown.js +127 -0
- package/dist/src/ui/options.d.ts +48 -0
- package/dist/src/ui/options.js +81 -0
- package/dist/src/ui/security.d.ts +34 -0
- package/dist/src/ui/security.js +38 -0
- package/dist/src/ui/server.d.ts +39 -0
- package/dist/src/ui/server.js +347 -0
- package/dist/src/ui/sse.d.ts +14 -0
- package/dist/src/ui/sse.js +281 -0
- package/dist/src/ui/views/board.d.ts +7 -0
- package/dist/src/ui/views/board.js +131 -0
- package/dist/src/ui/views/changes.d.ts +19 -0
- package/dist/src/ui/views/changes.js +154 -0
- package/dist/src/ui/views/components.d.ts +56 -0
- package/dist/src/ui/views/components.js +113 -0
- package/dist/src/ui/views/docs.d.ts +15 -0
- package/dist/src/ui/views/docs.js +64 -0
- package/dist/src/ui/views/layout.d.ts +44 -0
- package/dist/src/ui/views/layout.js +233 -0
- package/dist/src/ui/views/task.d.ts +25 -0
- package/dist/src/ui/views/task.js +320 -0
- package/dist/src/upgrade-board.js +10 -10
- package/dist/src/upgrade.d.ts +0 -1
- package/dist/src/upgrade.js +24 -85
- package/dist/src/workflow.d.ts +4 -0
- package/dist/src/workflow.js +36 -4
- package/docs/README.md +41 -22
- package/docs/architecture.md +101 -37
- package/docs/command-reference.md +289 -52
- package/docs/configuration.md +70 -30
- package/docs/coordination-service.md +91 -30
- package/docs/design-decisions.md +87 -0
- package/docs/development.md +124 -49
- package/docs/loop-local-run.md +228 -0
- package/docs/loop-runbook.md +214 -0
- package/docs/operating-workflow.md +55 -42
- package/docs/testing-and-release.md +72 -49
- package/docs/troubleshooting.md +221 -0
- package/package.json +4 -1
- package/dist/src/ledger.d.ts +0 -22
- package/dist/src/ledger.js +0 -119
- package/dist/src/state/shared.d.ts +0 -29
- package/dist/src/state/shared.js +0 -71
- package/dist/src/tracker.d.ts +0 -36
- package/dist/src/tracker.js +0 -44
- /package/dist/src/state/{archive.d.ts → migrate.d.ts} +0 -0
package/dist/src/ledger.js
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
-
import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { dirname, join, resolve } from "node:path";
|
|
4
|
-
import { validateState } from "./state.js";
|
|
5
|
-
export const trackedTasksPath = (root) => join(resolve(root), ".agents/workflow/tasks");
|
|
6
|
-
export const taskEventsPath = (root, taskId) => join(trackedTasksPath(root), taskId, "events");
|
|
7
|
-
const digest = (value) => createHash("sha256").update(JSON.stringify(value)).digest("hex");
|
|
8
|
-
const eventContent = (event) => `${JSON.stringify(event, null, 2)}\n`;
|
|
9
|
-
const eventPath = (root, event) => join(taskEventsPath(root, event.taskId), `${event.id}.json`);
|
|
10
|
-
const taskIdPattern = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
11
|
-
const iso = (value) => typeof value === "string" && Number.isFinite(Date.parse(value)) && new Date(Date.parse(value)).toISOString() === value;
|
|
12
|
-
const assertSafeTaskId = (taskId) => {
|
|
13
|
-
if (!taskIdPattern.test(taskId))
|
|
14
|
-
throw new Error(`Invalid ledger task id: ${taskId}`);
|
|
15
|
-
};
|
|
16
|
-
const atomicWrite = (path, content) => {
|
|
17
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
18
|
-
const temporary = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
19
|
-
writeFileSync(temporary, content, "utf8");
|
|
20
|
-
renameSync(temporary, path);
|
|
21
|
-
};
|
|
22
|
-
export const validateLedgerEvent = (value) => {
|
|
23
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
24
|
-
throw new Error("Ledger event must be an object");
|
|
25
|
-
const event = value;
|
|
26
|
-
if (event.schemaVersion !== 1 || typeof event.id !== "string" || !taskIdPattern.test(event.id) || typeof event.taskId !== "string" || !taskIdPattern.test(event.taskId) || (event.parentDigest !== null && !/^[a-f0-9]{64}$/.test(event.parentDigest ?? "")) || typeof event.actor !== "string" || !event.actor.trim() || !iso(event.recordedAt) || !event.snapshot || typeof event.digest !== "string" || !/^[a-f0-9]{64}$/.test(event.digest))
|
|
27
|
-
throw new Error("Invalid ledger event fields");
|
|
28
|
-
if (event.snapshot.id !== event.taskId)
|
|
29
|
-
throw new Error(`Ledger event task mismatch: ${event.id}`);
|
|
30
|
-
validateState({ schemaVersion: 4, tasks: { [event.taskId]: event.snapshot }, archive: {} });
|
|
31
|
-
const { digest: supplied, ...unsigned } = event;
|
|
32
|
-
if (digest(unsigned) !== supplied)
|
|
33
|
-
throw new Error(`Ledger event digest mismatch: ${event.id}`);
|
|
34
|
-
return event;
|
|
35
|
-
};
|
|
36
|
-
export const createLedgerEvent = (task, parentDigest, actor, recordedAt = new Date().toISOString(), id = randomUUID()) => {
|
|
37
|
-
assertSafeTaskId(task.id);
|
|
38
|
-
if (!actor.trim() || !iso(recordedAt) || !taskIdPattern.test(id))
|
|
39
|
-
throw new Error("Invalid ledger event metadata");
|
|
40
|
-
validateState({ schemaVersion: 4, tasks: { [task.id]: task }, archive: {} });
|
|
41
|
-
const unsigned = { schemaVersion: 1, id, taskId: task.id, parentDigest, actor, recordedAt, snapshot: task };
|
|
42
|
-
return { ...unsigned, digest: digest(unsigned) };
|
|
43
|
-
};
|
|
44
|
-
export const loadTaskLedger = (root, taskId) => {
|
|
45
|
-
assertSafeTaskId(taskId);
|
|
46
|
-
const directory = taskEventsPath(root, taskId);
|
|
47
|
-
if (!existsSync(directory))
|
|
48
|
-
return [];
|
|
49
|
-
if (lstatSync(directory).isSymbolicLink())
|
|
50
|
-
throw new Error(`Ledger path crosses a symlink: ${taskId}`);
|
|
51
|
-
const events = readdirSync(directory, { withFileTypes: true })
|
|
52
|
-
.filter((entry) => entry.isFile() && entry.name.endsWith(".json"))
|
|
53
|
-
.map((entry) => validateLedgerEvent(JSON.parse(readFileSync(join(directory, entry.name), "utf8"))))
|
|
54
|
-
.sort((left, right) => left.id.localeCompare(right.id));
|
|
55
|
-
if (events.some((event) => event.taskId !== taskId))
|
|
56
|
-
throw new Error(`Ledger event is in the wrong task directory: ${taskId}`);
|
|
57
|
-
return events;
|
|
58
|
-
};
|
|
59
|
-
export const reduceTaskLedger = (events) => {
|
|
60
|
-
if (!events.length)
|
|
61
|
-
return undefined;
|
|
62
|
-
const byDigest = new Map(events.map((event) => [event.digest, event]));
|
|
63
|
-
if (byDigest.size !== events.length)
|
|
64
|
-
throw new Error("Duplicate ledger event digest");
|
|
65
|
-
const roots = events.filter((event) => event.parentDigest === null);
|
|
66
|
-
if (roots.length !== 1)
|
|
67
|
-
throw new Error("Ledger must have exactly one root event");
|
|
68
|
-
const children = new Map();
|
|
69
|
-
for (const event of events)
|
|
70
|
-
if (event.parentDigest) {
|
|
71
|
-
if (!byDigest.has(event.parentDigest))
|
|
72
|
-
throw new Error(`Ledger event has unknown parent: ${event.id}`);
|
|
73
|
-
const siblings = children.get(event.parentDigest) ?? [];
|
|
74
|
-
siblings.push(event);
|
|
75
|
-
children.set(event.parentDigest, siblings);
|
|
76
|
-
}
|
|
77
|
-
const sibling = [...children.values()].find((items) => items.length > 1);
|
|
78
|
-
if (sibling)
|
|
79
|
-
throw new Error(`Concurrent ledger events require resolution: ${sibling.map((event) => event.id).join(", ")}`);
|
|
80
|
-
const visited = new Set();
|
|
81
|
-
let current = roots[0];
|
|
82
|
-
while (true) {
|
|
83
|
-
if (visited.has(current.digest))
|
|
84
|
-
throw new Error("Ledger event cycle");
|
|
85
|
-
visited.add(current.digest);
|
|
86
|
-
const next = children.get(current.digest) ?? [];
|
|
87
|
-
if (!next.length)
|
|
88
|
-
break;
|
|
89
|
-
current = next[0];
|
|
90
|
-
}
|
|
91
|
-
if (visited.size !== events.length)
|
|
92
|
-
throw new Error("Ledger contains disconnected events");
|
|
93
|
-
return { task: current.snapshot, headDigest: current.digest };
|
|
94
|
-
};
|
|
95
|
-
export const loadTrackedState = (root) => {
|
|
96
|
-
const directory = trackedTasksPath(root);
|
|
97
|
-
if (!existsSync(directory))
|
|
98
|
-
return undefined;
|
|
99
|
-
if (lstatSync(directory).isSymbolicLink())
|
|
100
|
-
throw new Error("Tracked ledger path crosses a symlink");
|
|
101
|
-
const tasks = {};
|
|
102
|
-
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
103
|
-
if (!entry.isDirectory() || !taskIdPattern.test(entry.name))
|
|
104
|
-
continue;
|
|
105
|
-
const reduced = reduceTaskLedger(loadTaskLedger(root, entry.name));
|
|
106
|
-
if (reduced)
|
|
107
|
-
tasks[entry.name] = reduced.task;
|
|
108
|
-
}
|
|
109
|
-
return validateState({ schemaVersion: 4, tasks, archive: {} });
|
|
110
|
-
};
|
|
111
|
-
export const appendTaskLedgerEvent = (root, task, actor) => {
|
|
112
|
-
const current = reduceTaskLedger(loadTaskLedger(root, task.id));
|
|
113
|
-
const event = createLedgerEvent(task, current?.headDigest ?? null, actor);
|
|
114
|
-
const path = eventPath(root, event);
|
|
115
|
-
if (existsSync(path))
|
|
116
|
-
throw new Error(`Ledger event already exists: ${event.id}`);
|
|
117
|
-
atomicWrite(path, eventContent(event));
|
|
118
|
-
return event;
|
|
119
|
-
};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { ArchivedTaskSummary, Gate, HandoffKind, Phase, TaskState, WorkflowState } from "../model.js";
|
|
2
|
-
export declare const statePath: (root: string) => string;
|
|
3
|
-
export declare const lessonIndexPath: (root: string) => string;
|
|
4
|
-
export declare const memoryRegistryPath: (root: string) => string;
|
|
5
|
-
export declare const stateLockPath: (root: string) => string;
|
|
6
|
-
export declare const stateLockGuardPath: (root: string) => string;
|
|
7
|
-
export declare const emptyState: () => WorkflowState;
|
|
8
|
-
export declare const legacyG2WaitSource = "schema-v4-migration";
|
|
9
|
-
export declare const phases: Phase[];
|
|
10
|
-
export declare const gates: Gate[];
|
|
11
|
-
export declare const handoffKinds: HandoffKind[];
|
|
12
|
-
export declare const terminal: (task: TaskState) => boolean;
|
|
13
|
-
export declare const phaseGate: (phase: Phase) => Gate;
|
|
14
|
-
export declare const iso: (value: unknown) => value is string;
|
|
15
|
-
export declare const text: (value: unknown) => value is string;
|
|
16
|
-
export declare const idPattern: RegExp;
|
|
17
|
-
export declare const digest: (content: string) => string;
|
|
18
|
-
export declare const archiveRecordPath: (id: string) => string;
|
|
19
|
-
export declare const taskRecordContent: (task: TaskState) => string;
|
|
20
|
-
export declare const assertNoSymlinkPath: (root: string, relative: string) => void;
|
|
21
|
-
export declare const writeAtomic: (path: string, content: string) => void;
|
|
22
|
-
export declare const parseJsonText: (content: string, label: string, recovery?: string) => unknown;
|
|
23
|
-
export declare const parseJsonFile: (path: string, label: string, recovery?: string) => unknown;
|
|
24
|
-
export declare const audited: (reason: string, source: string) => void;
|
|
25
|
-
export declare const tokens: (value: string) => string[];
|
|
26
|
-
/** Rejects artifact paths that escape the project-owned tasks directory. */
|
|
27
|
-
export declare const assertTaskArtifactPath: (id: string, path: string) => void;
|
|
28
|
-
/** Builds the immutable archive-catalog summary for a terminal task from its record content. */
|
|
29
|
-
export declare const archivedSummary: (task: TaskState, content?: string) => ArchivedTaskSummary;
|
package/dist/src/state/shared.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { dirname, isAbsolute, join, normalize, resolve } from "node:path";
|
|
4
|
-
import { resolveProjectPathWithoutSymlinks } from "../project-path.js";
|
|
5
|
-
export const statePath = (root) => join(resolve(root), ".agents/data/state/aidlc-state.json");
|
|
6
|
-
export const lessonIndexPath = (root) => join(resolve(root), ".agents/data/lessons/index.json");
|
|
7
|
-
export const memoryRegistryPath = (root) => join(resolve(root), ".agents/data/memory/agentic-memory.json");
|
|
8
|
-
export const stateLockPath = (root) => join(resolve(root), ".agents/data/state/.aidlc-state.lock");
|
|
9
|
-
export const stateLockGuardPath = (root) => join(resolve(root), ".agents/data/state/.aidlc-state.lock.guard");
|
|
10
|
-
export const emptyState = () => ({ schemaVersion: 4, tasks: {}, archive: {} });
|
|
11
|
-
export const legacyG2WaitSource = "schema-v4-migration";
|
|
12
|
-
export const phases = ["clarify", "plan", "build", "wrap", "done"];
|
|
13
|
-
export const gates = ["none", "G0_confirm", "G1_review", "G2_codereview"];
|
|
14
|
-
export const handoffKinds = ["repair_exhausted", "review_exhausted", "g2_failed", "release_failed", "structural_change", "other"];
|
|
15
|
-
export const terminal = (task) => task.status === "done" || task.status === "closed" || task.status === "superseded";
|
|
16
|
-
export const phaseGate = (phase) => phase === "clarify" ? "G0_confirm" : phase === "plan" ? "G1_review" : phase === "build" ? "G2_codereview" : "none";
|
|
17
|
-
export const iso = (value) => typeof value === "string" && Number.isFinite(Date.parse(value)) && new Date(Date.parse(value)).toISOString() === value;
|
|
18
|
-
export const text = (value) => typeof value === "string" && Boolean(value.trim());
|
|
19
|
-
export const idPattern = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
20
|
-
export const digest = (content) => createHash("sha256").update(content).digest("hex");
|
|
21
|
-
export const archiveRecordPath = (id) => `.agents/data/state/archive/${id}.json`;
|
|
22
|
-
export const taskRecordContent = (task) => `${JSON.stringify(task, null, 2)}\n`;
|
|
23
|
-
export const assertNoSymlinkPath = (root, relative) => {
|
|
24
|
-
resolveProjectPathWithoutSymlinks(root, relative, "Unsafe state path", "State path crosses a symlink");
|
|
25
|
-
};
|
|
26
|
-
export const writeAtomic = (path, content) => {
|
|
27
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
28
|
-
const temporary = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
29
|
-
writeFileSync(temporary, content, "utf8");
|
|
30
|
-
renameSync(temporary, path);
|
|
31
|
-
};
|
|
32
|
-
export const parseJsonText = (content, label, recovery = "") => {
|
|
33
|
-
try {
|
|
34
|
-
return JSON.parse(content);
|
|
35
|
-
}
|
|
36
|
-
catch (error) {
|
|
37
|
-
throw new Error(`${label} is corrupted or unreadable: ${error instanceof Error ? error.message : String(error)}${recovery ? `; ${recovery}` : ""}`);
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
export const parseJsonFile = (path, label, recovery = "") => parseJsonText(readFileSync(path, "utf8"), label, recovery);
|
|
41
|
-
export const audited = (reason, source) => {
|
|
42
|
-
if (!text(reason) || !text(source))
|
|
43
|
-
throw new Error("Lifecycle mutation requires non-empty --reason and --source");
|
|
44
|
-
};
|
|
45
|
-
export const tokens = (value) => [...new Set(value.toLocaleLowerCase().split(/[^\p{L}\p{N}]+/u).filter((item) => item.length > 1))];
|
|
46
|
-
/** Rejects artifact paths that escape the project-owned tasks directory. */
|
|
47
|
-
export const assertTaskArtifactPath = (id, path) => {
|
|
48
|
-
const separator = process.platform === "win32" ? "\\" : "/";
|
|
49
|
-
const cleaned = normalize(path);
|
|
50
|
-
if (isAbsolute(cleaned) || cleaned === ".." || cleaned.startsWith(`..${separator}`) || !cleaned.startsWith(`.agents${separator}data${separator}tasks${separator}`)) {
|
|
51
|
-
throw new Error(`Invalid artifact path for ${id}: ${path}`);
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
/** Builds the immutable archive-catalog summary for a terminal task from its record content. */
|
|
55
|
-
export const archivedSummary = (task, content = taskRecordContent(task)) => ({
|
|
56
|
-
id: task.id,
|
|
57
|
-
title: task.title,
|
|
58
|
-
type: task.type,
|
|
59
|
-
phase: task.phase,
|
|
60
|
-
gate: task.gate,
|
|
61
|
-
status: task.status,
|
|
62
|
-
risk: task.risk,
|
|
63
|
-
areas: task.areas,
|
|
64
|
-
record: archiveRecordPath(task.id),
|
|
65
|
-
digest: digest(content),
|
|
66
|
-
lessonCount: task.lessons?.length ?? 0,
|
|
67
|
-
predecessorTaskId: task.predecessorTaskId,
|
|
68
|
-
successorTaskId: task.successorTaskId,
|
|
69
|
-
createdAt: task.createdAt,
|
|
70
|
-
updatedAt: task.updatedAt
|
|
71
|
-
});
|
package/dist/src/tracker.d.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Backlog tracker integration: resolves tracker credentials from the environment
|
|
3
|
-
* and builds the HTTP requests used to mirror lifecycle phase transitions.
|
|
4
|
-
*/
|
|
5
|
-
import type { TrackerConfig } from "./model.js";
|
|
6
|
-
export interface TrackerDiagnostic {
|
|
7
|
-
code: "TRACKER_DISABLED" | "TRACKER_AUTH" | "TRACKER_RATE_LIMIT" | "TRACKER_REQUEST";
|
|
8
|
-
message: string;
|
|
9
|
-
retryable: boolean;
|
|
10
|
-
}
|
|
11
|
-
export interface BacklogRequest {
|
|
12
|
-
method: "GET" | "PATCH";
|
|
13
|
-
path: string;
|
|
14
|
-
form?: Record<string, string | number>;
|
|
15
|
-
}
|
|
16
|
-
export type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
|
|
17
|
-
export type TrackerResolution = {
|
|
18
|
-
enabled: false;
|
|
19
|
-
diagnostic: TrackerDiagnostic;
|
|
20
|
-
} | {
|
|
21
|
-
enabled: true;
|
|
22
|
-
config: TrackerConfig;
|
|
23
|
-
token: string;
|
|
24
|
-
};
|
|
25
|
-
/** Resolves a tracker configuration into either an enabled resolution (with token) or a disabled diagnostic. */
|
|
26
|
-
export declare const resolveTracker: (config: TrackerConfig | undefined, environment?: NodeJS.ProcessEnv) => TrackerResolution;
|
|
27
|
-
/** Executes a single Backlog request, mapping HTTP failures to retryable diagnostics. */
|
|
28
|
-
export declare const executeBacklog: (resolution: TrackerResolution, request: BacklogRequest, fetcher?: FetchLike) => Promise<{
|
|
29
|
-
ok: true;
|
|
30
|
-
body: unknown;
|
|
31
|
-
} | {
|
|
32
|
-
ok: false;
|
|
33
|
-
diagnostic: TrackerDiagnostic;
|
|
34
|
-
}>;
|
|
35
|
-
/** Builds the Backlog PATCH request that mirrors a lifecycle phase transition for an issue. */
|
|
36
|
-
export declare const gateUpdate: (config: TrackerConfig, issue: string, phase: "clarify" | "plan" | "build" | "wrap" | "done", idempotencyKey: string) => BacklogRequest;
|
package/dist/src/tracker.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/** Resolves a tracker configuration into either an enabled resolution (with token) or a disabled diagnostic. */
|
|
2
|
-
export const resolveTracker = (config, environment = process.env) => {
|
|
3
|
-
if (!config)
|
|
4
|
-
return { enabled: false, diagnostic: { code: "TRACKER_DISABLED", message: "Tracker is not configured; Git-only mode is active.", retryable: false } };
|
|
5
|
-
const token = environment[config.tokenEnv];
|
|
6
|
-
if (!token)
|
|
7
|
-
return { enabled: false, diagnostic: { code: "TRACKER_DISABLED", message: `Backlog tracker is disabled because ${config.tokenEnv} is unavailable.`, retryable: false } };
|
|
8
|
-
return { enabled: true, config, token };
|
|
9
|
-
};
|
|
10
|
-
const form = (values) => {
|
|
11
|
-
const body = new URLSearchParams();
|
|
12
|
-
for (const [key, value] of Object.entries(values))
|
|
13
|
-
body.set(key, String(value));
|
|
14
|
-
return body;
|
|
15
|
-
};
|
|
16
|
-
/** Executes a single Backlog request, mapping HTTP failures to retryable diagnostics. */
|
|
17
|
-
export const executeBacklog = async (resolution, request, fetcher = fetch) => {
|
|
18
|
-
if (!resolution.enabled)
|
|
19
|
-
return { ok: false, diagnostic: resolution.diagnostic };
|
|
20
|
-
const response = await fetcher(`${resolution.config.spaceUrl}/api/v2/${request.path.replace(/^\//, "")}`, {
|
|
21
|
-
method: request.method,
|
|
22
|
-
headers: { Authorization: `Bearer ${resolution.token}`, ...(request.form ? { "Content-Type": "application/x-www-form-urlencoded" } : {}) },
|
|
23
|
-
body: request.form ? form(request.form) : undefined
|
|
24
|
-
});
|
|
25
|
-
if (response.status === 401)
|
|
26
|
-
return { ok: false, diagnostic: { code: "TRACKER_AUTH", message: "Backlog authentication failed; Git state was not changed.", retryable: false } };
|
|
27
|
-
if (response.status === 429)
|
|
28
|
-
return { ok: false, diagnostic: { code: "TRACKER_RATE_LIMIT", message: "Backlog rate limit reached; retry after the provider reset window.", retryable: true } };
|
|
29
|
-
if (!response.ok)
|
|
30
|
-
return { ok: false, diagnostic: { code: "TRACKER_REQUEST", message: `Backlog request failed with HTTP ${response.status}.`, retryable: response.status >= 500 } };
|
|
31
|
-
return { ok: true, body: await response.json() };
|
|
32
|
-
};
|
|
33
|
-
/** Builds the Backlog PATCH request that mirrors a lifecycle phase transition for an issue. */
|
|
34
|
-
export const gateUpdate = (config, issue, phase, idempotencyKey) => {
|
|
35
|
-
const comment = `[aidlc:${idempotencyKey}] ${phase}`;
|
|
36
|
-
if (config.workflow === "waterfall") {
|
|
37
|
-
const statusId = config.mapping.statuses?.[phase];
|
|
38
|
-
if (!statusId)
|
|
39
|
-
throw new Error(`Backlog status mapping is required for Waterfall phase: ${phase}`);
|
|
40
|
-
return { method: "PATCH", path: `issues/${issue}`, form: { statusId, comment } };
|
|
41
|
-
}
|
|
42
|
-
const field = config.mapping.gateFieldId;
|
|
43
|
-
return { method: "PATCH", path: `issues/${issue}`, form: { ...(field ? { [`customField_${field}`]: phase } : {}), comment } };
|
|
44
|
-
};
|
|
File without changes
|