@cheongfish/bouncer 0.0.0-stage → 0.1.13
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/LICENSE +202 -0
- package/README.md +31 -2
- package/bin/bouncer +26 -0
- package/bin/bouncer-root +25 -0
- package/bin/build-stamp.js +78 -0
- package/bin/register-path.js +71 -0
- package/dist/.build-stamp +1 -0
- package/dist/approval-snapshot.js +99 -0
- package/dist/bouncer-root.js +80 -0
- package/dist/canonical-json.js +37 -0
- package/dist/cli-commit-guard-command.js +74 -0
- package/dist/cli-config-command.js +47 -0
- package/dist/cli-context-review-command.js +273 -0
- package/dist/cli-current-command.js +374 -0
- package/dist/cli-dispatch-command.js +119 -0
- package/dist/cli-doc-commands.js +352 -0
- package/dist/cli-epic-command.js +130 -0
- package/dist/cli-flags.js +50 -0
- package/dist/cli-git-commands.js +931 -0
- package/dist/cli-intent-command.js +491 -0
- package/dist/cli-metrics-command.js +134 -0
- package/dist/cli-ontology-command.js +109 -0
- package/dist/cli-project-commands.js +580 -0
- package/dist/cli-retro-command.js +138 -0
- package/dist/cli-review-command.js +251 -0
- package/dist/cli-review-dispatch-command.js +338 -0
- package/dist/cli-usage.js +72 -0
- package/dist/cli.js +70 -0
- package/dist/codex-agents.js +189 -0
- package/dist/command-argv.js +125 -0
- package/dist/commit-guard.js +72 -0
- package/dist/commit-hook.js +470 -0
- package/dist/commit-message.js +77 -0
- package/dist/commit-sha.js +107 -0
- package/dist/commit.js +519 -0
- package/dist/composite-gates.js +129 -0
- package/dist/comprehension.js +127 -0
- package/dist/config.js +298 -0
- package/dist/context-ids.js +288 -0
- package/dist/context-migration-rewrite.js +421 -0
- package/dist/context-ontology.js +746 -0
- package/dist/context-review-contracts.js +2 -0
- package/dist/context-review-projection.js +147 -0
- package/dist/context-review-state.js +824 -0
- package/dist/context-review-store.js +602 -0
- package/dist/context-review-transitions.js +412 -0
- package/dist/coordinate-advance.js +253 -0
- package/dist/coordinate-next.js +998 -0
- package/dist/coordinate-output.js +57 -0
- package/dist/coordinator-command-contracts.js +2 -0
- package/dist/coordinator-commands.js +1908 -0
- package/dist/coordinator-fanin.js +1021 -0
- package/dist/coordinator-git.js +121 -0
- package/dist/coordinator-input.js +37 -0
- package/dist/coordinator-ledger.js +381 -0
- package/dist/coordinator-prepare.js +1047 -0
- package/dist/coordinator-repair.js +1416 -0
- package/dist/coordinator-verification.js +42 -0
- package/dist/coordinator-worker.js +388 -0
- package/dist/coordinator.js +7 -0
- package/dist/cross-drive.js +85 -0
- package/dist/current.js +1148 -0
- package/dist/dag-shape.js +93 -0
- package/dist/doc-shape-contracts.js +241 -0
- package/dist/drive-metrics.js +691 -0
- package/dist/epic-index.js +347 -0
- package/dist/epic-registry.js +453 -0
- package/dist/execute-prepare.js +262 -0
- package/dist/execution-contracts.js +46 -0
- package/dist/execution-dag.js +148 -0
- package/dist/finalize-checks.js +177 -0
- package/dist/finalize-collect.js +343 -0
- package/dist/finalize-comprehension.js +116 -0
- package/dist/finalize-digest-collect.js +388 -0
- package/dist/finalize-digest-model.js +595 -0
- package/dist/finalize-digest.js +164 -0
- package/dist/finalize-explain.js +176 -0
- package/dist/finalize-pr.js +610 -0
- package/dist/finalize-release-main.js +652 -0
- package/dist/finalize.js +714 -0
- package/dist/frontmatter.js +22 -0
- package/dist/git-ops.js +49 -0
- package/dist/graph-exec.js +179 -0
- package/dist/graph-scope.js +268 -0
- package/dist/graphify.js +995 -0
- package/dist/guards.js +82 -0
- package/dist/import-git.js +78 -0
- package/dist/import-history.js +392 -0
- package/dist/import-render.js +59 -0
- package/dist/import-types.js +2 -0
- package/dist/init.js +571 -0
- package/dist/intent-bundle.js +936 -0
- package/dist/intent-provenance.js +927 -0
- package/dist/layout.js +131 -0
- package/dist/lease.js +145 -0
- package/dist/legacy-comments.js +71 -0
- package/dist/migrate-context-slugs.js +262 -0
- package/dist/migrate-merge-legacy-epics.js +392 -0
- package/dist/migrate-review-scope.js +144 -0
- package/dist/migrate-task-layout.js +194 -0
- package/dist/path-overlap.js +38 -0
- package/dist/paths.js +45 -0
- package/dist/plan-approve.js +218 -0
- package/dist/plan-inspect.js +575 -0
- package/dist/plan-prerequisites.js +197 -0
- package/dist/plan-snapshot-contract.js +98 -0
- package/dist/plan-snapshot.js +138 -0
- package/dist/plugin-root.js +237 -0
- package/dist/posix-path.js +14 -0
- package/dist/pre-commit-hook.js +170 -0
- package/dist/print-dispatch.js +285 -0
- package/dist/render.js +8 -0
- package/dist/retention-migration.js +595 -0
- package/dist/retro-read.js +259 -0
- package/dist/retro-sources.js +318 -0
- package/dist/review-dispatch.js +1054 -0
- package/dist/review-policy.js +28 -0
- package/dist/review-record.js +447 -0
- package/dist/review-repair-state.js +52 -0
- package/dist/review-snapshot.js +659 -0
- package/dist/run-detach.js +165 -0
- package/dist/run-preflight.js +368 -0
- package/dist/runtime-state.js +1038 -0
- package/dist/scaffold.js +533 -0
- package/dist/schema.js +294 -0
- package/dist/scope.js +1073 -0
- package/dist/seed-worktree.js +926 -0
- package/dist/session-graph.js +337 -0
- package/dist/subagents.js +86 -0
- package/dist/symbol-index.js +1390 -0
- package/dist/task-brief-hash.js +34 -0
- package/dist/task-commits.js +124 -0
- package/dist/tasks-docs.js +192 -0
- package/dist/templates.js +469 -0
- package/dist/time.js +21 -0
- package/dist/validate-docs.js +302 -0
- package/dist/validate-gates-finalize.js +303 -0
- package/dist/validate-gates-plan.js +720 -0
- package/dist/validate-gates-run.js +420 -0
- package/dist/validate-gates-shared.js +124 -0
- package/dist/validate-gates.js +87 -0
- package/dist/validate-sections.js +654 -0
- package/dist/validate-structural.js +347 -0
- package/dist/validate.js +417 -0
- package/dist/verification-contracts.js +26 -0
- package/dist/verification-evidence.js +233 -0
- package/dist/verification-execution.js +163 -0
- package/dist/verification-identity.js +413 -0
- package/dist/verification-target.js +51 -0
- package/dist/verification.js +383 -0
- package/dist/windows-npm.js +38 -0
- package/package.json +32 -4
- package/resources/graphify-compat.json +9 -0
- package/vendor/README.md +23 -0
- package/vendor/js-yaml.LICENSE +21 -0
- package/vendor/js-yaml.js +3022 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const executionDag = require("./execution-dag");
|
|
3
|
+
const { readyWave, normalizeOverlapPath } = executionDag;
|
|
4
|
+
const pathOverlapMod = require("./path-overlap");
|
|
5
|
+
const { pathsOverlap } = pathOverlapMod;
|
|
6
|
+
/**
|
|
7
|
+
* a의 경로 중 b의 어떤 경로와 겹치는(같거나 조상·자손) 것의 비율을 낸다.
|
|
8
|
+
* 분모는 더 짧은 쪽 길이다 — 작은 task가 큰 task 안에 거의 포함되는 경우를
|
|
9
|
+
* 큰 쪽 크기에 희석되지 않고 드러내기 위해서다. 겹침 판정은 plan gate와 같은
|
|
10
|
+
* validate-sections.pathsOverlap 하나만 쓴다.
|
|
11
|
+
*
|
|
12
|
+
* @param {string[]} a - 한쪽 affected_paths
|
|
13
|
+
* @param {string[]} b - 다른 쪽 affected_paths
|
|
14
|
+
* @returns {number} 0 이상 1 이하 비율. 어느 한쪽이 비면 0
|
|
15
|
+
*/
|
|
16
|
+
function pathOverlapRatio(a, b) {
|
|
17
|
+
if (a.length === 0 || b.length === 0)
|
|
18
|
+
return 0;
|
|
19
|
+
const bNorm = b.map(normalizeOverlapPath);
|
|
20
|
+
const hits = a.filter((p) => {
|
|
21
|
+
const norm = normalizeOverlapPath(p);
|
|
22
|
+
return bNorm.some((other) => pathsOverlap(norm, other));
|
|
23
|
+
}).length;
|
|
24
|
+
return Math.min(1, hits / Math.min(a.length, b.length));
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 열린 commit task만으로 prepare와 같은 readyWave 시뮬레이션을 돌려 DAG
|
|
28
|
+
* 모양을 낸다. 순수 함수이며 I/O가 없다.
|
|
29
|
+
*
|
|
30
|
+
* 열려 있지 않은 commit task는 이미 `integrated`로 두어 후속 gate를 통과시키고,
|
|
31
|
+
* verification 노드는 task와 그 노드를 향한 edge를 모두 무시한다 — 노드는 drive
|
|
32
|
+
* 대상이 아니라 마지막 확인 단계다. 선행이 목록에 없으면 그 task는 영영 열리지
|
|
33
|
+
* 않으므로 시뮬레이션이 멈춰 `unknown`이 된다. 종료 보장을 위해 반복은
|
|
34
|
+
* `tasks.length + 1`회로 제한한다.
|
|
35
|
+
*
|
|
36
|
+
* @param {ShapeTask[]} tasks - 문서에서 모은 전체 task(열림 여부 포함)
|
|
37
|
+
* @param {{ maxParallel: number }} opts - 동시 실행 상한. invalid config는 호출자가 1로 접는다
|
|
38
|
+
* @returns {DriveShapeResult} drive_shape와 요약 수치. 열린 commit task가 없으면
|
|
39
|
+
* drive_shape가 null, 시뮬레이션이 남은 task를 열지 못하면 'unknown'
|
|
40
|
+
*/
|
|
41
|
+
function analyzeDriveShape(tasks, opts) {
|
|
42
|
+
const commits = tasks.filter((task) => task.execution_kind === 'commit');
|
|
43
|
+
const verificationIds = new Set(tasks.filter((task) => task.execution_kind !== 'commit').map((task) => task.id));
|
|
44
|
+
const openCommits = commits.filter((task) => task.open);
|
|
45
|
+
// review_risk가 배열이 아닌 문서는 형식 거절이 S30 소관이라 여기서는 빈 위험으로 읽는다.
|
|
46
|
+
const riskSet = new Set();
|
|
47
|
+
for (const task of openCommits) {
|
|
48
|
+
if (Array.isArray(task.review_risk)) {
|
|
49
|
+
for (const risk of task.review_risk)
|
|
50
|
+
if (typeof risk === 'string')
|
|
51
|
+
riskSet.add(risk);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const summary = {
|
|
55
|
+
commit_tasks: openCommits.length,
|
|
56
|
+
review_risk: [...riskSet].sort(),
|
|
57
|
+
parallel_safe_tasks: openCommits.filter((task) => task.parallel_safe === true).length,
|
|
58
|
+
};
|
|
59
|
+
if (openCommits.length === 0) {
|
|
60
|
+
return { drive_shape: null, max_wave_width: 0, ...summary };
|
|
61
|
+
}
|
|
62
|
+
// 시뮬레이션 상태. 열린 task만 pending, 나머지는 선행 gate를 만족하는 integrated.
|
|
63
|
+
const sim = commits.map((task) => ({
|
|
64
|
+
id: task.id,
|
|
65
|
+
depends_on: (task.depends_on || []).filter((dep) => !verificationIds.has(dep)),
|
|
66
|
+
dependency_gate: task.dependency_gate,
|
|
67
|
+
parallel_safe: task.parallel_safe,
|
|
68
|
+
status: task.open ? 'pending' : 'integrated',
|
|
69
|
+
affected_paths: task.affected_paths,
|
|
70
|
+
exclusive_resources: task.exclusive_resources,
|
|
71
|
+
}));
|
|
72
|
+
const widths = [];
|
|
73
|
+
let remaining = openCommits.length;
|
|
74
|
+
for (let round = 0; remaining > 0; round += 1) {
|
|
75
|
+
const wave = round > tasks.length ? [] : readyWave(sim, { maxParallel: opts.maxParallel });
|
|
76
|
+
if (wave.length === 0) {
|
|
77
|
+
return { drive_shape: 'unknown', max_wave_width: Math.max(0, ...widths), ...summary };
|
|
78
|
+
}
|
|
79
|
+
widths.push(wave.length);
|
|
80
|
+
remaining -= wave.length;
|
|
81
|
+
for (const entry of sim)
|
|
82
|
+
if (wave.includes(entry.id))
|
|
83
|
+
entry.status = 'integrated';
|
|
84
|
+
}
|
|
85
|
+
const maxWidth = Math.max(...widths);
|
|
86
|
+
let shape = 'mixed';
|
|
87
|
+
if (maxWidth === 1)
|
|
88
|
+
shape = 'serial';
|
|
89
|
+
else if (widths.length === 1)
|
|
90
|
+
shape = 'parallel';
|
|
91
|
+
return { drive_shape: shape, max_wave_width: maxWidth, ...summary };
|
|
92
|
+
}
|
|
93
|
+
module.exports = { analyzeDriveShape, pathOverlapRatio };
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* 저장소 상대 경로를 skill-shape 문서 종류로 분류한다.
|
|
4
|
+
* 계약이 없는 companion·NOTICE·skill-local reference는 null을 돌려 기본 스캔에서
|
|
5
|
+
* 제외한다. 인자를 준 경우에는 호출부가 null을 오류로 처리한다.
|
|
6
|
+
*
|
|
7
|
+
* @param {string} relPath - cwd 기준 상대 경로
|
|
8
|
+
* @returns {DocKind|null} 문서 종류
|
|
9
|
+
*/
|
|
10
|
+
function classifyDocPath(relPath) {
|
|
11
|
+
const norm = relPath.replace(/\\/g, '/').replace(/^\.\//, '');
|
|
12
|
+
if (/^skills\/bouncer-[^/]+\/SKILL\.md$/.test(norm))
|
|
13
|
+
return 'workflow';
|
|
14
|
+
if (/^agents\/[^/]+\.md$/.test(norm))
|
|
15
|
+
return 'agent';
|
|
16
|
+
if (/^references\/[^/]+\/index\.md$/.test(norm))
|
|
17
|
+
return 'subskill';
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* coordinator 카드가 run 소유 reference를 읽을 때 요구하는 링크 계약을 만든다.
|
|
22
|
+
* 카드는 skills/bouncer-run/references/ 의 reader이므로 링크가 실재하고, 대상 선두 문단과
|
|
23
|
+
* 링크 문단이 같은 조건부 적재 trigger를 가져야 한다.
|
|
24
|
+
*
|
|
25
|
+
* @param {string} name - reference 파일 이름(확장자 제외)
|
|
26
|
+
* @param {string[]} triggers - 조건부 적재가 보존해야 하는 route 의미 단위
|
|
27
|
+
* @returns {LinkContract} links 계약 항목
|
|
28
|
+
*/
|
|
29
|
+
function runRefLink(name, triggers) {
|
|
30
|
+
return {
|
|
31
|
+
href: `../../skills/bouncer-run/references/${name}.md`,
|
|
32
|
+
resolve: true,
|
|
33
|
+
referencePreamble: true,
|
|
34
|
+
conditionalLoad: { triggers },
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
// 경로별 문서 구조 계약 표. 키는 저장소 상대 경로, 값은 checkDocShape의 두 번째 인자와
|
|
38
|
+
// 같은 계약 객체다. 종류별 고정 계약(classifyDocPath)이 표현하지 못하는 문서별 제목·단계·
|
|
39
|
+
// 링크 규칙을 테스트의 인라인 계약 대신 여기에 둔다. 새 검사 종류(문장 정규식 등)는
|
|
40
|
+
// 넣지 않는다 — 문구 고정은 문서를 다듬을 때마다 깨질 뿐 구조를 지키지 못한다.
|
|
41
|
+
const READONLY_ROLE_GUARDS = 'Hard guards (read-only)';
|
|
42
|
+
const DRIVE_METRICS_HEADINGS = ['Per coordinator session', 'Per root-direct session', 'Closing report'];
|
|
43
|
+
const AGENT_DISPATCH_HEADINGS = [
|
|
44
|
+
'Lightweight and implement dispatch', 'Named implementer', 'Implementer fallback', 'Intent bundle',
|
|
45
|
+
'Dispatch metadata and reports', 'Debugger dispatch', 'Worker model and token records', 'Worker hand-back',
|
|
46
|
+
];
|
|
47
|
+
const PATH_CONTRACTS = {
|
|
48
|
+
// 역할 문서: Authority → Hard guards → 역할 절차/rubric → Output contract 순서.
|
|
49
|
+
'agents/bouncer-implementer.md': {
|
|
50
|
+
headings: {
|
|
51
|
+
required: ['Authority', 'Hard guards', 'Procedure', 'Output contract'],
|
|
52
|
+
order: ['Authority', 'Hard guards', 'Procedure', 'Output contract'],
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
'agents/bouncer-coordinator.md': {
|
|
56
|
+
headings: {
|
|
57
|
+
required: ['Authority', 'Hard guards', 'Worker dispatch', 'Task round', 'Procedure', 'Output contract'],
|
|
58
|
+
order: ['Authority', 'Hard guards', 'Worker dispatch', 'Task round', 'Procedure', 'Output contract'],
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
'agents/bouncer-debugger.md': {
|
|
62
|
+
headings: {
|
|
63
|
+
required: ['Authority', READONLY_ROLE_GUARDS, 'Procedure', 'Output contract'],
|
|
64
|
+
order: ['Authority', READONLY_ROLE_GUARDS, 'Procedure', 'Output contract'],
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
'agents/bouncer-reviewer.md': {
|
|
68
|
+
headings: {
|
|
69
|
+
required: ['Authority', READONLY_ROLE_GUARDS, 'Review modes', 'Output contract'],
|
|
70
|
+
order: ['Authority', READONLY_ROLE_GUARDS, 'Review modes', 'Output contract'],
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
'agents/bouncer-context-reviewer.md': {
|
|
74
|
+
headings: {
|
|
75
|
+
required: ['Authority', READONLY_ROLE_GUARDS, 'Review modes', 'Output contract'],
|
|
76
|
+
order: ['Authority', READONLY_ROLE_GUARDS, 'Review modes', 'Output contract'],
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
// run 스킬의 dispatch reference: 종류가 없어 경로 계약이 유일한 구조 검사다. 기존 H2 절을
|
|
80
|
+
// 순서대로 고정하며 새 검사 종류는 넣지 않는다.
|
|
81
|
+
'skills/bouncer-run/references/agent-dispatch.md': {
|
|
82
|
+
headings: {
|
|
83
|
+
required: AGENT_DISPATCH_HEADINGS,
|
|
84
|
+
order: AGENT_DISPATCH_HEADINGS,
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
// run 스킬의 drive metrics reference: 종류가 없어 경로 계약이 유일한 구조 검사다. 기존 H2 절을
|
|
88
|
+
// 순서대로 고정하며 새 검사 종류는 넣지 않는다.
|
|
89
|
+
'skills/bouncer-run/references/drive-metrics.md': {
|
|
90
|
+
headings: {
|
|
91
|
+
required: DRIVE_METRICS_HEADINGS,
|
|
92
|
+
order: DRIVE_METRICS_HEADINGS,
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
// 루트 마스터 규칙: 하드룰 절과 검증 reference 링크(실재해야 한다).
|
|
96
|
+
'AGENTS.md': {
|
|
97
|
+
headings: { required: ['Hard rules'], order: ['Hard rules'] },
|
|
98
|
+
links: [{ href: 'references/verification/index.md', resolve: true }],
|
|
99
|
+
},
|
|
100
|
+
// 제품 규칙 문서: 소유 절 제목.
|
|
101
|
+
// coordinate repair의 거절 표(조건·reason 두 열)는 runCli가 coordinator-repair의 지원 reason과
|
|
102
|
+
// 대조한다. 필수 행은 두 거절 경로를 각각 설명하는 reason이다.
|
|
103
|
+
'rules/cli.md': {
|
|
104
|
+
rejectionTable: { required: ['final-review-single-round', 'final-review-repair-scope'] },
|
|
105
|
+
},
|
|
106
|
+
'rules/commit-scope.md': {
|
|
107
|
+
headings: {
|
|
108
|
+
required: ['Commit unit and staging', 'Approved and ledger scope', 'Worktree and enforcement layers'],
|
|
109
|
+
order: ['Commit unit and staging', 'Approved and ledger scope', 'Worktree and enforcement layers'],
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
'rules/current-pointer.md': {
|
|
113
|
+
headings: {
|
|
114
|
+
required: ['Read and task selection', 'Moves and clears'],
|
|
115
|
+
order: ['Read and task selection', 'Moves and clears'],
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
'rules/plugin-root.md': { headings: { required: ['Master and product rules'] } },
|
|
119
|
+
'rules/planning.md': { headings: { required: ['Lightweight cycle'] } },
|
|
120
|
+
// 102-001에서 execute 스킬의 reference가 run 소유로 옮겨졌다. coordinator 카드가 그
|
|
121
|
+
// reference의 읽는 쪽이라, 링크가 실재하고 조건부 적재 문장 안에 있어야 한다.
|
|
122
|
+
'references/coordinator-cards/implement.md': {
|
|
123
|
+
links: [
|
|
124
|
+
runRefLink('agent-dispatch', ['dispatch', 'fallback']),
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
'references/coordinator-cards/verify.md': {
|
|
128
|
+
links: [
|
|
129
|
+
runRefLink('verification-recovery', ['verify', 'recover']),
|
|
130
|
+
],
|
|
131
|
+
},
|
|
132
|
+
'references/coordinator-cards/review.md': {
|
|
133
|
+
links: [
|
|
134
|
+
runRefLink('agent-dispatch', ['dispatch', 'fallback']),
|
|
135
|
+
runRefLink('review-round', ['review', 'round']),
|
|
136
|
+
],
|
|
137
|
+
},
|
|
138
|
+
// subskill frontmatter 정체성(종류별 계약은 frontmatter를 보지 않는다).
|
|
139
|
+
'references/debugging/index.md': {
|
|
140
|
+
frontmatter: { required: ['name', 'description'], nonEmpty: ['description'], values: { name: 'debugging' } },
|
|
141
|
+
},
|
|
142
|
+
'references/explain-diff/index.md': {
|
|
143
|
+
frontmatter: { required: ['name', 'description'], nonEmpty: ['description'], values: { name: 'explain-diff' } },
|
|
144
|
+
},
|
|
145
|
+
'references/context-review/index.md': {
|
|
146
|
+
frontmatter: { required: ['name', 'description'], nonEmpty: ['description'], values: { name: 'context-review' } },
|
|
147
|
+
},
|
|
148
|
+
// plan 워크플로: 여덟 번호 단계, ACQ는 1·2·3·4·6단계에만 둔다.
|
|
149
|
+
'skills/bouncer-plan/SKILL.md': {
|
|
150
|
+
frontmatter: { required: ['name', 'description'], values: { name: 'bouncer-plan' } },
|
|
151
|
+
links: [{
|
|
152
|
+
href: './references/scope-confirm.md',
|
|
153
|
+
resolve: true,
|
|
154
|
+
referencePreamble: true,
|
|
155
|
+
conditionalLoad: { triggers: ['confirm', 'affected_paths'] },
|
|
156
|
+
}],
|
|
157
|
+
steps: {
|
|
158
|
+
required: [1, 2, 3, 4, 5, 6, 7, 8],
|
|
159
|
+
order: true,
|
|
160
|
+
acq: [1, 2, 3, 4, 6],
|
|
161
|
+
links: {
|
|
162
|
+
3: ['./references/evidence-dispatch.md'],
|
|
163
|
+
4: ['./references/scope-confirm.md'],
|
|
164
|
+
5: ['./references/context-review.md'],
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
acqIndex: { heading: 'ACQ (AskUserQuestion) gates', steps: [1, 2, 3, 4, 6], only: true },
|
|
168
|
+
},
|
|
169
|
+
// init 워크플로: 네 번호 단계. 결과 처리 reference는 단계 2에서만 적재하고 부트스트랩보다
|
|
170
|
+
// 앞서지 않는다(단계 번호 순서가 그 선후를 고정한다). 동의 ACQ 색인은 단계 2 하나다.
|
|
171
|
+
'skills/bouncer-init/SKILL.md': {
|
|
172
|
+
frontmatter: { required: ['name', 'description'], values: { name: 'bouncer-init' } },
|
|
173
|
+
steps: {
|
|
174
|
+
required: [1, 2, 3, 4],
|
|
175
|
+
order: true,
|
|
176
|
+
links: { 2: ['./references/init-result.md'] },
|
|
177
|
+
},
|
|
178
|
+
acqIndex: { heading: 'ACQ (AskUserQuestion) gates', steps: [2], only: true },
|
|
179
|
+
},
|
|
180
|
+
// 출력 계약 규칙: 보고 형식 절. 워크플로가 이 문서를 적재하므로 절이 사라지면 안 된다.
|
|
181
|
+
'rules/output.md': {
|
|
182
|
+
headings: { required: ['compact', 'coordinator 실행', 'debug', '숨길 수 없는 항목'] },
|
|
183
|
+
},
|
|
184
|
+
// 루트 README: 라이선스·보안·행동강령 문서로 가는 링크(실재해야 한다).
|
|
185
|
+
'README.md': {
|
|
186
|
+
links: [
|
|
187
|
+
{ href: 'LICENSE', resolve: true },
|
|
188
|
+
{ href: 'SECURITY.md', resolve: true },
|
|
189
|
+
{ href: 'CODE_OF_CONDUCT.md', resolve: true },
|
|
190
|
+
],
|
|
191
|
+
},
|
|
192
|
+
// 보조 스킬(subskill): frontmatter 정체성과 절차 번호. 종류별 계약은 frontmatter를 보지 않는다.
|
|
193
|
+
'references/graphify-runner/index.md': {
|
|
194
|
+
frontmatter: { required: ['name', 'description'], nonEmpty: ['description'], values: { name: 'graphify-runner' } },
|
|
195
|
+
steps: { required: [1, 2, 3, 4, 5], order: true },
|
|
196
|
+
},
|
|
197
|
+
'references/implementation/index.md': {
|
|
198
|
+
frontmatter: { required: ['name', 'description'], nonEmpty: ['description'], values: { name: 'implementation' } },
|
|
199
|
+
headings: {
|
|
200
|
+
required: ['When this applies', 'Steps', 'Guardrails', 'Return'],
|
|
201
|
+
order: ['When this applies', 'Steps', 'Guardrails', 'Return'],
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
// 공통 코딩 표준 정본: 역할 문서가 절 이름으로 가리키므로 아홉 절이 모두 있어야 한다.
|
|
205
|
+
'references/coding-standards/index.md': {
|
|
206
|
+
frontmatter: { required: ['name', 'description'], nonEmpty: ['description'], values: { name: 'coding-standards' } },
|
|
207
|
+
headings: {
|
|
208
|
+
required: [
|
|
209
|
+
'When this applies', 'Core rules', 'Tests', 'Test trust', 'Error handling',
|
|
210
|
+
'Reuse and abstraction', 'Comments and docstrings', 'Guardrails', 'Return',
|
|
211
|
+
],
|
|
212
|
+
order: [
|
|
213
|
+
'When this applies', 'Core rules', 'Tests', 'Test trust', 'Error handling',
|
|
214
|
+
'Reuse and abstraction', 'Comments and docstrings', 'Guardrails', 'Return',
|
|
215
|
+
],
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
// minimality 사다리는 일곱 단이며 단 번호가 갈라져 있어야 native/stdlib가 한 단으로 합쳐지지 않는다.
|
|
219
|
+
'references/minimality/index.md': {
|
|
220
|
+
frontmatter: { required: ['name', 'description'], nonEmpty: ['description'], values: { name: 'minimality' } },
|
|
221
|
+
steps: { required: [1, 2, 3, 4, 5, 6, 7], order: true },
|
|
222
|
+
},
|
|
223
|
+
'references/discovery/index.md': {
|
|
224
|
+
frontmatter: { required: ['name', 'description'], nonEmpty: ['description'], values: { name: 'discovery' } },
|
|
225
|
+
steps: { required: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], order: true },
|
|
226
|
+
},
|
|
227
|
+
'references/stop-slop/index.md': {
|
|
228
|
+
frontmatter: { required: ['name', 'description'], nonEmpty: ['description'], values: { name: 'stop-slop' } },
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
/**
|
|
232
|
+
* 경로 계약 표에서 상대 경로의 계약을 찾는다.
|
|
233
|
+
*
|
|
234
|
+
* @param {string} relPath - cwd 기준 상대 경로
|
|
235
|
+
* @returns {DocContract|null} 표에 있으면 계약 객체, 없으면 null
|
|
236
|
+
*/
|
|
237
|
+
function pathContractFor(relPath) {
|
|
238
|
+
const norm = relPath.replace(/\\/g, '/').replace(/^\.\//, '');
|
|
239
|
+
return Object.prototype.hasOwnProperty.call(PATH_CONTRACTS, norm) ? PATH_CONTRACTS[norm] : null;
|
|
240
|
+
}
|
|
241
|
+
module.exports = { classifyDocPath, pathContractFor, PATH_CONTRACTS };
|