gennady 0.7.0 → 0.8.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/ai/directives/coding/result-conventions.xml +25 -7
- package/ai/directives/sdd/audit.directive.xml +1 -1
- package/ai/directives/sdd/critic-protocol.xml +78 -0
- package/ai/directives/sdd/critic.directive.xml +158 -0
- package/ai/directives/sdd/phase-execution-protocol.xml +11 -9
- package/ai/skills/alt-opinion/SKILL.md +79 -0
- package/ai/skills/alt-opinion/opinion.prompt.md +11 -0
- package/ai/skills/alt-opinion/synth.prompt.md +8 -0
- package/ai/skills/sdd-audit/SKILL.md +13 -0
- package/ai/skills/sdd-check/SKILL.md +139 -0
- package/ai/skills/sdd-continue/SKILL.md +13 -0
- package/ai/skills/sdd-critic/SKILL.md +12 -0
- package/ai/skills/sdd-discover/SKILL.md +13 -0
- package/ai/skills/sdd-execute/SKILL.md +205 -0
- package/ai/skills/sdd-execute/scripts/README.md +84 -0
- package/ai/skills/sdd-execute/scripts/check-blockers.sh +158 -0
- package/ai/skills/sdd-execute/scripts/classify-scripts.js +111 -0
- package/ai/skills/sdd-execute/scripts/classify-scripts.ts +133 -0
- package/ai/skills/sdd-execute/scripts/extract-section.sh +219 -0
- package/ai/skills/sdd-execute/scripts/lint-artifacts.sh +143 -0
- package/ai/skills/sdd-execute/scripts/scan.sh +385 -0
- package/ai/skills/sdd-execute/scripts/sdd +114 -0
- package/ai/skills/sdd-execute/scripts/verify.sh +139 -0
- package/ai/skills/sdd-execute-batch/SKILL.md +213 -0
- package/ai/skills/sdd-fix/SKILL.md +13 -0
- package/ai/skills/sdd-infra/SKILL.md +13 -0
- package/ai/skills/sdd-module-decomposition/SKILL.md +13 -0
- package/ai/skills/sdd-scaffold/SKILL.md +13 -0
- package/ai/skills/sdd-setup/SKILL.md +13 -0
- package/dist/ai/directives/coding/result-conventions.xml +25 -7
- package/dist/ai/directives/sdd/audit.directive.xml +1 -1
- package/dist/ai/directives/sdd/critic-protocol.xml +78 -0
- package/dist/ai/directives/sdd/critic.directive.xml +158 -0
- package/dist/ai/directives/sdd/phase-execution-protocol.xml +11 -9
- package/dist/ai/skills/alt-opinion/SKILL.md +79 -0
- package/dist/ai/skills/alt-opinion/opinion.prompt.md +11 -0
- package/dist/ai/skills/alt-opinion/synth.prompt.md +8 -0
- package/dist/ai/skills/sdd-audit/SKILL.md +13 -0
- package/dist/ai/skills/sdd-check/SKILL.md +139 -0
- package/dist/ai/skills/sdd-continue/SKILL.md +13 -0
- package/dist/ai/skills/sdd-critic/SKILL.md +12 -0
- package/dist/ai/skills/sdd-discover/SKILL.md +13 -0
- package/dist/ai/skills/sdd-execute/SKILL.md +205 -0
- package/dist/ai/skills/sdd-execute/scripts/README.md +84 -0
- package/dist/ai/skills/sdd-execute/scripts/check-blockers.sh +158 -0
- package/dist/ai/skills/sdd-execute/scripts/classify-scripts.js +111 -0
- package/dist/ai/skills/sdd-execute/scripts/classify-scripts.ts +133 -0
- package/dist/ai/skills/sdd-execute/scripts/extract-section.sh +219 -0
- package/dist/ai/skills/sdd-execute/scripts/lint-artifacts.sh +143 -0
- package/dist/ai/skills/sdd-execute/scripts/scan.sh +385 -0
- package/dist/ai/skills/sdd-execute/scripts/sdd +114 -0
- package/dist/ai/skills/sdd-execute/scripts/verify.sh +139 -0
- package/dist/ai/skills/sdd-execute-batch/SKILL.md +213 -0
- package/dist/ai/skills/sdd-fix/SKILL.md +13 -0
- package/dist/ai/skills/sdd-infra/SKILL.md +13 -0
- package/dist/ai/skills/sdd-module-decomposition/SKILL.md +13 -0
- package/dist/ai/skills/sdd-scaffold/SKILL.md +13 -0
- package/dist/ai/skills/sdd-setup/SKILL.md +13 -0
- package/dist/chunks/_commonjsHelpers-DaMA6jEr.js +8 -0
- package/dist/chunks/{devtools-B-7ugZhF.js → devtools-CPZ0IUNM.js} +1 -1
- package/dist/chunks/help-5qCaicff.js +6 -0
- package/dist/chunks/help-B2ETH0j6.js +6 -0
- package/dist/chunks/help-BCDURaCQ.js +6 -0
- package/dist/chunks/help-BvgYOSyQ.js +6 -0
- package/dist/chunks/help-CSPhOoI9.js +8 -0
- package/dist/chunks/help-CV1vpwrh.js +6 -0
- package/dist/chunks/help-CaBNA6Qr.js +12 -0
- package/dist/chunks/help-CjkR6SB9.js +6 -0
- package/dist/chunks/help-Coi1l5u9.js +8 -0
- package/dist/chunks/help-CsuLpZn-.js +8 -0
- package/dist/chunks/help-DL_QBMwy.js +8 -0
- package/dist/chunks/help-DqBZ2xcp.js +6 -0
- package/dist/chunks/help-_Y_TN4DZ.js +6 -0
- package/dist/chunks/{help.cmd-B_G7EWzF.js → help.cmd-BseRtoBF.js} +10 -2
- package/dist/chunks/{index-zBnnuvLA.js → index-BU1AXJGA.js} +12 -7
- package/dist/chunks/{index-CXuhZzS3.js → index-BXWDYM_9.js} +1 -1
- package/dist/chunks/index-BgKyH0dB.js +658 -0
- package/dist/chunks/{index-CaahtXiM.js → index-BghL1-Nk.js} +2 -2
- package/dist/chunks/{index-BeL1Zcbg.js → index-BlqEQEGy.js} +1 -1
- package/dist/chunks/{index-D1qsi0Uc.js → index-CDM74qdR.js} +3 -3
- package/dist/chunks/{index-D9ceRUyB.js → index-CGsIRefC.js} +2 -2
- package/dist/chunks/{index-CiEM-8nJ.js → index-CIvkaAQ3.js} +2 -2
- package/dist/chunks/{index-UbHoePfr.js → index-CkczJ__m.js} +10 -10
- package/dist/chunks/index-CtJKSOL0.js +21 -0
- package/dist/chunks/index-DEzym4Ae.js +369 -0
- package/dist/chunks/{index-CVR66voe.js → index-DoaxOhQ8.js} +401 -393
- package/dist/chunks/index-Du1xR-qO.js +752 -0
- package/dist/chunks/{index-DU6jD7SS.js → index-OtehG7uM.js} +1 -1
- package/dist/chunks/index-ZM_FonZj.js +156 -0
- package/dist/chunks/{index-g1LXlp77.js → index-k0nToACp.js} +2 -2
- package/dist/chunks/{run-review-command.logic-DpkRoEi8.js → run-review-command.logic-BeYQin-I.js} +9 -9
- package/dist/chunks/services-IgZptnTi.js +2732 -0
- package/dist/chunks/shared-DL_1LG0K.js +753 -0
- package/dist/cli/cmd/agent-mon/help.d.ts +4 -0
- package/dist/cli/cmd/agents-rules/agents-rules.cmd.d.ts +8 -0
- package/dist/cli/cmd/agents-rules/index.d.ts +1 -0
- package/dist/cli/cmd/alt-opinion/help.d.ts +4 -0
- package/dist/cli/cmd/cat/help.d.ts +4 -0
- package/dist/cli/cmd/commit/help.d.ts +4 -0
- package/dist/cli/cmd/lint/checks/anchor-class-body.check.d.ts +11 -0
- package/dist/cli/cmd/lint/checks/invariant-count.check.d.ts +11 -0
- package/dist/cli/cmd/lint/checks/utils/glob-match.d.ts +15 -0
- package/dist/cli/cmd/lint/checks/utils/strip-strings-comments.d.ts +7 -0
- package/dist/cli/cmd/lint/help.d.ts +4 -0
- package/dist/cli/cmd/lint/lint.cmd.d.ts +1 -1
- package/dist/cli/cmd/lint/lint.types.d.ts +6 -0
- package/dist/cli/cmd/orient/core/build-index.d.ts +8 -0
- package/dist/cli/cmd/orient/core/damerau-levenshtein.d.ts +26 -0
- package/dist/cli/cmd/orient/core/extract-header.d.ts +8 -0
- package/dist/cli/cmd/orient/core/hints.d.ts +9 -0
- package/dist/cli/cmd/orient/core/query-consumer.d.ts +10 -0
- package/dist/cli/cmd/orient/core/query-entity.d.ts +11 -0
- package/dist/cli/cmd/orient/core/query-graph.d.ts +18 -0
- package/dist/cli/cmd/orient/core/query-keyword.d.ts +10 -0
- package/dist/cli/cmd/orient/core/query-spec.d.ts +15 -0
- package/dist/cli/cmd/orient/core/query-task.d.ts +8 -0
- package/dist/cli/cmd/orient/core/scan-files.d.ts +8 -0
- package/dist/cli/cmd/orient/help.d.ts +5 -0
- package/dist/cli/cmd/orient/index.d.ts +1 -0
- package/dist/cli/cmd/orient/orient.cmd.d.ts +7 -0
- package/dist/cli/cmd/orient/orient.types.d.ts +136 -0
- package/dist/cli/cmd/orient/render/render-detail.d.ts +10 -0
- package/dist/cli/cmd/orient/render/render-file-list.d.ts +15 -0
- package/dist/cli/cmd/orient/render/render-graph.d.ts +13 -0
- package/dist/cli/cmd/orient/render/render-search.d.ts +8 -0
- package/dist/cli/cmd/orient/render/render-specs.d.ts +13 -0
- package/dist/cli/cmd/orient/render/render-tree.d.ts +13 -0
- package/dist/cli/cmd/remote-console/help.d.ts +4 -0
- package/dist/cli/cmd/resolve-conflicts/help.d.ts +4 -0
- package/dist/cli/cmd/review/help.d.ts +4 -0
- package/dist/cli/cmd/review-issues/help.d.ts +4 -0
- package/dist/cli/cmd/review-verify/help.d.ts +4 -0
- package/dist/cli/cmd/sync/help.d.ts +4 -0
- package/dist/cli/cmd/sync/sync-core.d.ts +3 -2
- package/dist/cli/cmd/sync/sync-formatter.d.ts +8 -9
- package/dist/cli/cmd/sync/sync.cmd.d.ts +2 -21
- package/dist/cli/cmd/sync-skills/index.d.ts +1 -0
- package/dist/cli/cmd/sync-skills/sync-skills-core.d.ts +50 -0
- package/dist/cli/cmd/sync-skills/sync-skills-formatter.d.ts +13 -0
- package/dist/cli/cmd/sync-skills/sync-skills.cmd.d.ts +14 -0
- package/dist/cli/cmd/sync-skills/sync-skills.types.d.ts +56 -0
- package/dist/cli/cmd/vcs-reply/help.d.ts +4 -0
- package/dist/gennady.js +73 -18
- package/dist/index.js +5 -5
- package/dist/services/dbc/linter/implementations/ts/dbc-ts-ast-adapter.d.ts +3 -2
- package/dist/shared/common/sync/path-normalizer.d.ts +22 -0
- package/dist/shared/common/sync/sync-core.shared.d.ts +14 -0
- package/dist/shared/common/sync/sync-deps.type.d.ts +66 -0
- package/dist/shared/common/sync/sync-formatter.shared.d.ts +19 -0
- package/package.json +6 -5
- package/dist/chunks/index-DJpVmyp2.js +0 -176
- package/dist/chunks/index-KxSZKmZn.js +0 -540
- package/dist/chunks/services-CaLOhuLV.js +0 -2889
- package/dist/chunks/shared-Bjy30TeM.js +0 -665
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --import tsx
|
|
2
|
+
// @file: Heuristic npm script classifier — reads package.json, outputs discovered commands as JSON.
|
|
3
|
+
// @consumers: verify.sh
|
|
4
|
+
// @tasks: TSK-55
|
|
5
|
+
//
|
|
6
|
+
// Usage:
|
|
7
|
+
// classify-scripts.ts [--json] [project-root]
|
|
8
|
+
//
|
|
9
|
+
// Output:
|
|
10
|
+
// --json (default): JSON array [{name, body, classes}]
|
|
11
|
+
// no flag: human-readable summary
|
|
12
|
+
|
|
13
|
+
import { readFileSync } from 'node:fs';
|
|
14
|
+
import { resolve } from 'node:path';
|
|
15
|
+
|
|
16
|
+
type ScriptClass = 'typecheck' | 'gennady' | 'lint' | 'test' | 'format' | 'umbrella' | 'unknown';
|
|
17
|
+
|
|
18
|
+
interface ScriptEntry {
|
|
19
|
+
name: string;
|
|
20
|
+
body: string;
|
|
21
|
+
classes: ScriptClass[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface ClassifiedProject {
|
|
25
|
+
scripts: ScriptEntry[];
|
|
26
|
+
selected: Partial<Record<ScriptClass, string>>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function hasCategory(body: string, category: string): boolean {
|
|
30
|
+
const patterns: Record<string, RegExp> = {
|
|
31
|
+
tsc: /\b(tsc|tsgo)\b/,
|
|
32
|
+
lint: /\b(eslint|mail-core-lint\b|biome check\b|standard\b)\b/,
|
|
33
|
+
test: /\b(jest|vitest|playwright test|mocha\b|--test\b)\b/,
|
|
34
|
+
format: /\b(prettier|biome format)\b/,
|
|
35
|
+
};
|
|
36
|
+
return patterns[category]?.test(body) ?? false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function classify(name: string, body: string): ScriptClass[] {
|
|
40
|
+
const isUmbrellaName = /^(check|ci-check|check:all|verify)$/.test(name);
|
|
41
|
+
if (isUmbrellaName && body.length > 0) return ['umbrella'];
|
|
42
|
+
|
|
43
|
+
const tscCount = hasCategory(body, 'tsc') ? 1 : 0;
|
|
44
|
+
const lintCount = hasCategory(body, 'lint') ? 1 : 0;
|
|
45
|
+
const testCount = hasCategory(body, 'test') ? 1 : 0;
|
|
46
|
+
const hasGennady = /\bgennady\b/.test(body) || /lint:contracts/.test(body);
|
|
47
|
+
const hasChain = body.includes('&&');
|
|
48
|
+
const hasParallel = /[&]/.test(body) && /;\s*wait/.test(body);
|
|
49
|
+
|
|
50
|
+
if (tscCount + lintCount + testCount >= 2 && (hasChain || hasParallel)) return ['umbrella'];
|
|
51
|
+
if (hasGennady && hasChain) return ['umbrella'];
|
|
52
|
+
|
|
53
|
+
const classes: ScriptClass[] = [];
|
|
54
|
+
if (hasGennady) classes.push('gennady');
|
|
55
|
+
|
|
56
|
+
const typecheckName = /^(type-?check|typecheck|typecheck:|tsc)$/.test(name);
|
|
57
|
+
const typecheckBody = /\b(tsc|tsgo)\b/.test(body) && /--noEmit/.test(body);
|
|
58
|
+
if (
|
|
59
|
+
(typecheckName || typecheckBody || name === 'lint:ts') &&
|
|
60
|
+
!name.startsWith('build:') &&
|
|
61
|
+
!name.startsWith('prepublish')
|
|
62
|
+
)
|
|
63
|
+
classes.push('typecheck');
|
|
64
|
+
|
|
65
|
+
const lintName = /^(lint|lint:all|lint-check|eslint|mc:eslint|stylist:lint|stylelint)$/.test(
|
|
66
|
+
name
|
|
67
|
+
);
|
|
68
|
+
const lintBody = hasCategory(body, 'lint');
|
|
69
|
+
if (
|
|
70
|
+
(lintName || lintBody) &&
|
|
71
|
+
!name.startsWith('lint:fix') &&
|
|
72
|
+
!name.startsWith('lint:contracts') &&
|
|
73
|
+
!name.startsWith('lint:ts') &&
|
|
74
|
+
!hasGennady
|
|
75
|
+
)
|
|
76
|
+
classes.push('lint');
|
|
77
|
+
|
|
78
|
+
const testName = /^(test|test:|mc:test|mc:jest|jest)$/.test(name);
|
|
79
|
+
const testBody = hasCategory(body, 'test') || /\bnode\b.*--test\b/.test(body);
|
|
80
|
+
if (testName || (testBody && !name.startsWith('build:') && !name.startsWith('prepublish')))
|
|
81
|
+
classes.push('test');
|
|
82
|
+
|
|
83
|
+
const formatName = /^format(:?check)?$/.test(name);
|
|
84
|
+
const formatBody = hasCategory(body, 'format');
|
|
85
|
+
if (formatName || formatBody) classes.push('format');
|
|
86
|
+
|
|
87
|
+
return classes.length > 0 ? classes : ['unknown'];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function selectBest(entries: ScriptEntry[], cls: ScriptClass): string | undefined {
|
|
91
|
+
const candidates = entries.filter((e) => e.classes.includes(cls));
|
|
92
|
+
if (candidates.length === 0) return undefined;
|
|
93
|
+
|
|
94
|
+
// Prefer shorter, more specific names
|
|
95
|
+
const priority: Record<string, number> = {
|
|
96
|
+
typecheck: { 'type-check': 10, typecheck: 10, tsc: 5 },
|
|
97
|
+
gennady: { 'lint:contracts': 10 },
|
|
98
|
+
lint: { lint: 10, eslint: 7, 'lint:all': 5, 'lint-check': 5, 'mc:eslint': 3 },
|
|
99
|
+
test: { test: 10, 'test:unit': 7, 'mc:test': 5, 'mc:jest': 3, jest: 3 },
|
|
100
|
+
format: { 'format:check': 10, format: 5 },
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const rank = (name: string) => priority[cls]?.[name] ?? 1;
|
|
104
|
+
candidates.sort((a, b) => rank(b.name) - rank(a.name));
|
|
105
|
+
return candidates[0]?.name;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// --- Main ---
|
|
109
|
+
const root = process.argv.slice(2).find((a) => !a.startsWith('-')) || process.cwd();
|
|
110
|
+
const pkgPath = resolve(root, 'package.json');
|
|
111
|
+
|
|
112
|
+
let pkg: { scripts?: Record<string, string> };
|
|
113
|
+
try {
|
|
114
|
+
pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
115
|
+
} catch {
|
|
116
|
+
console.error(`[classify-scripts] package.json not found at ${pkgPath}`);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const entries: ScriptEntry[] = Object.entries(pkg.scripts ?? {}).map(([name, body]) => ({
|
|
121
|
+
name,
|
|
122
|
+
body,
|
|
123
|
+
classes: classify(name, body),
|
|
124
|
+
}));
|
|
125
|
+
|
|
126
|
+
const selected: Partial<Record<ScriptClass, string>> = {};
|
|
127
|
+
for (const cls of ['typecheck', 'gennady', 'lint', 'test', 'format'] as ScriptClass[]) {
|
|
128
|
+
const best = selectBest(entries, cls);
|
|
129
|
+
if (best) selected[cls] = best;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const result: ClassifiedProject = { scripts: entries, selected };
|
|
133
|
+
console.log(JSON.stringify(result));
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# @file: Extract a named section between <!--SECTION:<NAME>--> / <!--/SECTION:<NAME>--> markers from a markdown file.
|
|
3
|
+
# @consumers: sdd-execute, sdd-execute-batch (L2 orchestrator prompt-building); phase agents (rules extraction)
|
|
4
|
+
# @contract: AX_BASH_NO_SILENT_EMPTY — never produces empty stdout. On miss → emits actionable instruction for the orchestrator + exit ≠ 0.
|
|
5
|
+
#
|
|
6
|
+
# Anchor grammar (canonical, AX_TICKET_ANCHOR_FORMAT):
|
|
7
|
+
# Open marker: <!--SECTION:<NAME>-->
|
|
8
|
+
# Close marker: <!--/SECTION:<NAME>-->
|
|
9
|
+
# <NAME>: ^[A-Z][A-Z0-9_]*$ (uppercase, starts with letter, alnum + underscore only)
|
|
10
|
+
# No quotes, no spaces, no attributes — atomic identifiers only.
|
|
11
|
+
#
|
|
12
|
+
# Canonical names: META, PHASES_OVERVIEW, PHASE_P1, PHASE_P2, PHASE_P1_FIX, BDD, VERIFICATION, TEST_COVERAGE, EXECUTION_LOG.
|
|
13
|
+
#
|
|
14
|
+
# Usage:
|
|
15
|
+
# extract-section.sh <file> <NAME>
|
|
16
|
+
#
|
|
17
|
+
# Examples:
|
|
18
|
+
# extract-section.sh ticket.md META
|
|
19
|
+
# extract-section.sh ticket.md PHASE_P1
|
|
20
|
+
# extract-section.sh ticket.md EXECUTION_LOG
|
|
21
|
+
#
|
|
22
|
+
# Exit codes:
|
|
23
|
+
# 0 — section found, content emitted to stdout
|
|
24
|
+
# 1 — file not found / unreadable
|
|
25
|
+
# 2 — anchor markers not present in file
|
|
26
|
+
# 3 — START found but END missing, or vice versa (corrupted markers), or duplicate occurrences
|
|
27
|
+
# 4 — bad invocation (missing args, invalid NAME)
|
|
28
|
+
|
|
29
|
+
set -uo pipefail
|
|
30
|
+
|
|
31
|
+
PROG="extract-section"
|
|
32
|
+
NAME_REGEX='^[A-Z][A-Z0-9_]*$'
|
|
33
|
+
|
|
34
|
+
if [[ $# -ne 2 ]]; then
|
|
35
|
+
cat <<EOF
|
|
36
|
+
[$PROG] BAD_INVOCATION
|
|
37
|
+
expected: $PROG <file> <NAME>
|
|
38
|
+
got: $PROG $*
|
|
39
|
+
|
|
40
|
+
Required action (ORCHESTRATOR):
|
|
41
|
+
Pass exactly 2 arguments — file path and SECTION name.
|
|
42
|
+
NAME must match: $NAME_REGEX
|
|
43
|
+
Examples of valid names: META, PHASES_OVERVIEW, PHASE_P1, BDD, EXECUTION_LOG.
|
|
44
|
+
EOF
|
|
45
|
+
exit 4
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
file="$1"
|
|
49
|
+
name="$2"
|
|
50
|
+
|
|
51
|
+
# ---------------------------------------------------------------------------
|
|
52
|
+
# NAME validation
|
|
53
|
+
# ---------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
if [[ ! "$name" =~ $NAME_REGEX ]]; then
|
|
56
|
+
cat <<EOF
|
|
57
|
+
[$PROG] INVALID_NAME
|
|
58
|
+
name: $name
|
|
59
|
+
rule: $NAME_REGEX
|
|
60
|
+
|
|
61
|
+
Diagnosis: section name does not match canonical anchor grammar.
|
|
62
|
+
|
|
63
|
+
Required action (ORCHESTRATOR):
|
|
64
|
+
1. Use uppercase letters, digits, and underscores only.
|
|
65
|
+
2. Start with a letter (not a digit or underscore).
|
|
66
|
+
3. No spaces, no quotes, no attributes inside the name.
|
|
67
|
+
|
|
68
|
+
Canonical names: META, PHASES_OVERVIEW, PHASE_P1, PHASE_P2, PHASE_P1_FIX,
|
|
69
|
+
BDD, VERIFICATION, TEST_COVERAGE, EXECUTION_LOG.
|
|
70
|
+
|
|
71
|
+
If you need attributes (kind, rules, etc.) — put them inside the section content,
|
|
72
|
+
NOT inside the anchor name. The anchor is an identifier only.
|
|
73
|
+
EOF
|
|
74
|
+
exit 4
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
# ---------------------------------------------------------------------------
|
|
78
|
+
# File existence + readability
|
|
79
|
+
# ---------------------------------------------------------------------------
|
|
80
|
+
|
|
81
|
+
if [[ ! -f "$file" ]]; then
|
|
82
|
+
cat <<EOF
|
|
83
|
+
[$PROG] FILE_NOT_FOUND
|
|
84
|
+
file: $file
|
|
85
|
+
|
|
86
|
+
Required action (ORCHESTRATOR):
|
|
87
|
+
1. Verify the file path argument (typos, wrong scope, wrong task-id).
|
|
88
|
+
2. Check whether the ticket/spec exists at the expected location.
|
|
89
|
+
3. If task ID resolves to a different path — fix the resolution layer, not this script.
|
|
90
|
+
|
|
91
|
+
DO NOT proceed to dispatch phase agent until the file is located.
|
|
92
|
+
EOF
|
|
93
|
+
exit 1
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
if [[ ! -r "$file" ]]; then
|
|
97
|
+
cat <<EOF
|
|
98
|
+
[$PROG] FILE_NOT_READABLE
|
|
99
|
+
file: $file
|
|
100
|
+
perms: $(stat -f '%Sp' "$file" 2>/dev/null || stat -c '%A' "$file" 2>/dev/null || echo 'unknown')
|
|
101
|
+
|
|
102
|
+
Required action (ORCHESTRATOR):
|
|
103
|
+
Verify file permissions; chmod if needed.
|
|
104
|
+
EOF
|
|
105
|
+
exit 1
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
# ---------------------------------------------------------------------------
|
|
109
|
+
# Marker scan — pre-flight before extraction
|
|
110
|
+
# ---------------------------------------------------------------------------
|
|
111
|
+
|
|
112
|
+
start_marker="<!--SECTION:${name}-->"
|
|
113
|
+
end_marker="<!--/SECTION:${name}-->"
|
|
114
|
+
|
|
115
|
+
start_count=$(grep -cF "$start_marker" "$file" || true)
|
|
116
|
+
end_count=$(grep -cF "$end_marker" "$file" || true)
|
|
117
|
+
|
|
118
|
+
if [[ "$start_count" -eq 0 && "$end_count" -eq 0 ]]; then
|
|
119
|
+
cat <<EOF
|
|
120
|
+
[$PROG] ANCHOR_NOT_FOUND
|
|
121
|
+
section: $name
|
|
122
|
+
file: $file
|
|
123
|
+
searched markers:
|
|
124
|
+
$start_marker
|
|
125
|
+
$end_marker
|
|
126
|
+
|
|
127
|
+
Diagnosis: file does not contain anchor markers for this section.
|
|
128
|
+
|
|
129
|
+
Possible causes:
|
|
130
|
+
1. Ticket/spec scaffolded before anchor convention introduced (pre-2026-05-21).
|
|
131
|
+
2. Anchor was deleted or corrupted during manual edit.
|
|
132
|
+
3. Wrong section name — verify against canonical names
|
|
133
|
+
(META, PHASES_OVERVIEW, PHASE_P<N>, BDD, VERIFICATION, TEST_COVERAGE, EXECUTION_LOG).
|
|
134
|
+
4. Section uses non-canonical name — review file structure.
|
|
135
|
+
|
|
136
|
+
Required action (ORCHESTRATOR, not phase agent):
|
|
137
|
+
1. Read the file directly via Read tool.
|
|
138
|
+
2. Verify the section exists by markdown header (e.g. ## 1. Meta, ### P1 — impl).
|
|
139
|
+
3. If section exists in header form but lacks anchors → retrofit anchors per
|
|
140
|
+
AX_TICKET_ANCHOR_FORMAT in ~/Developer/gennady/ai/directives/sdd/scaffold.directive.xml.
|
|
141
|
+
4. If section does not exist at all → escalate to operator: ticket needs
|
|
142
|
+
re-scaffolding or section content authoring.
|
|
143
|
+
|
|
144
|
+
DO NOT proceed to dispatch a phase agent until anchors are in place.
|
|
145
|
+
EOF
|
|
146
|
+
exit 2
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
if [[ "$start_count" -ne "$end_count" ]]; then
|
|
150
|
+
cat <<EOF
|
|
151
|
+
[$PROG] ANCHOR_UNBALANCED
|
|
152
|
+
section: $name
|
|
153
|
+
file: $file
|
|
154
|
+
$start_marker count: $start_count
|
|
155
|
+
$end_marker count: $end_count
|
|
156
|
+
|
|
157
|
+
Diagnosis: markers are corrupted — counts of open and close markers do not match.
|
|
158
|
+
|
|
159
|
+
Required action (ORCHESTRATOR):
|
|
160
|
+
1. Read the file.
|
|
161
|
+
2. Locate the imbalanced marker via:
|
|
162
|
+
grep -nF '$start_marker' "$file"
|
|
163
|
+
grep -nF '$end_marker' "$file"
|
|
164
|
+
3. Restore the missing one OR remove the duplicate one.
|
|
165
|
+
4. Retry this script.
|
|
166
|
+
|
|
167
|
+
DO NOT proceed to dispatch a phase agent until markers are balanced.
|
|
168
|
+
EOF
|
|
169
|
+
exit 3
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
if [[ "$start_count" -gt 1 ]]; then
|
|
173
|
+
cat <<EOF
|
|
174
|
+
[$PROG] ANCHOR_DUPLICATED
|
|
175
|
+
section: $name
|
|
176
|
+
file: $file
|
|
177
|
+
occurrences: $start_count
|
|
178
|
+
|
|
179
|
+
Diagnosis: the same section appears more than once in this file — ambiguous extraction.
|
|
180
|
+
|
|
181
|
+
Required action (ORCHESTRATOR):
|
|
182
|
+
1. Read the file and identify duplicate sections.
|
|
183
|
+
2. Either merge them or rename one to be unique (e.g. PHASE_P1 vs PHASE_P1_FIX).
|
|
184
|
+
3. Retry this script.
|
|
185
|
+
EOF
|
|
186
|
+
exit 3
|
|
187
|
+
fi
|
|
188
|
+
|
|
189
|
+
# ---------------------------------------------------------------------------
|
|
190
|
+
# Extraction — markers verified present and balanced; emit content between them.
|
|
191
|
+
# Exclude the marker lines themselves from output.
|
|
192
|
+
# ---------------------------------------------------------------------------
|
|
193
|
+
|
|
194
|
+
content=$(awk -v start="$start_marker" -v end="$end_marker" '
|
|
195
|
+
$0 == start { in_block = 1; next }
|
|
196
|
+
$0 == end { in_block = 0; next }
|
|
197
|
+
in_block { print }
|
|
198
|
+
' "$file")
|
|
199
|
+
|
|
200
|
+
if [[ -z "$content" ]]; then
|
|
201
|
+
cat <<EOF
|
|
202
|
+
[$PROG] ANCHOR_EMPTY
|
|
203
|
+
section: $name
|
|
204
|
+
file: $file
|
|
205
|
+
|
|
206
|
+
Diagnosis: markers are present and balanced, but the section between them is empty.
|
|
207
|
+
|
|
208
|
+
Required action (ORCHESTRATOR):
|
|
209
|
+
1. Read the file.
|
|
210
|
+
2. Determine whether the section is intentionally empty (rare) or accidentally
|
|
211
|
+
stripped during refactor.
|
|
212
|
+
3. If accidental → re-author content.
|
|
213
|
+
4. If intentional → use a different section reference; this one carries no payload.
|
|
214
|
+
EOF
|
|
215
|
+
exit 2
|
|
216
|
+
fi
|
|
217
|
+
|
|
218
|
+
printf '%s\n' "$content"
|
|
219
|
+
exit 0
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# @file: Run gennady lint on phase artifacts; parse output for success/failure (gennady exit-code unreliable).
|
|
3
|
+
# @consumers: phase agents (STEP_5_VERIFY); audit subagents (STEP_1 pre-pass cross-check)
|
|
4
|
+
# @contract: AX_BASH_NO_SILENT_EMPTY — never produces empty stdout. On miss → actionable instruction.
|
|
5
|
+
#
|
|
6
|
+
# Why this wrapper exists:
|
|
7
|
+
# - gennady CLI lives outside the project (canonical: ~/Developer/gennady/cli/gennady.ts).
|
|
8
|
+
# - gennady requires `node --experimental-strip-types` (Node 22+) — the bare `node` invocation is non-obvious.
|
|
9
|
+
# - gennady returns exit code 0 even when lint reports errors (the failure signal is the literal token
|
|
10
|
+
# "[linting → failed]" in stdout). We must parse output, not trust exit code.
|
|
11
|
+
# - Success signal is the literal token "[linting → clean] no errors".
|
|
12
|
+
#
|
|
13
|
+
# Usage:
|
|
14
|
+
# lint-artifacts.sh <file1> [<file2> ...]
|
|
15
|
+
#
|
|
16
|
+
# Exit codes:
|
|
17
|
+
# 0 — all files clean (gennady output contains "[linting → clean]" and NOT "[linting → failed]")
|
|
18
|
+
# 1 — gennady CLI not found / unable to invoke
|
|
19
|
+
# 2 — lint reported errors (one or more violations); full output emitted
|
|
20
|
+
# 3 — ambiguous output (neither "clean" nor "failed" token present); investigate gennady CLI changes
|
|
21
|
+
# 4 — bad invocation (no args)
|
|
22
|
+
|
|
23
|
+
set -uo pipefail
|
|
24
|
+
|
|
25
|
+
PROG="lint-artifacts"
|
|
26
|
+
GENNADY_CLI=~/Developer/gennady/cli/gennady.ts
|
|
27
|
+
|
|
28
|
+
if [[ $# -lt 1 ]]; then
|
|
29
|
+
cat <<EOF
|
|
30
|
+
[$PROG] BAD_INVOCATION
|
|
31
|
+
expected: $PROG <file1> [<file2> ...]
|
|
32
|
+
got: $PROG (no args)
|
|
33
|
+
|
|
34
|
+
Required action (ORCHESTRATOR / phase agent):
|
|
35
|
+
Pass at least one TypeScript file path to lint.
|
|
36
|
+
Typically: phase's Target Files list.
|
|
37
|
+
EOF
|
|
38
|
+
exit 4
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
if [[ ! -f "$GENNADY_CLI" ]]; then
|
|
42
|
+
cat <<EOF
|
|
43
|
+
[$PROG] GENNADY_CLI_NOT_FOUND
|
|
44
|
+
expected at: $GENNADY_CLI
|
|
45
|
+
|
|
46
|
+
Diagnosis: the gennady AST DbC linter is unreachable from this environment.
|
|
47
|
+
|
|
48
|
+
Required action (ORCHESTRATOR):
|
|
49
|
+
1. Verify the gennady project is checked out at ~/Developer/gennady.
|
|
50
|
+
2. If gennady moved → update GENNADY_CLI variable in this script.
|
|
51
|
+
3. If on a CI/sandbox without gennady → this is a HARD blocker; phase cannot verify.
|
|
52
|
+
Report to operator: cannot complete phase without DBC contract verification.
|
|
53
|
+
|
|
54
|
+
DO NOT proceed to EMIT_HANDOFF without gennady lint passing.
|
|
55
|
+
EOF
|
|
56
|
+
exit 1
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# ---------------------------------------------------------------------------
|
|
60
|
+
# Run gennady lint and capture output
|
|
61
|
+
# ---------------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
# Use a temp file to capture full output; we need both grep on it and to emit on failure.
|
|
64
|
+
tmp_out=$(mktemp -t lint-artifacts.XXXXXX)
|
|
65
|
+
trap 'rm -f "$tmp_out"' EXIT
|
|
66
|
+
|
|
67
|
+
# Run gennady. We intentionally ignore its exit code (unreliable per contract above).
|
|
68
|
+
npx tsx "$GENNADY_CLI" lint "$@" > "$tmp_out" 2>&1 || true
|
|
69
|
+
|
|
70
|
+
has_clean=$(grep -c '\[linting → clean\]' "$tmp_out" 2>/dev/null || echo 0)
|
|
71
|
+
has_failed=$(grep -c '\[linting → failed\]' "$tmp_out" 2>/dev/null || echo 0)
|
|
72
|
+
|
|
73
|
+
# Convert to single-line numbers (grep -c with || echo 0 may produce odd output on some shells)
|
|
74
|
+
has_clean=${has_clean//[^0-9]/}
|
|
75
|
+
has_failed=${has_failed//[^0-9]/}
|
|
76
|
+
has_clean=${has_clean:-0}
|
|
77
|
+
has_failed=${has_failed:-0}
|
|
78
|
+
|
|
79
|
+
# ---------------------------------------------------------------------------
|
|
80
|
+
# Branch on tokens
|
|
81
|
+
# ---------------------------------------------------------------------------
|
|
82
|
+
|
|
83
|
+
if [[ "$has_failed" -gt 0 ]]; then
|
|
84
|
+
# Extract just the error lines (those with file:line: error: format) + final summary
|
|
85
|
+
cat <<EOF
|
|
86
|
+
[$PROG] LINT_FAILED
|
|
87
|
+
files lint'd: $#
|
|
88
|
+
gennady output token: [linting → failed]
|
|
89
|
+
|
|
90
|
+
Full lint output (gennady DBC AST findings):
|
|
91
|
+
EOF
|
|
92
|
+
# Print error lines and the failure summary line
|
|
93
|
+
grep -E '\[linting → failed\]|: error: |^---|^References:|^ ' "$tmp_out" | head -200
|
|
94
|
+
echo
|
|
95
|
+
cat <<EOF
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
Required action (PHASE AGENT, before EMIT_HANDOFF):
|
|
99
|
+
1. Read each error: format is <file>:<line>:<col>: error: <ERR_CODE>: <message>
|
|
100
|
+
2. Common categories:
|
|
101
|
+
- ERR_DBC_LINT_PARAM_MISSING — add @param <name> <coherent-role-description>
|
|
102
|
+
- ERR_DBC_LINT_RETURNS_MISSING — add @returns <business-purpose-of-value>
|
|
103
|
+
- ERR_DBC_ORDER — reorder JSDoc tags per AX_BASE_CONTRACT_SHAPE:
|
|
104
|
+
@purpose → @consumers → @implements → @invariant → @pre →
|
|
105
|
+
@param → @throws → @returns → @post → @sideEffect
|
|
106
|
+
3. Fix all violations in the target files.
|
|
107
|
+
4. Re-run this script. Repeat until clean.
|
|
108
|
+
5. Do NOT EMIT_HANDOFF with lint failures present — that is fabricated DONE.
|
|
109
|
+
|
|
110
|
+
References:
|
|
111
|
+
/Users/k.lebedev/Developer/vkt/ai/directives/coding/typescript-rules.xml
|
|
112
|
+
— AX_TAG_USAGE_MATRIX, AX_BASE_CONTRACT_SHAPE, AX_FLAT_JSDOC_FOR_PROPERTIES
|
|
113
|
+
EOF
|
|
114
|
+
exit 2
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
if [[ "$has_clean" -gt 0 ]]; then
|
|
118
|
+
# Clean. Emit concise PASS line to keep parent context light.
|
|
119
|
+
file_count=$#
|
|
120
|
+
echo "[$PROG] LINT_PASS"
|
|
121
|
+
echo " files lint'd: $file_count"
|
|
122
|
+
echo " gennady output token: [linting → clean]"
|
|
123
|
+
exit 0
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
# Neither token found — gennady output format may have changed.
|
|
127
|
+
cat <<EOF
|
|
128
|
+
[$PROG] AMBIGUOUS_OUTPUT
|
|
129
|
+
files lint'd: $#
|
|
130
|
+
gennady output token: (neither "linting → clean" nor "linting → failed" found)
|
|
131
|
+
|
|
132
|
+
Diagnosis: gennady CLI output format may have changed (or there is an unhandled edge case).
|
|
133
|
+
|
|
134
|
+
Captured output:
|
|
135
|
+
$(cat "$tmp_out" | head -50)
|
|
136
|
+
|
|
137
|
+
Required action (ORCHESTRATOR):
|
|
138
|
+
1. Re-read gennady source: ~/Developer/gennady/cli/gennady.ts
|
|
139
|
+
2. Check command output tokens in the LintCommand implementation.
|
|
140
|
+
3. Update this script's parsing to match new tokens.
|
|
141
|
+
4. Until resolved → treat as a HARD blocker; DO NOT assume PASS.
|
|
142
|
+
EOF
|
|
143
|
+
exit 3
|