@rasensio/aidlc 1.3.0 → 1.5.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/dist/commands/claim.d.ts +8 -6
- package/dist/commands/claim.d.ts.map +1 -1
- package/dist/commands/claim.js +49 -41
- package/dist/commands/claim.js.map +1 -1
- package/dist/commands/gate.d.ts.map +1 -1
- package/dist/commands/gate.js +17 -0
- package/dist/commands/gate.js.map +1 -1
- package/dist/commands/init.js +13 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +145 -4
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +109 -3
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/transition.d.ts.map +1 -1
- package/dist/commands/transition.js +39 -2
- package/dist/commands/transition.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +13 -0
- package/dist/commands/update.js.map +1 -1
- package/dist/concurrency/claim-store.d.ts +44 -0
- package/dist/concurrency/claim-store.d.ts.map +1 -0
- package/dist/concurrency/claim-store.js +273 -0
- package/dist/concurrency/claim-store.js.map +1 -0
- package/dist/concurrency/common-dir.d.ts +25 -0
- package/dist/concurrency/common-dir.d.ts.map +1 -0
- package/dist/concurrency/common-dir.js +81 -0
- package/dist/concurrency/common-dir.js.map +1 -0
- package/dist/concurrency/detect.d.ts +23 -0
- package/dist/concurrency/detect.d.ts.map +1 -0
- package/dist/concurrency/detect.js +59 -0
- package/dist/concurrency/detect.js.map +1 -0
- package/dist/concurrency/gitattributes.d.ts +23 -0
- package/dist/concurrency/gitattributes.d.ts.map +1 -0
- package/dist/concurrency/gitattributes.js +52 -0
- package/dist/concurrency/gitattributes.js.map +1 -0
- package/dist/concurrency/registry.d.ts +48 -0
- package/dist/concurrency/registry.d.ts.map +1 -0
- package/dist/concurrency/registry.js +163 -0
- package/dist/concurrency/registry.js.map +1 -0
- package/dist/concurrency/session-id.d.ts +22 -0
- package/dist/concurrency/session-id.d.ts.map +1 -0
- package/dist/concurrency/session-id.js +35 -0
- package/dist/concurrency/session-id.js.map +1 -0
- package/dist/concurrency/types.d.ts +39 -0
- package/dist/concurrency/types.d.ts.map +1 -0
- package/dist/concurrency/types.js +12 -0
- package/dist/concurrency/types.js.map +1 -0
- package/dist/concurrency/worktree.d.ts +49 -0
- package/dist/concurrency/worktree.d.ts.map +1 -0
- package/dist/concurrency/worktree.js +169 -0
- package/dist/concurrency/worktree.js.map +1 -0
- package/dist/core/gate.d.ts +7 -0
- package/dist/core/gate.d.ts.map +1 -1
- package/dist/core/gate.js.map +1 -1
- package/dist/core/types.d.ts +16 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/cost/ledger.d.ts.map +1 -1
- package/dist/cost/ledger.js +6 -0
- package/dist/cost/ledger.js.map +1 -1
- package/dist/cost/sessions.d.ts +6 -1
- package/dist/cost/sessions.d.ts.map +1 -1
- package/dist/cost/sessions.js +10 -1
- package/dist/cost/sessions.js.map +1 -1
- package/dist/traceability/cache.d.ts +21 -0
- package/dist/traceability/cache.d.ts.map +1 -0
- package/dist/traceability/cache.js +106 -0
- package/dist/traceability/cache.js.map +1 -0
- package/dist/traceability/coverage-block.d.ts +21 -0
- package/dist/traceability/coverage-block.d.ts.map +1 -0
- package/dist/traceability/coverage-block.js +41 -0
- package/dist/traceability/coverage-block.js.map +1 -0
- package/dist/traceability/gate-criterion.d.ts +34 -0
- package/dist/traceability/gate-criterion.d.ts.map +1 -0
- package/dist/traceability/gate-criterion.js +128 -0
- package/dist/traceability/gate-criterion.js.map +1 -0
- package/dist/traceability/matrix.d.ts +35 -0
- package/dist/traceability/matrix.d.ts.map +1 -0
- package/dist/traceability/matrix.js +93 -0
- package/dist/traceability/matrix.js.map +1 -0
- package/dist/traceability/parser.d.ts +27 -0
- package/dist/traceability/parser.d.ts.map +1 -0
- package/dist/traceability/parser.js +101 -0
- package/dist/traceability/parser.js.map +1 -0
- package/dist/traceability/scanner.d.ts +62 -0
- package/dist/traceability/scanner.d.ts.map +1 -0
- package/dist/traceability/scanner.js +198 -0
- package/dist/traceability/scanner.js.map +1 -0
- package/dist/traceability/types.d.ts +77 -0
- package/dist/traceability/types.d.ts.map +1 -0
- package/dist/traceability/types.js +8 -0
- package/dist/traceability/types.js.map +1 -0
- package/package.json +2 -2
- package/dist/commands/setup.d.ts +0 -24
- package/dist/commands/setup.d.ts.map +0 -1
- package/dist/commands/setup.js +0 -262
- package/dist/commands/setup.js.map +0 -1
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Instance registry: cross-worktree instance existence (AC-15, AC-16,
|
|
3
|
+
* AC-24, AC-26).
|
|
4
|
+
*
|
|
5
|
+
* One YAML file per instance under `<common-dir>/aidlc/registry/`.
|
|
6
|
+
* Creation writes with flag 'wx' DIRECTLY on the final path — the atomic
|
|
7
|
+
* exactly-one-success arbiter for racing `aidlc start` calls (AC-24).
|
|
8
|
+
* This is the one deliberate exception to the temp-rename discipline:
|
|
9
|
+
* creation is a single write, and readers tolerate parse failures as
|
|
10
|
+
* absent, so there is no partial-read hazard.
|
|
11
|
+
*
|
|
12
|
+
* The registry is live coordination data, not durable identity (design
|
|
13
|
+
* F5): entries exist from creation until pruned or completed. A merged
|
|
14
|
+
* instance with no entry and no claim is "complete and inactive".
|
|
15
|
+
*/
|
|
16
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync, } from 'node:fs';
|
|
17
|
+
import { join } from 'node:path';
|
|
18
|
+
import { execFileSync } from 'node:child_process';
|
|
19
|
+
import { parse as parseYaml } from 'yaml';
|
|
20
|
+
import { serializeYaml } from '../state/yaml-helpers.js';
|
|
21
|
+
import { coordinationRoot } from './common-dir.js';
|
|
22
|
+
const INSTANCE_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
23
|
+
/** Thrown when a registry entry for the name already exists (AC-24). */
|
|
24
|
+
export class RegistryConflictError extends Error {
|
|
25
|
+
instance;
|
|
26
|
+
constructor(instance) {
|
|
27
|
+
super(`instance '${instance}' already registered in this repository`);
|
|
28
|
+
this.instance = instance;
|
|
29
|
+
this.name = 'RegistryConflictError';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function isEntry(v) {
|
|
33
|
+
if (typeof v !== 'object' || v === null)
|
|
34
|
+
return false;
|
|
35
|
+
const r = v;
|
|
36
|
+
return (typeof r.name === 'string' &&
|
|
37
|
+
(typeof r.branch === 'string' || r.branch === null) &&
|
|
38
|
+
(typeof r.worktree_path === 'string' || r.worktree_path === null) &&
|
|
39
|
+
typeof r.created_at === 'string');
|
|
40
|
+
}
|
|
41
|
+
export class Registry {
|
|
42
|
+
dir;
|
|
43
|
+
projectRoot;
|
|
44
|
+
constructor(dir, projectRoot) {
|
|
45
|
+
this.dir = dir;
|
|
46
|
+
this.projectRoot = projectRoot;
|
|
47
|
+
}
|
|
48
|
+
entryPath(name) {
|
|
49
|
+
if (!INSTANCE_NAME_RE.test(name))
|
|
50
|
+
throw new Error(`invalid instance name: ${name}`);
|
|
51
|
+
return join(this.dir, `${name}.yaml`);
|
|
52
|
+
}
|
|
53
|
+
/** Register a new instance; fails atomically if it exists (AC-24). */
|
|
54
|
+
register(entry) {
|
|
55
|
+
mkdirSync(this.dir, { recursive: true });
|
|
56
|
+
try {
|
|
57
|
+
writeFileSync(this.entryPath(entry.name), serializeYaml(entry), {
|
|
58
|
+
encoding: 'utf8',
|
|
59
|
+
flag: 'wx',
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
if (err.code === 'EEXIST') {
|
|
64
|
+
throw new RegistryConflictError(entry.name);
|
|
65
|
+
}
|
|
66
|
+
throw err;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
lookup(name) {
|
|
70
|
+
try {
|
|
71
|
+
const data = parseYaml(readFileSync(this.entryPath(name), 'utf8'));
|
|
72
|
+
return isEntry(data) ? data : null;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
list() {
|
|
79
|
+
let files;
|
|
80
|
+
try {
|
|
81
|
+
files = readdirSync(this.dir);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
const entries = [];
|
|
87
|
+
for (const f of files) {
|
|
88
|
+
if (!f.endsWith('.yaml'))
|
|
89
|
+
continue;
|
|
90
|
+
const entry = this.lookup(f.slice(0, -'.yaml'.length));
|
|
91
|
+
if (entry)
|
|
92
|
+
entries.push(entry);
|
|
93
|
+
}
|
|
94
|
+
return entries;
|
|
95
|
+
}
|
|
96
|
+
/** Remove an entry (AC-17 completion cleanup). Missing entry is a no-op. */
|
|
97
|
+
remove(name) {
|
|
98
|
+
try {
|
|
99
|
+
unlinkSync(this.entryPath(name));
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
if (err.code !== 'ENOENT')
|
|
103
|
+
throw err;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/** True when `branch` is merged into main (AC-26). */
|
|
107
|
+
isMerged(branch) {
|
|
108
|
+
try {
|
|
109
|
+
execFileSync('git', ['merge-base', '--is-ancestor', branch, 'main'], {
|
|
110
|
+
cwd: this.projectRoot,
|
|
111
|
+
stdio: 'ignore',
|
|
112
|
+
});
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
branchExists(branch) {
|
|
120
|
+
try {
|
|
121
|
+
execFileSync('git', ['show-ref', '--verify', '--quiet', `refs/heads/${branch}`], {
|
|
122
|
+
cwd: this.projectRoot,
|
|
123
|
+
stdio: 'ignore',
|
|
124
|
+
});
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Identify stale entries: worktree path gone AND branch merged or
|
|
133
|
+
* deleted (AC-16). Removal only happens here — explicit prune.
|
|
134
|
+
*/
|
|
135
|
+
prune() {
|
|
136
|
+
const removed = [];
|
|
137
|
+
for (const entry of this.list()) {
|
|
138
|
+
const worktreeGone = entry.worktree_path === null || !existsSync(entry.worktree_path);
|
|
139
|
+
if (!worktreeGone)
|
|
140
|
+
continue;
|
|
141
|
+
if (entry.branch === null)
|
|
142
|
+
continue; // no-code instances are pruned on completion only
|
|
143
|
+
const merged = this.isMerged(entry.branch);
|
|
144
|
+
const deleted = !this.branchExists(entry.branch);
|
|
145
|
+
if (merged || deleted) {
|
|
146
|
+
this.remove(entry.name);
|
|
147
|
+
removed.push({
|
|
148
|
+
name: entry.name,
|
|
149
|
+
reason: merged ? 'worktree gone, branch merged' : 'worktree gone, branch deleted',
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return removed;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/** Open the registry, or null when no writable common dir exists (AC-27). */
|
|
157
|
+
export function openRegistry(projectRoot) {
|
|
158
|
+
const root = coordinationRoot(projectRoot);
|
|
159
|
+
if (root === null)
|
|
160
|
+
return null;
|
|
161
|
+
return new Registry(join(root, 'registry'), projectRoot);
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/concurrency/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable session identity for concurrency detection (design F2).
|
|
3
|
+
*
|
|
4
|
+
* `resolveSession` in commands/claim.ts used to mint a fresh agent UUID
|
|
5
|
+
* per invocation, so a solo agent session could never recognize its own
|
|
6
|
+
* claim and would block itself. Resolution order here:
|
|
7
|
+
*
|
|
8
|
+
* 1. AIDLC_SESSION_ID env var — set once by the agent/skill at session
|
|
9
|
+
* start, reused by every CLI invocation in that session.
|
|
10
|
+
* 2. Platform session from the active-session stash (strict
|
|
11
|
+
* single-candidate rule, unchanged).
|
|
12
|
+
* 3. Process-lifetime cached agent UUID — stable within one process,
|
|
13
|
+
* still fresh across processes (documented limitation for agents that
|
|
14
|
+
* neither stash nor set the env var).
|
|
15
|
+
*/
|
|
16
|
+
export interface SessionIdentity {
|
|
17
|
+
id: string;
|
|
18
|
+
source: 'platform' | 'agent';
|
|
19
|
+
agent: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function resolveSessionIdentity(projectRoot: string): SessionIdentity;
|
|
22
|
+
//# sourceMappingURL=session-id.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-id.d.ts","sourceRoot":"","sources":["../../src/concurrency/session-id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;CACf;AAID,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe,CAa3E"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable session identity for concurrency detection (design F2).
|
|
3
|
+
*
|
|
4
|
+
* `resolveSession` in commands/claim.ts used to mint a fresh agent UUID
|
|
5
|
+
* per invocation, so a solo agent session could never recognize its own
|
|
6
|
+
* claim and would block itself. Resolution order here:
|
|
7
|
+
*
|
|
8
|
+
* 1. AIDLC_SESSION_ID env var — set once by the agent/skill at session
|
|
9
|
+
* start, reused by every CLI invocation in that session.
|
|
10
|
+
* 2. Platform session from the active-session stash (strict
|
|
11
|
+
* single-candidate rule, unchanged).
|
|
12
|
+
* 3. Process-lifetime cached agent UUID — stable within one process,
|
|
13
|
+
* still fresh across processes (documented limitation for agents that
|
|
14
|
+
* neither stash nor set the env var).
|
|
15
|
+
*/
|
|
16
|
+
import { randomUUID } from 'node:crypto';
|
|
17
|
+
import { resolveCurrentSession } from '../cost/sessions.js';
|
|
18
|
+
let processAgentId = null;
|
|
19
|
+
export function resolveSessionIdentity(projectRoot) {
|
|
20
|
+
const envId = process.env.AIDLC_SESSION_ID;
|
|
21
|
+
if (envId && envId.trim() !== '') {
|
|
22
|
+
return {
|
|
23
|
+
id: envId.trim(),
|
|
24
|
+
source: envId.trim().startsWith('agent-') ? 'agent' : 'platform',
|
|
25
|
+
agent: process.env.AIDLC_AGENT ?? 'unknown',
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const active = resolveCurrentSession(projectRoot);
|
|
29
|
+
if (active)
|
|
30
|
+
return { id: active.session_id, source: 'platform', agent: active.agent };
|
|
31
|
+
if (processAgentId === null)
|
|
32
|
+
processAgentId = `agent-${randomUUID()}`;
|
|
33
|
+
return { id: processAgentId, source: 'agent', agent: process.env.AIDLC_AGENT ?? 'unknown' };
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=session-id.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-id.js","sourceRoot":"","sources":["../../src/concurrency/session-id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAQ5D,IAAI,cAAc,GAAkB,IAAI,CAAC;AAEzC,MAAM,UAAU,sBAAsB,CAAC,WAAmB;IACxD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC3C,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACjC,OAAO;YACL,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE;YAChB,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU;YAChE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,SAAS;SAC5C,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,qBAAqB,CAAC,WAAW,CAAC,CAAC;IAClD,IAAI,MAAM;QAAE,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;IACtF,IAAI,cAAc,KAAK,IAAI;QAAE,cAAc,GAAG,SAAS,UAAU,EAAE,EAAE,CAAC;IACtE,OAAO,EAAE,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,SAAS,EAAE,CAAC;AAC9F,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the concurrency module (git-worktree instance).
|
|
3
|
+
*
|
|
4
|
+
* Coordination data lives in `<git-common-dir>/aidlc/` so every worktree
|
|
5
|
+
* of a repository sees the same claims and registry (AC-1, AC-2, AC-15).
|
|
6
|
+
* Durable artifacts stay tracked in git; only live coordination moves here.
|
|
7
|
+
*/
|
|
8
|
+
/** A live claim on an instance (AC-1). Stored per instance, never committed. */
|
|
9
|
+
export interface Claim {
|
|
10
|
+
session: string;
|
|
11
|
+
claimed_at: string;
|
|
12
|
+
renewed_at?: string;
|
|
13
|
+
id_source: 'platform' | 'agent';
|
|
14
|
+
/** Set when the claiming session works in a linked worktree (AC-18b). */
|
|
15
|
+
worktree_path?: string;
|
|
16
|
+
}
|
|
17
|
+
/** A registry entry recording instance existence across worktrees (AC-26). */
|
|
18
|
+
export interface RegistryEntry {
|
|
19
|
+
name: string;
|
|
20
|
+
/** Branch owning the instance; null for no-code instances (AC-11). */
|
|
21
|
+
branch: string | null;
|
|
22
|
+
worktree_path: string | null;
|
|
23
|
+
created_at: string;
|
|
24
|
+
}
|
|
25
|
+
/** Concurrency policy from `.aidlc/config.yaml` (AC-13). */
|
|
26
|
+
export interface ConcurrencyConfig {
|
|
27
|
+
mode: 'offer-worktree' | 'forbid' | 'ask';
|
|
28
|
+
worktree_dir: string;
|
|
29
|
+
}
|
|
30
|
+
export declare const DEFAULT_CONCURRENCY: ConcurrencyConfig;
|
|
31
|
+
/** Result of concurrency detection (AC-7). */
|
|
32
|
+
export interface Detection {
|
|
33
|
+
busy: boolean;
|
|
34
|
+
holders: Array<{
|
|
35
|
+
instance: string;
|
|
36
|
+
session: string;
|
|
37
|
+
}>;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/concurrency/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,gFAAgF;AAChF,MAAM,WAAW,KAAK;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC;IAChC,yEAAyE;IACzE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,8EAA8E;AAC9E,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,4DAA4D;AAC5D,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,gBAAgB,GAAG,QAAQ,GAAG,KAAK,CAAC;IAC1C,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,mBAAmB,EAAE,iBAGjC,CAAC;AAEF,8CAA8C;AAC9C,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACvD"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the concurrency module (git-worktree instance).
|
|
3
|
+
*
|
|
4
|
+
* Coordination data lives in `<git-common-dir>/aidlc/` so every worktree
|
|
5
|
+
* of a repository sees the same claims and registry (AC-1, AC-2, AC-15).
|
|
6
|
+
* Durable artifacts stay tracked in git; only live coordination moves here.
|
|
7
|
+
*/
|
|
8
|
+
export const DEFAULT_CONCURRENCY = {
|
|
9
|
+
mode: 'offer-worktree',
|
|
10
|
+
worktree_dir: '../',
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/concurrency/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA2BH,MAAM,CAAC,MAAM,mBAAmB,GAAsB;IACpD,IAAI,EAAE,gBAAgB;IACtB,YAAY,EAAE,KAAK;CACpB,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git worktree wrappers (AC-9, AC-10, AC-17, NFR-5).
|
|
3
|
+
*
|
|
4
|
+
* `createWorktree` creates branch + worktree in one step, always based on
|
|
5
|
+
* main, so an in-flight session in the primary checkout is never moved
|
|
6
|
+
* off its branch (idea goal 2). Callers export AIDLC_WORKTREE=1 before
|
|
7
|
+
* firing on-instance-start actions so the shipped branch action no-ops
|
|
8
|
+
* (AC-10).
|
|
9
|
+
*
|
|
10
|
+
* Removal order (AC-17, design F6): worktree remove FIRST — the claim is
|
|
11
|
+
* released only after removal succeeds, so a dirty worktree keeps its
|
|
12
|
+
* instance locked.
|
|
13
|
+
*/
|
|
14
|
+
/** Sanitize a path component to [a-z0-9-] (NFR-5). */
|
|
15
|
+
export declare function sanitizeComponent(raw: string): string;
|
|
16
|
+
export interface CreateWorktreeOpts {
|
|
17
|
+
prefix: string;
|
|
18
|
+
name: string;
|
|
19
|
+
worktreeDir: string;
|
|
20
|
+
projectRoot: string;
|
|
21
|
+
/** YYYYMMDD stamp; injectable for tests. */
|
|
22
|
+
dateStamp?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface WorktreeRef {
|
|
25
|
+
branch: string;
|
|
26
|
+
path: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Create branch and worktree in one step, based on main (AC-9). Fails —
|
|
30
|
+
* never reuses — when the branch or target directory already exists (AC-24).
|
|
31
|
+
*/
|
|
32
|
+
export declare function createWorktree(opts: CreateWorktreeOpts): WorktreeRef;
|
|
33
|
+
export interface RemoveReport {
|
|
34
|
+
removedWorktree: boolean;
|
|
35
|
+
deletedBranch: boolean;
|
|
36
|
+
reason?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Remove a worktree and delete its branch iff merged into main (AC-17).
|
|
40
|
+
* A dirty worktree fails removal (no --force) and reports; the caller
|
|
41
|
+
* must NOT release the claim in that case (design F6).
|
|
42
|
+
*/
|
|
43
|
+
export declare function removeWorktree(ref: WorktreeRef, projectRoot: string): RemoveReport;
|
|
44
|
+
/** List worktrees known to git (for status cross-checks, AC-18). */
|
|
45
|
+
export declare function listWorktrees(projectRoot: string): Array<{
|
|
46
|
+
path: string;
|
|
47
|
+
branch: string | null;
|
|
48
|
+
}>;
|
|
49
|
+
//# sourceMappingURL=worktree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../src/concurrency/worktree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,sDAAsD;AACtD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIrD;AA2CD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,WAAW,CAsBpE;AAED,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,WAAW,EAChB,WAAW,EAAE,MAAM,GAClB,YAAY,CA4Cd;AAED,oEAAoE;AACpE,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAmBjG"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git worktree wrappers (AC-9, AC-10, AC-17, NFR-5).
|
|
3
|
+
*
|
|
4
|
+
* `createWorktree` creates branch + worktree in one step, always based on
|
|
5
|
+
* main, so an in-flight session in the primary checkout is never moved
|
|
6
|
+
* off its branch (idea goal 2). Callers export AIDLC_WORKTREE=1 before
|
|
7
|
+
* firing on-instance-start actions so the shipped branch action no-ops
|
|
8
|
+
* (AC-10).
|
|
9
|
+
*
|
|
10
|
+
* Removal order (AC-17, design F6): worktree remove FIRST — the claim is
|
|
11
|
+
* released only after removal succeeds, so a dirty worktree keeps its
|
|
12
|
+
* instance locked.
|
|
13
|
+
*/
|
|
14
|
+
import { existsSync, realpathSync } from 'node:fs';
|
|
15
|
+
import { basename, dirname, join, resolve, sep } from 'node:path';
|
|
16
|
+
import { execFileSync } from 'node:child_process';
|
|
17
|
+
/** Sanitize a path component to [a-z0-9-] (NFR-5). */
|
|
18
|
+
export function sanitizeComponent(raw) {
|
|
19
|
+
const cleaned = raw.toLowerCase().replace(/[^a-z0-9-]+/g, '-').replace(/^-+|-+$/g, '');
|
|
20
|
+
if (cleaned === '')
|
|
21
|
+
throw new Error(`unusable path component: ${raw}`);
|
|
22
|
+
return cleaned;
|
|
23
|
+
}
|
|
24
|
+
function git(args, cwd) {
|
|
25
|
+
return execFileSync('git', args, {
|
|
26
|
+
cwd,
|
|
27
|
+
encoding: 'utf8',
|
|
28
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
29
|
+
}).trim();
|
|
30
|
+
}
|
|
31
|
+
/** Resolve symlinks on the deepest existing ancestor of `p` (design F8). */
|
|
32
|
+
function realResolve(p) {
|
|
33
|
+
let probe = resolve(p);
|
|
34
|
+
const tail = [];
|
|
35
|
+
while (!existsSync(probe)) {
|
|
36
|
+
tail.unshift(basename(probe));
|
|
37
|
+
const parent = dirname(probe);
|
|
38
|
+
if (parent === probe)
|
|
39
|
+
break;
|
|
40
|
+
probe = parent;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
probe = realpathSync(probe);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// keep resolved path
|
|
47
|
+
}
|
|
48
|
+
return tail.length > 0 ? join(probe, ...tail) : probe;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Traversal guard (design F8): the worktree target must not live inside
|
|
52
|
+
* the project root or inside any `.git` directory.
|
|
53
|
+
*/
|
|
54
|
+
function assertSafeTarget(target, projectRoot) {
|
|
55
|
+
const realTarget = realResolve(target);
|
|
56
|
+
const realRoot = realResolve(projectRoot);
|
|
57
|
+
if (realTarget === realRoot || realTarget.startsWith(realRoot + sep)) {
|
|
58
|
+
throw new Error(`worktree target ${target} resolves inside the project root`);
|
|
59
|
+
}
|
|
60
|
+
if (realTarget.split(sep).includes('.git')) {
|
|
61
|
+
throw new Error(`worktree target ${target} resolves inside a .git directory`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Create branch and worktree in one step, based on main (AC-9). Fails —
|
|
66
|
+
* never reuses — when the branch or target directory already exists (AC-24).
|
|
67
|
+
*/
|
|
68
|
+
export function createWorktree(opts) {
|
|
69
|
+
const stamp = opts.dateStamp ?? new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
|
70
|
+
const name = sanitizeComponent(opts.name);
|
|
71
|
+
const repo = sanitizeComponent(basename(realResolve(opts.projectRoot)));
|
|
72
|
+
const branch = `${opts.prefix}/${stamp}-${name}`;
|
|
73
|
+
const target = resolve(opts.projectRoot, opts.worktreeDir, `${repo}-${name}`);
|
|
74
|
+
assertSafeTarget(target, opts.projectRoot);
|
|
75
|
+
if (existsSync(target)) {
|
|
76
|
+
throw new Error(`worktree target already exists: ${target}`);
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
git(['show-ref', '--verify', '--quiet', `refs/heads/${branch}`], opts.projectRoot);
|
|
80
|
+
throw new Error(`branch already exists: ${branch}`);
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
if (err.message.startsWith('branch already exists'))
|
|
84
|
+
throw err;
|
|
85
|
+
// show-ref failed → branch does not exist, proceed
|
|
86
|
+
}
|
|
87
|
+
git(['worktree', 'add', '-b', branch, target, 'main'], opts.projectRoot);
|
|
88
|
+
return { branch, path: target };
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Remove a worktree and delete its branch iff merged into main (AC-17).
|
|
92
|
+
* A dirty worktree fails removal (no --force) and reports; the caller
|
|
93
|
+
* must NOT release the claim in that case (design F6).
|
|
94
|
+
*/
|
|
95
|
+
export function removeWorktree(ref, projectRoot) {
|
|
96
|
+
if (existsSync(ref.path)) {
|
|
97
|
+
try {
|
|
98
|
+
git(['worktree', 'remove', ref.path], projectRoot);
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
return {
|
|
102
|
+
removedWorktree: false,
|
|
103
|
+
deletedBranch: false,
|
|
104
|
+
reason: `worktree not removed (dirty or locked): ${err.message.split('\n')[0]}`,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
// Directory already gone (manual removal) — let git drop the stale record.
|
|
110
|
+
try {
|
|
111
|
+
git(['worktree', 'prune'], projectRoot);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// non-fatal
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
let merged = false;
|
|
118
|
+
try {
|
|
119
|
+
git(['merge-base', '--is-ancestor', ref.branch, 'main'], projectRoot);
|
|
120
|
+
merged = true;
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
merged = false;
|
|
124
|
+
}
|
|
125
|
+
if (!merged) {
|
|
126
|
+
return {
|
|
127
|
+
removedWorktree: true,
|
|
128
|
+
deletedBranch: false,
|
|
129
|
+
reason: `branch ${ref.branch} is not merged into main — left in place`,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
git(['branch', '-d', ref.branch], projectRoot);
|
|
134
|
+
return { removedWorktree: true, deletedBranch: true };
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
return {
|
|
138
|
+
removedWorktree: true,
|
|
139
|
+
deletedBranch: false,
|
|
140
|
+
reason: `branch not deleted: ${err.message.split('\n')[0]}`,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/** List worktrees known to git (for status cross-checks, AC-18). */
|
|
145
|
+
export function listWorktrees(projectRoot) {
|
|
146
|
+
let out;
|
|
147
|
+
try {
|
|
148
|
+
out = git(['worktree', 'list', '--porcelain'], projectRoot);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
const result = [];
|
|
154
|
+
let current = null;
|
|
155
|
+
for (const line of out.split('\n')) {
|
|
156
|
+
if (line.startsWith('worktree ')) {
|
|
157
|
+
if (current)
|
|
158
|
+
result.push(current);
|
|
159
|
+
current = { path: line.slice('worktree '.length), branch: null };
|
|
160
|
+
}
|
|
161
|
+
else if (line.startsWith('branch ') && current) {
|
|
162
|
+
current.branch = line.slice('branch refs/heads/'.length);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (current)
|
|
166
|
+
result.push(current);
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=worktree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../src/concurrency/worktree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,sDAAsD;AACtD,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,MAAM,OAAO,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IACvF,IAAI,OAAO,KAAK,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,GAAG,EAAE,CAAC,CAAC;IACvE,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,GAAG,CAAC,IAAc,EAAE,GAAW;IACtC,OAAO,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE;QAC/B,GAAG;QACH,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;KAClC,CAAC,CAAC,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,4EAA4E;AAC5E,SAAS,WAAW,CAAC,CAAS;IAC5B,IAAI,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACvB,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9B,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,MAAM,KAAK,KAAK;YAAE,MAAM;QAC5B,KAAK,GAAG,MAAM,CAAC;IACjB,CAAC;IACD,IAAI,CAAC;QACH,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,qBAAqB;IACvB,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AACxD,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CAAC,MAAc,EAAE,WAAmB;IAC3D,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;IAC1C,IAAI,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,UAAU,CAAC,QAAQ,GAAG,GAAG,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,mCAAmC,CAAC,CAAC;IAChF,CAAC;IACD,IAAI,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,mCAAmC,CAAC,CAAC;IAChF,CAAC;AACH,CAAC;AAgBD;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAwB;IACrD,MAAM,KAAK,GACT,IAAI,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC5E,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,iBAAiB,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IACxE,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;IACjD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;IAE9E,gBAAgB,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAC3C,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,mCAAmC,MAAM,EAAE,CAAC,CAAC;IAC/D,CAAC;IACD,IAAI,CAAC;QACH,GAAG,CAAC,CAAC,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,cAAc,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACnF,MAAM,IAAI,KAAK,CAAC,0BAA0B,MAAM,EAAE,CAAC,CAAC;IACtD,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,IAAK,GAAa,CAAC,OAAO,CAAC,UAAU,CAAC,uBAAuB,CAAC;YAAE,MAAM,GAAG,CAAC;QAC1E,mDAAmD;IACrD,CAAC;IAED,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IACzE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAClC,CAAC;AAQD;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,GAAgB,EAChB,WAAmB;IAEnB,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,GAAG,CAAC,CAAC,UAAU,EAAE,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,CAAC;QACrD,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,OAAO;gBACL,eAAe,EAAE,KAAK;gBACtB,aAAa,EAAE,KAAK;gBACpB,MAAM,EAAE,2CAA4C,GAAa,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;aAC3F,CAAC;QACJ,CAAC;IACH,CAAC;SAAM,CAAC;QACN,2EAA2E;QAC3E,IAAI,CAAC;YACH,GAAG,CAAC,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE,WAAW,CAAC,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,YAAY;QACd,CAAC;IACH,CAAC;IAED,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,CAAC;QACH,GAAG,CAAC,CAAC,YAAY,EAAE,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC;QACtE,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,GAAG,KAAK,CAAC;IACjB,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;YACL,eAAe,EAAE,IAAI;YACrB,aAAa,EAAE,KAAK;YACpB,MAAM,EAAE,UAAU,GAAG,CAAC,MAAM,0CAA0C;SACvE,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,GAAG,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC;QAC/C,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;IACxD,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,OAAO;YACL,eAAe,EAAE,IAAI;YACrB,aAAa,EAAE,KAAK;YACpB,MAAM,EAAE,uBAAwB,GAAa,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;SACvE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,aAAa,CAAC,WAAmB;IAC/C,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,GAAG,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,WAAW,CAAC,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,MAAM,GAAmD,EAAE,CAAC;IAClE,IAAI,OAAO,GAAmD,IAAI,CAAC;IACnE,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,IAAI,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YACjC,IAAI,OAAO;gBAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAClC,OAAO,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QACnE,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,OAAO,EAAE,CAAC;YACjD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IACD,IAAI,OAAO;QAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAClC,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/core/gate.d.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* Requirements: 9.1, 9.6
|
|
9
9
|
*/
|
|
10
10
|
import type { PhaseState, WorkflowTemplate } from './types.js';
|
|
11
|
+
import type { TraceabilityResult } from '../traceability/types.js';
|
|
11
12
|
/**
|
|
12
13
|
* Gate check result for CI/CD integration.
|
|
13
14
|
*/
|
|
@@ -20,6 +21,12 @@ export interface GateCheckResult {
|
|
|
20
21
|
missingArtifacts: string[];
|
|
21
22
|
/** Unsatisfied exit criteria descriptions (empty if pass). */
|
|
22
23
|
unsatisfiedCriteria: string[];
|
|
24
|
+
/**
|
|
25
|
+
* AC coverage matrix — present only when the traceability criterion
|
|
26
|
+
* evaluated (testing phase, AC-bearing instance). Attached at the command
|
|
27
|
+
* layer; evaluateGate itself never sets it (traceability-ids AC-15).
|
|
28
|
+
*/
|
|
29
|
+
traceability?: TraceabilityResult;
|
|
23
30
|
}
|
|
24
31
|
/**
|
|
25
32
|
* Evaluate whether a phase passes its gate check.
|
package/dist/core/gate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../src/core/gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAiB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../src/core/gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAiB,MAAM,YAAY,CAAC;AAC9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAMnE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,mDAAmD;IACnD,IAAI,EAAE,OAAO,CAAC;IACd,0BAA0B;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,8DAA8D;IAC9D,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B;;;;OAIG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAC;CACnC;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EACpC,QAAQ,EAAE,gBAAgB,GACzB,eAAe,CAiCjB"}
|
package/dist/core/gate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../../src/core/gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../../src/core/gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA6BH,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E;;;;;;;;;;GAUG;AACH,MAAM,UAAU,YAAY,CAC1B,SAAiB,EACjB,WAAoC,EACpC,QAA0B;IAE1B,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAEzC,2BAA2B;IAC3B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO;YACL,IAAI,EAAE,KAAK;YACX,KAAK,EAAE,SAAS;YAChB,gBAAgB,EAAE,EAAE;YACpB,mBAAmB,EAAE,CAAC,mCAAmC,CAAC;SAC3D,CAAC;IACJ,CAAC;IAED,kCAAkC;IAClC,IAAI,KAAK,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QAChC,OAAO;YACL,IAAI,EAAE,IAAI;YACV,KAAK,EAAE,SAAS;YAChB,gBAAgB,EAAE,EAAE;YACpB,mBAAmB,EAAE,EAAE;SACxB,CAAC;IACJ,CAAC;IAED,yEAAyE;IACzE,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;IACzE,MAAM,mBAAmB,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAAC;IAE1D,OAAO;QACL,IAAI,EAAE,KAAK;QACX,KAAK,EAAE,SAAS;QAChB,gBAAgB;QAChB,mBAAmB;KACpB,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;;GAGG;AACH,SAAS,mBAAmB,CAC1B,SAAiB,EACjB,KAAiB,EACjB,QAA0B;IAE1B,qCAAqC;IACrC,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CACxC,CAAC,CAAgB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAC3C,CAAC;IAEF,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,6EAA6E;QAC7E,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,mEAAmE;IACnE,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAChC,KAAK,CAAC,SAAS;SACZ,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC;SACtC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CACtB,CAAC;IAEF,gDAAgD;IAChD,OAAO,aAAa,CAAC,kBAAkB;SACpC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;SACpD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,SAAS,sBAAsB,CAAC,KAAiB;IAC/C,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,QAAQ,KAAK,CAAC,MAAM,EAAE,CAAC;QACrB,KAAK,SAAS;YACZ,QAAQ,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;YAC9D,MAAM;QACR,KAAK,aAAa;YAChB,QAAQ,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;YAClE,MAAM;QACR,KAAK,SAAS;YACZ,QAAQ,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;YACrD,MAAM;QACR;YACE,QAAQ,CAAC,IAAI,CAAC,oBAAoB,KAAK,CAAC,MAAM,wBAAwB,CAAC,CAAC;IAC5E,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -207,6 +207,12 @@ export interface InstanceState {
|
|
|
207
207
|
claim: InstanceClaim | null;
|
|
208
208
|
/** History of scope upgrades. */
|
|
209
209
|
scope_history: ScopeUpgrade[];
|
|
210
|
+
/**
|
|
211
|
+
* Branch owning this instance's code changes (git-worktree AC-11).
|
|
212
|
+
* Explicit null = no-code instance, blocks implementation entry.
|
|
213
|
+
* Absent = pre-worktree instance, legacy-allowed (design F3).
|
|
214
|
+
*/
|
|
215
|
+
branch?: string | null;
|
|
210
216
|
}
|
|
211
217
|
/** Compact summary returned by listInstances(). */
|
|
212
218
|
export interface InstanceSummary {
|
|
@@ -219,6 +225,15 @@ export interface InstanceSummary {
|
|
|
219
225
|
stalled: boolean;
|
|
220
226
|
/** Formatted cost from the instance ledger ("$1.23", raw units, or "-"). */
|
|
221
227
|
cost?: string;
|
|
228
|
+
/**
|
|
229
|
+
* AC coverage for AC-bearing instances in testing or later; omitted when
|
|
230
|
+
* the traceability criterion does not apply (traceability-ids AC-17).
|
|
231
|
+
*/
|
|
232
|
+
coverage?: {
|
|
233
|
+
covered: number;
|
|
234
|
+
total: number;
|
|
235
|
+
stale: number;
|
|
236
|
+
};
|
|
222
237
|
}
|
|
223
238
|
/** Initialization parameters for creating a new instance. */
|
|
224
239
|
export interface InstanceInit {
|
|
@@ -320,7 +335,7 @@ export interface TransitionAllowed {
|
|
|
320
335
|
/** A single unsatisfied gate condition. */
|
|
321
336
|
export interface GateViolation {
|
|
322
337
|
/** Which gate failed. */
|
|
323
|
-
gate: 'exit-criteria' | 'required-artifacts' | 'review-gate' | 'ownership' | 'deployment-entry' | 'blocking-action' | 'knowledge-seeding';
|
|
338
|
+
gate: 'exit-criteria' | 'required-artifacts' | 'review-gate' | 'ownership' | 'deployment-entry' | 'blocking-action' | 'knowledge-seeding' | 'traceability' | 'branch';
|
|
324
339
|
/** Human-readable description of what is unsatisfied. */
|
|
325
340
|
reason: string;
|
|
326
341
|
}
|