thachvd-kit 1.0.31 → 1.0.33
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 +21 -21
- package/README.md +109 -99
- package/bin/cli.js +1223 -1814
- package/bin/entry.js +31 -0
- package/bin/policy.js +196 -0
- package/package.json +4 -4
package/bin/entry.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
snapshotPolicyFiles,
|
|
5
|
+
applyPolicyUpgrades
|
|
6
|
+
} = require('./policy');
|
|
7
|
+
|
|
8
|
+
function isInitInvocation(args) {
|
|
9
|
+
if (args.includes('--help') || args.includes('-h') || args.includes('--version') || args.includes('-v')) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
const first = args[0];
|
|
13
|
+
return !first || first === 'init' || first.startsWith('-');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const args = process.argv.slice(2);
|
|
17
|
+
const shouldUpgradeGeneratedPolicy = isInitInvocation(args);
|
|
18
|
+
const beforeSnapshot = shouldUpgradeGeneratedPolicy ? snapshotPolicyFiles(process.cwd()) : null;
|
|
19
|
+
const force = args.includes('--yes') || args.includes('-y');
|
|
20
|
+
|
|
21
|
+
if (shouldUpgradeGeneratedPolicy) {
|
|
22
|
+
process.once('beforeExit', code => {
|
|
23
|
+
if (code !== 0 || (process.exitCode && process.exitCode !== 0)) return;
|
|
24
|
+
const changed = applyPolicyUpgrades(process.cwd(), beforeSnapshot, { force });
|
|
25
|
+
if (changed.length > 0) {
|
|
26
|
+
console.log(` OK Applied engineering quality policy to ${changed.length} generated context file(s)`);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
require('./cli');
|
package/bin/policy.js
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const POLICY_PATHS = [
|
|
5
|
+
'AGENTS.md',
|
|
6
|
+
'.cursorrules',
|
|
7
|
+
path.join('.agent', 'docs', 'conventions.md'),
|
|
8
|
+
path.join('.agent', 'docs', 'workflow.md'),
|
|
9
|
+
path.join('.agent', 'docs', 'getting-started.md'),
|
|
10
|
+
path.join('.agent', 'docs', 'tooling.md')
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
const QUALITY_FLOOR_SECTION = `## Engineering Quality Floor
|
|
14
|
+
|
|
15
|
+
Prefer the smallest sufficient change, not the fewest lines of code.
|
|
16
|
+
|
|
17
|
+
A simpler implementation is acceptable only when it fully preserves:
|
|
18
|
+
|
|
19
|
+
- required behavior and acceptance criteria;
|
|
20
|
+
- existing product and architectural contracts;
|
|
21
|
+
- UX and accessibility behavior;
|
|
22
|
+
- security and data integrity;
|
|
23
|
+
- compatibility and expected performance;
|
|
24
|
+
- maintainability appropriate to the codebase.
|
|
25
|
+
|
|
26
|
+
Do not bypass an existing project abstraction merely because a lower-level primitive requires less code. Existing abstractions may encode product behavior and implicit requirements. Do not introduce speculative abstractions either; add complexity only when concrete requirements or codebase evidence justify it.`;
|
|
27
|
+
|
|
28
|
+
const AGENT_RULES_SECTION = `## Rules
|
|
29
|
+
|
|
30
|
+
- Respond in the user's language; keep code, identifiers, and code comments in English.
|
|
31
|
+
- State assumptions when the request is ambiguous.
|
|
32
|
+
- Prefer established project patterns and abstractions when they satisfy the required contract.
|
|
33
|
+
- Keep changes surgical, but never trade away required behavior, UX, accessibility, security, data integrity, compatibility, or maintainability just to reduce code.
|
|
34
|
+
- Do not split or reorganize code solely to satisfy a line-count target. Prefer cohesive modules with clear responsibilities; split only for a concrete cohesion, ownership, testability, or maintainability benefit.
|
|
35
|
+
- **Context retrieval**: use the cheapest source that can answer the question reliably. Read/search directly for a known local file or obvious local edit; use \`codebase-memory-mcp\` or another configured structural index for unknown ownership, symbol relationships, call paths, architecture, or impact; use \`context7\` for external API/docs uncertainty; use \`playwright\` for browser/UI verification. Avoid duplicate retrieval when one source already provides sufficient evidence.
|
|
36
|
+
- Prefer \`rtk\` by default for verbose shell commands such as git, tests, builds, package managers, Docker, and Kubernetes. Run the underlying command directly when RTK is unavailable or incompatible.
|
|
37
|
+
- Tests or equivalent verification are mandatory before claiming completion.`;
|
|
38
|
+
|
|
39
|
+
const CONVENTIONS_STANDARDS_SECTION = `## Current Standards
|
|
40
|
+
|
|
41
|
+
- Code comments and identifiers should be written in English.
|
|
42
|
+
- Keep changes scoped to the user request and preserve established local conventions.
|
|
43
|
+
- Prefer existing project abstractions when they satisfy the required contract; do not bypass them solely to save lines of code.
|
|
44
|
+
- Do not split or reorganize code solely to satisfy a line-count target. Prefer cohesive modules with clear responsibilities.
|
|
45
|
+
- Add abstractions only when concrete requirements or codebase evidence justify them.
|
|
46
|
+
- TODO: refine naming, formatting, folder, API, state, styling, and testing conventions from the real codebase.`;
|
|
47
|
+
|
|
48
|
+
const FAST_PATH_SECTION = `## Fast Path
|
|
49
|
+
|
|
50
|
+
Fast-path eligibility is based on risk and contract surface, not file count. Use it only when the change is localized, mechanically obvious, has no meaningful public API, schema, security, data-integrity, dependency, CI/release, or architectural risk, and has focused verification available. A two-file change such as code plus its focused test may still be fast-path; a one-file auth, payment, schema, concurrency, or other high-risk change is not.
|
|
51
|
+
|
|
52
|
+
State the narrow scope and verification before editing. If the task becomes ambiguous, introduces new behavior or architectural decisions, or its risk/contract surface grows, switch to brainstorming and planning.`;
|
|
53
|
+
|
|
54
|
+
const GETTING_STARTED_FAST_PATH_SECTION = `## Fast Path
|
|
55
|
+
|
|
56
|
+
Use a fast path when the change is localized, mechanically obvious, low-risk, and has focused verification. File count alone does not determine eligibility: code plus a focused test can still be trivial, while a one-file security, schema, payment, concurrency, or public-contract change requires the full workflow. If scope or risk grows, return to brainstorming and planning.`;
|
|
57
|
+
|
|
58
|
+
const TOOL_ROUTING_SECTION = `## Tool Routing
|
|
59
|
+
|
|
60
|
+
Use the cheapest source that can answer the question reliably and avoid retrieving the same evidence twice.
|
|
61
|
+
|
|
62
|
+
- Known local file or obvious local edit: read/search directly.
|
|
63
|
+
- Unknown ownership, symbol relationships, call paths, architecture, or impact: use \`codebase-memory-mcp\` or another configured structural index such as CodeGraph.
|
|
64
|
+
- External library/API uncertainty: use Context7.
|
|
65
|
+
- Browser/UI behavior: use Playwright.
|
|
66
|
+
- Noisy shell output: prefer RTK.
|
|
67
|
+
|
|
68
|
+
Structural tools are aids, not mandatory ceremony. If direct evidence is already sufficient, do not call extra MCP tools just because they are available.`;
|
|
69
|
+
|
|
70
|
+
function normalizeNewlines(text) {
|
|
71
|
+
return String(text || '').replace(/\r\n/g, '\n');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function replaceSection(markdown, heading, replacement) {
|
|
75
|
+
const text = normalizeNewlines(markdown);
|
|
76
|
+
const marker = `${heading}\n`;
|
|
77
|
+
const start = text.indexOf(marker);
|
|
78
|
+
if (start < 0) return text;
|
|
79
|
+
|
|
80
|
+
const searchFrom = start + marker.length;
|
|
81
|
+
const nextHeading = text.indexOf('\n## ', searchFrom);
|
|
82
|
+
const end = nextHeading >= 0 ? nextHeading + 1 : text.length;
|
|
83
|
+
const prefix = text.slice(0, start);
|
|
84
|
+
const suffix = text.slice(end).replace(/^\n+/, '');
|
|
85
|
+
return `${prefix}${replacement.trimEnd()}\n\n${suffix}`.replace(/\n{3,}/g, '\n\n');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function insertSectionBefore(markdown, beforeHeading, section) {
|
|
89
|
+
const text = normalizeNewlines(markdown);
|
|
90
|
+
const sectionHeading = section.split('\n', 1)[0];
|
|
91
|
+
if (text.includes(`${sectionHeading}\n`)) return text;
|
|
92
|
+
|
|
93
|
+
const marker = `${beforeHeading}\n`;
|
|
94
|
+
const index = text.indexOf(marker);
|
|
95
|
+
if (index < 0) return `${text.trimEnd()}\n\n${section.trimEnd()}\n`;
|
|
96
|
+
return `${text.slice(0, index)}${section.trimEnd()}\n\n${text.slice(index)}`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function replaceFastPathInline(markdown) {
|
|
100
|
+
return normalizeNewlines(markdown)
|
|
101
|
+
.replace(
|
|
102
|
+
'Questions and research do not edit product code. A simple fix may use a fast path only when it is one-file, unambiguous, and changes no behavior or contract. State the scope and verification before editing. If the scope grows, switch to the full Superpowers flow.',
|
|
103
|
+
'Questions and research do not edit product code. A fast path is allowed only when the change is localized, mechanically obvious, low-risk, and has focused verification; file count alone is not a gate. State the scope and verification before editing. If the task becomes ambiguous or its behavior, contract, or risk surface grows, switch to the full Superpowers flow.'
|
|
104
|
+
)
|
|
105
|
+
.replace(
|
|
106
|
+
'Questions and research do not edit product code. A simple fix may use a fast path only when it is one-file, unambiguous, and changes no behavior or contract. State the narrow scope and verification before editing. If the scope grows, return to brainstorming and planning.',
|
|
107
|
+
'Questions and research do not edit product code. A fast path is allowed only when the change is localized, mechanically obvious, low-risk, and has focused verification; file count alone is not a gate. State the narrow scope and verification before editing. If scope or risk grows, return to brainstorming and planning.'
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function upgradeAgentsMarkdown(markdown) {
|
|
112
|
+
let text = replaceFastPathInline(markdown);
|
|
113
|
+
text = insertSectionBefore(text, '## Rules', QUALITY_FLOOR_SECTION);
|
|
114
|
+
text = replaceSection(text, '## Rules', AGENT_RULES_SECTION);
|
|
115
|
+
return text.trimEnd() + '\n';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function upgradeConventionsMarkdown(markdown) {
|
|
119
|
+
let text = replaceSection(markdown, '## Current Standards', CONVENTIONS_STANDARDS_SECTION);
|
|
120
|
+
text = insertSectionBefore(text, '## Verification', QUALITY_FLOOR_SECTION);
|
|
121
|
+
return text.trimEnd() + '\n';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function upgradeWorkflowMarkdown(markdown) {
|
|
125
|
+
return replaceSection(markdown, '## Fast Path', FAST_PATH_SECTION).trimEnd() + '\n';
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function upgradeGettingStartedMarkdown(markdown) {
|
|
129
|
+
return replaceSection(markdown, '## Fast Path', GETTING_STARTED_FAST_PATH_SECTION).trimEnd() + '\n';
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function upgradeToolingMarkdown(markdown) {
|
|
133
|
+
const text = normalizeNewlines(markdown);
|
|
134
|
+
const targetHeading = text.includes('## Codebase Memory MCP\n')
|
|
135
|
+
? '## Codebase Memory MCP'
|
|
136
|
+
: '## codebase-memory-mcp';
|
|
137
|
+
return insertSectionBefore(text, targetHeading, TOOL_ROUTING_SECTION).trimEnd() + '\n';
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function upgradeGeneratedContent(relativePath, content) {
|
|
141
|
+
const normalized = relativePath.split(path.sep).join('/');
|
|
142
|
+
if (normalized === 'AGENTS.md' || normalized === '.cursorrules') return upgradeAgentsMarkdown(content);
|
|
143
|
+
if (normalized.endsWith('/conventions.md')) return upgradeConventionsMarkdown(content);
|
|
144
|
+
if (normalized.endsWith('/workflow.md')) return upgradeWorkflowMarkdown(content);
|
|
145
|
+
if (normalized.endsWith('/getting-started.md')) return upgradeGettingStartedMarkdown(content);
|
|
146
|
+
if (normalized.endsWith('/tooling.md')) return upgradeToolingMarkdown(content);
|
|
147
|
+
return normalizeNewlines(content);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function snapshotPolicyFiles(rootDir) {
|
|
151
|
+
const snapshot = new Map();
|
|
152
|
+
for (const relativePath of POLICY_PATHS) {
|
|
153
|
+
const fullPath = path.join(rootDir, relativePath);
|
|
154
|
+
snapshot.set(relativePath, fs.existsSync(fullPath) ? fs.readFileSync(fullPath, 'utf8') : null);
|
|
155
|
+
}
|
|
156
|
+
return snapshot;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function applyPolicyUpgrades(rootDir, beforeSnapshot, options = {}) {
|
|
160
|
+
const force = options.force === true;
|
|
161
|
+
const changed = [];
|
|
162
|
+
|
|
163
|
+
for (const relativePath of POLICY_PATHS) {
|
|
164
|
+
const fullPath = path.join(rootDir, relativePath);
|
|
165
|
+
if (!fs.existsSync(fullPath)) continue;
|
|
166
|
+
|
|
167
|
+
const current = fs.readFileSync(fullPath, 'utf8');
|
|
168
|
+
const before = beforeSnapshot ? beforeSnapshot.get(relativePath) : null;
|
|
169
|
+
const wasWritten = force || before === null || before !== current;
|
|
170
|
+
if (!wasWritten) continue;
|
|
171
|
+
|
|
172
|
+
const upgraded = upgradeGeneratedContent(relativePath, current);
|
|
173
|
+
if (upgraded !== normalizeNewlines(current)) {
|
|
174
|
+
fs.writeFileSync(fullPath, upgraded, 'utf8');
|
|
175
|
+
changed.push(relativePath);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return changed;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
module.exports = {
|
|
183
|
+
POLICY_PATHS,
|
|
184
|
+
QUALITY_FLOOR_SECTION,
|
|
185
|
+
AGENT_RULES_SECTION,
|
|
186
|
+
FAST_PATH_SECTION,
|
|
187
|
+
TOOL_ROUTING_SECTION,
|
|
188
|
+
upgradeGeneratedContent,
|
|
189
|
+
upgradeAgentsMarkdown,
|
|
190
|
+
upgradeConventionsMarkdown,
|
|
191
|
+
upgradeWorkflowMarkdown,
|
|
192
|
+
upgradeGettingStartedMarkdown,
|
|
193
|
+
upgradeToolingMarkdown,
|
|
194
|
+
snapshotPolicyFiles,
|
|
195
|
+
applyPolicyUpgrades
|
|
196
|
+
};
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thachvd-kit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.33",
|
|
4
4
|
"description": "Cross-agent project rules bootstrap kit for Codex, Antigravity, and Claude Code",
|
|
5
5
|
"bin": {
|
|
6
|
-
"thachvd-kit": "./bin/
|
|
6
|
+
"thachvd-kit": "./bin/entry.js"
|
|
7
7
|
},
|
|
8
8
|
"files": [
|
|
9
9
|
"bin",
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"node": ">=16.7"
|
|
16
16
|
},
|
|
17
17
|
"scripts": {
|
|
18
|
-
"test": "node test/cli.test.js",
|
|
19
|
-
"release:verify": "npm test && node --check bin/cli.js && npm pack --dry-run",
|
|
18
|
+
"test": "node test/cli.test.js && node test/policy.test.js",
|
|
19
|
+
"release:verify": "npm test && node --check bin/cli.js && node --check bin/entry.js && node --check bin/policy.js && npm pack --dry-run",
|
|
20
20
|
"preversion": "npm run release:verify",
|
|
21
21
|
"release:patch": "npm version patch",
|
|
22
22
|
"release:dry-run": "npm pack --dry-run",
|