jfl 0.1.0 → 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/README.md +443 -145
- package/clawdbot-plugin/clawdbot.plugin.json +20 -0
- package/clawdbot-plugin/index.js +555 -0
- package/clawdbot-plugin/index.ts +582 -0
- package/clawdbot-skill/SKILL.md +33 -336
- package/clawdbot-skill/index.ts +491 -321
- package/clawdbot-skill/skill.json +4 -13
- package/dist/commands/clawdbot.d.ts +11 -0
- package/dist/commands/clawdbot.d.ts.map +1 -0
- package/dist/commands/clawdbot.js +215 -0
- package/dist/commands/clawdbot.js.map +1 -0
- package/dist/commands/context-hub.d.ts +5 -0
- package/dist/commands/context-hub.d.ts.map +1 -1
- package/dist/commands/context-hub.js +394 -28
- package/dist/commands/context-hub.js.map +1 -1
- package/dist/commands/gtm-process-update.d.ts +10 -0
- package/dist/commands/gtm-process-update.d.ts.map +1 -0
- package/dist/commands/gtm-process-update.js +101 -0
- package/dist/commands/gtm-process-update.js.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +278 -4
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +32 -33
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/memory.d.ts +38 -0
- package/dist/commands/memory.d.ts.map +1 -0
- package/dist/commands/memory.js +229 -0
- package/dist/commands/memory.js.map +1 -0
- package/dist/commands/migrate-services.d.ts +8 -0
- package/dist/commands/migrate-services.d.ts.map +1 -0
- package/dist/commands/migrate-services.js +182 -0
- package/dist/commands/migrate-services.js.map +1 -0
- package/dist/commands/onboard.d.ts +24 -0
- package/dist/commands/onboard.d.ts.map +1 -0
- package/dist/commands/onboard.js +663 -0
- package/dist/commands/onboard.js.map +1 -0
- package/dist/commands/openclaw.d.ts +56 -0
- package/dist/commands/openclaw.d.ts.map +1 -0
- package/dist/commands/openclaw.js +700 -0
- package/dist/commands/openclaw.js.map +1 -0
- package/dist/commands/orchestrate.d.ts +14 -0
- package/dist/commands/orchestrate.d.ts.map +1 -0
- package/dist/commands/orchestrate.js +270 -0
- package/dist/commands/orchestrate.js.map +1 -0
- package/dist/commands/profile.d.ts +46 -0
- package/dist/commands/profile.d.ts.map +1 -0
- package/dist/commands/profile.js +498 -0
- package/dist/commands/profile.js.map +1 -0
- package/dist/commands/repair.d.ts.map +1 -1
- package/dist/commands/repair.js +37 -0
- package/dist/commands/repair.js.map +1 -1
- package/dist/commands/service-agent.d.ts +16 -0
- package/dist/commands/service-agent.d.ts.map +1 -0
- package/dist/commands/service-agent.js +375 -0
- package/dist/commands/service-agent.js.map +1 -0
- package/dist/commands/service-manager.d.ts +12 -0
- package/dist/commands/service-manager.d.ts.map +1 -0
- package/dist/commands/service-manager.js +967 -0
- package/dist/commands/service-manager.js.map +1 -0
- package/dist/commands/service-validate.d.ts +12 -0
- package/dist/commands/service-validate.d.ts.map +1 -0
- package/dist/commands/service-validate.js +611 -0
- package/dist/commands/service-validate.js.map +1 -0
- package/dist/commands/services-create.d.ts +15 -0
- package/dist/commands/services-create.d.ts.map +1 -0
- package/dist/commands/services-create.js +1452 -0
- package/dist/commands/services-create.js.map +1 -0
- package/dist/commands/services-scan.d.ts +13 -0
- package/dist/commands/services-scan.d.ts.map +1 -0
- package/dist/commands/services-scan.js +251 -0
- package/dist/commands/services-scan.js.map +1 -0
- package/dist/commands/services-sync-agents.d.ts +23 -0
- package/dist/commands/services-sync-agents.d.ts.map +1 -0
- package/dist/commands/services-sync-agents.js +207 -0
- package/dist/commands/services-sync-agents.js.map +1 -0
- package/dist/commands/services.d.ts +19 -0
- package/dist/commands/services.d.ts.map +1 -0
- package/dist/commands/services.js +742 -0
- package/dist/commands/services.js.map +1 -0
- package/dist/commands/session.d.ts +5 -1
- package/dist/commands/session.d.ts.map +1 -1
- package/dist/commands/session.js +68 -586
- package/dist/commands/session.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +17 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +75 -21
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/validate-settings.d.ts +37 -0
- package/dist/commands/validate-settings.d.ts.map +1 -0
- package/dist/commands/validate-settings.js +197 -0
- package/dist/commands/validate-settings.js.map +1 -0
- package/dist/commands/voice.d.ts +0 -1
- package/dist/commands/voice.d.ts.map +1 -1
- package/dist/commands/voice.js +16 -15
- package/dist/commands/voice.js.map +1 -1
- package/dist/index.js +395 -141
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-generator.d.ts +26 -0
- package/dist/lib/agent-generator.d.ts.map +1 -0
- package/dist/lib/agent-generator.js +331 -0
- package/dist/lib/agent-generator.js.map +1 -0
- package/dist/lib/memory-db.d.ts +102 -0
- package/dist/lib/memory-db.d.ts.map +1 -0
- package/dist/lib/memory-db.js +313 -0
- package/dist/lib/memory-db.js.map +1 -0
- package/dist/lib/memory-indexer.d.ts +47 -0
- package/dist/lib/memory-indexer.d.ts.map +1 -0
- package/dist/lib/memory-indexer.js +215 -0
- package/dist/lib/memory-indexer.js.map +1 -0
- package/dist/lib/memory-search.d.ts +41 -0
- package/dist/lib/memory-search.d.ts.map +1 -0
- package/dist/lib/memory-search.js +246 -0
- package/dist/lib/memory-search.js.map +1 -0
- package/dist/lib/openclaw-registry.d.ts +48 -0
- package/dist/lib/openclaw-registry.d.ts.map +1 -0
- package/dist/lib/openclaw-registry.js +181 -0
- package/dist/lib/openclaw-registry.js.map +1 -0
- package/dist/lib/openclaw-sdk.d.ts +107 -0
- package/dist/lib/openclaw-sdk.d.ts.map +1 -0
- package/dist/lib/openclaw-sdk.js +208 -0
- package/dist/lib/openclaw-sdk.js.map +1 -0
- package/dist/lib/peer-agent-generator.d.ts +44 -0
- package/dist/lib/peer-agent-generator.d.ts.map +1 -0
- package/dist/lib/peer-agent-generator.js +286 -0
- package/dist/lib/peer-agent-generator.js.map +1 -0
- package/dist/lib/service-dependencies.d.ts +44 -0
- package/dist/lib/service-dependencies.d.ts.map +1 -0
- package/dist/lib/service-dependencies.js +314 -0
- package/dist/lib/service-dependencies.js.map +1 -0
- package/dist/lib/service-detector.d.ts +61 -0
- package/dist/lib/service-detector.d.ts.map +1 -0
- package/dist/lib/service-detector.js +521 -0
- package/dist/lib/service-detector.js.map +1 -0
- package/dist/lib/service-gtm.d.ts +157 -0
- package/dist/lib/service-gtm.d.ts.map +1 -0
- package/dist/lib/service-gtm.js +786 -0
- package/dist/lib/service-gtm.js.map +1 -0
- package/dist/lib/service-mcp-base.d.ts +103 -0
- package/dist/lib/service-mcp-base.d.ts.map +1 -0
- package/dist/lib/service-mcp-base.js +263 -0
- package/dist/lib/service-mcp-base.js.map +1 -0
- package/dist/lib/service-utils.d.ts +103 -0
- package/dist/lib/service-utils.d.ts.map +1 -0
- package/dist/lib/service-utils.js +368 -0
- package/dist/lib/service-utils.js.map +1 -0
- package/dist/lib/skill-generator.d.ts +21 -0
- package/dist/lib/skill-generator.d.ts.map +1 -0
- package/dist/lib/skill-generator.js +253 -0
- package/dist/lib/skill-generator.js.map +1 -0
- package/dist/lib/stratus-client.d.ts +100 -0
- package/dist/lib/stratus-client.d.ts.map +1 -0
- package/dist/lib/stratus-client.js +255 -0
- package/dist/lib/stratus-client.js.map +1 -0
- package/dist/mcp/context-hub-mcp.js +135 -53
- package/dist/mcp/context-hub-mcp.js.map +1 -1
- package/dist/mcp/service-mcp-server.d.ts +12 -0
- package/dist/mcp/service-mcp-server.d.ts.map +1 -0
- package/dist/mcp/service-mcp-server.js +434 -0
- package/dist/mcp/service-mcp-server.js.map +1 -0
- package/dist/mcp/service-peer-mcp.d.ts +36 -0
- package/dist/mcp/service-peer-mcp.d.ts.map +1 -0
- package/dist/mcp/service-peer-mcp.js +220 -0
- package/dist/mcp/service-peer-mcp.js.map +1 -0
- package/dist/mcp/service-registry-mcp.d.ts +13 -0
- package/dist/mcp/service-registry-mcp.d.ts.map +1 -0
- package/dist/mcp/service-registry-mcp.js +330 -0
- package/dist/mcp/service-registry-mcp.js.map +1 -0
- package/dist/ui/banner.js +1 -1
- package/dist/ui/banner.js.map +1 -1
- package/dist/ui/context-hub-logs.d.ts +10 -0
- package/dist/ui/context-hub-logs.d.ts.map +1 -0
- package/dist/ui/context-hub-logs.js +175 -0
- package/dist/ui/context-hub-logs.js.map +1 -0
- package/dist/ui/service-dashboard.d.ts +11 -0
- package/dist/ui/service-dashboard.d.ts.map +1 -0
- package/dist/ui/service-dashboard.js +357 -0
- package/dist/ui/service-dashboard.js.map +1 -0
- package/dist/ui/services-manager.d.ts +11 -0
- package/dist/ui/services-manager.d.ts.map +1 -0
- package/dist/ui/services-manager.js +507 -0
- package/dist/ui/services-manager.js.map +1 -0
- package/dist/utils/auth-guard.d.ts.map +1 -1
- package/dist/utils/auth-guard.js +8 -9
- package/dist/utils/auth-guard.js.map +1 -1
- package/dist/utils/claude-md-generator.d.ts +10 -0
- package/dist/utils/claude-md-generator.d.ts.map +1 -0
- package/dist/utils/claude-md-generator.js +215 -0
- package/dist/utils/claude-md-generator.js.map +1 -0
- package/dist/utils/ensure-context-hub.d.ts +20 -0
- package/dist/utils/ensure-context-hub.d.ts.map +1 -0
- package/dist/utils/ensure-context-hub.js +65 -0
- package/dist/utils/ensure-context-hub.js.map +1 -0
- package/dist/utils/ensure-project.d.ts.map +1 -1
- package/dist/utils/ensure-project.js +3 -4
- package/dist/utils/ensure-project.js.map +1 -1
- package/dist/utils/jfl-config.d.ts +19 -0
- package/dist/utils/jfl-config.d.ts.map +1 -0
- package/dist/utils/jfl-config.js +112 -0
- package/dist/utils/jfl-config.js.map +1 -0
- package/dist/utils/jfl-migration.d.ts +29 -0
- package/dist/utils/jfl-migration.d.ts.map +1 -0
- package/dist/utils/jfl-migration.js +142 -0
- package/dist/utils/jfl-migration.js.map +1 -0
- package/dist/utils/jfl-paths.d.ts +55 -0
- package/dist/utils/jfl-paths.d.ts.map +1 -0
- package/dist/utils/jfl-paths.js +120 -0
- package/dist/utils/jfl-paths.js.map +1 -0
- package/dist/utils/settings-validator.d.ts +73 -0
- package/dist/utils/settings-validator.d.ts.map +1 -0
- package/dist/utils/settings-validator.js +222 -0
- package/dist/utils/settings-validator.js.map +1 -0
- package/package.json +19 -3
- package/scripts/commit-gtm.sh +56 -0
- package/scripts/commit-product.sh +68 -0
- package/scripts/context-query.sh +45 -0
- package/scripts/session/auto-commit.sh +297 -0
- package/scripts/session/jfl-doctor.sh +707 -0
- package/scripts/session/session-cleanup.sh +268 -0
- package/scripts/session/session-end.sh +198 -0
- package/scripts/session/session-init.sh +350 -0
- package/scripts/session/session-init.sh.backup +292 -0
- package/scripts/session/session-sync.sh +167 -0
- package/scripts/session/test-context-preservation.sh +160 -0
- package/scripts/session/test-critical-infrastructure.sh +293 -0
- package/scripts/session/test-experience-level.sh +336 -0
- package/scripts/session/test-session-cleanup.sh +268 -0
- package/scripts/session/test-session-sync.sh +320 -0
- package/scripts/voice-start.sh +36 -8
- package/scripts/where-am-i.sh +78 -0
- package/template/.claude/service-settings.json +32 -0
- package/template/.claude/settings.json +14 -1
- package/template/.claude/skills/end/SKILL.md +1780 -0
- package/template/.jfl/config.json +2 -1
- package/template/CLAUDE.md +1039 -134
- package/template/CLAUDE.md.bak +1187 -0
- package/template/scripts/commit-gtm.sh +56 -0
- package/template/scripts/commit-product.sh +68 -0
- package/template/scripts/migrate-to-branch-sessions.sh +201 -0
- package/template/scripts/session/auto-commit.sh +58 -6
- package/template/scripts/session/jfl-doctor.sh +137 -17
- package/template/scripts/session/session-cleanup.sh +268 -0
- package/template/scripts/session/session-end.sh +4 -0
- package/template/scripts/session/session-init.sh +253 -66
- package/template/scripts/session/test-critical-infrastructure.sh +293 -0
- package/template/scripts/session/test-experience-level.sh +336 -0
- package/template/scripts/session/test-session-cleanup.sh +268 -0
- package/template/scripts/session/test-session-sync.sh +320 -0
- package/template/scripts/where-am-i.sh +78 -0
- package/template/templates/service-agent/.claude/settings.json +32 -0
- package/template/templates/service-agent/CLAUDE.md +334 -0
- package/template/templates/service-agent/knowledge/ARCHITECTURE.md +115 -0
- package/template/templates/service-agent/knowledge/DEPLOYMENT.md +199 -0
- package/template/templates/service-agent/knowledge/RUNBOOK.md +412 -0
- package/template/templates/service-agent/knowledge/SERVICE_SPEC.md +77 -0
- package/dist/commands/session-mgmt.d.ts +0 -33
- package/dist/commands/session-mgmt.d.ts.map +0 -1
- package/dist/commands/session-mgmt.js +0 -404
- package/dist/commands/session-mgmt.js.map +0 -1
- package/template/scripts/session/auto-merge.sh +0 -325
package/dist/index.js
CHANGED
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { Command } from "commander";
|
|
9
9
|
import chalk from "chalk";
|
|
10
|
-
import { spawn
|
|
11
|
-
import { existsSync, symlinkSync, mkdirSync, unlinkSync } from "fs";
|
|
12
|
-
import { homedir } from "os";
|
|
10
|
+
import { spawn } from "child_process";
|
|
13
11
|
import { join } from "path";
|
|
12
|
+
import * as path from "path";
|
|
14
13
|
import { fileURLToPath } from "url";
|
|
15
14
|
import { initCommand } from "./commands/init.js";
|
|
16
15
|
import { repairCommand } from "./commands/repair.js";
|
|
16
|
+
import { validateSettingsCommand } from "./commands/validate-settings.js";
|
|
17
17
|
import { loginCommand, logout } from "./commands/login.js";
|
|
18
18
|
import { statusCommand } from "./commands/status.js";
|
|
19
19
|
import { deployCommand } from "./commands/deploy.js";
|
|
@@ -25,15 +25,23 @@ import { updateCommand } from "./commands/update.js";
|
|
|
25
25
|
import { contextHubCommand } from "./commands/context-hub.js";
|
|
26
26
|
import { voiceCommand } from "./commands/voice.js";
|
|
27
27
|
import { synopsisCommand } from "./commands/synopsis.js";
|
|
28
|
+
import { onboardCommand } from "./commands/onboard.js";
|
|
29
|
+
import { profileCommand } from "./commands/profile.js";
|
|
30
|
+
import { migrateServices } from "./commands/migrate-services.js";
|
|
31
|
+
import { memoryInitCommand, memoryStatusCommand, memorySearchCommand, memoryIndexCommand } from "./commands/memory.js";
|
|
28
32
|
import { listSkillsCommand, installSkillCommand, removeSkillCommand, updateSkillsCommand, searchSkillsCommand, } from "./commands/skills.js";
|
|
29
33
|
import { ralphCommand, showRalphHelp } from "./commands/ralph.js";
|
|
30
|
-
import {
|
|
34
|
+
import { clawdbotSetupCommand, clawdbotStatusCommand } from "./commands/clawdbot.js";
|
|
31
35
|
import { showDayPassStatus, hasWallet, getWalletAddress, } from "./utils/auth-guard.js";
|
|
36
|
+
import { checkAndMigrate } from "./utils/jfl-migration.js";
|
|
37
|
+
import { JFL_PATHS } from "./utils/jfl-paths.js";
|
|
38
|
+
// Auto-migrate from ~/.jfl/ to XDG directories if needed
|
|
39
|
+
await checkAndMigrate({ silent: true });
|
|
32
40
|
const program = new Command();
|
|
33
41
|
program
|
|
34
42
|
.name("jfl")
|
|
35
|
-
.description("Just Fucking Launch - AI
|
|
36
|
-
.version("0.1.
|
|
43
|
+
.description("Just Fucking Launch - AI gateway for GTM")
|
|
44
|
+
.version("0.1.1")
|
|
37
45
|
.option("--no-update", "Skip automatic update check")
|
|
38
46
|
.action(async (options) => {
|
|
39
47
|
// Always update on session start (unless --no-update flag)
|
|
@@ -41,7 +49,7 @@ program
|
|
|
41
49
|
await updateCommand({ autoUpdate: true });
|
|
42
50
|
console.log(); // Add spacing before session starts
|
|
43
51
|
}
|
|
44
|
-
await sessionCommand();
|
|
52
|
+
await sessionCommand({});
|
|
45
53
|
});
|
|
46
54
|
// ============================================================================
|
|
47
55
|
// FREE TIER COMMANDS (work offline/standalone)
|
|
@@ -55,6 +63,12 @@ program
|
|
|
55
63
|
.command("repair")
|
|
56
64
|
.description("Repair a JFL project missing .jfl directory")
|
|
57
65
|
.action(repairCommand);
|
|
66
|
+
program
|
|
67
|
+
.command("validate-settings")
|
|
68
|
+
.description("Validate and repair .claude/settings.json")
|
|
69
|
+
.option("--fix", "Attempt to auto-repair common issues")
|
|
70
|
+
.option("--json", "Output in JSON format")
|
|
71
|
+
.action(validateSettingsCommand);
|
|
58
72
|
program
|
|
59
73
|
.command("hud")
|
|
60
74
|
.description("Show campaign dashboard")
|
|
@@ -69,8 +83,12 @@ program
|
|
|
69
83
|
.description("Manage Context Hub daemon (unified context for AI agents)")
|
|
70
84
|
.argument("[action]", "start, stop, restart, status, ensure, query, serve")
|
|
71
85
|
.option("-p, --port <port>", "Port to run on (default: 4242)", "4242")
|
|
86
|
+
.option("-g, --global", "Run in global mode (serve all GTM projects)")
|
|
72
87
|
.action(async (action, options) => {
|
|
73
|
-
await contextHubCommand(action, {
|
|
88
|
+
await contextHubCommand(action, {
|
|
89
|
+
port: parseInt(options.port, 10),
|
|
90
|
+
global: options.global || false,
|
|
91
|
+
});
|
|
74
92
|
});
|
|
75
93
|
program
|
|
76
94
|
.command("synopsis")
|
|
@@ -80,6 +98,185 @@ program
|
|
|
80
98
|
.action(async (hours, author) => {
|
|
81
99
|
await synopsisCommand(hours, author);
|
|
82
100
|
});
|
|
101
|
+
program
|
|
102
|
+
.command("service-manager")
|
|
103
|
+
.description("Manage Service Manager API daemon")
|
|
104
|
+
.argument("[action]", "start, stop, restart, status, serve")
|
|
105
|
+
.option("-p, --port <port>", "Port to run on (default: from config or 3402)")
|
|
106
|
+
.action(async (action, options) => {
|
|
107
|
+
const { serviceManagerCommand } = await import("./commands/service-manager.js");
|
|
108
|
+
await serviceManagerCommand(action, {
|
|
109
|
+
port: options.port ? parseInt(options.port, 10) : undefined
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
program
|
|
113
|
+
.command("services")
|
|
114
|
+
.description("Manage services across all GTM projects (interactive TUI or CLI)")
|
|
115
|
+
.argument("[action]", "create, scan, list, status, start, stop, deps, validate, sync-agents, or leave empty for TUI")
|
|
116
|
+
.argument("[service]", "Service name")
|
|
117
|
+
.option("--dry-run", "Preview what would be discovered (for scan) or preview sync changes (for sync-agents)")
|
|
118
|
+
.option("--current", "Sync only current service (for sync-agents)")
|
|
119
|
+
.option("--path <path>", "Path to scan (default: current directory)")
|
|
120
|
+
.option("--force", "Force operation (for stop with dependents)")
|
|
121
|
+
.option("--verbose", "Verbose output")
|
|
122
|
+
.option("--fix", "Auto-repair issues (for validate)")
|
|
123
|
+
.option("--json", "Output JSON (for validate)")
|
|
124
|
+
.option("--skip-ai", "Skip AI tool, just scaffold (for create)")
|
|
125
|
+
.action(async (action, service, options) => {
|
|
126
|
+
// Handle scan action
|
|
127
|
+
if (action === "scan") {
|
|
128
|
+
const { scanServices } = await import("./commands/services-scan.js");
|
|
129
|
+
await scanServices({
|
|
130
|
+
path: options.path,
|
|
131
|
+
dryRun: options.dryRun
|
|
132
|
+
});
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
// Handle dependency actions
|
|
136
|
+
if (action === "deps" || action === "dependencies") {
|
|
137
|
+
const { buildDependencyGraph, visualizeDependencies, validateDependencies } = await import("./lib/service-dependencies.js");
|
|
138
|
+
const fs = await import("fs");
|
|
139
|
+
const servicesConfigPath = path.join(JFL_PATHS.data, "services.json");
|
|
140
|
+
const servicesConfig = JSON.parse(fs.readFileSync(servicesConfigPath, "utf-8"));
|
|
141
|
+
if (service === "validate") {
|
|
142
|
+
const result = validateDependencies(servicesConfig.services);
|
|
143
|
+
if (result.valid) {
|
|
144
|
+
console.log(chalk.green("\n✓ All dependencies valid\n"));
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
console.log(chalk.red("\n✗ Dependency validation failed:\n"));
|
|
148
|
+
result.errors.forEach(err => console.log(chalk.red(` - ${err}`)));
|
|
149
|
+
console.log();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
console.log(visualizeDependencies(servicesConfig.services));
|
|
154
|
+
}
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
// If no action, launch interactive TUI
|
|
158
|
+
if (!action) {
|
|
159
|
+
const { spawn } = await import("child_process");
|
|
160
|
+
const { fileURLToPath } = await import("url");
|
|
161
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
162
|
+
const __dirname = path.dirname(__filename);
|
|
163
|
+
const tui = spawn(process.execPath, [
|
|
164
|
+
path.join(__dirname, "../dist/ui/services-manager.js")
|
|
165
|
+
], {
|
|
166
|
+
stdio: "inherit"
|
|
167
|
+
});
|
|
168
|
+
tui.on("exit", (code) => {
|
|
169
|
+
process.exit(code || 0);
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
// CLI mode
|
|
174
|
+
const { servicesCommand } = await import("./commands/services.js");
|
|
175
|
+
await servicesCommand(action, service, {
|
|
176
|
+
fix: options.fix,
|
|
177
|
+
json: options.json,
|
|
178
|
+
dryRun: options.dryRun,
|
|
179
|
+
current: options.current,
|
|
180
|
+
skipAI: options.skipAi
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
program
|
|
185
|
+
.command("onboard <path-or-url>")
|
|
186
|
+
.description("Onboard a service repo as a service agent")
|
|
187
|
+
.option("-n, --name <name>", "Override service name")
|
|
188
|
+
.option("-t, --type <type>", "Override service type (web, api, container, worker, cli, infrastructure, library)")
|
|
189
|
+
.option("-d, --description <desc>", "Override service description")
|
|
190
|
+
.option("--skip-git", "Skip git clone (treat URL as local path)")
|
|
191
|
+
.action(async (pathOrUrl, options) => {
|
|
192
|
+
await onboardCommand(pathOrUrl, options);
|
|
193
|
+
});
|
|
194
|
+
program
|
|
195
|
+
.command("orchestrate [name]")
|
|
196
|
+
.description("Execute multi-service orchestration workflows")
|
|
197
|
+
.option("--dry-run", "Preview orchestration steps without executing")
|
|
198
|
+
.option("--list", "List available orchestrations")
|
|
199
|
+
.option("--create <name>", "Create new orchestration template")
|
|
200
|
+
.action(async (name, options) => {
|
|
201
|
+
const { orchestrate, listOrchestrations, createOrchestration } = await import("./commands/orchestrate.js");
|
|
202
|
+
if (options.list) {
|
|
203
|
+
await listOrchestrations();
|
|
204
|
+
}
|
|
205
|
+
else if (options.create) {
|
|
206
|
+
await createOrchestration(options.create);
|
|
207
|
+
}
|
|
208
|
+
else if (name) {
|
|
209
|
+
await orchestrate(name, { dryRun: options.dryRun });
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
await listOrchestrations();
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
program
|
|
216
|
+
.command("dashboard")
|
|
217
|
+
.description("Launch interactive service monitoring dashboard")
|
|
218
|
+
.action(async () => {
|
|
219
|
+
const { startDashboard } = await import("./ui/service-dashboard.js");
|
|
220
|
+
await startDashboard();
|
|
221
|
+
});
|
|
222
|
+
program
|
|
223
|
+
.command("service-agent <action> [name]")
|
|
224
|
+
.description("Manage service MCP agents (init, generate, register, list)")
|
|
225
|
+
.action(async (action, name) => {
|
|
226
|
+
const { init, generate, generateAll, register, unregister, list, clean } = await import("./commands/service-agent.js");
|
|
227
|
+
switch (action) {
|
|
228
|
+
case "init":
|
|
229
|
+
await init(name); // name is optional path
|
|
230
|
+
break;
|
|
231
|
+
case "generate":
|
|
232
|
+
if (!name) {
|
|
233
|
+
console.log(chalk.red("Error: service name required"));
|
|
234
|
+
console.log(chalk.gray("Usage: jfl service-agent generate <service-name>"));
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
await generate(name);
|
|
238
|
+
break;
|
|
239
|
+
case "generate-all":
|
|
240
|
+
await generateAll();
|
|
241
|
+
break;
|
|
242
|
+
case "register":
|
|
243
|
+
await register(name);
|
|
244
|
+
break;
|
|
245
|
+
case "unregister":
|
|
246
|
+
if (!name) {
|
|
247
|
+
console.log(chalk.red("Error: service name required"));
|
|
248
|
+
console.log(chalk.gray("Usage: jfl service-agent unregister <service-name>"));
|
|
249
|
+
process.exit(1);
|
|
250
|
+
}
|
|
251
|
+
await unregister(name);
|
|
252
|
+
break;
|
|
253
|
+
case "list":
|
|
254
|
+
await list();
|
|
255
|
+
break;
|
|
256
|
+
case "clean":
|
|
257
|
+
await clean();
|
|
258
|
+
break;
|
|
259
|
+
default:
|
|
260
|
+
console.log(chalk.red(`Unknown action: ${action}`));
|
|
261
|
+
console.log(chalk.gray("Available actions: init, generate, generate-all, register, unregister, list, clean"));
|
|
262
|
+
process.exit(1);
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
program
|
|
266
|
+
.command("profile [action]")
|
|
267
|
+
.description("Manage your JFL profile (stored in config)")
|
|
268
|
+
.argument("[action]", "show, edit, export, import, generate")
|
|
269
|
+
.option("-f, --file <path>", "File path for export/import/generate output")
|
|
270
|
+
.action(async (action, options) => {
|
|
271
|
+
await profileCommand(action, options);
|
|
272
|
+
});
|
|
273
|
+
program
|
|
274
|
+
.command("migrate-services")
|
|
275
|
+
.description("Migrate services from references/ to service manager")
|
|
276
|
+
.argument("[gtm-path]", "Path to GTM project (default: current directory)")
|
|
277
|
+
.action(async (gtmPath) => {
|
|
278
|
+
await migrateServices(gtmPath);
|
|
279
|
+
});
|
|
83
280
|
// ============================================================================
|
|
84
281
|
// PLATFORM COMMANDS (require login for full features)
|
|
85
282
|
// ============================================================================
|
|
@@ -100,6 +297,28 @@ program
|
|
|
100
297
|
logout();
|
|
101
298
|
console.log(chalk.green("Logged out successfully."));
|
|
102
299
|
});
|
|
300
|
+
program
|
|
301
|
+
.command("preferences")
|
|
302
|
+
.description("Manage JFL preferences")
|
|
303
|
+
.option("--clear-ai", "Clear saved AI CLI preference")
|
|
304
|
+
.option("--show", "Show current preferences")
|
|
305
|
+
.action(async (options) => {
|
|
306
|
+
const { getConfigValue, deleteConfigKey, getConfig } = await import("./utils/jfl-config.js");
|
|
307
|
+
if (options.clearAi) {
|
|
308
|
+
deleteConfigKey("aiCLI");
|
|
309
|
+
console.log(chalk.green("\n✓ Cleared AI CLI preference"));
|
|
310
|
+
console.log(chalk.gray(" Next 'jfl' will show selection menu\n"));
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (options.show || !options.clearAi) {
|
|
314
|
+
console.log(chalk.bold("\n⚙️ JFL Preferences\n"));
|
|
315
|
+
console.log(chalk.gray("AI CLI:") + " " + (getConfigValue("aiCLI") || chalk.gray("none")));
|
|
316
|
+
console.log(chalk.gray("Projects tracked:") + " " + ((getConfigValue("projects") || []).length));
|
|
317
|
+
console.log();
|
|
318
|
+
console.log(chalk.gray("To clear AI preference: jfl preferences --clear-ai"));
|
|
319
|
+
console.log();
|
|
320
|
+
}
|
|
321
|
+
});
|
|
103
322
|
program
|
|
104
323
|
.command("wallet")
|
|
105
324
|
.description("Show wallet and day pass status")
|
|
@@ -282,6 +501,38 @@ voice
|
|
|
282
501
|
});
|
|
283
502
|
});
|
|
284
503
|
// ============================================================================
|
|
504
|
+
// MEMORY SYSTEM (work offline)
|
|
505
|
+
// ============================================================================
|
|
506
|
+
const memory = program.command("memory").description("Memory system management");
|
|
507
|
+
memory
|
|
508
|
+
.command("init")
|
|
509
|
+
.description("Initialize memory database")
|
|
510
|
+
.action(memoryInitCommand);
|
|
511
|
+
memory
|
|
512
|
+
.command("status")
|
|
513
|
+
.description("Show memory statistics")
|
|
514
|
+
.action(memoryStatusCommand);
|
|
515
|
+
memory
|
|
516
|
+
.command("search <query>")
|
|
517
|
+
.description("Search memories")
|
|
518
|
+
.option("-t, --type <type>", "Filter by type (feature, fix, decision, etc.)")
|
|
519
|
+
.option("-n, --max <n>", "Maximum results", "10")
|
|
520
|
+
.action(memorySearchCommand);
|
|
521
|
+
memory
|
|
522
|
+
.command("index")
|
|
523
|
+
.description("Reindex journal entries")
|
|
524
|
+
.option("-f, --force", "Force full reindex")
|
|
525
|
+
.action(memoryIndexCommand);
|
|
526
|
+
// Alias: jfl ask <question> → jfl memory search <question>
|
|
527
|
+
program
|
|
528
|
+
.command("ask <question>")
|
|
529
|
+
.description("Ask a question - searches memory system")
|
|
530
|
+
.option("-t, --type <type>", "Filter by type (feature, fix, decision, etc.)")
|
|
531
|
+
.option("-n, --max <n>", "Maximum results", "5")
|
|
532
|
+
.action(async (question, options) => {
|
|
533
|
+
await memorySearchCommand(question, options);
|
|
534
|
+
});
|
|
535
|
+
// ============================================================================
|
|
285
536
|
// SKILL SHORTCUTS (work offline)
|
|
286
537
|
// ============================================================================
|
|
287
538
|
program
|
|
@@ -320,86 +571,6 @@ program
|
|
|
320
571
|
await ralphCommand(args);
|
|
321
572
|
});
|
|
322
573
|
// ============================================================================
|
|
323
|
-
// SESSION MANAGEMENT (multi-platform sessions)
|
|
324
|
-
// ============================================================================
|
|
325
|
-
const session = program
|
|
326
|
-
.command("session")
|
|
327
|
-
.description("Manage GTM sessions across platforms (CLI, Telegram, Slack, Web)");
|
|
328
|
-
session
|
|
329
|
-
.command("create")
|
|
330
|
-
.description("Create or get existing session")
|
|
331
|
-
.requiredOption("-p, --platform <platform>", "Platform (cli, telegram, slack, web)")
|
|
332
|
-
.option("-t, --thread <id>", "Thread/channel ID")
|
|
333
|
-
.option("-u, --user <name>", "User name")
|
|
334
|
-
.action(async (options) => {
|
|
335
|
-
try {
|
|
336
|
-
const sessionId = await sessionCreate({
|
|
337
|
-
platform: options.platform,
|
|
338
|
-
thread: options.thread,
|
|
339
|
-
user: options.user
|
|
340
|
-
});
|
|
341
|
-
console.log(sessionId);
|
|
342
|
-
}
|
|
343
|
-
catch (error) {
|
|
344
|
-
console.error(chalk.red(`Error: ${error.message}`));
|
|
345
|
-
process.exit(1);
|
|
346
|
-
}
|
|
347
|
-
});
|
|
348
|
-
session
|
|
349
|
-
.command("exec")
|
|
350
|
-
.description("Execute command in session context")
|
|
351
|
-
.argument("<sessionId>", "Session ID")
|
|
352
|
-
.argument("<command>", "Command to execute")
|
|
353
|
-
.action(async (sessionId, command) => {
|
|
354
|
-
try {
|
|
355
|
-
const output = await sessionExec(sessionId, command);
|
|
356
|
-
console.log(output);
|
|
357
|
-
}
|
|
358
|
-
catch (error) {
|
|
359
|
-
console.error(chalk.red(`Error: ${error.message}`));
|
|
360
|
-
process.exit(1);
|
|
361
|
-
}
|
|
362
|
-
});
|
|
363
|
-
session
|
|
364
|
-
.command("list")
|
|
365
|
-
.description("List all active sessions")
|
|
366
|
-
.action(async () => {
|
|
367
|
-
try {
|
|
368
|
-
await sessionList();
|
|
369
|
-
}
|
|
370
|
-
catch (error) {
|
|
371
|
-
console.error(chalk.red(`Error: ${error.message}`));
|
|
372
|
-
process.exit(1);
|
|
373
|
-
}
|
|
374
|
-
});
|
|
375
|
-
session
|
|
376
|
-
.command("info")
|
|
377
|
-
.description("Show session information")
|
|
378
|
-
.argument("<sessionId>", "Session ID")
|
|
379
|
-
.action(async (sessionId) => {
|
|
380
|
-
try {
|
|
381
|
-
await sessionInfo(sessionId);
|
|
382
|
-
}
|
|
383
|
-
catch (error) {
|
|
384
|
-
console.error(chalk.red(`Error: ${error.message}`));
|
|
385
|
-
process.exit(1);
|
|
386
|
-
}
|
|
387
|
-
});
|
|
388
|
-
session
|
|
389
|
-
.command("destroy")
|
|
390
|
-
.description("Destroy session")
|
|
391
|
-
.argument("<sessionId>", "Session ID")
|
|
392
|
-
.option("-f, --force", "Force destroy even with uncommitted changes")
|
|
393
|
-
.action(async (sessionId, options) => {
|
|
394
|
-
try {
|
|
395
|
-
await sessionDestroy(sessionId, { force: options.force });
|
|
396
|
-
}
|
|
397
|
-
catch (error) {
|
|
398
|
-
console.error(chalk.red(`Error: ${error.message}`));
|
|
399
|
-
process.exit(1);
|
|
400
|
-
}
|
|
401
|
-
});
|
|
402
|
-
// ============================================================================
|
|
403
574
|
// TEST MODE (for development)
|
|
404
575
|
// ============================================================================
|
|
405
576
|
program
|
|
@@ -420,63 +591,140 @@ program
|
|
|
420
591
|
// ============================================================================
|
|
421
592
|
// CLAWDBOT INTEGRATION
|
|
422
593
|
// ============================================================================
|
|
423
|
-
program
|
|
424
|
-
|
|
425
|
-
.
|
|
426
|
-
.
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
594
|
+
const clawdbot = program.command("clawdbot").description("Manage JFL plugin for Clawdbot gateway");
|
|
595
|
+
clawdbot
|
|
596
|
+
.command("setup")
|
|
597
|
+
.description("Install JFL plugin into Clawdbot and configure it")
|
|
598
|
+
.action(clawdbotSetupCommand);
|
|
599
|
+
clawdbot
|
|
600
|
+
.command("status")
|
|
601
|
+
.description("Show JFL Clawdbot plugin installation status")
|
|
602
|
+
.action(clawdbotStatusCommand);
|
|
603
|
+
// Default action: show status
|
|
604
|
+
clawdbot.action(clawdbotStatusCommand);
|
|
605
|
+
// ============================================================================
|
|
606
|
+
// OPENCLAW (runtime-agnostic agent protocol)
|
|
607
|
+
// ============================================================================
|
|
608
|
+
const openclaw = program.command("openclaw").description("OpenClaw agent protocol - runtime-agnostic JFL integration");
|
|
609
|
+
openclaw
|
|
610
|
+
.command("session-start")
|
|
611
|
+
.description("Start an agent session (branch, auto-commit, Context Hub)")
|
|
612
|
+
.requiredOption("-a, --agent <name>", "Agent name/ID")
|
|
613
|
+
.option("-g, --gtm <path>", "GTM workspace path")
|
|
614
|
+
.option("--json", "Output JSON")
|
|
615
|
+
.action(async (options) => {
|
|
616
|
+
const { sessionStartCommand } = await import("./commands/openclaw.js");
|
|
617
|
+
await sessionStartCommand(options);
|
|
618
|
+
});
|
|
619
|
+
openclaw
|
|
620
|
+
.command("session-end")
|
|
621
|
+
.description("End session (commit, merge, cleanup)")
|
|
622
|
+
.option("-s, --sync", "Sync to GTM parent (for services)")
|
|
623
|
+
.option("--json", "Output JSON")
|
|
624
|
+
.action(async (options) => {
|
|
625
|
+
const { sessionEndCommand } = await import("./commands/openclaw.js");
|
|
626
|
+
await sessionEndCommand(options);
|
|
627
|
+
});
|
|
628
|
+
openclaw
|
|
629
|
+
.command("heartbeat")
|
|
630
|
+
.description("Health pulse (auto-commit, check Context Hub)")
|
|
631
|
+
.option("--json", "Output JSON")
|
|
632
|
+
.action(async (options) => {
|
|
633
|
+
const { heartbeatCommand: openclawHeartbeat } = await import("./commands/openclaw.js");
|
|
634
|
+
await openclawHeartbeat(options);
|
|
635
|
+
});
|
|
636
|
+
openclaw
|
|
637
|
+
.command("context")
|
|
638
|
+
.description("Get unified context from Context Hub")
|
|
639
|
+
.option("-q, --query <query>", "Search query")
|
|
640
|
+
.option("-t, --task-type <type>", "Task type (code, spec, content, strategy, general)")
|
|
641
|
+
.option("--json", "Output JSON")
|
|
642
|
+
.action(async (options) => {
|
|
643
|
+
const { contextCommand } = await import("./commands/openclaw.js");
|
|
644
|
+
await contextCommand(options);
|
|
645
|
+
});
|
|
646
|
+
openclaw
|
|
647
|
+
.command("journal")
|
|
648
|
+
.description("Write a journal entry")
|
|
649
|
+
.requiredOption("--type <type>", "Entry type (feature, fix, decision, milestone, spec, discovery)")
|
|
650
|
+
.requiredOption("--title <title>", "Entry title")
|
|
651
|
+
.requiredOption("--summary <summary>", "Entry summary")
|
|
652
|
+
.option("--detail <detail>", "Full detail")
|
|
653
|
+
.option("--files <files>", "Comma-separated file paths")
|
|
654
|
+
.option("--json", "Output JSON")
|
|
655
|
+
.action(async (options) => {
|
|
656
|
+
const { journalCommand } = await import("./commands/openclaw.js");
|
|
657
|
+
await journalCommand(options);
|
|
658
|
+
});
|
|
659
|
+
openclaw
|
|
660
|
+
.command("status")
|
|
661
|
+
.description("Show agent session state and health")
|
|
662
|
+
.option("--json", "Output JSON")
|
|
663
|
+
.action(async (options) => {
|
|
664
|
+
const { statusCommand: openclawStatus } = await import("./commands/openclaw.js");
|
|
665
|
+
await openclawStatus(options);
|
|
666
|
+
});
|
|
667
|
+
openclaw
|
|
668
|
+
.command("gtm-list")
|
|
669
|
+
.description("List registered GTM workspaces")
|
|
670
|
+
.option("--json", "Output JSON")
|
|
671
|
+
.action(async (options) => {
|
|
672
|
+
const { gtmListCommand } = await import("./commands/openclaw.js");
|
|
673
|
+
await gtmListCommand(options);
|
|
674
|
+
});
|
|
675
|
+
openclaw
|
|
676
|
+
.command("gtm-switch")
|
|
677
|
+
.description("Switch active GTM workspace")
|
|
678
|
+
.argument("<gtm-id>", "GTM ID to switch to")
|
|
679
|
+
.option("--json", "Output JSON")
|
|
680
|
+
.action(async (gtmId, options) => {
|
|
681
|
+
const { gtmSwitchCommand } = await import("./commands/openclaw.js");
|
|
682
|
+
await gtmSwitchCommand(gtmId, options);
|
|
683
|
+
});
|
|
684
|
+
openclaw
|
|
685
|
+
.command("gtm-create")
|
|
686
|
+
.description("Create and register a new GTM workspace")
|
|
687
|
+
.argument("<name>", "GTM workspace name")
|
|
688
|
+
.option("-p, --path <dir>", "Target directory")
|
|
689
|
+
.option("--json", "Output JSON")
|
|
690
|
+
.action(async (name, options) => {
|
|
691
|
+
const { gtmCreateCommand } = await import("./commands/openclaw.js");
|
|
692
|
+
await gtmCreateCommand(name, options);
|
|
693
|
+
});
|
|
694
|
+
openclaw
|
|
695
|
+
.command("register")
|
|
696
|
+
.description("Register agent with a GTM workspace")
|
|
697
|
+
.requiredOption("-g, --gtm <path>", "GTM workspace path")
|
|
698
|
+
.option("-a, --agent <name>", "Agent name (auto-detected from manifest)")
|
|
699
|
+
.option("--json", "Output JSON")
|
|
700
|
+
.action(async (options) => {
|
|
701
|
+
const { registerCommand } = await import("./commands/openclaw.js");
|
|
702
|
+
await registerCommand(options);
|
|
703
|
+
});
|
|
704
|
+
openclaw
|
|
705
|
+
.command("tag")
|
|
706
|
+
.description("Send message to a service agent")
|
|
707
|
+
.argument("<service>", "Service name")
|
|
708
|
+
.argument("<message>", "Message to send")
|
|
709
|
+
.option("--json", "Output JSON")
|
|
710
|
+
.action(async (service, message, options) => {
|
|
711
|
+
const { tagCommand } = await import("./commands/openclaw.js");
|
|
712
|
+
await tagCommand(service, message, options);
|
|
476
713
|
});
|
|
477
714
|
// ============================================================================
|
|
478
715
|
// HELP
|
|
479
716
|
// ============================================================================
|
|
717
|
+
// GTM COMMANDS
|
|
718
|
+
// ============================================================================
|
|
719
|
+
const gtm = program.command("gtm").description("GTM workspace management");
|
|
720
|
+
gtm
|
|
721
|
+
.command("process-service-update [event-file]")
|
|
722
|
+
.description("Process service sync notification (called by hooks)")
|
|
723
|
+
.action(async (eventFile) => {
|
|
724
|
+
const { gtmProcessUpdate } = await import("./commands/gtm-process-update.js");
|
|
725
|
+
await gtmProcessUpdate(eventFile);
|
|
726
|
+
});
|
|
727
|
+
// ============================================================================
|
|
480
728
|
program
|
|
481
729
|
.command("help")
|
|
482
730
|
.description("Show help")
|
|
@@ -486,14 +734,20 @@ program
|
|
|
486
734
|
console.log(chalk.cyan(" Free Tier (works offline):"));
|
|
487
735
|
console.log(" jfl init Initialize project");
|
|
488
736
|
console.log(" jfl repair Repair missing .jfl directory");
|
|
737
|
+
console.log(" jfl validate-settings Validate .claude/settings.json");
|
|
489
738
|
console.log(" jfl update Pull latest JFL updates");
|
|
739
|
+
console.log(" jfl profile Manage your profile");
|
|
740
|
+
console.log(" jfl profile generate Generate CLAUDE.md w/ AI");
|
|
490
741
|
console.log(" jfl hud Project dashboard");
|
|
491
742
|
console.log(" jfl status Project status");
|
|
743
|
+
console.log(" jfl onboard Onboard service as agent");
|
|
744
|
+
console.log(" jfl services Manage services");
|
|
492
745
|
console.log(" jfl brand Brand architect");
|
|
493
746
|
console.log(" jfl content Content creator");
|
|
494
747
|
console.log(" jfl voice Voice input commands");
|
|
495
748
|
console.log(" jfl ralph AI agent loop (ralph-tui)");
|
|
496
749
|
console.log(" jfl context-hub Context Hub (unified AI context)");
|
|
750
|
+
console.log(" jfl openclaw OpenClaw agent protocol");
|
|
497
751
|
console.log(" jfl test Test onboarding (isolated)");
|
|
498
752
|
console.log(chalk.cyan("\n Platform (requires login):"));
|
|
499
753
|
console.log(" jfl login Login to platform");
|