shabti 2.7.0 → 2.8.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 CHANGED
@@ -56,6 +56,7 @@ shabti status
56
56
  | `snapshot` | Manage storage snapshots |
57
57
  | `config` | Manage configuration |
58
58
  | `gc` | Garbage collect expired entries |
59
+ | `health` | Run health checks on engine |
59
60
  | `a2a` | Start A2A protocol server |
60
61
  | `chat` | Interactive chat with OpenAI |
61
62
  | `mcp-config` | Print MCP server configuration JSON |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shabti",
3
- "version": "2.7.0",
3
+ "version": "2.8.0",
4
4
  "description": "Agent Memory OS — semantic memory for AI agents",
5
5
  "type": "module",
6
6
  "main": "native.cjs",
@@ -0,0 +1,104 @@
1
+ import chalk from "chalk";
2
+ import { createEngine, loadConfig } from "../core/engine.js";
3
+ import { heading, success, warn } from "../utils/style.js";
4
+
5
+ export function registerHealth(program) {
6
+ program
7
+ .command("health")
8
+ .description("Run health checks on the shabti engine")
9
+ .option("-j, --json", "Output as JSON")
10
+ .action(async (opts) => {
11
+ const checks = [];
12
+
13
+ // 1. Qdrant connectivity
14
+ const config = loadConfig();
15
+ const qdrantUrl = config.qdrant_url.replace(/:\d+$/, ":6333");
16
+ try {
17
+ const res = await fetch(`${qdrantUrl}/healthz`, {
18
+ signal: AbortSignal.timeout(3000),
19
+ });
20
+ checks.push({
21
+ name: "qdrant",
22
+ status: res.ok ? "ok" : "degraded",
23
+ message: res.ok ? "Reachable" : `HTTP ${res.status}`,
24
+ });
25
+ } catch (err) {
26
+ checks.push({
27
+ name: "qdrant",
28
+ status: "error",
29
+ message: err.message,
30
+ });
31
+ }
32
+
33
+ // 2. Engine initialization
34
+ let engine = null;
35
+ try {
36
+ engine = createEngine();
37
+ const status = engine.status();
38
+ checks.push({
39
+ name: "engine",
40
+ status: "ok",
41
+ message: `${status.entryCount} entries, tier: ${status.tier}`,
42
+ });
43
+ } catch (err) {
44
+ checks.push({
45
+ name: "engine",
46
+ status: "error",
47
+ message: err.message,
48
+ });
49
+ }
50
+
51
+ // 3. Embedding model
52
+ if (engine) {
53
+ try {
54
+ const modelId = engine.modelId();
55
+ checks.push({
56
+ name: "embedding",
57
+ status: "ok",
58
+ message: modelId,
59
+ });
60
+ } catch (err) {
61
+ checks.push({
62
+ name: "embedding",
63
+ status: "error",
64
+ message: err.message,
65
+ });
66
+ }
67
+ }
68
+
69
+ const allOk = checks.every((c) => c.status === "ok");
70
+
71
+ if (opts.json) {
72
+ console.log(JSON.stringify({ healthy: allOk, checks }, null, 2));
73
+ } else {
74
+ heading("Health Check");
75
+ console.log();
76
+ for (const check of checks) {
77
+ const icon =
78
+ check.status === "ok"
79
+ ? chalk.green("✓")
80
+ : check.status === "degraded"
81
+ ? chalk.yellow("⚠")
82
+ : chalk.red("✗");
83
+ console.log(` ${icon} ${chalk.cyan(check.name.padEnd(12))} ${check.message}`);
84
+ }
85
+ console.log();
86
+ if (allOk) {
87
+ success("All checks passed");
88
+ } else {
89
+ warn("Some checks failed");
90
+ }
91
+ console.log();
92
+ }
93
+
94
+ if (engine) {
95
+ try {
96
+ await engine.shutdown();
97
+ } catch (_) {
98
+ // best-effort
99
+ }
100
+ }
101
+
102
+ if (!allOk) process.exitCode = 1;
103
+ });
104
+ }
package/src/index.js CHANGED
@@ -16,6 +16,7 @@ import { registerExport } from "./commands/export.js";
16
16
  import { registerImport } from "./commands/import.js";
17
17
  import { registerStore } from "./commands/store.js";
18
18
  import { registerDelete } from "./commands/delete.js";
19
+ import { registerHealth } from "./commands/health.js";
19
20
 
20
21
  const { version } = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
21
22
 
@@ -86,6 +87,7 @@ function buildProgram() {
86
87
  registerImport(program);
87
88
  registerStore(program);
88
89
  registerDelete(program);
90
+ registerHealth(program);
89
91
 
90
92
  program
91
93
  .command("gc")