@aman_asmuei/aman 0.5.2 → 0.5.3
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/index.js +123 -90
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4,9 +4,9 @@ import { Command } from "commander";
|
|
|
4
4
|
// src/commands/setup.ts
|
|
5
5
|
import * as p from "@clack/prompts";
|
|
6
6
|
import pc from "picocolors";
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
7
|
+
import fs5 from "fs";
|
|
8
|
+
import path4 from "path";
|
|
9
|
+
import os3 from "os";
|
|
10
10
|
|
|
11
11
|
// src/lib/detect.ts
|
|
12
12
|
import fs from "fs";
|
|
@@ -266,6 +266,58 @@ function getPlatformFile(platform) {
|
|
|
266
266
|
}
|
|
267
267
|
}
|
|
268
268
|
|
|
269
|
+
// src/lib/heal.ts
|
|
270
|
+
import fs4 from "fs";
|
|
271
|
+
import path3 from "path";
|
|
272
|
+
import os2 from "os";
|
|
273
|
+
var TEMPLATE_MARKERS = /\[your name\]|\[YOUR_NAME\]|\[AI_NAME\]/;
|
|
274
|
+
function healLayerScope(layerDir, filename, home) {
|
|
275
|
+
const homeDir = home ?? os2.homedir();
|
|
276
|
+
const scopedPath = path3.join(homeDir, layerDir, "dev", "plugin", filename);
|
|
277
|
+
const legacyPath = path3.join(homeDir, layerDir, filename);
|
|
278
|
+
const scopedExists = fs4.existsSync(scopedPath);
|
|
279
|
+
const legacyExists = fs4.existsSync(legacyPath);
|
|
280
|
+
if (!legacyExists) {
|
|
281
|
+
return scopedExists ? "ok" : "no-op";
|
|
282
|
+
}
|
|
283
|
+
const legacyContent = fs4.readFileSync(legacyPath, "utf-8");
|
|
284
|
+
if (TEMPLATE_MARKERS.test(legacyContent)) {
|
|
285
|
+
return "no-op";
|
|
286
|
+
}
|
|
287
|
+
if (!scopedExists) {
|
|
288
|
+
fs4.mkdirSync(path3.dirname(scopedPath), { recursive: true });
|
|
289
|
+
fs4.writeFileSync(scopedPath, legacyContent, "utf-8");
|
|
290
|
+
return "migrated";
|
|
291
|
+
}
|
|
292
|
+
const scopedContent = fs4.readFileSync(scopedPath, "utf-8");
|
|
293
|
+
if (TEMPLATE_MARKERS.test(scopedContent)) {
|
|
294
|
+
fs4.writeFileSync(scopedPath, legacyContent, "utf-8");
|
|
295
|
+
return "repaired";
|
|
296
|
+
}
|
|
297
|
+
return "ok";
|
|
298
|
+
}
|
|
299
|
+
function healResultMessage(layerDir, filename, result) {
|
|
300
|
+
if (result === "migrated") {
|
|
301
|
+
return `${layerDir.replace(/^\./, "")}: migrated ~/${layerDir}/${filename} \u2192 ~/${layerDir}/dev/plugin/${filename}`;
|
|
302
|
+
}
|
|
303
|
+
if (result === "repaired") {
|
|
304
|
+
return `${layerDir.replace(/^\./, "")}: replaced unfilled template at ~/${layerDir}/dev/plugin/${filename} with your personalised content`;
|
|
305
|
+
}
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
function runAutoHeal(home) {
|
|
309
|
+
const messages = [];
|
|
310
|
+
for (const [layerDir, filename] of [
|
|
311
|
+
[".acore", "core.md"],
|
|
312
|
+
[".arules", "rules.md"]
|
|
313
|
+
]) {
|
|
314
|
+
const result = healLayerScope(layerDir, filename, home);
|
|
315
|
+
const msg = healResultMessage(layerDir, filename, result);
|
|
316
|
+
if (msg) messages.push(msg);
|
|
317
|
+
}
|
|
318
|
+
return messages;
|
|
319
|
+
}
|
|
320
|
+
|
|
269
321
|
// src/templates.ts
|
|
270
322
|
var STARTER_FLOW = `# My Workflows
|
|
271
323
|
|
|
@@ -383,40 +435,12 @@ var ARCHETYPES = {
|
|
|
383
435
|
};
|
|
384
436
|
async function setupCommand() {
|
|
385
437
|
p.intro(pc.bold("aman") + " \u2014 your complete AI companion");
|
|
438
|
+
for (const msg of runAutoHeal()) {
|
|
439
|
+
p.log.success(msg);
|
|
440
|
+
}
|
|
386
441
|
const ecosystem = detectEcosystem();
|
|
387
|
-
const scopedCorePath = path3.join(os2.homedir(), ".acore", "dev", "plugin", "core.md");
|
|
388
|
-
const legacyCorePath = path3.join(os2.homedir(), ".acore", "core.md");
|
|
389
442
|
if (ecosystem.acore.installed) {
|
|
390
|
-
|
|
391
|
-
const legacyExists = fs4.existsSync(legacyCorePath);
|
|
392
|
-
if (legacyExists) {
|
|
393
|
-
const legacyContent = fs4.readFileSync(legacyCorePath, "utf-8");
|
|
394
|
-
const legacyIsTemplate = /\[your name\]|\[YOUR_NAME\]|\[AI_NAME\]/.test(legacyContent);
|
|
395
|
-
if (!legacyIsTemplate) {
|
|
396
|
-
if (!scopedExists) {
|
|
397
|
-
fs4.mkdirSync(path3.dirname(scopedCorePath), { recursive: true });
|
|
398
|
-
fs4.writeFileSync(scopedCorePath, legacyContent, "utf-8");
|
|
399
|
-
p.log.success(
|
|
400
|
-
`Identity: migrated ${pc.dim("~/.acore/core.md")} \u2192 ${pc.dim("~/.acore/dev/plugin/core.md")}`
|
|
401
|
-
);
|
|
402
|
-
} else {
|
|
403
|
-
const scopedContent = fs4.readFileSync(scopedCorePath, "utf-8");
|
|
404
|
-
const scopedIsTemplate = /\[your name\]|\[YOUR_NAME\]|\[AI_NAME\]/.test(scopedContent);
|
|
405
|
-
if (scopedIsTemplate) {
|
|
406
|
-
fs4.writeFileSync(scopedCorePath, legacyContent, "utf-8");
|
|
407
|
-
p.log.success(
|
|
408
|
-
`Identity: replaced unfilled template at ${pc.dim("~/.acore/dev/plugin/core.md")} with your personalized identity`
|
|
409
|
-
);
|
|
410
|
-
} else {
|
|
411
|
-
p.log.success(`Identity: ${pc.dim(ecosystem.acore.path)} already exists`);
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
} else {
|
|
415
|
-
p.log.success(`Identity: ${pc.dim(ecosystem.acore.path)} already exists`);
|
|
416
|
-
}
|
|
417
|
-
} else {
|
|
418
|
-
p.log.success(`Identity: ${pc.dim(ecosystem.acore.path)} already exists`);
|
|
419
|
-
}
|
|
443
|
+
p.log.success(`Identity: ${pc.dim(ecosystem.acore.path)} already exists`);
|
|
420
444
|
} else {
|
|
421
445
|
p.log.step("Setting up your AI identity...");
|
|
422
446
|
let userName = detectUserName();
|
|
@@ -462,13 +486,13 @@ async function setupCommand() {
|
|
|
462
486
|
DATE: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
463
487
|
UPDATE_INSTRUCTIONS: getUpdateInstructions(platform)
|
|
464
488
|
});
|
|
465
|
-
const scopedAcoreDir =
|
|
466
|
-
|
|
467
|
-
|
|
489
|
+
const scopedAcoreDir = path4.join(os3.homedir(), ".acore", "dev", "plugin");
|
|
490
|
+
fs5.mkdirSync(scopedAcoreDir, { recursive: true });
|
|
491
|
+
fs5.writeFileSync(path4.join(scopedAcoreDir, "core.md"), content, "utf-8");
|
|
468
492
|
p.log.success(`Created ${pc.dim("~/.acore/dev/plugin/core.md")} (identity)`);
|
|
469
493
|
if (stack) {
|
|
470
|
-
const localDir =
|
|
471
|
-
|
|
494
|
+
const localDir = path4.join(process.cwd(), ".acore");
|
|
495
|
+
fs5.mkdirSync(localDir, { recursive: true });
|
|
472
496
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
473
497
|
const contextContent = `## Work
|
|
474
498
|
- Stack: ${stack}
|
|
@@ -485,9 +509,9 @@ async function setupCommand() {
|
|
|
485
509
|
## Project Patterns
|
|
486
510
|
- [observations specific to this project \u2014 built over time]
|
|
487
511
|
`;
|
|
488
|
-
|
|
512
|
+
fs5.writeFileSync(path4.join(localDir, "context.md"), contextContent, "utf-8");
|
|
489
513
|
const configContent = JSON.stringify({ platform: platform || "other" }, null, 2) + "\n";
|
|
490
|
-
|
|
514
|
+
fs5.writeFileSync(path4.join(localDir, "config.json"), configContent, "utf-8");
|
|
491
515
|
} else {
|
|
492
516
|
p.log.info(
|
|
493
517
|
`No project detected here \u2014 run ${pc.bold("aman here")} later from inside any repo to add per-project context.`
|
|
@@ -495,7 +519,7 @@ async function setupCommand() {
|
|
|
495
519
|
}
|
|
496
520
|
const platformFile = getPlatformFile(platform);
|
|
497
521
|
if (platformFile) {
|
|
498
|
-
const filePath =
|
|
522
|
+
const filePath = path4.join(process.cwd(), platformFile);
|
|
499
523
|
const result = injectIntoFile(filePath, content);
|
|
500
524
|
if (result.created) {
|
|
501
525
|
p.log.success(`Created ${pc.dim(platformFile)} with identity`);
|
|
@@ -507,7 +531,7 @@ async function setupCommand() {
|
|
|
507
531
|
if (stack) inferredParts.push(stack);
|
|
508
532
|
p.log.info(`Inferred: ${pc.dim(inferredParts.join(" \xB7 "))}`);
|
|
509
533
|
}
|
|
510
|
-
const home =
|
|
534
|
+
const home = os3.homedir();
|
|
511
535
|
const aflowExists = ecosystem.aflow.installed;
|
|
512
536
|
const arulesExists = ecosystem.arules.installed;
|
|
513
537
|
const aevalExists = ecosystem.aeval.installed;
|
|
@@ -550,26 +574,26 @@ async function setupCommand() {
|
|
|
550
574
|
doEval = selected.includes("eval");
|
|
551
575
|
}
|
|
552
576
|
if (doFlow) {
|
|
553
|
-
const aflowDir =
|
|
554
|
-
|
|
555
|
-
|
|
577
|
+
const aflowDir = path4.join(home, ".aflow");
|
|
578
|
+
fs5.mkdirSync(aflowDir, { recursive: true });
|
|
579
|
+
fs5.writeFileSync(path4.join(aflowDir, "flow.md"), STARTER_FLOW, "utf-8");
|
|
556
580
|
p.log.success(`Workflows: created ${pc.dim("~/.aflow/flow.md")} (4 starter workflows)`);
|
|
557
581
|
} else if (aflowExists) {
|
|
558
582
|
p.log.success(`Workflows: ${ecosystem.aflow.workflowCount} defined`);
|
|
559
583
|
}
|
|
560
584
|
if (doRules) {
|
|
561
|
-
const arulesDir =
|
|
562
|
-
|
|
563
|
-
|
|
585
|
+
const arulesDir = path4.join(home, ".arules", "dev", "plugin");
|
|
586
|
+
fs5.mkdirSync(arulesDir, { recursive: true });
|
|
587
|
+
fs5.writeFileSync(path4.join(arulesDir, "rules.md"), STARTER_RULES, "utf-8");
|
|
564
588
|
p.log.success(`Guardrails: created ${pc.dim("~/.arules/dev/plugin/rules.md")} (24 rules)`);
|
|
565
589
|
} else if (arulesExists) {
|
|
566
590
|
p.log.success(`Guardrails: ${ecosystem.arules.ruleCount} rules`);
|
|
567
591
|
}
|
|
568
592
|
if (doEval) {
|
|
569
|
-
const aevalDir =
|
|
570
|
-
|
|
593
|
+
const aevalDir = path4.join(home, ".aeval");
|
|
594
|
+
fs5.mkdirSync(aevalDir, { recursive: true });
|
|
571
595
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
572
|
-
|
|
596
|
+
fs5.writeFileSync(path4.join(aevalDir, "eval.md"), STARTER_EVAL.replace("{{DATE}}", today), "utf-8");
|
|
573
597
|
p.log.success(`Evaluation: created ${pc.dim("~/.aeval/eval.md")}`);
|
|
574
598
|
} else if (aevalExists) {
|
|
575
599
|
p.log.success("Evaluation: already configured");
|
|
@@ -603,13 +627,13 @@ async function setupCommand() {
|
|
|
603
627
|
// src/commands/status.ts
|
|
604
628
|
import * as p2 from "@clack/prompts";
|
|
605
629
|
import pc2 from "picocolors";
|
|
606
|
-
import
|
|
630
|
+
import fs6 from "fs";
|
|
607
631
|
function statusCommand() {
|
|
608
632
|
p2.intro(pc2.bold("aman") + " \u2014 ecosystem status");
|
|
609
633
|
const ecosystem = detectEcosystem();
|
|
610
634
|
const platform = detectPlatform();
|
|
611
635
|
if (ecosystem.acore.installed) {
|
|
612
|
-
const content =
|
|
636
|
+
const content = fs6.readFileSync(ecosystem.acore.path, "utf-8");
|
|
613
637
|
const aiName = content.match(/^# (.+)$/m)?.[1] || "Companion";
|
|
614
638
|
const userName = content.match(/- Name: (.+)$/m)?.[1] || "Unknown";
|
|
615
639
|
p2.log.success(`Identity: ${pc2.bold(aiName)} + ${pc2.bold(userName)}`);
|
|
@@ -674,8 +698,8 @@ function statusCommand() {
|
|
|
674
698
|
}
|
|
675
699
|
|
|
676
700
|
// src/commands/deploy.ts
|
|
677
|
-
import
|
|
678
|
-
import
|
|
701
|
+
import fs7 from "fs";
|
|
702
|
+
import path5 from "path";
|
|
679
703
|
import * as p3 from "@clack/prompts";
|
|
680
704
|
import pc3 from "picocolors";
|
|
681
705
|
async function deployCommand() {
|
|
@@ -732,15 +756,15 @@ AMAN_MODEL=${isAnthropic ? "claude-sonnet-4-6" : "gpt-4o"}
|
|
|
732
756
|
# TELEGRAM_BOT_TOKEN=
|
|
733
757
|
# DISCORD_BOT_TOKEN=
|
|
734
758
|
`;
|
|
735
|
-
const envPath =
|
|
736
|
-
|
|
759
|
+
const envPath = path5.join(cwd, ".env");
|
|
760
|
+
fs7.writeFileSync(envPath, envContent, "utf-8");
|
|
737
761
|
p3.log.success(`Created ${pc3.bold(".env")} with API key`);
|
|
738
762
|
const pkgDir = findPackageDir();
|
|
739
763
|
copyDeployFile(pkgDir, cwd, "Dockerfile");
|
|
740
764
|
copyDeployFile(pkgDir, cwd, "docker-entrypoint.sh");
|
|
741
765
|
copyDeployFile(pkgDir, cwd, "docker-compose.yml");
|
|
742
766
|
try {
|
|
743
|
-
|
|
767
|
+
fs7.chmodSync(path5.join(cwd, "docker-entrypoint.sh"), 493);
|
|
744
768
|
} catch {
|
|
745
769
|
}
|
|
746
770
|
p3.log.success(`Created ${pc3.bold("Dockerfile")} + ${pc3.bold("docker-compose.yml")}`);
|
|
@@ -776,20 +800,20 @@ AMAN_MODEL=${model}
|
|
|
776
800
|
# TELEGRAM_BOT_TOKEN=
|
|
777
801
|
# DISCORD_BOT_TOKEN=
|
|
778
802
|
`;
|
|
779
|
-
const envPath =
|
|
780
|
-
|
|
803
|
+
const envPath = path5.join(cwd, ".env");
|
|
804
|
+
fs7.writeFileSync(envPath, envContent, "utf-8");
|
|
781
805
|
p3.log.success(`Created ${pc3.bold(".env")} with Ollama config`);
|
|
782
806
|
const pkgDir = findPackageDir();
|
|
783
807
|
copyDeployFile(pkgDir, cwd, "Dockerfile");
|
|
784
808
|
copyDeployFile(pkgDir, cwd, "docker-entrypoint.sh");
|
|
785
809
|
copyDeployFile(pkgDir, cwd, "docker-compose.ollama.yml");
|
|
786
|
-
const src =
|
|
787
|
-
const dest =
|
|
788
|
-
if (
|
|
789
|
-
|
|
810
|
+
const src = path5.join(cwd, "docker-compose.ollama.yml");
|
|
811
|
+
const dest = path5.join(cwd, "docker-compose.yml");
|
|
812
|
+
if (fs7.existsSync(src) && !fs7.existsSync(dest)) {
|
|
813
|
+
fs7.renameSync(src, dest);
|
|
790
814
|
}
|
|
791
815
|
try {
|
|
792
|
-
|
|
816
|
+
fs7.chmodSync(path5.join(cwd, "docker-entrypoint.sh"), 493);
|
|
793
817
|
} catch {
|
|
794
818
|
}
|
|
795
819
|
p3.log.success(`Created ${pc3.bold("Dockerfile")} + ${pc3.bold("docker-compose.yml")} (with Ollama)`);
|
|
@@ -866,18 +890,18 @@ ${pc3.bold("Raspberry Pi:")}
|
|
|
866
890
|
function findPackageDir() {
|
|
867
891
|
let dir = new URL(".", import.meta.url).pathname;
|
|
868
892
|
for (let i = 0; i < 5; i++) {
|
|
869
|
-
if (
|
|
870
|
-
dir =
|
|
893
|
+
if (fs7.existsSync(path5.join(dir, "Dockerfile"))) return dir;
|
|
894
|
+
dir = path5.dirname(dir);
|
|
871
895
|
}
|
|
872
|
-
const globalDir =
|
|
873
|
-
if (
|
|
896
|
+
const globalDir = path5.join(process.env.npm_config_prefix || "/usr/local", "lib/node_modules/@aman_asmuei/aman");
|
|
897
|
+
if (fs7.existsSync(path5.join(globalDir, "Dockerfile"))) return globalDir;
|
|
874
898
|
return process.cwd();
|
|
875
899
|
}
|
|
876
900
|
function copyDeployFile(pkgDir, destDir, filename) {
|
|
877
|
-
const src =
|
|
878
|
-
const dest =
|
|
879
|
-
if (
|
|
880
|
-
|
|
901
|
+
const src = path5.join(pkgDir, filename);
|
|
902
|
+
const dest = path5.join(destDir, filename);
|
|
903
|
+
if (fs7.existsSync(src)) {
|
|
904
|
+
fs7.copyFileSync(src, dest);
|
|
881
905
|
}
|
|
882
906
|
}
|
|
883
907
|
|
|
@@ -1007,14 +1031,14 @@ async function showcaseCommand(nameArg, opts = {}) {
|
|
|
1007
1031
|
// src/commands/here.ts
|
|
1008
1032
|
import * as p5 from "@clack/prompts";
|
|
1009
1033
|
import pc5 from "picocolors";
|
|
1010
|
-
import
|
|
1011
|
-
import
|
|
1034
|
+
import fs8 from "fs";
|
|
1035
|
+
import path6 from "path";
|
|
1012
1036
|
async function hereCommand(opts = {}) {
|
|
1013
1037
|
const cwd = process.cwd();
|
|
1014
|
-
const acoreDir =
|
|
1015
|
-
const contextPath =
|
|
1016
|
-
const configPath =
|
|
1017
|
-
if (
|
|
1038
|
+
const acoreDir = path6.join(cwd, ".acore");
|
|
1039
|
+
const contextPath = path6.join(acoreDir, "context.md");
|
|
1040
|
+
const configPath = path6.join(acoreDir, "config.json");
|
|
1041
|
+
if (fs8.existsSync(contextPath) && !opts.force) {
|
|
1018
1042
|
p5.intro(pc5.bold("aman here") + " \u2014 project context card");
|
|
1019
1043
|
const overwrite = await p5.confirm({
|
|
1020
1044
|
message: `${pc5.dim(".acore/context.md")} already exists. Overwrite?`,
|
|
@@ -1028,7 +1052,7 @@ async function hereCommand(opts = {}) {
|
|
|
1028
1052
|
const stack = detectStack() || "unknown";
|
|
1029
1053
|
const platform = detectPlatform();
|
|
1030
1054
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1031
|
-
|
|
1055
|
+
fs8.mkdirSync(acoreDir, { recursive: true });
|
|
1032
1056
|
const contextContent = `## Work
|
|
1033
1057
|
- Stack: ${stack}
|
|
1034
1058
|
- Domain:
|
|
@@ -1044,21 +1068,21 @@ async function hereCommand(opts = {}) {
|
|
|
1044
1068
|
## Project Patterns
|
|
1045
1069
|
- [observations specific to this project \u2014 built over time]
|
|
1046
1070
|
`;
|
|
1047
|
-
|
|
1048
|
-
if (
|
|
1071
|
+
fs8.writeFileSync(contextPath, contextContent, "utf-8");
|
|
1072
|
+
if (fs8.existsSync(configPath)) {
|
|
1049
1073
|
try {
|
|
1050
|
-
const existing = JSON.parse(
|
|
1074
|
+
const existing = JSON.parse(fs8.readFileSync(configPath, "utf-8"));
|
|
1051
1075
|
if (typeof existing.platform !== "string" || existing.platform === "") {
|
|
1052
1076
|
existing.platform = platform || "other";
|
|
1053
|
-
|
|
1077
|
+
fs8.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n", "utf-8");
|
|
1054
1078
|
}
|
|
1055
1079
|
} catch {
|
|
1056
1080
|
const fresh = { platform: platform || "other" };
|
|
1057
|
-
|
|
1081
|
+
fs8.writeFileSync(configPath, JSON.stringify(fresh, null, 2) + "\n", "utf-8");
|
|
1058
1082
|
}
|
|
1059
1083
|
} else {
|
|
1060
1084
|
const fresh = { platform: platform || "other" };
|
|
1061
|
-
|
|
1085
|
+
fs8.writeFileSync(configPath, JSON.stringify(fresh, null, 2) + "\n", "utf-8");
|
|
1062
1086
|
}
|
|
1063
1087
|
if (opts.force) {
|
|
1064
1088
|
return;
|
|
@@ -1071,8 +1095,12 @@ async function hereCommand(opts = {}) {
|
|
|
1071
1095
|
}
|
|
1072
1096
|
|
|
1073
1097
|
// src/index.ts
|
|
1098
|
+
import pc6 from "picocolors";
|
|
1074
1099
|
var program = new Command();
|
|
1075
|
-
program.name("aman").description("Your complete AI companion \u2014 identity, memory, and tools in one command").version("0.5.
|
|
1100
|
+
program.name("aman").description("Your complete AI companion \u2014 identity, memory, and tools in one command").version("0.5.3").action(() => {
|
|
1101
|
+
for (const msg of runAutoHeal()) {
|
|
1102
|
+
console.log(` ${pc6.green("\u2714")} ${msg}`);
|
|
1103
|
+
}
|
|
1076
1104
|
const ecosystem = detectEcosystem();
|
|
1077
1105
|
if (ecosystem.acore.installed) {
|
|
1078
1106
|
statusCommand();
|
|
@@ -1081,7 +1109,12 @@ program.name("aman").description("Your complete AI companion \u2014 identity, me
|
|
|
1081
1109
|
}
|
|
1082
1110
|
});
|
|
1083
1111
|
program.command("setup").description("Set up your AI companion (identity + memory + tools)").action(() => setupCommand());
|
|
1084
|
-
program.command("status").description("View your full ecosystem status").action(() =>
|
|
1112
|
+
program.command("status").description("View your full ecosystem status").action(() => {
|
|
1113
|
+
for (const msg of runAutoHeal()) {
|
|
1114
|
+
console.log(` ${pc6.green("\u2714")} ${msg}`);
|
|
1115
|
+
}
|
|
1116
|
+
statusCommand();
|
|
1117
|
+
});
|
|
1085
1118
|
program.command("deploy").description("Deploy your AI companion (Docker, systemd, or cloud)").action(() => deployCommand());
|
|
1086
1119
|
program.command("showcase [name]").description("Set up a showcase AI companion (rutin, kedai, monitor, ...)").option("--dry-run", "preview files without installing").option("--list", "list all available showcases").action(
|
|
1087
1120
|
(name, opts) => showcaseCommand(name, opts)
|