@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.
Files changed (2) hide show
  1. package/dist/index.js +123 -90
  2. 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 fs4 from "fs";
8
- import path3 from "path";
9
- import os2 from "os";
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
- const scopedExists = fs4.existsSync(scopedCorePath);
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 = path3.join(os2.homedir(), ".acore", "dev", "plugin");
466
- fs4.mkdirSync(scopedAcoreDir, { recursive: true });
467
- fs4.writeFileSync(path3.join(scopedAcoreDir, "core.md"), content, "utf-8");
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 = path3.join(process.cwd(), ".acore");
471
- fs4.mkdirSync(localDir, { recursive: true });
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
- fs4.writeFileSync(path3.join(localDir, "context.md"), contextContent, "utf-8");
512
+ fs5.writeFileSync(path4.join(localDir, "context.md"), contextContent, "utf-8");
489
513
  const configContent = JSON.stringify({ platform: platform || "other" }, null, 2) + "\n";
490
- fs4.writeFileSync(path3.join(localDir, "config.json"), configContent, "utf-8");
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 = path3.join(process.cwd(), platformFile);
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 = os2.homedir();
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 = path3.join(home, ".aflow");
554
- fs4.mkdirSync(aflowDir, { recursive: true });
555
- fs4.writeFileSync(path3.join(aflowDir, "flow.md"), STARTER_FLOW, "utf-8");
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 = path3.join(home, ".arules", "dev", "plugin");
562
- fs4.mkdirSync(arulesDir, { recursive: true });
563
- fs4.writeFileSync(path3.join(arulesDir, "rules.md"), STARTER_RULES, "utf-8");
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 = path3.join(home, ".aeval");
570
- fs4.mkdirSync(aevalDir, { recursive: true });
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
- fs4.writeFileSync(path3.join(aevalDir, "eval.md"), STARTER_EVAL.replace("{{DATE}}", today), "utf-8");
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 fs5 from "fs";
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 = fs5.readFileSync(ecosystem.acore.path, "utf-8");
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 fs6 from "fs";
678
- import path4 from "path";
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 = path4.join(cwd, ".env");
736
- fs6.writeFileSync(envPath, envContent, "utf-8");
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
- fs6.chmodSync(path4.join(cwd, "docker-entrypoint.sh"), 493);
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 = path4.join(cwd, ".env");
780
- fs6.writeFileSync(envPath, envContent, "utf-8");
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 = path4.join(cwd, "docker-compose.ollama.yml");
787
- const dest = path4.join(cwd, "docker-compose.yml");
788
- if (fs6.existsSync(src) && !fs6.existsSync(dest)) {
789
- fs6.renameSync(src, dest);
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
- fs6.chmodSync(path4.join(cwd, "docker-entrypoint.sh"), 493);
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 (fs6.existsSync(path4.join(dir, "Dockerfile"))) return dir;
870
- dir = path4.dirname(dir);
893
+ if (fs7.existsSync(path5.join(dir, "Dockerfile"))) return dir;
894
+ dir = path5.dirname(dir);
871
895
  }
872
- const globalDir = path4.join(process.env.npm_config_prefix || "/usr/local", "lib/node_modules/@aman_asmuei/aman");
873
- if (fs6.existsSync(path4.join(globalDir, "Dockerfile"))) return globalDir;
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 = path4.join(pkgDir, filename);
878
- const dest = path4.join(destDir, filename);
879
- if (fs6.existsSync(src)) {
880
- fs6.copyFileSync(src, dest);
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 fs7 from "fs";
1011
- import path5 from "path";
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 = path5.join(cwd, ".acore");
1015
- const contextPath = path5.join(acoreDir, "context.md");
1016
- const configPath = path5.join(acoreDir, "config.json");
1017
- if (fs7.existsSync(contextPath) && !opts.force) {
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
- fs7.mkdirSync(acoreDir, { recursive: true });
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
- fs7.writeFileSync(contextPath, contextContent, "utf-8");
1048
- if (fs7.existsSync(configPath)) {
1071
+ fs8.writeFileSync(contextPath, contextContent, "utf-8");
1072
+ if (fs8.existsSync(configPath)) {
1049
1073
  try {
1050
- const existing = JSON.parse(fs7.readFileSync(configPath, "utf-8"));
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
- fs7.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n", "utf-8");
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
- fs7.writeFileSync(configPath, JSON.stringify(fresh, null, 2) + "\n", "utf-8");
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
- fs7.writeFileSync(configPath, JSON.stringify(fresh, null, 2) + "\n", "utf-8");
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.2").action(() => {
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(() => statusCommand());
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)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aman_asmuei/aman",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "Your complete AI companion — identity, memory, and tools in one command",
5
5
  "type": "module",
6
6
  "bin": {