@ai-sdlc/orchestrator 0.5.0 → 0.9.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/action-enforcement.d.ts +26 -0
- package/dist/action-enforcement.js +70 -0
- package/dist/admission-composite.d.ts +67 -0
- package/dist/admission-composite.js +158 -0
- package/dist/admission-enrichment.d.ts +142 -0
- package/dist/admission-enrichment.js +331 -0
- package/dist/admission-hc.d.ts +62 -0
- package/dist/admission-hc.js +83 -0
- package/dist/admission-score.d.ts +148 -0
- package/dist/admission-score.js +237 -0
- package/dist/analysis/analyzer.js +3 -2
- package/dist/analysis/convention-detector.d.ts +85 -2
- package/dist/analysis/convention-detector.js +375 -70
- package/dist/analysis/diff-analyzer.d.ts +33 -0
- package/dist/analysis/diff-analyzer.js +122 -0
- package/dist/analysis/hotspot-analyzer.js +3 -1
- package/dist/analysis/index.d.ts +2 -1
- package/dist/analysis/index.js +2 -1
- package/dist/artifacts/index.d.ts +65 -0
- package/dist/artifacts/index.js +142 -0
- package/dist/backlog-adapter.d.ts +121 -0
- package/dist/backlog-adapter.js +438 -0
- package/dist/calibration.d.ts +43 -0
- package/dist/calibration.js +76 -0
- package/dist/cli/commands/agents.d.ts +24 -0
- package/dist/cli/commands/agents.js +66 -1
- package/dist/cli/commands/git-remote.d.ts +49 -0
- package/dist/cli/commands/git-remote.js +91 -0
- package/dist/cli/commands/health.d.ts +4 -0
- package/dist/cli/commands/health.js +13 -1
- package/dist/cli/commands/init.d.ts +26 -0
- package/dist/cli/commands/init.js +164 -22
- package/dist/cli/commands/mcp-setup.d.ts +31 -0
- package/dist/cli/commands/mcp-setup.js +78 -8
- package/dist/cli/formatters/table.js +15 -2
- package/dist/cli/index.d.ts +14 -1
- package/dist/cli/index.js +81 -20
- package/dist/cli/versions.d.ts +57 -0
- package/dist/cli/versions.js +128 -0
- package/dist/code-area-classifier.d.ts +21 -0
- package/dist/code-area-classifier.js +48 -0
- package/dist/config.d.ts +33 -1
- package/dist/config.js +78 -8
- package/dist/cycle-utils.d.ts +51 -0
- package/dist/cycle-utils.js +77 -0
- package/dist/database/adapters/external.d.ts +24 -0
- package/dist/database/adapters/external.js +80 -0
- package/dist/database/adapters/neon.d.ts +41 -0
- package/dist/database/adapters/neon.js +98 -0
- package/dist/database/adapters/pg-snapshot-restore.d.ts +28 -0
- package/dist/database/adapters/pg-snapshot-restore.js +68 -0
- package/dist/database/adapters/sqlite-copy.d.ts +32 -0
- package/dist/database/adapters/sqlite-copy.js +145 -0
- package/dist/database/connection-injection.d.ts +35 -0
- package/dist/database/connection-injection.js +93 -0
- package/dist/database/index.d.ts +12 -0
- package/dist/database/index.js +23 -0
- package/dist/database/registry.d.ts +13 -0
- package/dist/database/registry.js +27 -0
- package/dist/database/topology.d.ts +52 -0
- package/dist/database/topology.js +44 -0
- package/dist/database/types.d.ts +89 -0
- package/dist/database/types.js +26 -0
- package/dist/defaults.d.ts +5 -0
- package/dist/defaults.js +5 -0
- package/dist/design-authority.d.ts +40 -0
- package/dist/design-authority.js +71 -0
- package/dist/design-lookahead.d.ts +64 -0
- package/dist/design-lookahead.js +86 -0
- package/dist/design-quality-trend.d.ts +87 -0
- package/dist/design-quality-trend.js +190 -0
- package/dist/design-system-context.d.ts +46 -0
- package/dist/design-system-context.js +80 -0
- package/dist/design-system-correction-loop.d.ts +64 -0
- package/dist/design-system-correction-loop.js +128 -0
- package/dist/design-system-metrics.d.ts +61 -0
- package/dist/design-system-metrics.js +104 -0
- package/dist/design-system-stewardship.d.ts +22 -0
- package/dist/design-system-stewardship.js +85 -0
- package/dist/design-system-validation.d.ts +37 -0
- package/dist/design-system-validation.js +88 -0
- package/dist/dispatch/index.d.ts +4 -0
- package/dist/dispatch/index.js +4 -0
- package/dist/dispatch/merge-gate.d.ts +46 -0
- package/dist/dispatch/merge-gate.js +90 -0
- package/dist/dispatch/requeue.d.ts +57 -0
- package/dist/dispatch/requeue.js +131 -0
- package/dist/dispatch/worker-pool.d.ts +62 -0
- package/dist/dispatch/worker-pool.js +60 -0
- package/dist/execute.d.ts +40 -0
- package/dist/execute.js +295 -30
- package/dist/fix-ci.js +40 -3
- package/dist/fix-review.d.ts +66 -0
- package/dist/fix-review.js +448 -0
- package/dist/harness/adapters/claude-code.d.ts +29 -0
- package/dist/harness/adapters/claude-code.js +191 -0
- package/dist/harness/adapters/codex.d.ts +25 -0
- package/dist/harness/adapters/codex.js +61 -0
- package/dist/harness/independence.d.ts +51 -0
- package/dist/harness/independence.js +67 -0
- package/dist/harness/index.d.ts +14 -0
- package/dist/harness/index.js +20 -0
- package/dist/harness/registry.d.ts +17 -0
- package/dist/harness/registry.js +31 -0
- package/dist/harness/types.d.ts +123 -0
- package/dist/harness/types.js +8 -0
- package/dist/harness/version-probe.d.ts +14 -0
- package/dist/harness/version-probe.js +123 -0
- package/dist/index.d.ts +39 -5
- package/dist/index.js +48 -3
- package/dist/models/classifier.d.ts +76 -0
- package/dist/models/classifier.js +221 -0
- package/dist/models/index.d.ts +3 -0
- package/dist/models/index.js +3 -0
- package/dist/models/registry.d.ts +97 -0
- package/dist/models/registry.js +173 -0
- package/dist/pillar-breakdown.d.ts +63 -0
- package/dist/pillar-breakdown.js +153 -0
- package/dist/pipeline-cycle-detector.d.ts +70 -0
- package/dist/pipeline-cycle-detector.js +111 -0
- package/dist/priority.d.ts +7 -76
- package/dist/priority.js +18 -5
- package/dist/review-meta.d.ts +65 -0
- package/dist/review-meta.js +149 -0
- package/dist/review.d.ts +35 -0
- package/dist/review.js +84 -0
- package/dist/runners/claude-code-sdk.d.ts +31 -0
- package/dist/runners/claude-code-sdk.js +238 -0
- package/dist/runners/claude-code.d.ts +3 -0
- package/dist/runners/claude-code.js +319 -73
- package/dist/runners/codex.js +4 -1
- package/dist/runners/copilot.js +4 -1
- package/dist/runners/cursor.js +4 -1
- package/dist/runners/git-utils.d.ts +81 -0
- package/dist/runners/git-utils.js +201 -0
- package/dist/runners/index.d.ts +5 -1
- package/dist/runners/index.js +4 -0
- package/dist/runners/review-agent.d.ts +67 -0
- package/dist/runners/review-agent.js +350 -0
- package/dist/runners/runner-registry.js +10 -0
- package/dist/runners/sdk-review-runner.d.ts +65 -0
- package/dist/runners/sdk-review-runner.js +185 -0
- package/dist/runners/security-triage.d.ts +20 -4
- package/dist/runners/security-triage.js +42 -14
- package/dist/runners/types.d.ts +25 -0
- package/dist/runtime/attestations.d.ts +274 -0
- package/dist/runtime/attestations.js +460 -0
- package/dist/runtime/git-env.d.ts +53 -0
- package/dist/runtime/git-env.js +60 -0
- package/dist/runtime/index.d.ts +7 -0
- package/dist/runtime/index.js +7 -0
- package/dist/runtime/parallelism-flag.d.ts +10 -0
- package/dist/runtime/parallelism-flag.js +18 -0
- package/dist/runtime/port-allocator.d.ts +21 -0
- package/dist/runtime/port-allocator.js +66 -0
- package/dist/runtime/worktree-pool.d.ts +86 -0
- package/dist/runtime/worktree-pool.js +204 -0
- package/dist/runtime/worktree.d.ts +25 -0
- package/dist/runtime/worktree.js +111 -0
- package/dist/sa-scoring/auto-calibrate.d.ts +69 -0
- package/dist/sa-scoring/auto-calibrate.js +107 -0
- package/dist/sa-scoring/c1-sa2-computable.d.ts +42 -0
- package/dist/sa-scoring/c1-sa2-computable.js +59 -0
- package/dist/sa-scoring/composite.d.ts +107 -0
- package/dist/sa-scoring/composite.js +139 -0
- package/dist/sa-scoring/depparse-client.d.ts +79 -0
- package/dist/sa-scoring/depparse-client.js +187 -0
- package/dist/sa-scoring/did-compiler.d.ts +122 -0
- package/dist/sa-scoring/did-compiler.js +286 -0
- package/dist/sa-scoring/drift-monitor.d.ts +84 -0
- package/dist/sa-scoring/drift-monitor.js +186 -0
- package/dist/sa-scoring/exemplar-bank.d.ts +78 -0
- package/dist/sa-scoring/exemplar-bank.js +154 -0
- package/dist/sa-scoring/feedback-store.d.ts +100 -0
- package/dist/sa-scoring/feedback-store.js +156 -0
- package/dist/sa-scoring/index.d.ts +71 -0
- package/dist/sa-scoring/index.js +158 -0
- package/dist/sa-scoring/layer1-deterministic.d.ts +115 -0
- package/dist/sa-scoring/layer1-deterministic.js +298 -0
- package/dist/sa-scoring/layer2-structural.d.ts +71 -0
- package/dist/sa-scoring/layer2-structural.js +151 -0
- package/dist/sa-scoring/layer3-llm.d.ts +86 -0
- package/dist/sa-scoring/layer3-llm.js +282 -0
- package/dist/sa-scoring/rescore-orchestrator.d.ts +52 -0
- package/dist/sa-scoring/rescore-orchestrator.js +47 -0
- package/dist/scheduling/burn-down.d.ts +27 -0
- package/dist/scheduling/burn-down.js +43 -0
- package/dist/scheduling/calibration.d.ts +42 -0
- package/dist/scheduling/calibration.js +150 -0
- package/dist/scheduling/index.d.ts +8 -0
- package/dist/scheduling/index.js +8 -0
- package/dist/scheduling/ledger.d.ts +59 -0
- package/dist/scheduling/ledger.js +216 -0
- package/dist/scheduling/off-peak.d.ts +27 -0
- package/dist/scheduling/off-peak.js +112 -0
- package/dist/scheduling/schedule-decision.d.ts +39 -0
- package/dist/scheduling/schedule-decision.js +89 -0
- package/dist/scheduling/tier-analysis.d.ts +47 -0
- package/dist/scheduling/tier-analysis.js +81 -0
- package/dist/scheduling/types.d.ts +140 -0
- package/dist/scheduling/types.js +11 -0
- package/dist/shared.d.ts +13 -0
- package/dist/shared.js +32 -0
- package/dist/state/index.d.ts +1 -1
- package/dist/state/schema.d.ts +6 -1
- package/dist/state/schema.js +276 -1
- package/dist/state/store.d.ts +71 -1
- package/dist/state/store.js +464 -7
- package/dist/state/types.d.ts +174 -0
- package/dist/types.d.ts +1 -1
- package/dist/validate-agent-output.js +4 -1
- package/dist/watch.js +6 -0
- package/dist/workflow-patterns/artifact-writer.d.ts +16 -0
- package/dist/workflow-patterns/artifact-writer.js +34 -0
- package/dist/workflow-patterns/classifiers.d.ts +10 -0
- package/dist/workflow-patterns/classifiers.js +72 -0
- package/dist/workflow-patterns/detector.d.ts +27 -0
- package/dist/workflow-patterns/detector.js +186 -0
- package/dist/workflow-patterns/index.d.ts +8 -0
- package/dist/workflow-patterns/index.js +7 -0
- package/dist/workflow-patterns/proposal-generator.d.ts +15 -0
- package/dist/workflow-patterns/proposal-generator.js +183 -0
- package/dist/workflow-patterns/telemetry-ingest.d.ts +27 -0
- package/dist/workflow-patterns/telemetry-ingest.js +103 -0
- package/dist/workflow-patterns/types.d.ts +61 -0
- package/dist/workflow-patterns/types.js +11 -0
- package/package.json +2 -2
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SqliteCopyAdapter per RFC §15.2. Copies the upstream `.sqlite` file to a per-branch
|
|
3
|
+
* file in the worktree. Hardlinks for read-only branches; full copy for write/migrate.
|
|
4
|
+
*
|
|
5
|
+
* Connection-string format (the orchestrator's existing convention): plain absolute
|
|
6
|
+
* file path, optionally prefixed with `file://`.
|
|
7
|
+
*/
|
|
8
|
+
import { copyFile, link, mkdir, readdir, rm, stat } from 'node:fs/promises';
|
|
9
|
+
import { dirname, join } from 'node:path';
|
|
10
|
+
import { DatabaseBranchAdapterError, } from '../types.js';
|
|
11
|
+
export class SqliteCopyAdapter {
|
|
12
|
+
deps;
|
|
13
|
+
name = 'sqlite-copy';
|
|
14
|
+
capabilities = {
|
|
15
|
+
branchCreationLatencyP50Ms: 50,
|
|
16
|
+
maxBranches: 10_000,
|
|
17
|
+
supportsMigrations: true,
|
|
18
|
+
supportsReadOnlyBranches: true,
|
|
19
|
+
supportsBranchFromBranch: true,
|
|
20
|
+
multiDatabase: false,
|
|
21
|
+
costModel: 'free',
|
|
22
|
+
};
|
|
23
|
+
constructor(deps = {}) {
|
|
24
|
+
this.deps = deps;
|
|
25
|
+
}
|
|
26
|
+
storageRootFor(_pool) {
|
|
27
|
+
return this.deps.storageRoot ?? join(process.cwd(), '.ai-sdlc', 'db');
|
|
28
|
+
}
|
|
29
|
+
async validate(pool) {
|
|
30
|
+
const env = this.deps.env ?? process.env;
|
|
31
|
+
const upstreamPath = env[pool.upstream.connectionStringEnv];
|
|
32
|
+
if (!upstreamPath) {
|
|
33
|
+
return {
|
|
34
|
+
ok: false,
|
|
35
|
+
error: `${pool.upstream.connectionStringEnv} is not set in env; cannot locate upstream SQLite file`,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const s = await stat(stripFileScheme(upstreamPath));
|
|
40
|
+
if (!s.isFile()) {
|
|
41
|
+
return { ok: false, error: `upstream SQLite path is not a file: ${upstreamPath}` };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return { ok: false, error: `upstream SQLite file not found: ${upstreamPath}` };
|
|
46
|
+
}
|
|
47
|
+
return { ok: true };
|
|
48
|
+
}
|
|
49
|
+
async allocate(pool, branchKey) {
|
|
50
|
+
const env = this.deps.env ?? process.env;
|
|
51
|
+
const upstreamRaw = env[pool.upstream.connectionStringEnv];
|
|
52
|
+
if (!upstreamRaw) {
|
|
53
|
+
throw new DatabaseBranchAdapterError(`${pool.upstream.connectionStringEnv} not set`, this.name, branchKey);
|
|
54
|
+
}
|
|
55
|
+
const upstreamPath = stripFileScheme(upstreamRaw);
|
|
56
|
+
const branchPath = join(this.storageRootFor(pool), `${branchKey}.sqlite`);
|
|
57
|
+
await mkdir(dirname(branchPath), { recursive: true });
|
|
58
|
+
try {
|
|
59
|
+
await copyFile(upstreamPath, branchPath);
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
throw new DatabaseBranchAdapterError(`failed to copy SQLite database for branch '${branchKey}': ${err.message}`, this.name, branchKey, err);
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
branchKey,
|
|
66
|
+
connectionString: `file://${branchPath}`,
|
|
67
|
+
createdAt: new Date(),
|
|
68
|
+
upstream: upstreamPath,
|
|
69
|
+
metadata: { branchPath, mode: 'copy' },
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Read-only branch via hardlink (saves disk space when many readers share the same
|
|
74
|
+
* upstream snapshot). Caller is responsible for never opening the resulting file
|
|
75
|
+
* for write — SQLite will happily corrupt the hardlinked upstream if treated as RW.
|
|
76
|
+
*/
|
|
77
|
+
async allocateReadOnly(pool, branchKey) {
|
|
78
|
+
const env = this.deps.env ?? process.env;
|
|
79
|
+
const upstreamRaw = env[pool.upstream.connectionStringEnv];
|
|
80
|
+
if (!upstreamRaw) {
|
|
81
|
+
throw new DatabaseBranchAdapterError(`${pool.upstream.connectionStringEnv} not set`, this.name, branchKey);
|
|
82
|
+
}
|
|
83
|
+
const upstreamPath = stripFileScheme(upstreamRaw);
|
|
84
|
+
const branchPath = join(this.storageRootFor(pool), `${branchKey}.ro.sqlite`);
|
|
85
|
+
await mkdir(dirname(branchPath), { recursive: true });
|
|
86
|
+
try {
|
|
87
|
+
await link(upstreamPath, branchPath);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Fall back to a copy if hardlink fails (e.g., across filesystems).
|
|
91
|
+
await copyFile(upstreamPath, branchPath);
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
branchKey,
|
|
95
|
+
connectionString: `file://${branchPath}?mode=ro`,
|
|
96
|
+
createdAt: new Date(),
|
|
97
|
+
upstream: upstreamPath,
|
|
98
|
+
metadata: { branchPath, mode: 'hardlink-ro' },
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
async reclaim(handle) {
|
|
102
|
+
const path = handle.metadata.branchPath;
|
|
103
|
+
if (!path)
|
|
104
|
+
return;
|
|
105
|
+
await rm(path, { force: true });
|
|
106
|
+
}
|
|
107
|
+
async list(pool) {
|
|
108
|
+
const root = this.storageRootFor(pool);
|
|
109
|
+
let entries;
|
|
110
|
+
try {
|
|
111
|
+
entries = await readdir(root);
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
if (err.code === 'ENOENT')
|
|
115
|
+
return [];
|
|
116
|
+
throw err;
|
|
117
|
+
}
|
|
118
|
+
const handles = [];
|
|
119
|
+
for (const entry of entries) {
|
|
120
|
+
if (!entry.endsWith('.sqlite'))
|
|
121
|
+
continue;
|
|
122
|
+
const branchPath = join(root, entry);
|
|
123
|
+
const s = await stat(branchPath);
|
|
124
|
+
const branchKey = entry.replace(/\.(?:ro\.)?sqlite$/, '');
|
|
125
|
+
handles.push({
|
|
126
|
+
branchKey,
|
|
127
|
+
connectionString: `file://${branchPath}`,
|
|
128
|
+
createdAt: new Date(s.birthtimeMs || s.mtimeMs),
|
|
129
|
+
upstream: 'unknown',
|
|
130
|
+
metadata: { branchPath, mode: entry.includes('.ro.') ? 'hardlink-ro' : 'copy' },
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return handles;
|
|
134
|
+
}
|
|
135
|
+
async isAvailable(pool) {
|
|
136
|
+
const validation = await this.validate(pool);
|
|
137
|
+
return validation.ok;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function stripFileScheme(path) {
|
|
141
|
+
if (path.startsWith('file://'))
|
|
142
|
+
return path.slice('file://'.length);
|
|
143
|
+
return path;
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=sqlite-copy.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connection-string injection per RFC §15.6. The agent sees the per-worktree branch
|
|
3
|
+
* via the same env-var name (`DATABASE_URL` etc.) the application expects. Adapters
|
|
4
|
+
* provide the rewritten string; this module derives optional component env vars
|
|
5
|
+
* (PGHOST, PGDATABASE, etc.) from it.
|
|
6
|
+
*/
|
|
7
|
+
import type { DatabaseBranchHandle, ResolvedDatabaseBranchPool } from './types.js';
|
|
8
|
+
export interface InjectedEnvOverrides {
|
|
9
|
+
[envName: string]: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Build the env-var overlay for a single (handle, pool) pair. The agent's process
|
|
13
|
+
* env is the orchestrator's env merged with this overlay.
|
|
14
|
+
*
|
|
15
|
+
* Component derivation supports postgres:// connection strings — for non-Postgres
|
|
16
|
+
* URLs (e.g., sqlite file paths), additionalEnvs is silently ignored.
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildInjectionOverrides(handle: DatabaseBranchHandle, pool: ResolvedDatabaseBranchPool): InjectedEnvOverrides;
|
|
19
|
+
interface ConnectionComponents {
|
|
20
|
+
host: string;
|
|
21
|
+
port: string;
|
|
22
|
+
database: string;
|
|
23
|
+
user: string;
|
|
24
|
+
password: string;
|
|
25
|
+
}
|
|
26
|
+
export declare function parsePostgresUrl(url: string): ConnectionComponents | null;
|
|
27
|
+
/**
|
|
28
|
+
* Mask a connection string for safe logging. Replaces the password segment with
|
|
29
|
+
* `****`. Per RFC §15.1 the connection string itself MUST NEVER appear in any
|
|
30
|
+
* observability output — this helper exists for adapter error messages where
|
|
31
|
+
* the URL form might leak.
|
|
32
|
+
*/
|
|
33
|
+
export declare function maskConnectionString(url: string): string;
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=connection-injection.d.ts.map
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connection-string injection per RFC §15.6. The agent sees the per-worktree branch
|
|
3
|
+
* via the same env-var name (`DATABASE_URL` etc.) the application expects. Adapters
|
|
4
|
+
* provide the rewritten string; this module derives optional component env vars
|
|
5
|
+
* (PGHOST, PGDATABASE, etc.) from it.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Build the env-var overlay for a single (handle, pool) pair. The agent's process
|
|
9
|
+
* env is the orchestrator's env merged with this overlay.
|
|
10
|
+
*
|
|
11
|
+
* Component derivation supports postgres:// connection strings — for non-Postgres
|
|
12
|
+
* URLs (e.g., sqlite file paths), additionalEnvs is silently ignored.
|
|
13
|
+
*/
|
|
14
|
+
export function buildInjectionOverrides(handle, pool) {
|
|
15
|
+
const overrides = {};
|
|
16
|
+
overrides[pool.injection.targetEnv] = handle.connectionString;
|
|
17
|
+
if (pool.injection.additionalEnvs && pool.injection.additionalEnvs.length > 0) {
|
|
18
|
+
const components = parsePostgresUrl(handle.connectionString);
|
|
19
|
+
if (components) {
|
|
20
|
+
for (const envName of pool.injection.additionalEnvs) {
|
|
21
|
+
const mapped = mapEnvNameToComponent(envName, components);
|
|
22
|
+
if (mapped !== null)
|
|
23
|
+
overrides[envName] = mapped;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return overrides;
|
|
28
|
+
}
|
|
29
|
+
export function parsePostgresUrl(url) {
|
|
30
|
+
// postgres://[user[:password]@]host[:port][/database][?...]
|
|
31
|
+
// Also handles postgresql:// scheme.
|
|
32
|
+
try {
|
|
33
|
+
const parsed = new URL(url);
|
|
34
|
+
if (!/^postgres(?:ql)?:$/.test(parsed.protocol))
|
|
35
|
+
return null;
|
|
36
|
+
return {
|
|
37
|
+
host: parsed.hostname,
|
|
38
|
+
port: parsed.port || '5432',
|
|
39
|
+
database: parsed.pathname.replace(/^\//, ''),
|
|
40
|
+
user: decodeURIComponent(parsed.username),
|
|
41
|
+
password: decodeURIComponent(parsed.password),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function mapEnvNameToComponent(name, c) {
|
|
49
|
+
const upper = name.toUpperCase();
|
|
50
|
+
switch (upper) {
|
|
51
|
+
case 'PGHOST':
|
|
52
|
+
case 'POSTGRES_HOST':
|
|
53
|
+
case 'DB_HOST':
|
|
54
|
+
return c.host;
|
|
55
|
+
case 'PGPORT':
|
|
56
|
+
case 'POSTGRES_PORT':
|
|
57
|
+
case 'DB_PORT':
|
|
58
|
+
return c.port;
|
|
59
|
+
case 'PGDATABASE':
|
|
60
|
+
case 'POSTGRES_DB':
|
|
61
|
+
case 'DB_NAME':
|
|
62
|
+
return c.database;
|
|
63
|
+
case 'PGUSER':
|
|
64
|
+
case 'POSTGRES_USER':
|
|
65
|
+
case 'DB_USER':
|
|
66
|
+
return c.user;
|
|
67
|
+
case 'PGPASSWORD':
|
|
68
|
+
case 'POSTGRES_PASSWORD':
|
|
69
|
+
case 'DB_PASSWORD':
|
|
70
|
+
return c.password;
|
|
71
|
+
default:
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Mask a connection string for safe logging. Replaces the password segment with
|
|
77
|
+
* `****`. Per RFC §15.1 the connection string itself MUST NEVER appear in any
|
|
78
|
+
* observability output — this helper exists for adapter error messages where
|
|
79
|
+
* the URL form might leak.
|
|
80
|
+
*/
|
|
81
|
+
export function maskConnectionString(url) {
|
|
82
|
+
try {
|
|
83
|
+
const parsed = new URL(url);
|
|
84
|
+
if (parsed.password) {
|
|
85
|
+
parsed.password = '****';
|
|
86
|
+
}
|
|
87
|
+
return parsed.toString();
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return '<unparseable connection string>';
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=connection-injection.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export { DatabaseAdapterRegistry, UnknownDatabaseAdapterError } from './registry.js';
|
|
3
|
+
export { buildInjectionOverrides, parsePostgresUrl, maskConnectionString, type InjectedEnvOverrides, } from './connection-injection.js';
|
|
4
|
+
export { enforceTopologyGuard, buildMigrationDivergedEvent, type KnownInFlightBranches, type MigrationDivergedEvent, } from './topology.js';
|
|
5
|
+
export { SqliteCopyAdapter, type SqliteCopyAdapterDeps } from './adapters/sqlite-copy.js';
|
|
6
|
+
export { NeonAdapter, type NeonAdapterDeps } from './adapters/neon.js';
|
|
7
|
+
export { PgSnapshotRestoreAdapter, type PgSnapshotRestoreAdapterDeps, } from './adapters/pg-snapshot-restore.js';
|
|
8
|
+
export { ExternalAdapter, type ExternalAdapterDeps } from './adapters/external.js';
|
|
9
|
+
import { DatabaseAdapterRegistry } from './registry.js';
|
|
10
|
+
/** Pre-populated registry with the four shipped v1 adapters. */
|
|
11
|
+
export declare function createDefaultDatabaseAdapterRegistry(): DatabaseAdapterRegistry;
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export { DatabaseAdapterRegistry, UnknownDatabaseAdapterError } from './registry.js';
|
|
3
|
+
export { buildInjectionOverrides, parsePostgresUrl, maskConnectionString, } from './connection-injection.js';
|
|
4
|
+
export { enforceTopologyGuard, buildMigrationDivergedEvent, } from './topology.js';
|
|
5
|
+
export { SqliteCopyAdapter } from './adapters/sqlite-copy.js';
|
|
6
|
+
export { NeonAdapter } from './adapters/neon.js';
|
|
7
|
+
export { PgSnapshotRestoreAdapter, } from './adapters/pg-snapshot-restore.js';
|
|
8
|
+
export { ExternalAdapter } from './adapters/external.js';
|
|
9
|
+
import { DatabaseAdapterRegistry } from './registry.js';
|
|
10
|
+
import { SqliteCopyAdapter } from './adapters/sqlite-copy.js';
|
|
11
|
+
import { NeonAdapter } from './adapters/neon.js';
|
|
12
|
+
import { PgSnapshotRestoreAdapter } from './adapters/pg-snapshot-restore.js';
|
|
13
|
+
import { ExternalAdapter } from './adapters/external.js';
|
|
14
|
+
/** Pre-populated registry with the four shipped v1 adapters. */
|
|
15
|
+
export function createDefaultDatabaseAdapterRegistry() {
|
|
16
|
+
const reg = new DatabaseAdapterRegistry();
|
|
17
|
+
reg.register(new SqliteCopyAdapter());
|
|
18
|
+
reg.register(new NeonAdapter());
|
|
19
|
+
reg.register(new PgSnapshotRestoreAdapter());
|
|
20
|
+
reg.register(new ExternalAdapter());
|
|
21
|
+
return reg;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DatabaseAdapterName, DatabaseBranchAdapter } from './types.js';
|
|
2
|
+
export declare class UnknownDatabaseAdapterError extends Error {
|
|
3
|
+
readonly name: string;
|
|
4
|
+
constructor(name: string);
|
|
5
|
+
}
|
|
6
|
+
export declare class DatabaseAdapterRegistry {
|
|
7
|
+
private readonly adapters;
|
|
8
|
+
register(adapter: DatabaseBranchAdapter): void;
|
|
9
|
+
get(name: string): DatabaseBranchAdapter;
|
|
10
|
+
has(name: string): boolean;
|
|
11
|
+
list(): DatabaseAdapterName[];
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export class UnknownDatabaseAdapterError extends Error {
|
|
2
|
+
name;
|
|
3
|
+
constructor(name) {
|
|
4
|
+
super(`Unknown DatabaseBranchAdapter: ${name}`);
|
|
5
|
+
this.name = name;
|
|
6
|
+
this.name = 'UnknownDatabaseAdapterError';
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export class DatabaseAdapterRegistry {
|
|
10
|
+
adapters = new Map();
|
|
11
|
+
register(adapter) {
|
|
12
|
+
this.adapters.set(adapter.name, adapter);
|
|
13
|
+
}
|
|
14
|
+
get(name) {
|
|
15
|
+
const a = this.adapters.get(name);
|
|
16
|
+
if (!a)
|
|
17
|
+
throw new UnknownDatabaseAdapterError(name);
|
|
18
|
+
return a;
|
|
19
|
+
}
|
|
20
|
+
has(name) {
|
|
21
|
+
return this.adapters.has(name);
|
|
22
|
+
}
|
|
23
|
+
list() {
|
|
24
|
+
return Array.from(this.adapters.keys());
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Branch topology guard per RFC §15.5.1 (Q15 resolution). Defaults `allowBranchFromBranch`
|
|
3
|
+
* to false, refusing to allocate a branch whose upstream is itself an in-flight feature
|
|
4
|
+
* branch. Eliminates MigrationDiverged for ~95% of pipelines that don't need stacked PRs.
|
|
5
|
+
*/
|
|
6
|
+
import { type ResolvedDatabaseBranchPool } from './types.js';
|
|
7
|
+
export interface KnownInFlightBranches {
|
|
8
|
+
/** Branch names currently allocated as DatabaseBranch handles in this pool. */
|
|
9
|
+
inFlightBranchNames: Set<string>;
|
|
10
|
+
/** Stable upstream branch names the operator considers safe to branch from. */
|
|
11
|
+
stableUpstreams: Set<string>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Validate a branchFrom request against the topology guard. Throws
|
|
15
|
+
* BranchTopologyForbiddenError if the upstream is an in-flight branch and
|
|
16
|
+
* `allowBranchFromBranch` is false.
|
|
17
|
+
*/
|
|
18
|
+
export declare function enforceTopologyGuard(pool: ResolvedDatabaseBranchPool, state: KnownInFlightBranches): void;
|
|
19
|
+
/**
|
|
20
|
+
* MigrationDiverged event payload per RFC §15.5.1. Emitted by the orchestrator when a
|
|
21
|
+
* branch with active children is reclaimed (parent PR abandoned).
|
|
22
|
+
*/
|
|
23
|
+
export interface MigrationDivergedEvent {
|
|
24
|
+
type: 'MigrationDiverged';
|
|
25
|
+
reclaimedBranch: {
|
|
26
|
+
branchKey: string;
|
|
27
|
+
reason: 'pr-abandoned' | 'manual-reclaim' | 'ttl-expired';
|
|
28
|
+
issueId?: string;
|
|
29
|
+
};
|
|
30
|
+
divergentChildren: Array<{
|
|
31
|
+
branchKey: string;
|
|
32
|
+
issueId?: string;
|
|
33
|
+
lastActivity: string;
|
|
34
|
+
}>;
|
|
35
|
+
interpretation: string;
|
|
36
|
+
recommendation: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Build a MigrationDiverged event from the parent reclaim + a snapshot of children.
|
|
40
|
+
* The orchestrator emits this through its event stream; the operator triages per
|
|
41
|
+
* the runbook. NO auto-action.
|
|
42
|
+
*/
|
|
43
|
+
export declare function buildMigrationDivergedEvent(parent: {
|
|
44
|
+
branchKey: string;
|
|
45
|
+
reason: 'pr-abandoned' | 'manual-reclaim' | 'ttl-expired';
|
|
46
|
+
issueId?: string;
|
|
47
|
+
}, children: Array<{
|
|
48
|
+
branchKey: string;
|
|
49
|
+
issueId?: string;
|
|
50
|
+
lastActivity: Date;
|
|
51
|
+
}>): MigrationDivergedEvent;
|
|
52
|
+
//# sourceMappingURL=topology.d.ts.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Branch topology guard per RFC §15.5.1 (Q15 resolution). Defaults `allowBranchFromBranch`
|
|
3
|
+
* to false, refusing to allocate a branch whose upstream is itself an in-flight feature
|
|
4
|
+
* branch. Eliminates MigrationDiverged for ~95% of pipelines that don't need stacked PRs.
|
|
5
|
+
*/
|
|
6
|
+
import { BranchTopologyForbiddenError } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Validate a branchFrom request against the topology guard. Throws
|
|
9
|
+
* BranchTopologyForbiddenError if the upstream is an in-flight branch and
|
|
10
|
+
* `allowBranchFromBranch` is false.
|
|
11
|
+
*/
|
|
12
|
+
export function enforceTopologyGuard(pool, state) {
|
|
13
|
+
const branchFrom = pool.upstream.branchFrom;
|
|
14
|
+
if (!branchFrom)
|
|
15
|
+
return;
|
|
16
|
+
// Always allowed when the upstream is a declared stable branch.
|
|
17
|
+
if (state.stableUpstreams.has(branchFrom))
|
|
18
|
+
return;
|
|
19
|
+
if (state.inFlightBranchNames.has(branchFrom)) {
|
|
20
|
+
if (pool.allowBranchFromBranch !== true) {
|
|
21
|
+
throw new BranchTopologyForbiddenError(`DatabaseBranchPool '${pool.name}' attempted to branch from in-flight branch '${branchFrom}'; ` +
|
|
22
|
+
`set allowBranchFromBranch: true to opt in to chained branching (and accept MigrationDiverged risk).`, pool.name);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Build a MigrationDiverged event from the parent reclaim + a snapshot of children.
|
|
28
|
+
* The orchestrator emits this through its event stream; the operator triages per
|
|
29
|
+
* the runbook. NO auto-action.
|
|
30
|
+
*/
|
|
31
|
+
export function buildMigrationDivergedEvent(parent, children) {
|
|
32
|
+
return {
|
|
33
|
+
type: 'MigrationDiverged',
|
|
34
|
+
reclaimedBranch: parent,
|
|
35
|
+
divergentChildren: children.map((c) => ({
|
|
36
|
+
branchKey: c.branchKey,
|
|
37
|
+
issueId: c.issueId,
|
|
38
|
+
lastActivity: c.lastActivity.toISOString(),
|
|
39
|
+
})),
|
|
40
|
+
interpretation: 'child branches inherit a migration that no longer exists in any merged code. Their PRs may pass tests but break on merge to main.',
|
|
41
|
+
recommendation: 'operator triage: rebase children onto current upstream, accept divergence, or reclaim children. The orchestrator does NOT auto-rebase or auto-reclaim.',
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=topology.js.map
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DatabaseBranchAdapter framework per RFC-0010 §15. Each adapter abstracts a database
|
|
3
|
+
* branching mechanism; the orchestrator allocates a branch per worktree, injects the
|
|
4
|
+
* branch's connection string into the agent's environment, and reclaims on PR merge.
|
|
5
|
+
*/
|
|
6
|
+
export type DatabaseAdapterName = 'sqlite-copy' | 'neon' | 'pg-snapshot-restore' | 'supabase' | 'external';
|
|
7
|
+
export interface DatabaseBranchCapabilities {
|
|
8
|
+
branchCreationLatencyP50Ms: number;
|
|
9
|
+
maxBranches: number;
|
|
10
|
+
supportsMigrations: boolean;
|
|
11
|
+
supportsReadOnlyBranches: boolean;
|
|
12
|
+
supportsBranchFromBranch: boolean;
|
|
13
|
+
multiDatabase: boolean;
|
|
14
|
+
costModel: 'per-branch-storage' | 'per-snapshot' | 'free';
|
|
15
|
+
}
|
|
16
|
+
export interface DatabaseBranchHandle {
|
|
17
|
+
/** Stable key derived from the worktree branch name. */
|
|
18
|
+
branchKey: string;
|
|
19
|
+
/**
|
|
20
|
+
* Connection URL the agent will use. NEVER logged in cleartext per RFC §15.1
|
|
21
|
+
* (security review property — adapters MUST mask credentials in any error returned).
|
|
22
|
+
*/
|
|
23
|
+
connectionString: string;
|
|
24
|
+
createdAt: Date;
|
|
25
|
+
/** Upstream branch the handle was derived from. */
|
|
26
|
+
upstream: string;
|
|
27
|
+
upstreamCommitId?: string;
|
|
28
|
+
/** Adapter-specific metadata (Neon: branch_id; pg-snapshot-restore: snapshot id). */
|
|
29
|
+
metadata: Record<string, string>;
|
|
30
|
+
}
|
|
31
|
+
export interface ResolvedDatabaseBranchPool {
|
|
32
|
+
name: string;
|
|
33
|
+
adapter: DatabaseAdapterName;
|
|
34
|
+
upstream: {
|
|
35
|
+
connectionStringEnv: string;
|
|
36
|
+
branchFrom?: string;
|
|
37
|
+
};
|
|
38
|
+
injection: {
|
|
39
|
+
targetEnv: string;
|
|
40
|
+
additionalEnvs?: string[];
|
|
41
|
+
};
|
|
42
|
+
lifecycle?: {
|
|
43
|
+
createOn?: 'worktree-allocation' | 'first-write-stage';
|
|
44
|
+
reclaimOn?: 'pr-merge' | 'worktree-reclaim' | 'manual';
|
|
45
|
+
maxConcurrent?: number;
|
|
46
|
+
branchTtl?: string;
|
|
47
|
+
abandonAfter?: string;
|
|
48
|
+
warmPoolSize?: number;
|
|
49
|
+
};
|
|
50
|
+
allowBranchFromBranch?: boolean;
|
|
51
|
+
migrations?: {
|
|
52
|
+
runOnBranchCreate?: boolean;
|
|
53
|
+
migrationCommand?: string;
|
|
54
|
+
migrationCwd?: string;
|
|
55
|
+
};
|
|
56
|
+
credentials?: Record<string, unknown>;
|
|
57
|
+
}
|
|
58
|
+
export type ValidationResult = {
|
|
59
|
+
ok: true;
|
|
60
|
+
} | {
|
|
61
|
+
ok: false;
|
|
62
|
+
error: string;
|
|
63
|
+
};
|
|
64
|
+
export interface DatabaseBranchAdapter {
|
|
65
|
+
readonly name: DatabaseAdapterName;
|
|
66
|
+
readonly capabilities: DatabaseBranchCapabilities;
|
|
67
|
+
/** Pipeline-load validation; checks credentials + adapter-specific config. */
|
|
68
|
+
validate(pool: ResolvedDatabaseBranchPool): Promise<ValidationResult>;
|
|
69
|
+
/** Provision a new branch from the pool's upstream. */
|
|
70
|
+
allocate(pool: ResolvedDatabaseBranchPool, branchKey: string): Promise<DatabaseBranchHandle>;
|
|
71
|
+
/** Destroy a branch and free its quota slot. */
|
|
72
|
+
reclaim(handle: DatabaseBranchHandle): Promise<void>;
|
|
73
|
+
/** Enumerate currently active branches (for stale-branch sweep on startup). */
|
|
74
|
+
list(pool: ResolvedDatabaseBranchPool): Promise<DatabaseBranchHandle[]>;
|
|
75
|
+
/** Cheap liveness probe. */
|
|
76
|
+
isAvailable(pool: ResolvedDatabaseBranchPool): Promise<boolean>;
|
|
77
|
+
}
|
|
78
|
+
export declare class DatabaseBranchAdapterError extends Error {
|
|
79
|
+
readonly adapter: DatabaseAdapterName;
|
|
80
|
+
readonly branchKey?: string | undefined;
|
|
81
|
+
readonly cause?: unknown | undefined;
|
|
82
|
+
constructor(message: string, adapter: DatabaseAdapterName, branchKey?: string | undefined, cause?: unknown | undefined);
|
|
83
|
+
}
|
|
84
|
+
export declare class BranchTopologyForbiddenError extends Error {
|
|
85
|
+
readonly poolName: string;
|
|
86
|
+
constructor(message: string, poolName: string);
|
|
87
|
+
}
|
|
88
|
+
export type DatabaseAccess = 'none' | 'read' | 'write' | 'migrate';
|
|
89
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DatabaseBranchAdapter framework per RFC-0010 §15. Each adapter abstracts a database
|
|
3
|
+
* branching mechanism; the orchestrator allocates a branch per worktree, injects the
|
|
4
|
+
* branch's connection string into the agent's environment, and reclaims on PR merge.
|
|
5
|
+
*/
|
|
6
|
+
export class DatabaseBranchAdapterError extends Error {
|
|
7
|
+
adapter;
|
|
8
|
+
branchKey;
|
|
9
|
+
cause;
|
|
10
|
+
constructor(message, adapter, branchKey, cause) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.adapter = adapter;
|
|
13
|
+
this.branchKey = branchKey;
|
|
14
|
+
this.cause = cause;
|
|
15
|
+
this.name = 'DatabaseBranchAdapterError';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export class BranchTopologyForbiddenError extends Error {
|
|
19
|
+
poolName;
|
|
20
|
+
constructor(message, poolName) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.poolName = poolName;
|
|
23
|
+
this.name = 'BranchTopologyForbiddenError';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=types.js.map
|
package/dist/defaults.d.ts
CHANGED
|
@@ -136,5 +136,10 @@ export declare const NOTIFICATION_TITLES: {
|
|
|
136
136
|
readonly fixCIAgentFailed: "AI-SDLC: Fix-CI Agent Failed";
|
|
137
137
|
readonly fixCIGuardrailViolations: "AI-SDLC: Fix-CI Guardrail Violations";
|
|
138
138
|
readonly fixCIApplied: "AI-SDLC: Fix-CI Applied";
|
|
139
|
+
readonly fixReviewRetryLimit: "AI-SDLC: Fix-Review Retry Limit Reached";
|
|
140
|
+
readonly fixReviewAgentFailed: "AI-SDLC: Fix-Review Agent Failed";
|
|
141
|
+
readonly fixReviewGuardrailViolations: "AI-SDLC: Fix-Review Guardrail Violations";
|
|
142
|
+
readonly fixReviewApplied: "AI-SDLC: Fix-Review Applied";
|
|
143
|
+
readonly pipelineCycleDetected: "AI-SDLC: Pipeline Cycle Detected";
|
|
139
144
|
};
|
|
140
145
|
//# sourceMappingURL=defaults.d.ts.map
|
package/dist/defaults.js
CHANGED
|
@@ -214,5 +214,10 @@ export const NOTIFICATION_TITLES = {
|
|
|
214
214
|
fixCIAgentFailed: 'AI-SDLC: Fix-CI Agent Failed',
|
|
215
215
|
fixCIGuardrailViolations: 'AI-SDLC: Fix-CI Guardrail Violations',
|
|
216
216
|
fixCIApplied: 'AI-SDLC: Fix-CI Applied',
|
|
217
|
+
fixReviewRetryLimit: 'AI-SDLC: Fix-Review Retry Limit Reached',
|
|
218
|
+
fixReviewAgentFailed: 'AI-SDLC: Fix-Review Agent Failed',
|
|
219
|
+
fixReviewGuardrailViolations: 'AI-SDLC: Fix-Review Guardrail Violations',
|
|
220
|
+
fixReviewApplied: 'AI-SDLC: Fix-Review Applied',
|
|
221
|
+
pipelineCycleDetected: 'AI-SDLC: Pipeline Cycle Detected',
|
|
217
222
|
};
|
|
218
223
|
//# sourceMappingURL=defaults.js.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* C5 — Design authority signal detection (RFC-0008 §A.5).
|
|
3
|
+
*
|
|
4
|
+
* Determines whether the issue's author or any commenter is listed as a
|
|
5
|
+
* `designAuthority` principal on the resolved DesignSystemBinding, and
|
|
6
|
+
* parses the explicit signal type from issue labels (preferred) or
|
|
7
|
+
* structured comment markers.
|
|
8
|
+
*/
|
|
9
|
+
import type { DesignSystemBinding } from '@ai-sdlc/reference';
|
|
10
|
+
import type { DesignAuthoritySignalType } from './admission-score.js';
|
|
11
|
+
export interface CheckDesignAuthorityInput {
|
|
12
|
+
/** GitHub login of the issue author. */
|
|
13
|
+
authorLogin?: string;
|
|
14
|
+
/** GitHub logins of anyone who commented on the issue. */
|
|
15
|
+
commenterLogins?: readonly string[];
|
|
16
|
+
/** Labels attached to the issue — used to parse the signal type. */
|
|
17
|
+
labels: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
export interface DesignAuthoritySignalResult {
|
|
20
|
+
isDesignAuthority: boolean;
|
|
21
|
+
signalType: DesignAuthoritySignalType;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Determine whether the issue author or any commenter is a
|
|
25
|
+
* designAuthority principal, and resolve the signal type from labels.
|
|
26
|
+
* Returns `{ isDesignAuthority: false, signalType: 'unspecified' }`
|
|
27
|
+
* when no DSB is present.
|
|
28
|
+
*/
|
|
29
|
+
export declare function checkDesignAuthority(input: CheckDesignAuthorityInput, binding: DesignSystemBinding | undefined): DesignAuthoritySignalResult;
|
|
30
|
+
/**
|
|
31
|
+
* Resolve the design-signal type from issue labels.
|
|
32
|
+
*
|
|
33
|
+
* Priority order mirrors the RFC's weighting (positive signals first),
|
|
34
|
+
* so an issue tagged with both a positive and a negative label resolves
|
|
35
|
+
* to the positive one. This is deliberate: design authorities shouldn't
|
|
36
|
+
* dual-tag in practice, but if they do, we don't want to default to the
|
|
37
|
+
* punitive path.
|
|
38
|
+
*/
|
|
39
|
+
export declare function parseDesignSignalType(labels: readonly string[]): DesignAuthoritySignalType;
|
|
40
|
+
//# sourceMappingURL=design-authority.d.ts.map
|