jdi-cli 0.1.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/AGENTS.md +209 -0
- package/ARCHITECTURE.md +210 -0
- package/COMMANDS.md +241 -0
- package/CREATE-EXAMPLE.md +385 -0
- package/CREATE.md +315 -0
- package/EXTENSION.md +141 -0
- package/LICENSE +21 -0
- package/MEMORY.md +471 -0
- package/PORTABILITY.md +438 -0
- package/README.md +789 -0
- package/bin/git-hooks/post-commit +16 -0
- package/bin/git-hooks/pre-commit +21 -0
- package/bin/jdi-build.ps1 +381 -0
- package/bin/jdi-build.sh +332 -0
- package/bin/jdi-doctor.ps1 +403 -0
- package/bin/jdi-doctor.sh +400 -0
- package/bin/jdi-install-caveman.ps1 +97 -0
- package/bin/jdi-install-caveman.sh +99 -0
- package/bin/jdi-install-playwright.ps1 +319 -0
- package/bin/jdi-install-playwright.sh +284 -0
- package/bin/jdi-install.ps1 +154 -0
- package/bin/jdi-install.sh +132 -0
- package/bin/jdi-uninstall.ps1 +309 -0
- package/bin/jdi-uninstall.sh +264 -0
- package/bin/jdi-update.ps1 +215 -0
- package/bin/jdi-update.sh +209 -0
- package/bin/jdi.js +460 -0
- package/bin/lib/jdi-monitor.ps1 +66 -0
- package/bin/lib/jdi-monitor.sh +74 -0
- package/bin/lib/jdi-truncate.ps1 +96 -0
- package/bin/lib/jdi-truncate.sh +99 -0
- package/bin/lib/ui.js +197 -0
- package/core/agents/jdi-adopter.md +465 -0
- package/core/agents/jdi-architect.md +894 -0
- package/core/agents/jdi-asker.md +153 -0
- package/core/agents/jdi-bootstrap.md +247 -0
- package/core/agents/jdi-planner.md +254 -0
- package/core/agents/jdi-researcher.md +303 -0
- package/core/commands/jdi-adopt.md +155 -0
- package/core/commands/jdi-bootstrap.md +81 -0
- package/core/commands/jdi-create.md +80 -0
- package/core/commands/jdi-discuss.md +80 -0
- package/core/commands/jdi-do.md +200 -0
- package/core/commands/jdi-loop.md +315 -0
- package/core/commands/jdi-new.md +131 -0
- package/core/commands/jdi-plan.md +73 -0
- package/core/commands/jdi-ship.md +146 -0
- package/core/commands/jdi-verify.md +159 -0
- package/core/skills/clean-code/SKILL.md +261 -0
- package/core/skills/dry/SKILL.md +150 -0
- package/core/skills/frontend-rules/SKILL.md +386 -0
- package/core/skills/frontend-validator/SKILL.md +567 -0
- package/core/skills/kiss/SKILL.md +178 -0
- package/core/skills/solid/SKILL.md +281 -0
- package/core/skills/yagni/SKILL.md +207 -0
- package/core/templates/agent.md +72 -0
- package/core/templates/doer-specialist.md +216 -0
- package/core/templates/reviewer-specialist.md +405 -0
- package/core/templates/skill.md +66 -0
- package/package.json +70 -0
- package/runtimes/antigravity/agents.md +74 -0
- package/runtimes/antigravity/skills/clean-code/SKILL.md +252 -0
- package/runtimes/antigravity/skills/dry/SKILL.md +141 -0
- package/runtimes/antigravity/skills/frontend-rules/SKILL.md +376 -0
- package/runtimes/antigravity/skills/frontend-validator/SKILL.md +559 -0
- package/runtimes/antigravity/skills/jdi-adopt/SKILL.md +155 -0
- package/runtimes/antigravity/skills/jdi-adopter/SKILL.md +436 -0
- package/runtimes/antigravity/skills/jdi-architect/SKILL.md +872 -0
- package/runtimes/antigravity/skills/jdi-asker/SKILL.md +125 -0
- package/runtimes/antigravity/skills/jdi-asker/references/context-template.md +34 -0
- package/runtimes/antigravity/skills/jdi-asker/references/decision-format.md +19 -0
- package/runtimes/antigravity/skills/jdi-asker/scripts/find_phase_dir.sh +25 -0
- package/runtimes/antigravity/skills/jdi-bootstrap/SKILL.md +81 -0
- package/runtimes/antigravity/skills/jdi-create/SKILL.md +80 -0
- package/runtimes/antigravity/skills/jdi-discuss/SKILL.md +80 -0
- package/runtimes/antigravity/skills/jdi-discuss/scripts/run_command.sh +62 -0
- package/runtimes/antigravity/skills/jdi-do/SKILL.md +200 -0
- package/runtimes/antigravity/skills/jdi-loop/SKILL.md +315 -0
- package/runtimes/antigravity/skills/jdi-new/SKILL.md +131 -0
- package/runtimes/antigravity/skills/jdi-plan/SKILL.md +73 -0
- package/runtimes/antigravity/skills/jdi-planner/SKILL.md +225 -0
- package/runtimes/antigravity/skills/jdi-researcher/SKILL.md +274 -0
- package/runtimes/antigravity/skills/jdi-ship/SKILL.md +146 -0
- package/runtimes/antigravity/skills/jdi-verify/SKILL.md +159 -0
- package/runtimes/antigravity/skills/kiss/SKILL.md +169 -0
- package/runtimes/antigravity/skills/solid/SKILL.md +272 -0
- package/runtimes/antigravity/skills/yagni/SKILL.md +198 -0
- package/runtimes/claude/CLAUDE.md +91 -0
- package/runtimes/claude/agents/jdi-adopter.md +430 -0
- package/runtimes/claude/agents/jdi-architect.md +864 -0
- package/runtimes/claude/agents/jdi-asker.md +119 -0
- package/runtimes/claude/agents/jdi-bootstrap.md +213 -0
- package/runtimes/claude/agents/jdi-planner.md +221 -0
- package/runtimes/claude/agents/jdi-researcher.md +269 -0
- package/runtimes/claude/commands/jdi-adopt.md +155 -0
- package/runtimes/claude/commands/jdi-bootstrap.md +81 -0
- package/runtimes/claude/commands/jdi-create.md +80 -0
- package/runtimes/claude/commands/jdi-discuss.md +80 -0
- package/runtimes/claude/commands/jdi-do.md +200 -0
- package/runtimes/claude/commands/jdi-loop.md +315 -0
- package/runtimes/claude/commands/jdi-new.md +131 -0
- package/runtimes/claude/commands/jdi-plan.md +73 -0
- package/runtimes/claude/commands/jdi-ship.md +146 -0
- package/runtimes/claude/commands/jdi-verify.md +159 -0
- package/runtimes/claude/settings.example.json +132 -0
- package/runtimes/claude/skills/clean-code/SKILL.md +247 -0
- package/runtimes/claude/skills/dry/SKILL.md +136 -0
- package/runtimes/claude/skills/frontend-rules/SKILL.md +369 -0
- package/runtimes/claude/skills/frontend-validator/SKILL.md +553 -0
- package/runtimes/claude/skills/kiss/SKILL.md +164 -0
- package/runtimes/claude/skills/solid/SKILL.md +267 -0
- package/runtimes/claude/skills/yagni/SKILL.md +193 -0
- package/runtimes/copilot/agents/jdi-adopter.agent.md +430 -0
- package/runtimes/copilot/agents/jdi-architect.agent.md +864 -0
- package/runtimes/copilot/agents/jdi-asker.agent.md +119 -0
- package/runtimes/copilot/agents/jdi-bootstrap.agent.md +213 -0
- package/runtimes/copilot/agents/jdi-planner.agent.md +221 -0
- package/runtimes/copilot/agents/jdi-researcher.agent.md +269 -0
- package/runtimes/copilot/copilot-instructions.md +80 -0
- package/runtimes/copilot/prompts/jdi-adopt.prompt.md +155 -0
- package/runtimes/copilot/prompts/jdi-bootstrap.prompt.md +81 -0
- package/runtimes/copilot/prompts/jdi-create.prompt.md +80 -0
- package/runtimes/copilot/prompts/jdi-discuss.prompt.md +80 -0
- package/runtimes/copilot/prompts/jdi-do.prompt.md +200 -0
- package/runtimes/copilot/prompts/jdi-loop.prompt.md +315 -0
- package/runtimes/copilot/prompts/jdi-new.prompt.md +131 -0
- package/runtimes/copilot/prompts/jdi-plan.prompt.md +73 -0
- package/runtimes/copilot/prompts/jdi-ship.prompt.md +146 -0
- package/runtimes/copilot/prompts/jdi-verify.prompt.md +159 -0
- package/runtimes/opencode/AGENTS.md +87 -0
- package/runtimes/opencode/agents/jdi-adopter.md +434 -0
- package/runtimes/opencode/agents/jdi-architect.md +861 -0
- package/runtimes/opencode/agents/jdi-asker.md +123 -0
- package/runtimes/opencode/agents/jdi-bootstrap.md +217 -0
- package/runtimes/opencode/agents/jdi-planner.md +225 -0
- package/runtimes/opencode/agents/jdi-researcher.md +273 -0
- package/runtimes/opencode/commands/jdi-adopt.md +155 -0
- package/runtimes/opencode/commands/jdi-bootstrap.md +81 -0
- package/runtimes/opencode/commands/jdi-create.md +80 -0
- package/runtimes/opencode/commands/jdi-discuss.md +80 -0
- package/runtimes/opencode/commands/jdi-do.md +200 -0
- package/runtimes/opencode/commands/jdi-loop.md +315 -0
- package/runtimes/opencode/commands/jdi-new.md +131 -0
- package/runtimes/opencode/commands/jdi-plan.md +73 -0
- package/runtimes/opencode/commands/jdi-ship.md +146 -0
- package/runtimes/opencode/commands/jdi-verify.md +159 -0
- package/runtimes/opencode/opencode.example.jsonc +169 -0
- package/runtimes/opencode/skills/clean-code/SKILL.md +247 -0
- package/runtimes/opencode/skills/dry/SKILL.md +136 -0
- package/runtimes/opencode/skills/frontend-rules/SKILL.md +369 -0
- package/runtimes/opencode/skills/frontend-validator/SKILL.md +553 -0
- package/runtimes/opencode/skills/kiss/SKILL.md +164 -0
- package/runtimes/opencode/skills/solid/SKILL.md +267 -0
- package/runtimes/opencode/skills/yagni/SKILL.md +193 -0
- package/templates-jdi-folder/config.json +18 -0
- package/templates-jdi-folder/registry.md +31 -0
- package/templates-jdi-folder/reviewers.md +33 -0
- package/templates-jdi-folder/skills-registry.md +32 -0
- package/templates-jdi-folder/specialists.md +39 -0
package/bin/jdi.js
ADDED
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const { spawn, spawnSync } = require('child_process');
|
|
7
|
+
const ui = require('./lib/ui');
|
|
8
|
+
const { c, sym } = ui;
|
|
9
|
+
|
|
10
|
+
const VERSION = require('../package.json').version;
|
|
11
|
+
const PKG_ROOT = path.resolve(__dirname, '..');
|
|
12
|
+
const isWindows = process.platform === 'win32';
|
|
13
|
+
|
|
14
|
+
const VALID_RUNTIMES = ['claude', 'copilot', 'antigravity', 'opencode', 'all'];
|
|
15
|
+
const VALID_SCOPES = ['user', 'project'];
|
|
16
|
+
|
|
17
|
+
// =================================================================
|
|
18
|
+
// Argument parsing — minimal, no deps
|
|
19
|
+
// =================================================================
|
|
20
|
+
|
|
21
|
+
function parseArgs(argv) {
|
|
22
|
+
const args = argv.slice(2);
|
|
23
|
+
if (args.length === 0) return { cmd: 'help' };
|
|
24
|
+
|
|
25
|
+
const cmd = args[0];
|
|
26
|
+
const rest = args.slice(1);
|
|
27
|
+
const flags = {};
|
|
28
|
+
const positional = [];
|
|
29
|
+
|
|
30
|
+
for (let i = 0; i < rest.length; i++) {
|
|
31
|
+
const a = rest[i];
|
|
32
|
+
if (a === '--scope' || a === '-s') {
|
|
33
|
+
flags.scope = rest[++i];
|
|
34
|
+
} else if (a === '--verbose' || a === '-v') {
|
|
35
|
+
flags.verbose = true;
|
|
36
|
+
} else if (a === '--help' || a === '-h') {
|
|
37
|
+
flags.help = true;
|
|
38
|
+
} else if (a === '--version') {
|
|
39
|
+
flags.version = true;
|
|
40
|
+
} else if (a === '--no-color') {
|
|
41
|
+
flags.noColor = true;
|
|
42
|
+
} else if (a.startsWith('--')) {
|
|
43
|
+
const [k, v] = a.slice(2).split('=');
|
|
44
|
+
flags[k] = v === undefined ? true : v;
|
|
45
|
+
} else {
|
|
46
|
+
positional.push(a);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return { cmd, positional, flags };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// =================================================================
|
|
54
|
+
// Spawn helpers — delegate to .sh / .ps1
|
|
55
|
+
// =================================================================
|
|
56
|
+
|
|
57
|
+
function getScriptPath(name) {
|
|
58
|
+
const ext = isWindows ? '.ps1' : '.sh';
|
|
59
|
+
return path.join(PKG_ROOT, 'bin', `${name}${ext}`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function runShellScript(scriptName, scriptArgs = []) {
|
|
63
|
+
const scriptPath = getScriptPath(scriptName);
|
|
64
|
+
|
|
65
|
+
if (!fs.existsSync(scriptPath)) {
|
|
66
|
+
ui.fail(`Script nao encontrado: ${scriptPath}`);
|
|
67
|
+
return { code: 1 };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
let cmd, args;
|
|
71
|
+
if (isWindows) {
|
|
72
|
+
cmd = 'powershell.exe';
|
|
73
|
+
args = ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', scriptPath, ...scriptArgs];
|
|
74
|
+
} else {
|
|
75
|
+
cmd = 'bash';
|
|
76
|
+
args = [scriptPath, ...scriptArgs];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const result = spawnSync(cmd, args, {
|
|
80
|
+
stdio: 'inherit',
|
|
81
|
+
cwd: process.cwd(),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
return { code: result.status ?? 0 };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// =================================================================
|
|
88
|
+
// Validation helpers
|
|
89
|
+
// =================================================================
|
|
90
|
+
|
|
91
|
+
function ensureRuntime(runtime) {
|
|
92
|
+
if (!runtime) {
|
|
93
|
+
ui.fail('Runtime obrigatorio.');
|
|
94
|
+
console.log('');
|
|
95
|
+
console.log(` Uso: ${c.cyan}jdi install <runtime> [--scope user|project]${c.reset}`);
|
|
96
|
+
console.log(` Runtimes: ${VALID_RUNTIMES.join(', ')}`);
|
|
97
|
+
console.log('');
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
if (!VALID_RUNTIMES.includes(runtime)) {
|
|
101
|
+
ui.fail(`Runtime invalido: ${runtime}`);
|
|
102
|
+
console.log(` Validos: ${VALID_RUNTIMES.join(', ')}`);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function ensureScope(scope) {
|
|
108
|
+
if (scope && !VALID_SCOPES.includes(scope)) {
|
|
109
|
+
ui.fail(`Scope invalido: ${scope}`);
|
|
110
|
+
console.log(` Validos: ${VALID_SCOPES.join(', ')}`);
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// =================================================================
|
|
116
|
+
// Commands
|
|
117
|
+
// =================================================================
|
|
118
|
+
|
|
119
|
+
function cmdInstall({ positional, flags }) {
|
|
120
|
+
const runtime = positional[0];
|
|
121
|
+
const scope = flags.scope || 'project';
|
|
122
|
+
|
|
123
|
+
ensureRuntime(runtime);
|
|
124
|
+
ensureScope(scope);
|
|
125
|
+
|
|
126
|
+
ui.banner();
|
|
127
|
+
|
|
128
|
+
ui.header(`Instalando JDI para ${c.bold}${runtime}${c.reset}`);
|
|
129
|
+
ui.info(`Diretorio: ${c.dim}${process.cwd()}${c.reset}`);
|
|
130
|
+
ui.info(`Scope: ${c.dim}${scope}${c.reset}`);
|
|
131
|
+
ui.info(`Plataforma: ${c.dim}${process.platform} (${isWindows ? 'PowerShell' : 'bash'})${c.reset}`);
|
|
132
|
+
console.log('');
|
|
133
|
+
|
|
134
|
+
const args = isWindows
|
|
135
|
+
? ['-Runtime', runtime, '-Scope', scope]
|
|
136
|
+
: [runtime, '--scope', scope];
|
|
137
|
+
|
|
138
|
+
const sp = ui.spinner(`Instalando adapters em ${runtime}...`);
|
|
139
|
+
sp.stop();
|
|
140
|
+
|
|
141
|
+
const { code } = runShellScript('jdi-install', args);
|
|
142
|
+
|
|
143
|
+
if (code === 0) {
|
|
144
|
+
ui.successSummary('JDI instalado com sucesso', [
|
|
145
|
+
`${sym.success} Runtime: ${c.bold}${runtime}${c.reset}`,
|
|
146
|
+
`${sym.success} Scope: ${c.bold}${scope}${c.reset}`,
|
|
147
|
+
`${sym.success} Diretorio: ${c.dim}${process.cwd()}${c.reset}`,
|
|
148
|
+
]);
|
|
149
|
+
|
|
150
|
+
const nextStepList = [
|
|
151
|
+
`Abre teu runtime (${runtime}) no diretorio do projeto`,
|
|
152
|
+
`Roda ${c.cyan}/jdi-new "<descricao do projeto>"${c.reset} pra inicializar`,
|
|
153
|
+
`Depois ${c.cyan}/jdi-bootstrap${c.reset} pra criar specialists per-project`,
|
|
154
|
+
`Comando ${c.cyan}npx jdi-cli doctor${c.reset} pra diagnostico`,
|
|
155
|
+
];
|
|
156
|
+
ui.nextSteps(nextStepList);
|
|
157
|
+
} else {
|
|
158
|
+
ui.errorSummary('Instalacao falhou', [
|
|
159
|
+
`${sym.error} Exit code: ${code}`,
|
|
160
|
+
`${sym.info} Tente ${c.cyan}npx jdi-cli doctor${c.reset} pra diagnostico`,
|
|
161
|
+
]);
|
|
162
|
+
process.exit(code);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function cmdBuild({ flags }) {
|
|
167
|
+
ui.banner();
|
|
168
|
+
|
|
169
|
+
ui.header('Building JDI runtimes');
|
|
170
|
+
ui.info(`Source: ${c.dim}${PKG_ROOT}/core/${c.reset}`);
|
|
171
|
+
ui.info(`Output: ${c.dim}${PKG_ROOT}/runtimes/${c.reset}`);
|
|
172
|
+
console.log('');
|
|
173
|
+
|
|
174
|
+
const { code } = runShellScript('jdi-build');
|
|
175
|
+
|
|
176
|
+
if (code === 0) {
|
|
177
|
+
ui.successSummary('Build completo', [
|
|
178
|
+
`${sym.success} 4 runtimes gerados (claude, copilot, antigravity, opencode)`,
|
|
179
|
+
`${sym.success} Adapters em ${c.dim}runtimes/${c.reset}`,
|
|
180
|
+
]);
|
|
181
|
+
ui.nextSteps([
|
|
182
|
+
`Instala em projeto: ${c.cyan}npx jdi-cli install <runtime>${c.reset}`,
|
|
183
|
+
`Diagnostico: ${c.cyan}npx jdi-cli doctor${c.reset}`,
|
|
184
|
+
]);
|
|
185
|
+
} else {
|
|
186
|
+
ui.errorSummary('Build falhou', [`${sym.error} Exit code: ${code}`]);
|
|
187
|
+
process.exit(code);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function cmdUpdate({ flags }) {
|
|
192
|
+
ui.banner();
|
|
193
|
+
|
|
194
|
+
ui.header('JDI Update');
|
|
195
|
+
ui.info(`Diretorio: ${c.dim}${process.cwd()}${c.reset}`);
|
|
196
|
+
console.log('');
|
|
197
|
+
|
|
198
|
+
const args = [];
|
|
199
|
+
if (isWindows) {
|
|
200
|
+
if (flags['force-specialists']) args.push('-ForceSpecialists');
|
|
201
|
+
if (flags['skip-specialists']) args.push('-SkipSpecialists');
|
|
202
|
+
if (flags['dry-run']) args.push('-DryRun');
|
|
203
|
+
} else {
|
|
204
|
+
if (flags['force-specialists']) args.push('--force-specialists');
|
|
205
|
+
if (flags['skip-specialists']) args.push('--skip-specialists');
|
|
206
|
+
if (flags['dry-run']) args.push('--dry-run');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const { code } = runShellScript('jdi-update', args);
|
|
210
|
+
|
|
211
|
+
if (code !== 0) {
|
|
212
|
+
process.exit(code);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function cmdUninstall({ positional, flags }) {
|
|
217
|
+
ui.banner();
|
|
218
|
+
|
|
219
|
+
ui.header('JDI Uninstall');
|
|
220
|
+
ui.info(`Diretorio: ${c.dim}${process.cwd()}${c.reset}`);
|
|
221
|
+
console.log('');
|
|
222
|
+
|
|
223
|
+
const runtime = positional[0] || 'all';
|
|
224
|
+
ensureRuntime(runtime);
|
|
225
|
+
|
|
226
|
+
const args = [];
|
|
227
|
+
if (isWindows) {
|
|
228
|
+
args.push('-Runtime', runtime);
|
|
229
|
+
if (flags.scope) args.push('-Scope', flags.scope);
|
|
230
|
+
if (flags.purge) args.push('-Purge');
|
|
231
|
+
if (flags.yes) args.push('-Yes');
|
|
232
|
+
if (flags['dry-run']) args.push('-DryRun');
|
|
233
|
+
} else {
|
|
234
|
+
args.push('--runtime', runtime);
|
|
235
|
+
if (flags.scope) args.push('--scope', flags.scope);
|
|
236
|
+
if (flags.purge) args.push('--purge');
|
|
237
|
+
if (flags.yes) args.push('--yes');
|
|
238
|
+
if (flags['dry-run']) args.push('--dry-run');
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const { code } = runShellScript('jdi-uninstall', args);
|
|
242
|
+
|
|
243
|
+
if (code !== 0) {
|
|
244
|
+
process.exit(code);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function cmdInstallPlaywright({ flags }) {
|
|
249
|
+
ui.banner();
|
|
250
|
+
|
|
251
|
+
ui.header('JDI: Install Playwright + MCP');
|
|
252
|
+
ui.info(`Directory: ${c.dim}${process.cwd()}${c.reset}`);
|
|
253
|
+
console.log('');
|
|
254
|
+
|
|
255
|
+
const args = [];
|
|
256
|
+
if (isWindows) {
|
|
257
|
+
if (flags['skip-browser']) args.push('-SkipBrowser');
|
|
258
|
+
if (flags['skip-mcp']) args.push('-SkipMcp');
|
|
259
|
+
if (flags.runtime) args.push('-Runtime', flags.runtime);
|
|
260
|
+
} else {
|
|
261
|
+
if (flags['skip-browser']) args.push('--skip-browser');
|
|
262
|
+
if (flags['skip-mcp']) args.push('--skip-mcp');
|
|
263
|
+
if (flags.runtime) args.push('--runtime', flags.runtime);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const { code } = runShellScript('jdi-install-playwright', args);
|
|
267
|
+
|
|
268
|
+
if (code === 0) {
|
|
269
|
+
ui.successSummary('Playwright + MCP ready', [
|
|
270
|
+
`${sym.success} @playwright/test installed`,
|
|
271
|
+
`${sym.success} chromium browser ${flags['skip-browser'] ? 'skipped' : 'installed'}`,
|
|
272
|
+
`${sym.success} MCP config ${flags['skip-mcp'] ? 'skipped' : 'injected (where runtime present)'}`,
|
|
273
|
+
]);
|
|
274
|
+
ui.nextSteps([
|
|
275
|
+
`Restart your runtime to pick up MCP changes`,
|
|
276
|
+
`Claude Code: ${c.cyan}/mcp${c.reset} to verify`,
|
|
277
|
+
`OpenCode: ${c.cyan}opencode reload${c.reset}`,
|
|
278
|
+
]);
|
|
279
|
+
} else {
|
|
280
|
+
ui.errorSummary('Playwright install failed', [`${sym.error} Exit code: ${code}`]);
|
|
281
|
+
process.exit(code);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function cmdInstallCaveman({ flags }) {
|
|
286
|
+
ui.banner();
|
|
287
|
+
|
|
288
|
+
ui.header('JDI: Install Caveman plugin');
|
|
289
|
+
ui.info(`Directory: ${c.dim}${process.cwd()}${c.reset}`);
|
|
290
|
+
console.log('');
|
|
291
|
+
|
|
292
|
+
const args = [];
|
|
293
|
+
if (isWindows) {
|
|
294
|
+
if (flags.repo) args.push('-Repo', flags.repo);
|
|
295
|
+
if (flags.scope) args.push('-Scope', flags.scope);
|
|
296
|
+
if (flags.force) args.push('-Force');
|
|
297
|
+
} else {
|
|
298
|
+
if (flags.repo) args.push('--repo', flags.repo);
|
|
299
|
+
if (flags.scope) args.push('--scope', flags.scope);
|
|
300
|
+
if (flags.force) args.push('--force');
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const { code } = runShellScript('jdi-install-caveman', args);
|
|
304
|
+
|
|
305
|
+
if (code === 0) {
|
|
306
|
+
ui.successSummary('Caveman ready', [
|
|
307
|
+
`${sym.success} Plugin cloned`,
|
|
308
|
+
`${sym.info} Restart Claude Code to load`,
|
|
309
|
+
]);
|
|
310
|
+
ui.nextSteps([
|
|
311
|
+
`Verify: ${c.cyan}/caveman-help${c.reset}`,
|
|
312
|
+
`Toggle mode: ${c.cyan}/caveman lite|full|ultra${c.reset}`,
|
|
313
|
+
]);
|
|
314
|
+
} else {
|
|
315
|
+
ui.errorSummary('Caveman install failed', [`${sym.error} Exit code: ${code}`]);
|
|
316
|
+
process.exit(code);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function cmdDoctor({ flags }) {
|
|
321
|
+
ui.banner();
|
|
322
|
+
|
|
323
|
+
ui.header('JDI Doctor');
|
|
324
|
+
ui.info(`Diretorio atual: ${c.dim}${process.cwd()}${c.reset}`);
|
|
325
|
+
console.log('');
|
|
326
|
+
|
|
327
|
+
const args = flags.verbose ? (isWindows ? ['-Verbose'] : ['--verbose']) : [];
|
|
328
|
+
const { code } = runShellScript('jdi-doctor', args);
|
|
329
|
+
|
|
330
|
+
if (code !== 0) {
|
|
331
|
+
process.exit(code);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function cmdHelp() {
|
|
336
|
+
ui.banner();
|
|
337
|
+
|
|
338
|
+
console.log(`${c.bold}Uso:${c.reset}`);
|
|
339
|
+
console.log(` ${c.cyan}npx jdi-cli <comando> [opcoes]${c.reset}`);
|
|
340
|
+
console.log('');
|
|
341
|
+
|
|
342
|
+
console.log(`${c.bold}Comandos:${c.reset}`);
|
|
343
|
+
console.log(` ${c.cyan}install${c.reset} ${c.gray}<runtime>${c.reset} Instala JDI no projeto atual`);
|
|
344
|
+
console.log(` ${c.cyan}update${c.reset} Atualiza JDI ja instalado (preserva state)`);
|
|
345
|
+
console.log(` ${c.cyan}uninstall${c.reset} ${c.gray}[runtime]${c.reset} Remove JDI do projeto (preserva .jdi/ por default)`);
|
|
346
|
+
console.log(` ${c.cyan}build${c.reset} Re-builda runtimes/ a partir de core/`);
|
|
347
|
+
console.log(` ${c.cyan}doctor${c.reset} Diagnostico do projeto + JDI`);
|
|
348
|
+
console.log(` ${c.cyan}install-playwright${c.reset} Instala @playwright/test + chromium + MCP config`);
|
|
349
|
+
console.log(` ${c.cyan}install-caveman${c.reset} Instala plugin caveman (modo ultra-compresso)`);
|
|
350
|
+
console.log(` ${c.cyan}help${c.reset} Mostra esta ajuda`);
|
|
351
|
+
console.log(` ${c.cyan}--version${c.reset} Mostra versao`);
|
|
352
|
+
console.log('');
|
|
353
|
+
|
|
354
|
+
console.log(`${c.bold}Runtimes (install):${c.reset}`);
|
|
355
|
+
console.log(` ${c.cyan}claude${c.reset} Claude Code`);
|
|
356
|
+
console.log(` ${c.cyan}copilot${c.reset} GitHub Copilot`);
|
|
357
|
+
console.log(` ${c.cyan}antigravity${c.reset} Google Antigravity`);
|
|
358
|
+
console.log(` ${c.cyan}opencode${c.reset} OpenCode`);
|
|
359
|
+
console.log(` ${c.cyan}all${c.reset} Todos os 4`);
|
|
360
|
+
console.log('');
|
|
361
|
+
|
|
362
|
+
console.log(`${c.bold}Opcoes:${c.reset}`);
|
|
363
|
+
console.log(` ${c.cyan}--scope${c.reset} ${c.gray}<user|project|both>${c.reset} Escopo (default install: project; default uninstall: both)`);
|
|
364
|
+
console.log(` ${c.cyan}--verbose${c.reset} Output detalhado (so doctor)`);
|
|
365
|
+
console.log(` ${c.cyan}--dry-run${c.reset} Mostra o que faria sem aplicar (update, uninstall)`);
|
|
366
|
+
console.log(` ${c.cyan}--purge${c.reset} Uninstall: remove tambem .jdi/ (DESTRUTIVO)`);
|
|
367
|
+
console.log(` ${c.cyan}--yes${c.reset} Uninstall: pula confirmacoes interativas`);
|
|
368
|
+
console.log(` ${c.cyan}--force-specialists${c.reset} Update: regenera specialists sem perguntar`);
|
|
369
|
+
console.log(` ${c.cyan}--skip-specialists${c.reset} Update: nao mexe em specialists`);
|
|
370
|
+
console.log(` ${c.cyan}--no-color${c.reset} Desabilita cores ANSI`);
|
|
371
|
+
console.log(` ${c.cyan}-h, --help${c.reset} Esta ajuda`);
|
|
372
|
+
console.log('');
|
|
373
|
+
|
|
374
|
+
console.log(`${c.bold}Exemplos:${c.reset}`);
|
|
375
|
+
console.log(` ${c.dim}# Instalacao no projeto atual${c.reset}`);
|
|
376
|
+
console.log(` ${c.cyan}npx jdi-cli@latest install opencode${c.reset}`);
|
|
377
|
+
console.log('');
|
|
378
|
+
console.log(` ${c.dim}# Atualizar projeto ja instalado pra versao mais recente${c.reset}`);
|
|
379
|
+
console.log(` ${c.cyan}npx jdi-cli@latest update${c.reset}`);
|
|
380
|
+
console.log('');
|
|
381
|
+
console.log(` ${c.dim}# Preview do que update faria${c.reset}`);
|
|
382
|
+
console.log(` ${c.cyan}npx jdi-cli@latest update --dry-run${c.reset}`);
|
|
383
|
+
console.log('');
|
|
384
|
+
console.log(` ${c.dim}# Desinstalar (preserva .jdi/ state)${c.reset}`);
|
|
385
|
+
console.log(` ${c.cyan}npx jdi-cli@latest uninstall${c.reset}`);
|
|
386
|
+
console.log('');
|
|
387
|
+
console.log(` ${c.dim}# Desinstalar tudo, incluindo state files${c.reset}`);
|
|
388
|
+
console.log(` ${c.cyan}npx jdi-cli@latest uninstall --purge --yes${c.reset}`);
|
|
389
|
+
console.log('');
|
|
390
|
+
console.log(` ${c.dim}# Diagnostico${c.reset}`);
|
|
391
|
+
console.log(` ${c.cyan}npx jdi-cli@latest doctor${c.reset}`);
|
|
392
|
+
console.log('');
|
|
393
|
+
|
|
394
|
+
console.log(`${c.bold}Saiba mais:${c.reset} ${c.cyan}https://github.com/<owner>/jdi${c.reset}`);
|
|
395
|
+
console.log('');
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function cmdVersion() {
|
|
399
|
+
console.log(`jdi-cli ${c.bold}v${VERSION}${c.reset}`);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// =================================================================
|
|
403
|
+
// Main dispatcher
|
|
404
|
+
// =================================================================
|
|
405
|
+
|
|
406
|
+
function main() {
|
|
407
|
+
const parsed = parseArgs(process.argv);
|
|
408
|
+
|
|
409
|
+
if (parsed.flags && parsed.flags.noColor) {
|
|
410
|
+
process.env.NO_COLOR = '1';
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (parsed.flags && parsed.flags.version) {
|
|
414
|
+
cmdVersion();
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
switch (parsed.cmd) {
|
|
419
|
+
case 'install':
|
|
420
|
+
cmdInstall(parsed);
|
|
421
|
+
break;
|
|
422
|
+
case 'update':
|
|
423
|
+
case 'upgrade':
|
|
424
|
+
cmdUpdate(parsed);
|
|
425
|
+
break;
|
|
426
|
+
case 'uninstall':
|
|
427
|
+
case 'remove':
|
|
428
|
+
cmdUninstall(parsed);
|
|
429
|
+
break;
|
|
430
|
+
case 'build':
|
|
431
|
+
cmdBuild(parsed);
|
|
432
|
+
break;
|
|
433
|
+
case 'install-playwright':
|
|
434
|
+
case 'playwright':
|
|
435
|
+
cmdInstallPlaywright(parsed);
|
|
436
|
+
break;
|
|
437
|
+
case 'install-caveman':
|
|
438
|
+
case 'caveman':
|
|
439
|
+
cmdInstallCaveman(parsed);
|
|
440
|
+
break;
|
|
441
|
+
case 'doctor':
|
|
442
|
+
cmdDoctor(parsed);
|
|
443
|
+
break;
|
|
444
|
+
case 'help':
|
|
445
|
+
case '--help':
|
|
446
|
+
case '-h':
|
|
447
|
+
cmdHelp();
|
|
448
|
+
break;
|
|
449
|
+
case '--version':
|
|
450
|
+
case '-V':
|
|
451
|
+
cmdVersion();
|
|
452
|
+
break;
|
|
453
|
+
default:
|
|
454
|
+
ui.fail(`Comando desconhecido: ${parsed.cmd}`);
|
|
455
|
+
console.log(` Use ${c.cyan}npx jdi-cli help${c.reset} pra ver comandos disponiveis.`);
|
|
456
|
+
process.exit(1);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
main();
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# jdi-monitor.ps1 — context budget monitor (heuristica)
|
|
2
|
+
#
|
|
3
|
+
# Uso:
|
|
4
|
+
# pwsh -File jdi-monitor.ps1 -Paths @("a.md","b.md")
|
|
5
|
+
#
|
|
6
|
+
# Estima tokens consumidos por leitura inline dos paths informados
|
|
7
|
+
# (heuristica chars/4 = tokens). Le .jdi/config.json pra resolver
|
|
8
|
+
# context_window + thresholds. Imprime status pra stderr e sai 0.
|
|
9
|
+
#
|
|
10
|
+
# Status:
|
|
11
|
+
# PEAK 0-30% ok, full operations
|
|
12
|
+
# GOOD 30-60% ok, prefere frontmatter
|
|
13
|
+
# WARN 60-70% context aquecendo, considere checkpoint
|
|
14
|
+
# CRITICAL 70%+ fracture zone — sugere /jdi-thread
|
|
15
|
+
|
|
16
|
+
param(
|
|
17
|
+
[string[]]$Paths = @()
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
$ErrorActionPreference = "Stop"
|
|
21
|
+
|
|
22
|
+
# Defaults
|
|
23
|
+
$ContextWindow = 200000
|
|
24
|
+
$WarnPct = 60
|
|
25
|
+
$CriticalPct = 70
|
|
26
|
+
|
|
27
|
+
if (Test-Path -LiteralPath ".jdi/config.json") {
|
|
28
|
+
try {
|
|
29
|
+
$cfg = Get-Content -LiteralPath ".jdi/config.json" -Raw -Encoding UTF8 | ConvertFrom-Json
|
|
30
|
+
if ($cfg.context_window) { $ContextWindow = [int]$cfg.context_window }
|
|
31
|
+
if ($cfg.thresholds) {
|
|
32
|
+
if ($cfg.thresholds.warn_pct) { $WarnPct = [int]$cfg.thresholds.warn_pct }
|
|
33
|
+
if ($cfg.thresholds.critical_pct) { $CriticalPct = [int]$cfg.thresholds.critical_pct }
|
|
34
|
+
}
|
|
35
|
+
} catch {
|
|
36
|
+
# config invalido — usa defaults
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
$totalChars = 0
|
|
41
|
+
foreach ($p in $Paths) {
|
|
42
|
+
if (Test-Path -LiteralPath $p -PathType Leaf) {
|
|
43
|
+
$totalChars += (Get-Item -LiteralPath $p).Length
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
$tokens = [int]([math]::Floor($totalChars / 4))
|
|
48
|
+
$pct = if ($ContextWindow -gt 0) { [int]([math]::Floor($tokens * 100 / $ContextWindow)) } else { 0 }
|
|
49
|
+
|
|
50
|
+
$state = "PEAK"
|
|
51
|
+
$hint = ""
|
|
52
|
+
if ($pct -ge $CriticalPct) {
|
|
53
|
+
$state = "CRITICAL"
|
|
54
|
+
$hint = "fracture zone — considere /jdi-thread (proxima phase em sessao nova)"
|
|
55
|
+
} elseif ($pct -ge $WarnPct) {
|
|
56
|
+
$state = "WARN"
|
|
57
|
+
$hint = "context aquecendo — checkpoint recomendado"
|
|
58
|
+
} elseif ($pct -ge 30) {
|
|
59
|
+
$state = "GOOD"
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
$msg = "[jdi-monitor] $state ${pct}% (~${tokens} tokens / ${ContextWindow})"
|
|
63
|
+
if ($hint) { $msg = "$msg. $hint" }
|
|
64
|
+
|
|
65
|
+
[Console]::Error.WriteLine($msg)
|
|
66
|
+
exit 0
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# jdi-monitor.sh — context budget monitor (heuristica)
|
|
3
|
+
#
|
|
4
|
+
# Uso:
|
|
5
|
+
# jdi-monitor.sh [path1 path2 ...]
|
|
6
|
+
#
|
|
7
|
+
# Estima tokens consumidos por leitura inline dos paths informados
|
|
8
|
+
# (heuristica chars/4 = tokens). Le .jdi/config.json pra resolver
|
|
9
|
+
# context_window + thresholds. Imprime status pra stderr e sai 0.
|
|
10
|
+
#
|
|
11
|
+
# Status:
|
|
12
|
+
# PEAK 0-30% ok, full operations
|
|
13
|
+
# GOOD 30-60% ok, prefere frontmatter
|
|
14
|
+
# WARN 60-70% context aquecendo, considere checkpoint
|
|
15
|
+
# CRITICAL 70%+ fracture zone — sugere /jdi-thread
|
|
16
|
+
#
|
|
17
|
+
# Sai 0 sempre (nao bloqueia). Saida via stderr nao polui pipe.
|
|
18
|
+
|
|
19
|
+
set -euo pipefail
|
|
20
|
+
|
|
21
|
+
CONFIG=".jdi/config.json"
|
|
22
|
+
|
|
23
|
+
# Defaults se config ausente
|
|
24
|
+
CONTEXT_WINDOW=200000
|
|
25
|
+
WARN_PCT=60
|
|
26
|
+
CRITICAL_PCT=70
|
|
27
|
+
|
|
28
|
+
if [ -f "$CONFIG" ]; then
|
|
29
|
+
if command -v jq >/dev/null 2>&1; then
|
|
30
|
+
CONTEXT_WINDOW=$(jq -r '.context_window // 200000' "$CONFIG")
|
|
31
|
+
WARN_PCT=$(jq -r '.thresholds.warn_pct // 60' "$CONFIG")
|
|
32
|
+
CRITICAL_PCT=$(jq -r '.thresholds.critical_pct // 70' "$CONFIG")
|
|
33
|
+
else
|
|
34
|
+
# Fallback grep — funciona pro JSON simples do JDI
|
|
35
|
+
CONTEXT_WINDOW=$(grep -oE '"context_window":[[:space:]]*[0-9]+' "$CONFIG" | head -1 | grep -oE '[0-9]+' || echo 200000)
|
|
36
|
+
WARN_PCT=$(grep -oE '"warn_pct":[[:space:]]*[0-9]+' "$CONFIG" | head -1 | grep -oE '[0-9]+' || echo 60)
|
|
37
|
+
CRITICAL_PCT=$(grep -oE '"critical_pct":[[:space:]]*[0-9]+' "$CONFIG" | head -1 | grep -oE '[0-9]+' || echo 70)
|
|
38
|
+
fi
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# Soma chars dos paths informados
|
|
42
|
+
TOTAL_CHARS=0
|
|
43
|
+
for p in "$@"; do
|
|
44
|
+
if [ -f "$p" ]; then
|
|
45
|
+
SZ=$(wc -c < "$p" | tr -d ' ')
|
|
46
|
+
TOTAL_CHARS=$((TOTAL_CHARS + SZ))
|
|
47
|
+
fi
|
|
48
|
+
done
|
|
49
|
+
|
|
50
|
+
# Heuristica: 4 chars ~ 1 token
|
|
51
|
+
TOKENS=$((TOTAL_CHARS / 4))
|
|
52
|
+
PCT=$((TOKENS * 100 / CONTEXT_WINDOW))
|
|
53
|
+
|
|
54
|
+
if [ "$PCT" -ge "$CRITICAL_PCT" ]; then
|
|
55
|
+
STATE="CRITICAL"
|
|
56
|
+
HINT="fracture zone — considere /jdi-thread (proxima phase em sessao nova)"
|
|
57
|
+
elif [ "$PCT" -ge "$WARN_PCT" ]; then
|
|
58
|
+
STATE="WARN"
|
|
59
|
+
HINT="context aquecendo — checkpoint recomendado"
|
|
60
|
+
elif [ "$PCT" -ge 30 ]; then
|
|
61
|
+
STATE="GOOD"
|
|
62
|
+
HINT=""
|
|
63
|
+
else
|
|
64
|
+
STATE="PEAK"
|
|
65
|
+
HINT=""
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
if [ -n "$HINT" ]; then
|
|
69
|
+
echo "[jdi-monitor] $STATE ${PCT}% (~${TOKENS} tokens / ${CONTEXT_WINDOW}). $HINT" >&2
|
|
70
|
+
else
|
|
71
|
+
echo "[jdi-monitor] $STATE ${PCT}% (~${TOKENS} tokens / ${CONTEXT_WINDOW})" >&2
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
exit 0
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# jdi-truncate.ps1 — markdown-aware truncation pra context budget
|
|
2
|
+
#
|
|
3
|
+
# Uso:
|
|
4
|
+
# pwsh -File jdi-truncate.ps1 -Path <path> [-Budget 8192]
|
|
5
|
+
#
|
|
6
|
+
# Estrategia:
|
|
7
|
+
# - Preserva YAML frontmatter inteiro
|
|
8
|
+
# - Preserva TODAS as linhas de heading (#, ##, ...)
|
|
9
|
+
# - Preserva 1a linha nao-vazia de cada secao
|
|
10
|
+
# - Resto vira "[... N lines omitted]"
|
|
11
|
+
# - Footer aponta pro arquivo original
|
|
12
|
+
#
|
|
13
|
+
# Se file <= budget, ecoa inteiro. Output sempre pra stdout.
|
|
14
|
+
|
|
15
|
+
param(
|
|
16
|
+
[Parameter(Mandatory = $true)]
|
|
17
|
+
[string]$Path,
|
|
18
|
+
|
|
19
|
+
[int]$Budget = 8192
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
$ErrorActionPreference = "Stop"
|
|
23
|
+
|
|
24
|
+
if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
|
|
25
|
+
Write-Error "arquivo nao encontrado: $Path"
|
|
26
|
+
exit 1
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
$content = Get-Content -LiteralPath $Path -Raw -Encoding UTF8
|
|
30
|
+
if ($null -eq $content) { $content = "" }
|
|
31
|
+
|
|
32
|
+
if ($content.Length -le $Budget) {
|
|
33
|
+
Write-Output $content
|
|
34
|
+
exit 0
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
$lines = $content -split "`r?`n"
|
|
38
|
+
$inFrontmatter = $false
|
|
39
|
+
$paragraphKept = $false
|
|
40
|
+
$omitted = 0
|
|
41
|
+
$out = New-Object System.Collections.Generic.List[string]
|
|
42
|
+
|
|
43
|
+
for ($i = 0; $i -lt $lines.Length; $i++) {
|
|
44
|
+
$line = $lines[$i]
|
|
45
|
+
|
|
46
|
+
# Frontmatter (so se comecar na linha 1 = index 0)
|
|
47
|
+
if ($i -eq 0 -and $line -eq "---") {
|
|
48
|
+
$inFrontmatter = $true
|
|
49
|
+
$out.Add($line)
|
|
50
|
+
continue
|
|
51
|
+
}
|
|
52
|
+
if ($inFrontmatter) {
|
|
53
|
+
$out.Add($line)
|
|
54
|
+
if ($line -eq "---") {
|
|
55
|
+
$inFrontmatter = $false
|
|
56
|
+
}
|
|
57
|
+
continue
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# Heading — sempre preserva
|
|
61
|
+
if ($line -match '^#{1,6}\s') {
|
|
62
|
+
if ($omitted -gt 0) {
|
|
63
|
+
$out.Add("[... $omitted lines omitted]")
|
|
64
|
+
$omitted = 0
|
|
65
|
+
}
|
|
66
|
+
$out.Add($line)
|
|
67
|
+
$paragraphKept = $false
|
|
68
|
+
continue
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
# Linha vazia
|
|
72
|
+
if ($line -match '^\s*$') {
|
|
73
|
+
if (-not $paragraphKept) {
|
|
74
|
+
$out.Add($line)
|
|
75
|
+
} else {
|
|
76
|
+
$omitted++
|
|
77
|
+
}
|
|
78
|
+
continue
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
# Conteudo
|
|
82
|
+
if (-not $paragraphKept) {
|
|
83
|
+
$out.Add($line)
|
|
84
|
+
$paragraphKept = $true
|
|
85
|
+
} else {
|
|
86
|
+
$omitted++
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if ($omitted -gt 0) {
|
|
91
|
+
$out.Add("[... $omitted lines omitted]")
|
|
92
|
+
}
|
|
93
|
+
$out.Add("")
|
|
94
|
+
$out.Add("[Truncated by jdi-truncate. Read $Path for full content]")
|
|
95
|
+
|
|
96
|
+
Write-Output ($out -join "`n")
|