@ctxkit/cli 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/apply.d.ts +3 -0
- package/dist/commands/apply.d.ts.map +1 -0
- package/dist/commands/apply.js +45 -0
- package/dist/commands/apply.js.map +1 -0
- package/dist/commands/bootstrap-cmd.d.ts +3 -0
- package/dist/commands/bootstrap-cmd.d.ts.map +1 -0
- package/dist/commands/bootstrap-cmd.js +104 -0
- package/dist/commands/bootstrap-cmd.js.map +1 -0
- package/dist/commands/codex.d.ts +3 -0
- package/dist/commands/codex.d.ts.map +1 -0
- package/dist/commands/codex.js +64 -0
- package/dist/commands/codex.js.map +1 -0
- package/dist/commands/conflicts-cmd.d.ts +3 -0
- package/dist/commands/conflicts-cmd.d.ts.map +1 -0
- package/dist/commands/conflicts-cmd.js +178 -0
- package/dist/commands/conflicts-cmd.js.map +1 -0
- package/dist/commands/daemon.d.ts +4 -0
- package/dist/commands/daemon.d.ts.map +1 -0
- package/dist/commands/daemon.js +107 -0
- package/dist/commands/daemon.js.map +1 -0
- package/dist/commands/drift.d.ts +3 -0
- package/dist/commands/drift.d.ts.map +1 -0
- package/dist/commands/drift.js +65 -0
- package/dist/commands/drift.js.map +1 -0
- package/dist/commands/history-cmd.d.ts +3 -0
- package/dist/commands/history-cmd.d.ts.map +1 -0
- package/dist/commands/history-cmd.js +100 -0
- package/dist/commands/history-cmd.js.map +1 -0
- package/dist/commands/hooks-cmd.d.ts +3 -0
- package/dist/commands/hooks-cmd.d.ts.map +1 -0
- package/dist/commands/hooks-cmd.js +98 -0
- package/dist/commands/hooks-cmd.js.map +1 -0
- package/dist/commands/index-cmd.d.ts +3 -0
- package/dist/commands/index-cmd.d.ts.map +1 -0
- package/dist/commands/index-cmd.js +112 -0
- package/dist/commands/index-cmd.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +158 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/inject.d.ts +3 -0
- package/dist/commands/inject.d.ts.map +1 -0
- package/dist/commands/inject.js +68 -0
- package/dist/commands/inject.js.map +1 -0
- package/dist/commands/migrate-cmd.d.ts +3 -0
- package/dist/commands/migrate-cmd.d.ts.map +1 -0
- package/dist/commands/migrate-cmd.js +132 -0
- package/dist/commands/migrate-cmd.js.map +1 -0
- package/dist/commands/plugin.d.ts +3 -0
- package/dist/commands/plugin.d.ts.map +1 -0
- package/dist/commands/plugin.js +327 -0
- package/dist/commands/plugin.js.map +1 -0
- package/dist/commands/pr-context-cmd.d.ts +3 -0
- package/dist/commands/pr-context-cmd.d.ts.map +1 -0
- package/dist/commands/pr-context-cmd.js +128 -0
- package/dist/commands/pr-context-cmd.js.map +1 -0
- package/dist/commands/propose.d.ts +3 -0
- package/dist/commands/propose.d.ts.map +1 -0
- package/dist/commands/propose.js +109 -0
- package/dist/commands/propose.js.map +1 -0
- package/dist/commands/run.d.ts +3 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +133 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/sessions.d.ts +3 -0
- package/dist/commands/sessions.d.ts.map +1 -0
- package/dist/commands/sessions.js +93 -0
- package/dist/commands/sessions.js.map +1 -0
- package/dist/commands/speckit-cmd.d.ts +3 -0
- package/dist/commands/speckit-cmd.d.ts.map +1 -0
- package/dist/commands/speckit-cmd.js +196 -0
- package/dist/commands/speckit-cmd.js.map +1 -0
- package/dist/commands/validate.d.ts +3 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +75 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/services/agents-md.d.ts +34 -0
- package/dist/services/agents-md.d.ts.map +1 -0
- package/dist/services/agents-md.js +248 -0
- package/dist/services/agents-md.js.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { execSync } from 'node:child_process';
|
|
3
|
+
export const speckitCommand = new Command('speckit')
|
|
4
|
+
.description('Spec-kit integration bridge');
|
|
5
|
+
function getRepoRoot() {
|
|
6
|
+
try {
|
|
7
|
+
return execSync('git rev-parse --show-toplevel', {
|
|
8
|
+
encoding: 'utf-8',
|
|
9
|
+
timeout: 3000,
|
|
10
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
11
|
+
}).trim();
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
console.error('Error: Not a git repository');
|
|
15
|
+
process.exit(1);
|
|
16
|
+
return '';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
speckitCommand
|
|
20
|
+
.command('import')
|
|
21
|
+
.description('Import spec-kit artifacts into .ctx files')
|
|
22
|
+
.option('--constitution <path>', 'Path to constitution file', '.specify/memory/constitution.md')
|
|
23
|
+
.option('--specs <dir>', 'Path to spec-kit specs directory', 'specs/')
|
|
24
|
+
.option('--dry-run', 'Preview changes without writing')
|
|
25
|
+
.option('--json', 'Output as JSON')
|
|
26
|
+
.action(async (options) => {
|
|
27
|
+
try {
|
|
28
|
+
const repoRoot = getRepoRoot();
|
|
29
|
+
const { importConstitution, importSpecs } = await import('@ctxkit/speckit-bridge');
|
|
30
|
+
let totalDecisions = 0;
|
|
31
|
+
let totalContracts = 0;
|
|
32
|
+
let totalGotchas = 0;
|
|
33
|
+
const allFilesUpdated = [];
|
|
34
|
+
// Import constitution
|
|
35
|
+
const constResult = importConstitution(repoRoot, options.constitution, options.dryRun);
|
|
36
|
+
totalDecisions += constResult.decisions;
|
|
37
|
+
totalContracts += constResult.contracts;
|
|
38
|
+
allFilesUpdated.push(...constResult.files_updated);
|
|
39
|
+
// Import specs
|
|
40
|
+
const specsResult = importSpecs(repoRoot, options.specs, options.dryRun);
|
|
41
|
+
totalContracts += specsResult.contracts;
|
|
42
|
+
totalGotchas += specsResult.gotchas;
|
|
43
|
+
allFilesUpdated.push(...specsResult.files_updated);
|
|
44
|
+
if (options.json) {
|
|
45
|
+
console.log(JSON.stringify({
|
|
46
|
+
imported: {
|
|
47
|
+
decisions: totalDecisions,
|
|
48
|
+
contracts: totalContracts,
|
|
49
|
+
gotchas: totalGotchas,
|
|
50
|
+
},
|
|
51
|
+
files_updated: allFilesUpdated,
|
|
52
|
+
dry_run: !!options.dryRun,
|
|
53
|
+
}, null, 2));
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
console.log(`Import ${options.dryRun ? '(dry-run) ' : ''}complete:`);
|
|
57
|
+
console.log(` Decisions: ${totalDecisions}`);
|
|
58
|
+
console.log(` Contracts: ${totalContracts}`);
|
|
59
|
+
console.log(` Gotchas: ${totalGotchas}`);
|
|
60
|
+
if (allFilesUpdated.length > 0) {
|
|
61
|
+
console.log(` Files updated: ${allFilesUpdated.join(', ')}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
67
|
+
if (options.json) {
|
|
68
|
+
console.log(JSON.stringify({ error: message }));
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
console.error(`Error: ${message}`);
|
|
72
|
+
}
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
speckitCommand
|
|
77
|
+
.command('export')
|
|
78
|
+
.description('Export .ctx content to spec-kit format')
|
|
79
|
+
.option('--output <dir>', 'Output directory for spec-kit files', 'specs/exported/')
|
|
80
|
+
.option('--format <md|yaml>', 'Output format', 'md')
|
|
81
|
+
.option('--json', 'Output as JSON')
|
|
82
|
+
.action(async (options) => {
|
|
83
|
+
try {
|
|
84
|
+
const repoRoot = getRepoRoot();
|
|
85
|
+
const { exportToSpecKit } = await import('@ctxkit/speckit-bridge');
|
|
86
|
+
const result = exportToSpecKit(repoRoot, options.output, options.format);
|
|
87
|
+
if (options.json) {
|
|
88
|
+
console.log(JSON.stringify(result, null, 2));
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
if (result.exported_files.length === 0) {
|
|
92
|
+
console.log('No .ctx files with exportable content found.');
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
console.log('Export complete:');
|
|
96
|
+
for (const f of result.exported_files) {
|
|
97
|
+
console.log(` - ${f}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
104
|
+
if (options.json) {
|
|
105
|
+
console.log(JSON.stringify({ error: message }));
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
console.error(`Error: ${message}`);
|
|
109
|
+
}
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
speckitCommand
|
|
114
|
+
.command('validate')
|
|
115
|
+
.description('Validate .ctx files against constitution')
|
|
116
|
+
.option('--constitution <path>', 'Path to constitution file', '.specify/memory/constitution.md')
|
|
117
|
+
.option('--json', 'Output as JSON')
|
|
118
|
+
.action(async (options) => {
|
|
119
|
+
try {
|
|
120
|
+
const repoRoot = getRepoRoot();
|
|
121
|
+
const { validateConstitution } = await import('@ctxkit/speckit-bridge');
|
|
122
|
+
const result = validateConstitution(repoRoot, options.constitution);
|
|
123
|
+
if (options.json) {
|
|
124
|
+
console.log(JSON.stringify(result, null, 2));
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
if (result.valid) {
|
|
128
|
+
console.log('All .ctx files are compliant with the constitution.');
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
console.log('Validation failed:');
|
|
132
|
+
for (const v of result.violations) {
|
|
133
|
+
console.log(` [${v.severity}] ${v.ctx_path}: ${v.violation}`);
|
|
134
|
+
console.log(` Principle: ${v.principle}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (!result.valid) {
|
|
139
|
+
process.exit(1);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
144
|
+
if (options.json) {
|
|
145
|
+
console.log(JSON.stringify({ error: message }));
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
console.error(`Error: ${message}`);
|
|
149
|
+
}
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
speckitCommand
|
|
154
|
+
.command('sync')
|
|
155
|
+
.description('Bidirectional sync between spec-kit and .ctx')
|
|
156
|
+
.option('--dry-run', 'Preview changes without writing')
|
|
157
|
+
.option('--force <direction>', 'Force sync direction (spec-to-ctx | ctx-to-spec)')
|
|
158
|
+
.option('--json', 'Output as JSON')
|
|
159
|
+
.action(async (options) => {
|
|
160
|
+
try {
|
|
161
|
+
const repoRoot = getRepoRoot();
|
|
162
|
+
const { syncBidirectional } = await import('@ctxkit/speckit-bridge');
|
|
163
|
+
const result = syncBidirectional(repoRoot, {
|
|
164
|
+
dryRun: options.dryRun,
|
|
165
|
+
forceDirection: options.force,
|
|
166
|
+
});
|
|
167
|
+
if (options.json) {
|
|
168
|
+
console.log(JSON.stringify(result, null, 2));
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
console.log(`Sync ${options.dryRun ? '(dry-run) ' : ''}complete:`);
|
|
172
|
+
console.log(` Synced: ${result.synced}`);
|
|
173
|
+
console.log(` Conflicts: ${result.conflicts}`);
|
|
174
|
+
if (result.files_updated.length > 0) {
|
|
175
|
+
console.log(` .ctx files updated: ${result.files_updated.join(', ')}`);
|
|
176
|
+
}
|
|
177
|
+
if (result.specs_updated.length > 0) {
|
|
178
|
+
console.log(` Spec files updated: ${result.specs_updated.join(', ')}`);
|
|
179
|
+
}
|
|
180
|
+
if (result.conflicts > 0) {
|
|
181
|
+
console.log('\n Conflicts detected. Use --force to resolve.');
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
187
|
+
if (options.json) {
|
|
188
|
+
console.log(JSON.stringify({ error: message }));
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
console.error(`Error: ${message}`);
|
|
192
|
+
}
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
//# sourceMappingURL=speckit-cmd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"speckit-cmd.js","sourceRoot":"","sources":["../../src/commands/speckit-cmd.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,eAAO,MAAM,eAAe,SA8ExB,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
3
|
+
import { resolve, join, dirname } from 'node:path';
|
|
4
|
+
import { parseCtxFile, validateCtxFile } from '@ctxkit/core';
|
|
5
|
+
export const validateCommand = new Command('validate')
|
|
6
|
+
.description('Validate a .ctx file for structural correctness')
|
|
7
|
+
.argument('[path]', 'Path to .ctx file or directory containing one', '.')
|
|
8
|
+
.option('--check-files', 'Verify referenced files exist on disk', false)
|
|
9
|
+
.action((pathArg, options) => {
|
|
10
|
+
const targetPath = resolve(pathArg);
|
|
11
|
+
const ctxPath = targetPath.endsWith('.ctx')
|
|
12
|
+
? targetPath
|
|
13
|
+
: join(targetPath, '.ctx');
|
|
14
|
+
if (!existsSync(ctxPath)) {
|
|
15
|
+
console.error(`Error: No .ctx file found at ${ctxPath}`);
|
|
16
|
+
process.exitCode = 1;
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
let content;
|
|
20
|
+
try {
|
|
21
|
+
content = readFileSync(ctxPath, 'utf-8');
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
console.error(`Error reading ${ctxPath}: ${err.message}`);
|
|
25
|
+
process.exitCode = 1;
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
let ctx;
|
|
29
|
+
try {
|
|
30
|
+
const result = parseCtxFile(content);
|
|
31
|
+
ctx = result.ctx;
|
|
32
|
+
if (result.warnings.length > 0) {
|
|
33
|
+
for (const w of result.warnings) {
|
|
34
|
+
console.error(`Warning: ${w}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
console.error(`Parse error: ${err.message}`);
|
|
40
|
+
process.exitCode = 1;
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const errors = validateCtxFile(ctx);
|
|
44
|
+
// Check referenced files exist
|
|
45
|
+
if (options.checkFiles) {
|
|
46
|
+
const ctxDir = dirname(ctxPath);
|
|
47
|
+
for (const kf of ctx.key_files) {
|
|
48
|
+
if (kf.path && !existsSync(join(ctxDir, kf.path))) {
|
|
49
|
+
errors.push({
|
|
50
|
+
path: `key_files: ${kf.path}`,
|
|
51
|
+
message: `Referenced file does not exist: ${kf.path}`,
|
|
52
|
+
severity: 'warning',
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Output results
|
|
58
|
+
const errorCount = errors.filter((e) => e.severity === 'error').length;
|
|
59
|
+
const warningCount = errors.filter((e) => e.severity === 'warning').length;
|
|
60
|
+
if (errors.length === 0) {
|
|
61
|
+
console.log(`✓ ${ctxPath} is valid`);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
console.log(`Validation results for ${ctxPath}:\n`);
|
|
65
|
+
for (const err of errors) {
|
|
66
|
+
const prefix = err.severity === 'error' ? '✗ ERROR' : '⚠ WARN ';
|
|
67
|
+
console.log(` ${prefix} ${err.path}: ${err.message}`);
|
|
68
|
+
}
|
|
69
|
+
console.log();
|
|
70
|
+
console.log(` ${errorCount} error(s), ${warningCount} warning(s)`);
|
|
71
|
+
if (errorCount > 0) {
|
|
72
|
+
process.exitCode = 1;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { injectCommand } from './commands/inject.js';
|
|
4
|
+
import { initCommand } from './commands/init.js';
|
|
5
|
+
import { validateCommand } from './commands/validate.js';
|
|
6
|
+
import { proposeCommand } from './commands/propose.js';
|
|
7
|
+
import { applyCommand } from './commands/apply.js';
|
|
8
|
+
import { sessionsCommand } from './commands/sessions.js';
|
|
9
|
+
import { driftCommand } from './commands/drift.js';
|
|
10
|
+
import { daemonCommand, dashboardCommand } from './commands/daemon.js';
|
|
11
|
+
import { runCommand } from './commands/run.js';
|
|
12
|
+
import { codexCommand } from './commands/codex.js';
|
|
13
|
+
import { pluginCommand } from './commands/plugin.js';
|
|
14
|
+
import { indexCommand } from './commands/index-cmd.js';
|
|
15
|
+
import { historyCommand } from './commands/history-cmd.js';
|
|
16
|
+
import { conflictsCommand } from './commands/conflicts-cmd.js';
|
|
17
|
+
import { bootstrapCommand } from './commands/bootstrap-cmd.js';
|
|
18
|
+
import { migrateCommand } from './commands/migrate-cmd.js';
|
|
19
|
+
import { hooksCommand } from './commands/hooks-cmd.js';
|
|
20
|
+
import { speckitCommand } from './commands/speckit-cmd.js';
|
|
21
|
+
import { prContextCommand } from './commands/pr-context-cmd.js';
|
|
22
|
+
const program = new Command();
|
|
23
|
+
program
|
|
24
|
+
.name('ctxkit')
|
|
25
|
+
.description('Context & Memory Manager CLI')
|
|
26
|
+
.version('0.1.0');
|
|
27
|
+
// Register subcommands
|
|
28
|
+
program.addCommand(injectCommand);
|
|
29
|
+
program.addCommand(initCommand);
|
|
30
|
+
program.addCommand(validateCommand);
|
|
31
|
+
program.addCommand(proposeCommand);
|
|
32
|
+
program.addCommand(applyCommand);
|
|
33
|
+
program.addCommand(sessionsCommand);
|
|
34
|
+
program.addCommand(driftCommand);
|
|
35
|
+
program.addCommand(daemonCommand);
|
|
36
|
+
program.addCommand(dashboardCommand);
|
|
37
|
+
program.addCommand(runCommand);
|
|
38
|
+
program.addCommand(codexCommand);
|
|
39
|
+
program.addCommand(pluginCommand);
|
|
40
|
+
program.addCommand(indexCommand);
|
|
41
|
+
program.addCommand(historyCommand);
|
|
42
|
+
program.addCommand(conflictsCommand);
|
|
43
|
+
program.addCommand(bootstrapCommand);
|
|
44
|
+
program.addCommand(migrateCommand);
|
|
45
|
+
program.addCommand(hooksCommand);
|
|
46
|
+
program.addCommand(speckitCommand);
|
|
47
|
+
program.addCommand(prContextCommand);
|
|
48
|
+
program.parse();
|
|
49
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAEhE,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CAAC,8BAA8B,CAAC;KAC3C,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,uBAAuB;AACvB,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;AACrC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;AAC/B,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;AACrC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;AACrC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;AAErC,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type CtxFile } from '@ctxkit/core';
|
|
2
|
+
export interface SyncResult {
|
|
3
|
+
dir: string;
|
|
4
|
+
relativePath: string;
|
|
5
|
+
action: 'created' | 'updated' | 'unchanged';
|
|
6
|
+
tokens: number;
|
|
7
|
+
}
|
|
8
|
+
export interface SyncOptions {
|
|
9
|
+
repoRoot: string;
|
|
10
|
+
budget: number;
|
|
11
|
+
dryRun: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Walk the repo to find all directories containing .ctx files.
|
|
15
|
+
*/
|
|
16
|
+
export declare function findCtxDirectories(repoRoot: string): string[];
|
|
17
|
+
/**
|
|
18
|
+
* Generate the CtxKit-managed content block for a directory's .ctx file.
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateCtxKitSection(ctx: CtxFile, dir: string, repoRoot: string, budget: number): string;
|
|
21
|
+
/**
|
|
22
|
+
* Merge CtxKit-managed content into an existing AGENTS.md file,
|
|
23
|
+
* preserving user-written content outside the markers.
|
|
24
|
+
*/
|
|
25
|
+
export declare function mergeWithExisting(existingContent: string, ctxkitSection: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Extract the CtxKit-managed section from an existing file.
|
|
28
|
+
*/
|
|
29
|
+
export declare function extractManagedSection(content: string): string | null;
|
|
30
|
+
/**
|
|
31
|
+
* Run the sync-agents command: walk .ctx hierarchy, generate AGENTS.md files.
|
|
32
|
+
*/
|
|
33
|
+
export declare function syncAgents(options: SyncOptions): SyncResult[];
|
|
34
|
+
//# sourceMappingURL=agents-md.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents-md.d.ts","sourceRoot":"","sources":["../../src/services/agents-md.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,OAAO,EAEb,MAAM,cAAc,CAAC;AAKtB,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;IAC5C,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAiC7D;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,MAAM,CAsGR;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,eAAe,EAAE,MAAM,EACvB,aAAa,EAAE,MAAM,GACpB,MAAM,CAgBR;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKpE;AAUD;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,UAAU,EAAE,CA+E7D"}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, readdirSync, statSync } from 'node:fs';
|
|
2
|
+
import { join, relative } from 'node:path';
|
|
3
|
+
import { parseCtxFile, redactSecrets, estimateTokens, loadProfile, } from '@ctxkit/core';
|
|
4
|
+
const CTXKIT_BEGIN = '<!-- CTXKIT:BEGIN - Managed by CtxKit. Do not edit this section. -->';
|
|
5
|
+
const CTXKIT_END = '<!-- CTXKIT:END -->';
|
|
6
|
+
/**
|
|
7
|
+
* Walk the repo to find all directories containing .ctx files.
|
|
8
|
+
*/
|
|
9
|
+
export function findCtxDirectories(repoRoot) {
|
|
10
|
+
const dirs = [];
|
|
11
|
+
function walk(dir) {
|
|
12
|
+
const ctxPath = join(dir, '.ctx');
|
|
13
|
+
if (existsSync(ctxPath) && statSync(ctxPath).isFile()) {
|
|
14
|
+
dirs.push(dir);
|
|
15
|
+
}
|
|
16
|
+
let entries;
|
|
17
|
+
try {
|
|
18
|
+
entries = readdirSync(dir);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
for (const entry of entries) {
|
|
24
|
+
if (entry.startsWith('.') || entry === 'node_modules' || entry === 'dist') {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
const fullPath = join(dir, entry);
|
|
28
|
+
try {
|
|
29
|
+
if (statSync(fullPath).isDirectory()) {
|
|
30
|
+
walk(fullPath);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// Skip inaccessible dirs
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
walk(repoRoot);
|
|
39
|
+
return dirs;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Generate the CtxKit-managed content block for a directory's .ctx file.
|
|
43
|
+
*/
|
|
44
|
+
export function generateCtxKitSection(ctx, dir, repoRoot, budget) {
|
|
45
|
+
const contextBudget = Math.floor(budget * 0.7);
|
|
46
|
+
const lines = [];
|
|
47
|
+
lines.push(`<!-- Generated: ${new Date().toISOString()} | Source: .ctx hierarchy -->`);
|
|
48
|
+
lines.push('');
|
|
49
|
+
lines.push('## CtxKit Project Context');
|
|
50
|
+
lines.push('');
|
|
51
|
+
if (ctx.summary) {
|
|
52
|
+
lines.push(redactSecrets(ctx.summary));
|
|
53
|
+
lines.push('');
|
|
54
|
+
}
|
|
55
|
+
// Key Files
|
|
56
|
+
if (ctx.key_files.length > 0) {
|
|
57
|
+
lines.push('### Key Files');
|
|
58
|
+
for (const kf of ctx.key_files) {
|
|
59
|
+
const purpose = kf.purpose ? ` \u2014 ${redactSecrets(kf.purpose)}` : '';
|
|
60
|
+
lines.push(`- \`${kf.path}\`${purpose}`);
|
|
61
|
+
}
|
|
62
|
+
lines.push('');
|
|
63
|
+
}
|
|
64
|
+
// Decisions (only active ones)
|
|
65
|
+
const activeDecisions = ctx.decisions.filter((d) => d.status === 'accepted');
|
|
66
|
+
if (activeDecisions.length > 0) {
|
|
67
|
+
lines.push('### Decisions');
|
|
68
|
+
for (const d of activeDecisions) {
|
|
69
|
+
const date = d.date ? ` (decided ${d.date})` : '';
|
|
70
|
+
lines.push(`- ${redactSecrets(d.title)}${date}`);
|
|
71
|
+
}
|
|
72
|
+
lines.push('');
|
|
73
|
+
}
|
|
74
|
+
// Gotchas
|
|
75
|
+
if (ctx.gotchas.length > 0) {
|
|
76
|
+
lines.push('### Gotchas');
|
|
77
|
+
for (const g of ctx.gotchas) {
|
|
78
|
+
lines.push(`- ${redactSecrets(g.text)}`);
|
|
79
|
+
}
|
|
80
|
+
lines.push('');
|
|
81
|
+
}
|
|
82
|
+
// Contracts
|
|
83
|
+
if (ctx.contracts.length > 0) {
|
|
84
|
+
lines.push('### Contracts');
|
|
85
|
+
for (const c of ctx.contracts) {
|
|
86
|
+
lines.push(`- **${c.name}**: ${redactSecrets(c.content).slice(0, 100)}`);
|
|
87
|
+
}
|
|
88
|
+
lines.push('');
|
|
89
|
+
}
|
|
90
|
+
// Check context budget — truncate if needed
|
|
91
|
+
let contextContent = lines.join('\n');
|
|
92
|
+
let contextTokens = estimateTokens(contextContent);
|
|
93
|
+
if (contextTokens > contextBudget) {
|
|
94
|
+
// Progressively remove sections to fit budget
|
|
95
|
+
// Remove contracts first (least critical for AGENTS.md)
|
|
96
|
+
if (ctx.contracts.length > 0) {
|
|
97
|
+
const contractIdx = contextContent.indexOf('### Contracts');
|
|
98
|
+
if (contractIdx >= 0) {
|
|
99
|
+
contextContent = contextContent.slice(0, contractIdx).trimEnd() + '\n';
|
|
100
|
+
contextTokens = estimateTokens(contextContent);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// If still over, remove gotchas
|
|
104
|
+
if (contextTokens > contextBudget && ctx.gotchas.length > 0) {
|
|
105
|
+
const gotchaIdx = contextContent.indexOf('### Gotchas');
|
|
106
|
+
if (gotchaIdx >= 0) {
|
|
107
|
+
contextContent = contextContent.slice(0, gotchaIdx).trimEnd() + '\n';
|
|
108
|
+
contextTokens = estimateTokens(contextContent);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Policy section (uses remaining budget)
|
|
113
|
+
const policyLines = [];
|
|
114
|
+
policyLines.push('## CtxKit Usage Policy');
|
|
115
|
+
policyLines.push('');
|
|
116
|
+
policyLines.push('When working in this project, you have access to CtxKit tools for context and memory management.');
|
|
117
|
+
policyLines.push('');
|
|
118
|
+
policyLines.push('### Preferred: MCP Tools');
|
|
119
|
+
policyLines.push('If CtxKit MCP server is available (check with `/mcp`), use these tools:');
|
|
120
|
+
policyLines.push('- `ctxkit.context_pack` \u2014 Get relevant context before responding');
|
|
121
|
+
policyLines.push('- `ctxkit.log_event` \u2014 Log tool calls for session tracking');
|
|
122
|
+
policyLines.push('- `ctxkit.propose_update` \u2014 Propose .ctx memory updates');
|
|
123
|
+
policyLines.push('- `ctxkit.memory.search` \u2014 Search project memory');
|
|
124
|
+
policyLines.push('');
|
|
125
|
+
policyLines.push('### Fallback: CLI Commands');
|
|
126
|
+
policyLines.push('If MCP is unavailable, use the CLI directly:');
|
|
127
|
+
policyLines.push('- `ctxkit inject "<request>" --json` \u2014 Get context pack');
|
|
128
|
+
policyLines.push('- `ctxkit sessions list --json` \u2014 List sessions');
|
|
129
|
+
policyLines.push('- `ctxkit propose --json` \u2014 Propose updates');
|
|
130
|
+
policyLines.push('');
|
|
131
|
+
policyLines.push('### Best Practices');
|
|
132
|
+
policyLines.push('- Call `ctxkit.context_pack(mode=turn)` before responding to user prompts');
|
|
133
|
+
policyLines.push('- Call `ctxkit.log_event` after each tool invocation');
|
|
134
|
+
policyLines.push('- Call `ctxkit.propose_update` when you learn something new about the project');
|
|
135
|
+
const fullContent = contextContent + '\n' + policyLines.join('\n');
|
|
136
|
+
return fullContent;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Merge CtxKit-managed content into an existing AGENTS.md file,
|
|
140
|
+
* preserving user-written content outside the markers.
|
|
141
|
+
*/
|
|
142
|
+
export function mergeWithExisting(existingContent, ctxkitSection) {
|
|
143
|
+
const beginIdx = existingContent.indexOf(CTXKIT_BEGIN);
|
|
144
|
+
const endIdx = existingContent.indexOf(CTXKIT_END);
|
|
145
|
+
const managedBlock = `${CTXKIT_BEGIN}\n${ctxkitSection}\n${CTXKIT_END}`;
|
|
146
|
+
if (beginIdx >= 0 && endIdx >= 0) {
|
|
147
|
+
// Replace existing managed section
|
|
148
|
+
const before = existingContent.slice(0, beginIdx);
|
|
149
|
+
const after = existingContent.slice(endIdx + CTXKIT_END.length);
|
|
150
|
+
return before + managedBlock + after;
|
|
151
|
+
}
|
|
152
|
+
// No markers found — append at the end
|
|
153
|
+
const separator = existingContent.endsWith('\n') ? '\n' : '\n\n';
|
|
154
|
+
return existingContent + separator + managedBlock + '\n';
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Extract the CtxKit-managed section from an existing file.
|
|
158
|
+
*/
|
|
159
|
+
export function extractManagedSection(content) {
|
|
160
|
+
const beginIdx = content.indexOf(CTXKIT_BEGIN);
|
|
161
|
+
const endIdx = content.indexOf(CTXKIT_END);
|
|
162
|
+
if (beginIdx < 0 || endIdx < 0)
|
|
163
|
+
return null;
|
|
164
|
+
return content.slice(beginIdx + CTXKIT_BEGIN.length, endIdx).trim();
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Strip the generated timestamp line for idempotency comparison.
|
|
168
|
+
* The timestamp changes on every run but the content is otherwise identical.
|
|
169
|
+
*/
|
|
170
|
+
function stripTimestamp(text) {
|
|
171
|
+
return text.replace(/<!-- Generated: .* \| Source: .ctx hierarchy -->\n?/, '');
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Run the sync-agents command: walk .ctx hierarchy, generate AGENTS.md files.
|
|
175
|
+
*/
|
|
176
|
+
export function syncAgents(options) {
|
|
177
|
+
const { repoRoot, budget, dryRun } = options;
|
|
178
|
+
const results = [];
|
|
179
|
+
// Load profile for ignore policies
|
|
180
|
+
const profile = loadProfile(repoRoot);
|
|
181
|
+
const neverRead = new Set(profile.ignore.never_read);
|
|
182
|
+
// Find all directories with .ctx files
|
|
183
|
+
const ctxDirs = findCtxDirectories(repoRoot);
|
|
184
|
+
for (const dir of ctxDirs) {
|
|
185
|
+
const ctxPath = join(dir, '.ctx');
|
|
186
|
+
const relDir = relative(repoRoot, dir) || '.';
|
|
187
|
+
const agentsPath = join(dir, 'AGENTS.md');
|
|
188
|
+
// Check ignore policy
|
|
189
|
+
const relCtxPath = relative(repoRoot, ctxPath);
|
|
190
|
+
if (neverRead.has(relCtxPath) || neverRead.has(relDir)) {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
// Parse .ctx file
|
|
194
|
+
let ctx;
|
|
195
|
+
try {
|
|
196
|
+
const raw = readFileSync(ctxPath, 'utf-8');
|
|
197
|
+
const result = parseCtxFile(raw);
|
|
198
|
+
ctx = result.ctx;
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
continue; // Skip invalid .ctx files
|
|
202
|
+
}
|
|
203
|
+
// Generate CtxKit section
|
|
204
|
+
const section = generateCtxKitSection(ctx, dir, repoRoot, budget);
|
|
205
|
+
const tokens = estimateTokens(section);
|
|
206
|
+
// Check existing file for idempotency
|
|
207
|
+
if (existsSync(agentsPath)) {
|
|
208
|
+
const existing = readFileSync(agentsPath, 'utf-8');
|
|
209
|
+
const existingManaged = extractManagedSection(existing);
|
|
210
|
+
// Compare without timestamps (they change every run)
|
|
211
|
+
if (existingManaged !== null && stripTimestamp(existingManaged) === stripTimestamp(section.trim())) {
|
|
212
|
+
results.push({
|
|
213
|
+
dir: relDir,
|
|
214
|
+
relativePath: relative(repoRoot, agentsPath),
|
|
215
|
+
action: 'unchanged',
|
|
216
|
+
tokens,
|
|
217
|
+
});
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
// Merge with existing content (preserve user sections)
|
|
221
|
+
const merged = mergeWithExisting(existing, section);
|
|
222
|
+
if (!dryRun) {
|
|
223
|
+
writeFileSync(agentsPath, merged, 'utf-8');
|
|
224
|
+
}
|
|
225
|
+
results.push({
|
|
226
|
+
dir: relDir,
|
|
227
|
+
relativePath: relative(repoRoot, agentsPath),
|
|
228
|
+
action: 'updated',
|
|
229
|
+
tokens,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
// Create new file
|
|
234
|
+
const newContent = `${CTXKIT_BEGIN}\n${section}\n${CTXKIT_END}\n`;
|
|
235
|
+
if (!dryRun) {
|
|
236
|
+
writeFileSync(agentsPath, newContent, 'utf-8');
|
|
237
|
+
}
|
|
238
|
+
results.push({
|
|
239
|
+
dir: relDir,
|
|
240
|
+
relativePath: relative(repoRoot, agentsPath),
|
|
241
|
+
action: 'created',
|
|
242
|
+
tokens,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return results;
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=agents-md.js.map
|