@ekkos/cli 1.3.2 → 1.3.6
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/capture/jsonl-rewriter.d.ts +1 -1
- package/dist/capture/jsonl-rewriter.js +3 -3
- package/dist/capture/transcript-repair.d.ts +2 -2
- package/dist/capture/transcript-repair.js +2 -2
- package/dist/commands/claw.d.ts +13 -0
- package/dist/commands/claw.js +253 -0
- package/dist/commands/dashboard.js +617 -83
- package/dist/commands/doctor.d.ts +3 -3
- package/dist/commands/doctor.js +6 -79
- package/dist/commands/gemini.d.ts +19 -0
- package/dist/commands/gemini.js +193 -0
- package/dist/commands/init.js +2 -25
- package/dist/commands/run.d.ts +0 -1
- package/dist/commands/run.js +147 -241
- package/dist/commands/scan.d.ts +21 -0
- package/dist/commands/scan.js +386 -0
- package/dist/commands/swarm-dashboard.js +156 -28
- package/dist/commands/swarm.d.ts +1 -1
- package/dist/commands/swarm.js +1 -1
- package/dist/commands/test-claude.d.ts +2 -2
- package/dist/commands/test-claude.js +3 -3
- package/dist/deploy/index.d.ts +0 -2
- package/dist/deploy/index.js +0 -2
- package/dist/deploy/settings.d.ts +2 -2
- package/dist/deploy/settings.js +42 -4
- package/dist/deploy/skills.js +1 -2
- package/dist/index.js +79 -19
- package/dist/lib/usage-parser.js +5 -4
- package/dist/utils/proxy-url.d.ts +12 -1
- package/dist/utils/proxy-url.js +16 -1
- package/dist/utils/templates.js +1 -1
- package/package.json +4 -6
- package/templates/CLAUDE.md +49 -107
- package/dist/agent/daemon.d.ts +0 -130
- package/dist/agent/daemon.js +0 -606
- package/dist/agent/health-check.d.ts +0 -35
- package/dist/agent/health-check.js +0 -243
- package/dist/agent/pty-runner.d.ts +0 -53
- package/dist/agent/pty-runner.js +0 -190
- package/dist/commands/agent.d.ts +0 -50
- package/dist/commands/agent.js +0 -544
- package/dist/commands/setup-remote.d.ts +0 -20
- package/dist/commands/setup-remote.js +0 -582
- package/dist/commands/synk.d.ts +0 -7
- package/dist/commands/synk.js +0 -339
- package/dist/cron/index.d.ts +0 -7
- package/dist/cron/index.js +0 -13
- package/dist/cron/promoter.d.ts +0 -70
- package/dist/cron/promoter.js +0 -403
- package/dist/synk/api.d.ts +0 -22
- package/dist/synk/api.js +0 -133
- package/dist/synk/auth.d.ts +0 -7
- package/dist/synk/auth.js +0 -30
- package/dist/synk/config.d.ts +0 -18
- package/dist/synk/config.js +0 -37
- package/dist/synk/daemon/control-client.d.ts +0 -11
- package/dist/synk/daemon/control-client.js +0 -101
- package/dist/synk/daemon/control-server.d.ts +0 -24
- package/dist/synk/daemon/control-server.js +0 -91
- package/dist/synk/daemon/run.d.ts +0 -14
- package/dist/synk/daemon/run.js +0 -338
- package/dist/synk/encryption.d.ts +0 -17
- package/dist/synk/encryption.js +0 -133
- package/dist/synk/index.d.ts +0 -13
- package/dist/synk/index.js +0 -36
- package/dist/synk/machine-client.d.ts +0 -42
- package/dist/synk/machine-client.js +0 -218
- package/dist/synk/persistence.d.ts +0 -51
- package/dist/synk/persistence.js +0 -211
- package/dist/synk/qr.d.ts +0 -5
- package/dist/synk/qr.js +0 -33
- package/dist/synk/session-bridge.d.ts +0 -58
- package/dist/synk/session-bridge.js +0 -171
- package/dist/synk/session-client.d.ts +0 -46
- package/dist/synk/session-client.js +0 -240
- package/dist/synk/types.d.ts +0 -574
- package/dist/synk/types.js +0 -74
- package/dist/utils/verify-remote-terminal.d.ts +0 -10
- package/dist/utils/verify-remote-terminal.js +0 -415
- package/templates/README.md +0 -378
- package/templates/claude-plugins/PHASE2_COMPLETION.md +0 -346
- package/templates/claude-plugins/PLUGIN_PROPOSALS.md +0 -1776
- package/templates/claude-plugins/README.md +0 -587
- package/templates/claude-plugins/agents/code-reviewer.json +0 -14
- package/templates/claude-plugins/agents/debug-detective.json +0 -15
- package/templates/claude-plugins/agents/git-companion.json +0 -14
- package/templates/claude-plugins/blog-manager/.claude-plugin/plugin.json +0 -8
- package/templates/claude-plugins/blog-manager/commands/blog.md +0 -691
- package/templates/claude-plugins/golden-loop-monitor/.claude-plugin/plugin.json +0 -8
- package/templates/claude-plugins/golden-loop-monitor/commands/loop-status.md +0 -434
- package/templates/claude-plugins/learning-tracker/.claude-plugin/plugin.json +0 -8
- package/templates/claude-plugins/learning-tracker/commands/my-patterns.md +0 -282
- package/templates/claude-plugins/memory-lens/.claude-plugin/plugin.json +0 -8
- package/templates/claude-plugins/memory-lens/commands/memory-search.md +0 -181
- package/templates/claude-plugins/pattern-coach/.claude-plugin/plugin.json +0 -8
- package/templates/claude-plugins/pattern-coach/commands/forge.md +0 -365
- package/templates/claude-plugins/project-schema-validator/.claude-plugin/plugin.json +0 -8
- package/templates/claude-plugins/project-schema-validator/commands/validate-schema.md +0 -582
- package/templates/commands/continue.md +0 -47
- package/templates/cursor-rules/ekkos-memory.md +0 -127
- package/templates/ekkos-manifest.json +0 -223
- package/templates/helpers/json-parse.cjs +0 -101
- package/templates/plan-template.md +0 -306
- package/templates/shared/hooks-enabled.json +0 -22
- package/templates/shared/session-words.json +0 -45
- package/templates/skills/ekkOS_Deep_Recall/Skill.md +0 -282
- package/templates/skills/ekkOS_Learn/Skill.md +0 -265
- package/templates/skills/ekkOS_Memory_First/Skill.md +0 -206
- package/templates/skills/ekkOS_Plan_Assist/Skill.md +0 -302
- package/templates/skills/ekkOS_Preferences/Skill.md +0 -247
- package/templates/skills/ekkOS_Reflect/Skill.md +0 -257
- package/templates/skills/ekkOS_Safety/Skill.md +0 -265
- package/templates/skills/ekkOS_Schema/Skill.md +0 -251
- package/templates/skills/ekkOS_Summary/Skill.md +0 -257
- package/templates/spec-template.md +0 -159
- package/templates/windsurf-rules/ekkos-memory.md +0 -127
- package/templates/windsurf-skills/README.md +0 -58
- package/templates/windsurf-skills/ekkos-continue/SKILL.md +0 -81
- package/templates/windsurf-skills/ekkos-golden-loop/SKILL.md +0 -225
- package/templates/windsurf-skills/ekkos-insights/SKILL.md +0 -138
- package/templates/windsurf-skills/ekkos-recall/SKILL.md +0 -96
- package/templates/windsurf-skills/ekkos-safety/SKILL.md +0 -89
- package/templates/windsurf-skills/ekkos-vault/SKILL.md +0 -86
package/dist/commands/run.js
CHANGED
|
@@ -43,140 +43,6 @@ const fs = __importStar(require("fs"));
|
|
|
43
43
|
const path = __importStar(require("path"));
|
|
44
44
|
const os = __importStar(require("os"));
|
|
45
45
|
const child_process_1 = require("child_process");
|
|
46
|
-
const session_bridge_1 = require("../synk/session-bridge");
|
|
47
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
48
|
-
// ccDNA AUTO-LOAD: Apply Claude Code patches before spawning
|
|
49
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
50
|
-
const CCDNA_PATHS = [
|
|
51
|
-
// Development path (DEV sibling directory)
|
|
52
|
-
// From: EKKOS/packages/ekkos-cli/dist/commands/ → DEV/ekkos-ccdna/
|
|
53
|
-
path.join(__dirname, '..', '..', '..', '..', '..', 'ekkos-ccdna', 'dist', 'index.mjs'),
|
|
54
|
-
// User install path
|
|
55
|
-
path.join(os.homedir(), '.ekkos', 'ccdna', 'dist', 'index.mjs'),
|
|
56
|
-
// npm global (homebrew)
|
|
57
|
-
'/opt/homebrew/lib/node_modules/ekkos-ccdna/dist/index.mjs',
|
|
58
|
-
// npm global (standard)
|
|
59
|
-
path.join(os.homedir(), '.npm-global', 'lib', 'node_modules', 'ekkos-ccdna', 'dist', 'index.mjs'),
|
|
60
|
-
];
|
|
61
|
-
/**
|
|
62
|
-
* Find ccDNA installation path
|
|
63
|
-
*/
|
|
64
|
-
function findCcdnaPath() {
|
|
65
|
-
for (const p of CCDNA_PATHS) {
|
|
66
|
-
if (fs.existsSync(p)) {
|
|
67
|
-
return p;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
return null;
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Apply ccDNA patches silently before Claude spawns
|
|
74
|
-
* Returns version string if patches were applied, null otherwise
|
|
75
|
-
*
|
|
76
|
-
* @param verbose - Show detailed output
|
|
77
|
-
* @param claudePath - Path to Claude Code to patch (if different from default)
|
|
78
|
-
*/
|
|
79
|
-
function applyCcdnaPatches(verbose, claudePath) {
|
|
80
|
-
// DISABLED: ccDNA patching is currently corrupting cli.js (JSON parse error at position 7945)
|
|
81
|
-
// See: https://github.com/anthropics/ekkos/issues/2856
|
|
82
|
-
// The patching process is injecting code that breaks the minified cli.js
|
|
83
|
-
// Temporarily disabled until ccDNA is fixed upstream
|
|
84
|
-
if (verbose) {
|
|
85
|
-
console.log(chalk_1.default.gray(' ccDNA patching disabled (see issue #2856)'));
|
|
86
|
-
}
|
|
87
|
-
return null;
|
|
88
|
-
// Original implementation (disabled):
|
|
89
|
-
/*
|
|
90
|
-
const ccdnaPath = findCcdnaPath();
|
|
91
|
-
if (!ccdnaPath) {
|
|
92
|
-
if (verbose) {
|
|
93
|
-
console.log(chalk.gray(' ccDNA not found - skipping patches'));
|
|
94
|
-
}
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Read ccDNA version from package.json FIRST
|
|
99
|
-
let ccdnaVersion = 'unknown';
|
|
100
|
-
try {
|
|
101
|
-
const pkgPath = path.join(path.dirname(ccdnaPath), '..', 'package.json');
|
|
102
|
-
if (fs.existsSync(pkgPath)) {
|
|
103
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
104
|
-
ccdnaVersion = pkg.version || 'unknown';
|
|
105
|
-
}
|
|
106
|
-
} catch {
|
|
107
|
-
// Ignore version detection errors
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
try {
|
|
111
|
-
// Set env var to tell ccDNA which Claude to patch
|
|
112
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
113
|
-
const env = { ...process.env };
|
|
114
|
-
if (claudePath) {
|
|
115
|
-
// ccDNA checks CCDNA_CC_INSTALLATION_PATH to override default detection
|
|
116
|
-
env.CCDNA_CC_INSTALLATION_PATH = claudePath;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Run ccDNA in apply mode (non-interactive)
|
|
120
|
-
execSync(`node "${ccdnaPath}" -a`, {
|
|
121
|
-
stdio: verbose ? 'inherit' : 'pipe',
|
|
122
|
-
timeout: 30000, // 30 second timeout
|
|
123
|
-
env,
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
if (verbose) {
|
|
127
|
-
console.log(chalk.green(` ✓ ccDNA v${ccdnaVersion} patches applied`));
|
|
128
|
-
}
|
|
129
|
-
return ccdnaVersion;
|
|
130
|
-
} catch (err) {
|
|
131
|
-
if (verbose) {
|
|
132
|
-
console.log(chalk.yellow(` ⚠ ccDNA patch failed: ${(err as Error).message}`));
|
|
133
|
-
}
|
|
134
|
-
return null;
|
|
135
|
-
}
|
|
136
|
-
*/
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* Restore original Claude Code (remove ccDNA patches) on exit
|
|
140
|
-
* This restores the ekkOS-managed installation (~/.ekkos/claude-code/) to its base state
|
|
141
|
-
*
|
|
142
|
-
* NOTE: We intentionally DON'T restore on exit anymore because:
|
|
143
|
-
* 1. ekkOS uses a SEPARATE installation (~/.ekkos/claude-code/) from homebrew
|
|
144
|
-
* 2. The homebrew `claude` command should always be vanilla (untouched)
|
|
145
|
-
* 3. The ekkOS installation can stay patched - it's only used by `ekkos run`
|
|
146
|
-
*
|
|
147
|
-
* This function is kept for manual/explicit restore scenarios.
|
|
148
|
-
*/
|
|
149
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
150
|
-
function restoreCcdnaPatches(verbose, claudePath) {
|
|
151
|
-
const ccdnaPath = findCcdnaPath();
|
|
152
|
-
if (!ccdnaPath) {
|
|
153
|
-
return false;
|
|
154
|
-
}
|
|
155
|
-
try {
|
|
156
|
-
// Set env var to tell ccDNA which Claude to restore
|
|
157
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
158
|
-
const env = { ...process.env };
|
|
159
|
-
if (claudePath) {
|
|
160
|
-
env.CCDNA_CC_INSTALLATION_PATH = claudePath;
|
|
161
|
-
}
|
|
162
|
-
// Run ccDNA in restore mode (non-interactive)
|
|
163
|
-
(0, child_process_1.execSync)(`node "${ccdnaPath}" -r`, {
|
|
164
|
-
stdio: verbose ? 'inherit' : 'pipe',
|
|
165
|
-
timeout: 30000, // 30 second timeout
|
|
166
|
-
env,
|
|
167
|
-
});
|
|
168
|
-
if (verbose) {
|
|
169
|
-
console.log(chalk_1.default.green(' ✓ ccDNA patches removed (vanilla restored)'));
|
|
170
|
-
}
|
|
171
|
-
return true;
|
|
172
|
-
}
|
|
173
|
-
catch (err) {
|
|
174
|
-
if (verbose) {
|
|
175
|
-
console.log(chalk_1.default.yellow(` ⚠ ccDNA restore failed: ${err.message}`));
|
|
176
|
-
}
|
|
177
|
-
return false;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
46
|
const state_1 = require("../utils/state");
|
|
181
47
|
const session_binding_1 = require("../utils/session-binding");
|
|
182
48
|
const doctor_1 = require("./doctor");
|
|
@@ -215,7 +81,7 @@ function getConfig(options) {
|
|
|
215
81
|
maxIdleWaitMs: parseInt(process.env.EKKOS_MAX_IDLE_WAIT_MS || '2000', 10), // was 10000
|
|
216
82
|
debugLogPath: options.debugLogPath ??
|
|
217
83
|
process.env.EKKOS_DEBUG_LOG_PATH ??
|
|
218
|
-
path.join(os.homedir(), '.ekkos', '
|
|
84
|
+
path.join(os.homedir(), '.ekkos', 'ekkos-debug.log')
|
|
219
85
|
};
|
|
220
86
|
/* eslint-enable no-restricted-syntax */
|
|
221
87
|
}
|
|
@@ -256,7 +122,7 @@ const PALETTE_INDICATOR_REGEX = /\/(clear|continue|compact|help|bug|config)/i;
|
|
|
256
122
|
const SESSION_NAME_IN_STATUS_REGEX = /turn\s+\d+\s*·\s*([a-z]+-[a-z]+-[a-z]+)\s*·/i;
|
|
257
123
|
// Weaker signal: any 3-word slug (word-word-word pattern)
|
|
258
124
|
const SESSION_NAME_REGEX = /\b([a-z]+-[a-z]+-[a-z]+)\b/i;
|
|
259
|
-
// Orphan tool_result marker
|
|
125
|
+
// Orphan tool_result marker
|
|
260
126
|
// Example: [ekkOS] ORPHAN_TOOL_RESULT {"idx":0,"tool_use_id":"toolu_01...","block_idx":0}
|
|
261
127
|
const ORPHAN_MARKER_REGEX = /\[ekkOS\]\s+ORPHAN_TOOL_RESULT\s+(\{.*?\})/gi;
|
|
262
128
|
// Cooldown to prevent thrashing if output repeats the marker
|
|
@@ -283,7 +149,7 @@ function isValidSessionName(name) {
|
|
|
283
149
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
284
150
|
// LOGGING (FILE ONLY DURING TUI - NO TERMINAL CORRUPTION)
|
|
285
151
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
286
|
-
let _debugLogPath = path.join(os.homedir(), '.ekkos', '
|
|
152
|
+
let _debugLogPath = path.join(os.homedir(), '.ekkos', 'ekkos-debug.log');
|
|
287
153
|
/**
|
|
288
154
|
* Set the debug log path (called once during init)
|
|
289
155
|
*/
|
|
@@ -709,6 +575,116 @@ function resolveGlobalClaudePath() {
|
|
|
709
575
|
function sleep(ms) {
|
|
710
576
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
711
577
|
}
|
|
578
|
+
/**
|
|
579
|
+
* Show morning dreams with WOW factor right after sparkle animation.
|
|
580
|
+
* Colorful, lively, readable — real magic moment. Then pause for Enter.
|
|
581
|
+
* Uses ~/.ekkos/.last-dream-shown marker (once per day, zero clutter on repeat).
|
|
582
|
+
*/
|
|
583
|
+
async function showMorningDreamsIfNeeded() {
|
|
584
|
+
const markerPath = path.join(state_1.EKKOS_DIR, '.last-dream-shown');
|
|
585
|
+
const today = new Date().toISOString().split('T')[0];
|
|
586
|
+
// Fast path: already shown today
|
|
587
|
+
try {
|
|
588
|
+
if (fs.existsSync(markerPath)) {
|
|
589
|
+
const lastShown = fs.readFileSync(markerPath, 'utf-8').trim();
|
|
590
|
+
if (lastShown === today)
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
catch { }
|
|
595
|
+
// Fetch digest from memory API (2s timeout — never blocks startup)
|
|
596
|
+
try {
|
|
597
|
+
const authToken = (0, state_1.getAuthToken)();
|
|
598
|
+
if (!authToken)
|
|
599
|
+
return;
|
|
600
|
+
const controller = new AbortController();
|
|
601
|
+
const fetchTimeout = setTimeout(() => controller.abort(), 2000);
|
|
602
|
+
const res = await fetch(`${MEMORY_API_URL}/api/v1/dreams/digest`, {
|
|
603
|
+
headers: { Authorization: `Bearer ${authToken}` },
|
|
604
|
+
signal: controller.signal,
|
|
605
|
+
});
|
|
606
|
+
clearTimeout(fetchTimeout);
|
|
607
|
+
if (!res.ok)
|
|
608
|
+
return;
|
|
609
|
+
const digest = await res.json();
|
|
610
|
+
if (!digest.dreams || digest.dreams.length === 0)
|
|
611
|
+
return;
|
|
612
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
613
|
+
// WOW FACTOR RENDERING — colorful, alive, readable
|
|
614
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
615
|
+
const dreamTime = new Date(digest.dreams[0].dreamedAt);
|
|
616
|
+
const timeStr = dreamTime.toLocaleTimeString('en-US', {
|
|
617
|
+
hour: 'numeric', minute: '2-digit', hour12: true,
|
|
618
|
+
}).toLowerCase();
|
|
619
|
+
console.log('');
|
|
620
|
+
console.log(chalk_1.default.cyan.bold(' ' + '═'.repeat(66)));
|
|
621
|
+
console.log(chalk_1.default.hex('#FF69B4').bold(` 🌙 While you slept, I had ${digest.dreams.length} idea${digest.dreams.length === 1 ? '' : 's'} for you`) +
|
|
622
|
+
chalk_1.default.gray(` (forged at ${timeStr})`));
|
|
623
|
+
console.log(chalk_1.default.gray.dim(' From your personal knowledge graph — concepts you\'ve never combined'));
|
|
624
|
+
console.log(chalk_1.default.cyan.bold(' ' + '═'.repeat(66)));
|
|
625
|
+
console.log('');
|
|
626
|
+
digest.dreams.forEach((dream, i) => {
|
|
627
|
+
const filled = Math.round(dream.creativityScore * 5);
|
|
628
|
+
const stars = chalk_1.default.yellow('★'.repeat(filled)) + chalk_1.default.gray('☆'.repeat(5 - filled));
|
|
629
|
+
// Dream title line with creativity stars
|
|
630
|
+
console.log(chalk_1.default.hex('#7C6BFF').bold(` 💭 [Dream ${i + 1}] `) +
|
|
631
|
+
chalk_1.default.white.bold(`"${dream.title}"`) +
|
|
632
|
+
' ' + stars);
|
|
633
|
+
// Solution insight (up to 140 chars, two lines max)
|
|
634
|
+
const solution = dream.solution.length > 140
|
|
635
|
+
? dream.solution.slice(0, 137) + '...'
|
|
636
|
+
: dream.solution;
|
|
637
|
+
console.log(chalk_1.default.gray(` ${solution}`));
|
|
638
|
+
// Lineage: origin ↔ discovery with domain colors
|
|
639
|
+
const crossDomain = dream.originDomain !== dream.discoveryDomain;
|
|
640
|
+
const lineage = crossDomain
|
|
641
|
+
? chalk_1.default.cyan(dream.originConcept) +
|
|
642
|
+
chalk_1.default.hex('#FFA500')(' ⚡ ') +
|
|
643
|
+
chalk_1.default.hex('#DA70D6')(dream.discoveryConcept) +
|
|
644
|
+
chalk_1.default.gray.dim(` (${dream.originDomain} × ${dream.discoveryDomain})`)
|
|
645
|
+
: chalk_1.default.cyan(dream.originConcept) +
|
|
646
|
+
chalk_1.default.gray(' ↔ ') +
|
|
647
|
+
chalk_1.default.cyan(dream.discoveryConcept);
|
|
648
|
+
console.log(` ${lineage}`);
|
|
649
|
+
console.log('');
|
|
650
|
+
});
|
|
651
|
+
// Action hints
|
|
652
|
+
console.log(chalk_1.default.gray.dim(` Reply ${chalk_1.default.white('"promote 1"')} to make it permanent, ` +
|
|
653
|
+
`${chalk_1.default.white('"dismiss 1"')} to kill it, or just ignore — it'll decay naturally.`));
|
|
654
|
+
if (digest.streak > 1) {
|
|
655
|
+
console.log(chalk_1.default.hex('#FF8800')(` 🔥 ${digest.streak}-night dream streak`) + chalk_1.default.gray.dim(` (${digest.totalDreamsEver} total dreams)`));
|
|
656
|
+
}
|
|
657
|
+
// Clickable link to expanded dashboard (OSC 8 hyperlink — supported by iTerm2, Warp, Ghostty, etc.)
|
|
658
|
+
const dashUrl = 'https://platform.ekkos.dev/dashboard/dreams';
|
|
659
|
+
console.log('');
|
|
660
|
+
console.log(chalk_1.default.gray.dim(' 📊 Full Dream Journal: ') + chalk_1.default.cyan.underline(`\x1B]8;;${dashUrl}\x07${dashUrl}\x1B]8;;\x07`));
|
|
661
|
+
console.log('');
|
|
662
|
+
console.log(chalk_1.default.hex('#FFA500').bold(' Press Enter to continue to Claude...'));
|
|
663
|
+
console.log('');
|
|
664
|
+
// Wait for any keypress — clean, non-blocking
|
|
665
|
+
await new Promise(resolve => {
|
|
666
|
+
if (process.stdin.isTTY) {
|
|
667
|
+
process.stdin.setRawMode(true);
|
|
668
|
+
process.stdin.resume();
|
|
669
|
+
process.stdin.once('data', () => {
|
|
670
|
+
process.stdin.setRawMode(false);
|
|
671
|
+
process.stdin.pause();
|
|
672
|
+
resolve();
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
else {
|
|
676
|
+
// Non-TTY (piped input) — don't block
|
|
677
|
+
resolve();
|
|
678
|
+
}
|
|
679
|
+
});
|
|
680
|
+
// Mark as shown for today
|
|
681
|
+
fs.writeFileSync(markerPath, today);
|
|
682
|
+
dlog(`🌙 Wow-factor morning dreams shown for ${today}`);
|
|
683
|
+
}
|
|
684
|
+
catch (err) {
|
|
685
|
+
dlog(`Morning dreams fetch failed (silent): ${err.message}`);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
712
688
|
/**
|
|
713
689
|
* Emergency capture before clear - saves current state to ekkOS
|
|
714
690
|
*/
|
|
@@ -853,8 +829,6 @@ function launchWithDashboard(options) {
|
|
|
853
829
|
runArgs.push('-r');
|
|
854
830
|
if (options.noInject)
|
|
855
831
|
runArgs.push('--skip-inject');
|
|
856
|
-
if (options.noDna)
|
|
857
|
-
runArgs.push('--skip-dna');
|
|
858
832
|
if (options.noProxy)
|
|
859
833
|
runArgs.push('--skip-proxy');
|
|
860
834
|
const ekkosCmd = process.argv[1]; // Path to ekkos CLI
|
|
@@ -885,6 +859,10 @@ function launchWithDashboard(options) {
|
|
|
885
859
|
applyTmuxOpt(`set-option -sa -t "${tmuxSession}" terminal-overrides ",xterm-256color:Tc:smcup@:rmcup@"`);
|
|
886
860
|
// Session/window isolation and quality-of-life settings
|
|
887
861
|
applyTmuxOpt(`set-option -t "${tmuxSession}" mouse on`);
|
|
862
|
+
// Auto-cleanup on disconnect without breaking startup:
|
|
863
|
+
// kill this tmux session only when the last client detaches.
|
|
864
|
+
const detachCleanupHook = `if-shell -F '#{==:#{session_attached},0}' 'kill-session -t ${tmuxSession}'`;
|
|
865
|
+
applyTmuxOpt(`set-hook -t "${tmuxSession}" client-detached "${detachCleanupHook}"`);
|
|
888
866
|
applyTmuxOpt(`set-window-option -t "${tmuxSession}" history-limit 100000`);
|
|
889
867
|
applyTmuxOpt(`set-window-option -t "${tmuxSession}" mode-keys vi`);
|
|
890
868
|
applyTmuxOpt(`set-window-option -t "${tmuxSession}:claude" synchronize-panes off`);
|
|
@@ -936,8 +914,6 @@ function launchWithWindowsTerminal(options) {
|
|
|
936
914
|
runArgs.push('-r');
|
|
937
915
|
if (options.noInject)
|
|
938
916
|
runArgs.push('--skip-inject');
|
|
939
|
-
if (options.noDna)
|
|
940
|
-
runArgs.push('--skip-dna');
|
|
941
917
|
if (options.noProxy)
|
|
942
918
|
runArgs.push('--skip-proxy');
|
|
943
919
|
// Write a temp batch file to avoid all quoting issues
|
|
@@ -1067,43 +1043,9 @@ async function run(options) {
|
|
|
1067
1043
|
// ══════════════════════════════════════════════════════════════════════════
|
|
1068
1044
|
(0, state_1.ensureEkkosDir)();
|
|
1069
1045
|
(0, state_1.clearAutoClearFlag)();
|
|
1070
|
-
// Resolve Claude path
|
|
1046
|
+
// Resolve Claude path
|
|
1071
1047
|
const rawClaudePath = resolveClaudePath();
|
|
1072
1048
|
const isNpxMode = rawClaudePath.startsWith('npx:');
|
|
1073
|
-
// Get the actual CLI path for ccDNA to patch
|
|
1074
|
-
// CRITICAL: ONLY patch the ekkOS-managed installation, NEVER touch Homebrew/global!
|
|
1075
|
-
let claudeCliPath;
|
|
1076
|
-
// Always target the ekkOS-managed installation for patching
|
|
1077
|
-
// Even if we're running from Homebrew, we only patch our own installation
|
|
1078
|
-
if (fs.existsSync(EKKOS_CLAUDE_BIN)) {
|
|
1079
|
-
try {
|
|
1080
|
-
const realPath = fs.realpathSync(EKKOS_CLAUDE_BIN);
|
|
1081
|
-
if (realPath.endsWith('.js') && fs.existsSync(realPath)) {
|
|
1082
|
-
claudeCliPath = realPath;
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
catch {
|
|
1086
|
-
// Ignore - will use default detection
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
// ══════════════════════════════════════════════════════════════════════════
|
|
1090
|
-
// ccDNA AUTO-PATCH: Apply Claude Code customizations before spawn
|
|
1091
|
-
// This patches the context warning, themes, and other ccDNA features
|
|
1092
|
-
// Skip if --no-dna flag is set
|
|
1093
|
-
// ══════════════════════════════════════════════════════════════════════════
|
|
1094
|
-
const noDna = options.noDna || false;
|
|
1095
|
-
let ccdnaVersion = null;
|
|
1096
|
-
if (noDna) {
|
|
1097
|
-
if (verbose) {
|
|
1098
|
-
console.log(chalk_1.default.yellow(' ⏭️ Skipping ccDNA injection (--no-dna)'));
|
|
1099
|
-
}
|
|
1100
|
-
}
|
|
1101
|
-
else {
|
|
1102
|
-
if (verbose && claudeCliPath) {
|
|
1103
|
-
console.log(chalk_1.default.gray(` 🔧 Patching: ${claudeCliPath}`));
|
|
1104
|
-
}
|
|
1105
|
-
ccdnaVersion = applyCcdnaPatches(verbose, claudeCliPath);
|
|
1106
|
-
}
|
|
1107
1049
|
const pinnedVersion = isNpxMode ? rawClaudePath.split(':')[1] : null;
|
|
1108
1050
|
const claudePath = isNpxMode ? 'npx' : rawClaudePath;
|
|
1109
1051
|
// Build args early
|
|
@@ -1349,9 +1291,6 @@ async function run(options) {
|
|
|
1349
1291
|
if (bypass) {
|
|
1350
1292
|
console.log(chalk_1.default.yellow(' ⚡ Bypass permissions mode enabled'));
|
|
1351
1293
|
}
|
|
1352
|
-
if (noDna) {
|
|
1353
|
-
console.log(chalk_1.default.yellow(' ⏭️ ccDNA injection skipped (--no-dna)'));
|
|
1354
|
-
}
|
|
1355
1294
|
if (verbose) {
|
|
1356
1295
|
console.log(chalk_1.default.gray(` 📁 Debug log: ${config.debugLogPath}`));
|
|
1357
1296
|
console.log(chalk_1.default.gray(` ⏱ Timing: clear=${config.clearWaitMs}ms, idleMax=${config.maxIdleWaitMs}ms (~${Math.round((config.clearWaitMs + config.maxIdleWaitMs * 2 + 1700) / 1000)}s total)`));
|
|
@@ -1366,15 +1305,16 @@ async function run(options) {
|
|
|
1366
1305
|
if (bypass) {
|
|
1367
1306
|
console.log(chalk_1.default.yellow(' ⚡ Bypass permissions mode enabled'));
|
|
1368
1307
|
}
|
|
1369
|
-
if (noDna) {
|
|
1370
|
-
console.log(chalk_1.default.yellow(' ⏭️ ccDNA injection skipped (--no-dna)'));
|
|
1371
|
-
}
|
|
1372
1308
|
if (verbose) {
|
|
1373
1309
|
console.log(chalk_1.default.gray(` 📁 Debug log: ${config.debugLogPath}`));
|
|
1374
1310
|
}
|
|
1375
1311
|
console.log('');
|
|
1376
1312
|
}
|
|
1377
1313
|
// ══════════════════════════════════════════════════════════════════════════
|
|
1314
|
+
// MAGIC MOMENT: Morning dreams right after sparkle, before Claude appears
|
|
1315
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
1316
|
+
await showMorningDreamsIfNeeded();
|
|
1317
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
1378
1318
|
// ANIMATION COMPLETE: Mark ready and flush buffered Claude output
|
|
1379
1319
|
// ══════════════════════════════════════════════════════════════════════════
|
|
1380
1320
|
animationComplete = true;
|
|
@@ -1419,8 +1359,6 @@ async function run(options) {
|
|
|
1419
1359
|
console.log(chalk_1.default.cyan(` 📊 Active ekkOS sessions: ${activeSessions.length}`));
|
|
1420
1360
|
}
|
|
1421
1361
|
}
|
|
1422
|
-
// Synk bridge — real-time session sync (null when synk not configured)
|
|
1423
|
-
const synkBridge = await session_bridge_1.SynkSessionBridge.create({ cwd: process.cwd(), verbose });
|
|
1424
1362
|
let isAutoClearInProgress = false;
|
|
1425
1363
|
let transcriptPath = null;
|
|
1426
1364
|
let currentSessionId = null;
|
|
@@ -1623,7 +1561,7 @@ async function run(options) {
|
|
|
1623
1561
|
// JSONL eviction tracking - prevent rapid re-eviction
|
|
1624
1562
|
let lastEvictionTime = 0;
|
|
1625
1563
|
// ══════════════════════════════════════════════════════════════════════════
|
|
1626
|
-
// ORPHAN TOOL_RESULT RECOVERY
|
|
1564
|
+
// ORPHAN TOOL_RESULT RECOVERY
|
|
1627
1565
|
// ══════════════════════════════════════════════════════════════════════════
|
|
1628
1566
|
let lastOrphanDetectionTime = 0;
|
|
1629
1567
|
let isOrphanRecoveryInProgress = false;
|
|
@@ -1863,11 +1801,9 @@ async function run(options) {
|
|
|
1863
1801
|
console.log(chalk_1.default.yellow(' Monitor-only mode (--no-inject)'));
|
|
1864
1802
|
}
|
|
1865
1803
|
if (verbose) {
|
|
1866
|
-
// Show Claude version
|
|
1804
|
+
// Show Claude version
|
|
1867
1805
|
const ccVersion = pinnedVersion || PINNED_CLAUDE_VERSION;
|
|
1868
|
-
const versionStr =
|
|
1869
|
-
? `Claude Code v${ccVersion} + ekkOS_Continuum v${ccdnaVersion}`
|
|
1870
|
-
: `Claude Code v${ccVersion}`;
|
|
1806
|
+
const versionStr = `Claude Code v${ccVersion}`;
|
|
1871
1807
|
console.log(chalk_1.default.gray(` 🤖 ${versionStr}`));
|
|
1872
1808
|
if (currentSession) {
|
|
1873
1809
|
console.log(chalk_1.default.green(` 📍 Session: ${currentSession}`));
|
|
@@ -1951,7 +1887,7 @@ async function run(options) {
|
|
|
1951
1887
|
}
|
|
1952
1888
|
else {
|
|
1953
1889
|
// PTY not available - use spawn with stdio inherit (clean pass-through)
|
|
1954
|
-
//
|
|
1890
|
+
// PTY not available — spawn with stdio inherit (clean pass-through)
|
|
1955
1891
|
dlog('PTY not available, using spawn pass-through mode');
|
|
1956
1892
|
const spawnedProcess = (0, child_process_1.spawn)(claudePath, args, {
|
|
1957
1893
|
stdio: 'inherit',
|
|
@@ -1983,17 +1919,6 @@ async function run(options) {
|
|
|
1983
1919
|
process.stdin.on('data', onStdinData);
|
|
1984
1920
|
// Helper to get current output buffer (for readiness checks)
|
|
1985
1921
|
const getOutputBuffer = () => outputBuffer;
|
|
1986
|
-
// Synk remote message injection — receive messages from mobile/web, inject into PTY
|
|
1987
|
-
if (synkBridge) {
|
|
1988
|
-
synkBridge.on('remote-message', async (msg) => {
|
|
1989
|
-
const { ready } = await waitForIdlePrompt(getOutputBuffer, config);
|
|
1990
|
-
if (ready) {
|
|
1991
|
-
shell.write('\x15'); // Ctrl+U clear line
|
|
1992
|
-
await typeSlowly(shell, msg.text, config.charDelayMs);
|
|
1993
|
-
shell.write('\r');
|
|
1994
|
-
}
|
|
1995
|
-
});
|
|
1996
|
-
}
|
|
1997
1922
|
// Handle context wall detection
|
|
1998
1923
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1999
1924
|
async function handleContextWall() {
|
|
@@ -2144,13 +2069,13 @@ async function run(options) {
|
|
|
2144
2069
|
}
|
|
2145
2070
|
// ══════════════════════════════════════════════════════════════════════════
|
|
2146
2071
|
// ORPHAN TOOL_RESULT RECOVERY
|
|
2147
|
-
// When
|
|
2072
|
+
// When orphan tool_results are detected in the terminal output,
|
|
2148
2073
|
// it emits [ekkOS] ORPHAN_TOOL_RESULT to the terminal. We detect this marker
|
|
2149
2074
|
// and repair the transcript (rollback or surgical).
|
|
2150
2075
|
//
|
|
2151
2076
|
// NOTE: We do NOT run /clear + /continue anymore. That was leftover from when
|
|
2152
|
-
//
|
|
2153
|
-
//
|
|
2077
|
+
// NOTE: We do NOT run /clear + /continue anymore. The JSONL rewriter
|
|
2078
|
+
// is the single disk authority; orphans indicate a bug, not a state desync.
|
|
2154
2079
|
// BUG in the sliding window - not a state desync that needs rebuilding.
|
|
2155
2080
|
// The in-memory state is fine; we just fix the disk and log the bug.
|
|
2156
2081
|
// ══════════════════════════════════════════════════════════════════════════
|
|
@@ -2193,8 +2118,8 @@ async function run(options) {
|
|
|
2193
2118
|
diagnosis: 'JSONL rewriter evicted tool_use without its tool_result, or vice versa',
|
|
2194
2119
|
action: 'Attempting disk repair via rollback or surgical removal',
|
|
2195
2120
|
});
|
|
2196
|
-
|
|
2197
|
-
|
|
2121
|
+
dlog(`🚨 BUG: Orphan tool_result detected (${orphan.tool_use_id})`);
|
|
2122
|
+
dlog(`🔧 Repairing disk transcript...`);
|
|
2198
2123
|
try {
|
|
2199
2124
|
// Repair the disk transcript if we have one
|
|
2200
2125
|
if (transcriptPath && validateTranscriptPath(transcriptPath)) {
|
|
@@ -2215,17 +2140,17 @@ async function run(options) {
|
|
|
2215
2140
|
});
|
|
2216
2141
|
dlog(`Orphan repair: ${repair.action} (orphans=${repair.orphansFound}, removed=${repair.removedLines ?? 0})`);
|
|
2217
2142
|
if (repair.action === 'failed') {
|
|
2218
|
-
|
|
2219
|
-
|
|
2143
|
+
dlog(`❌ WARNING: Orphan repair failed - session may be unstable`);
|
|
2144
|
+
dlog(` Reason: ${repair.reason}`);
|
|
2220
2145
|
}
|
|
2221
2146
|
else if (repair.action === 'rollback') {
|
|
2222
|
-
|
|
2147
|
+
dlog(`✅ Disk repaired via ROLLBACK to backup`);
|
|
2223
2148
|
}
|
|
2224
2149
|
else if (repair.action === 'surgical_repair') {
|
|
2225
|
-
|
|
2150
|
+
dlog(`✅ Disk repaired via SURGICAL removal (${repair.removedLines} lines removed)`);
|
|
2226
2151
|
}
|
|
2227
2152
|
else {
|
|
2228
|
-
|
|
2153
|
+
dlog(`✅ No repair needed - transcript is healthy`);
|
|
2229
2154
|
}
|
|
2230
2155
|
// POST-REPAIR VALIDATION: Verify repair actually worked
|
|
2231
2156
|
if (repair.action !== 'failed' && repair.action !== 'none') {
|
|
@@ -2239,8 +2164,8 @@ async function run(options) {
|
|
|
2239
2164
|
postRepairOrphans,
|
|
2240
2165
|
alert: 'REPAIR DID NOT FIX THE PROBLEM',
|
|
2241
2166
|
});
|
|
2242
|
-
|
|
2243
|
-
|
|
2167
|
+
dlog(`⚠️ Post-repair check: ${postRepairOrphans} orphan(s) still present!`);
|
|
2168
|
+
dlog(` Repair may have been incomplete - consider /clear + /continue`);
|
|
2244
2169
|
}
|
|
2245
2170
|
else {
|
|
2246
2171
|
evictionDebugLog('POST_REPAIR_VALIDATION_SUCCESS', '✅ Repair verified - no orphans remaining', {
|
|
@@ -2290,7 +2215,7 @@ async function run(options) {
|
|
|
2290
2215
|
continue;
|
|
2291
2216
|
}
|
|
2292
2217
|
dlog(`Detected ORPHAN_TOOL_RESULT: ${orphan.tool_use_id}`);
|
|
2293
|
-
evictionDebugLog('ORPHAN_MARKER_DETECTED', '
|
|
2218
|
+
evictionDebugLog('ORPHAN_MARKER_DETECTED', 'Orphan detected in PTY output', {
|
|
2294
2219
|
orphan,
|
|
2295
2220
|
bufferLen: orphanDetectionBuffer.length,
|
|
2296
2221
|
scanCursor: orphanScanCursor,
|
|
@@ -2371,8 +2296,6 @@ async function run(options) {
|
|
|
2371
2296
|
if (outputBuffer.length > 5000) {
|
|
2372
2297
|
outputBuffer = outputBuffer.slice(-2000);
|
|
2373
2298
|
}
|
|
2374
|
-
// Forward to synk real-time sync (batched internally)
|
|
2375
|
-
synkBridge?.onAgentOutput(data);
|
|
2376
2299
|
// ══════════════════════════════════════════════════════════════════════════
|
|
2377
2300
|
// PER-TURN BANNER (replaces hook-based terminal header)
|
|
2378
2301
|
// Prints once per turn when transitioning from idle → active (AI responding).
|
|
@@ -2388,40 +2311,26 @@ async function run(options) {
|
|
|
2388
2311
|
!trimmed.startsWith('%'); // zsh prompt artefact
|
|
2389
2312
|
if (isSubstantialOutput && Date.now() - lastBannerTime > 3000) {
|
|
2390
2313
|
turnCount++;
|
|
2391
|
-
const now = new Date();
|
|
2392
|
-
const timeStr = now.toLocaleTimeString('en-US', {
|
|
2393
|
-
hour: 'numeric',
|
|
2394
|
-
minute: '2-digit',
|
|
2395
|
-
hour12: true,
|
|
2396
|
-
timeZone: 'America/New_York',
|
|
2397
|
-
});
|
|
2398
|
-
const dateStr = now.toLocaleDateString('en-US', {
|
|
2399
|
-
year: 'numeric',
|
|
2400
|
-
month: '2-digit',
|
|
2401
|
-
day: '2-digit',
|
|
2402
|
-
timeZone: 'America/New_York',
|
|
2403
|
-
});
|
|
2404
2314
|
const sessionLabel = currentSession || cliSessionName || 'initializing';
|
|
2405
|
-
|
|
2315
|
+
// LOG ONLY — never write to stdout/stderr during Ink's render cycle.
|
|
2316
|
+
// stderr shares the same terminal as stdout; injecting text here
|
|
2317
|
+
// corrupts Ink's cursor positioning and causes TUI rendering artifacts.
|
|
2318
|
+
dlog(`[TURN ${turnCount}] ${sessionLabel}`);
|
|
2406
2319
|
lastBannerTime = Date.now();
|
|
2407
2320
|
wasIdle = false;
|
|
2408
|
-
synkBridge?.onIdleChange(false);
|
|
2409
2321
|
}
|
|
2410
2322
|
}
|
|
2411
2323
|
// Track idle state for the banner (works in both proxy and local mode).
|
|
2412
2324
|
// We check the raw outputBuffer (stripped) so the idle regex fires reliably.
|
|
2413
2325
|
if (IDLE_PROMPT_REGEX.test(stripAnsi(outputBuffer))) {
|
|
2414
|
-
if (!wasIdle)
|
|
2415
|
-
synkBridge?.onIdleChange(true);
|
|
2416
2326
|
wasIdle = true;
|
|
2417
2327
|
}
|
|
2418
2328
|
// ══════════════════════════════════════════════════════════════════════════
|
|
2419
2329
|
// ORPHAN TOOL_RESULT DETECTION (LOCAL MODE ONLY)
|
|
2420
|
-
//
|
|
2330
|
+
// [ekkOS] ORPHAN_TOOL_RESULT markers are emitted by the ekkOS memory system when it detects
|
|
2421
2331
|
// tool_results without matching tool_uses. This triggers automatic repair.
|
|
2422
2332
|
// DISABLED in proxy mode: proxy is sole eviction authority, CLI must not
|
|
2423
|
-
// touch the local JSONL.
|
|
2424
|
-
// ══════════════════════════════════════════════════════════════════════════
|
|
2333
|
+
// touch the local JSONL.
|
|
2425
2334
|
if (!proxyModeEnabled && !isAutoClearInProgress && !isOrphanRecoveryInProgress) {
|
|
2426
2335
|
orphanDetectionBuffer += stripAnsi(data);
|
|
2427
2336
|
if (orphanDetectionBuffer.length > 10000) {
|
|
@@ -2520,7 +2429,6 @@ async function run(options) {
|
|
|
2520
2429
|
dlog(`Session detected from status line: ${currentSession} (observedSessionThisRun=true)`);
|
|
2521
2430
|
bindRealSessionToProxy(currentSession, 'status-line', currentSessionId || undefined);
|
|
2522
2431
|
resolveTranscriptFromSessionId('status-line');
|
|
2523
|
-
synkBridge?.onSessionEstablished(currentSession, currentSessionId || 'unknown', { hostPid: process.pid });
|
|
2524
2432
|
}
|
|
2525
2433
|
}
|
|
2526
2434
|
else {
|
|
@@ -2804,10 +2712,9 @@ Use Perplexity for deep research. Be thorough but efficient. Start now.`;
|
|
|
2804
2712
|
shell.onExit(async ({ exitCode }) => {
|
|
2805
2713
|
(0, state_1.clearAutoClearFlag)();
|
|
2806
2714
|
stopStreamTailer(); // Stop stream capture
|
|
2807
|
-
await synkBridge?.shutdown(); // Close synk session
|
|
2808
2715
|
(0, state_1.unregisterActiveSession)(); // Remove from active sessions registry
|
|
2809
2716
|
cleanupInstanceFile(instanceId); // Clean up instance file
|
|
2810
|
-
// NOTE: No
|
|
2717
|
+
// NOTE: No restore needed - ekkOS uses separate installation from homebrew
|
|
2811
2718
|
// ~/.ekkos/claude-code/ stays patched, homebrew `claude` is always vanilla
|
|
2812
2719
|
// Restore terminal
|
|
2813
2720
|
if (process.stdin.isTTY) {
|
|
@@ -2824,10 +2731,9 @@ Use Perplexity for deep research. Be thorough but efficient. Start now.`;
|
|
|
2824
2731
|
const cleanup = () => {
|
|
2825
2732
|
(0, state_1.clearAutoClearFlag)();
|
|
2826
2733
|
stopStreamTailer(); // Stop stream capture
|
|
2827
|
-
synkBridge?.shutdown().catch(() => { }); // Close synk session (best-effort)
|
|
2828
2734
|
(0, state_1.unregisterActiveSession)(); // Remove from active sessions registry
|
|
2829
2735
|
cleanupInstanceFile(instanceId); // Clean up instance file
|
|
2830
|
-
// NOTE: No
|
|
2736
|
+
// NOTE: No restore needed - ekkOS uses separate installation from homebrew
|
|
2831
2737
|
if (process.stdin.isTTY) {
|
|
2832
2738
|
process.stdin.setRawMode(false);
|
|
2833
2739
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ekkos scan
|
|
3
|
+
*
|
|
4
|
+
* Scans the current directory's repo structure, discovers systems,
|
|
5
|
+
* and seeds them into ekkOS system_registry via the memory API.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ekkos scan Scan cwd and seed registry
|
|
9
|
+
* ekkos scan --compile Also trigger a compile pass after seeding
|
|
10
|
+
* ekkos scan --dry-run Show what would be seeded without calling API
|
|
11
|
+
* ekkos scan --path /my/repo Scan a specific directory
|
|
12
|
+
*
|
|
13
|
+
* Reuses discovery logic from apps/memory/workers/context-compiler/registry-seed.ts
|
|
14
|
+
*/
|
|
15
|
+
interface ScanOptions {
|
|
16
|
+
compile?: boolean;
|
|
17
|
+
dryRun?: boolean;
|
|
18
|
+
path?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function scan(options: ScanOptions): Promise<void>;
|
|
21
|
+
export {};
|