@ebowwa/stack 0.1.0 → 0.1.2

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 (3) hide show
  1. package/dist/index.js +47 -27
  2. package/package.json +1 -1
  3. package/src/index.ts +60 -28
package/dist/index.js CHANGED
@@ -52387,7 +52387,7 @@ ${taggedContent}`
52387
52387
  }
52388
52388
  function parseMemoryCommand(memory, channel, message) {
52389
52389
  const trimmed = message.trim();
52390
- const isMemoryCommand = trimmed.startsWith("/memory ") || trimmed.startsWith("!memory ");
52390
+ const isMemoryCommand = trimmed === "/memory" || trimmed === "!memory" || trimmed.startsWith("/memory ") || trimmed.startsWith("!memory ");
52391
52391
  if (!isMemoryCommand) {
52392
52392
  return { handled: false };
52393
52393
  }
@@ -57408,8 +57408,7 @@ class Stack {
57408
57408
  abortController = null;
57409
57409
  constructor(config) {
57410
57410
  this.config = {
57411
- ssh: config.ssh ?? { chatDir: "/root/.ssh-chat" },
57412
- telegram: config.telegram ?? {},
57411
+ ...config,
57413
57412
  api: config.api ?? { port: 8911 },
57414
57413
  ralph: config.ralph ?? { worktreesDir: "/root/worktrees", repoUrl: "" },
57415
57414
  ai: config.ai ?? { model: "GLM-4.7", temperature: 0.7, maxTokens: 4096 },
@@ -57418,27 +57417,37 @@ class Stack {
57418
57417
  this.state = {
57419
57418
  started: new Date,
57420
57419
  channels: { ssh: false, telegram: false },
57421
- api: { enabled: !!this.config.api },
57420
+ api: { enabled: !!this.config.api, port: this.config.api?.port },
57422
57421
  ralphLoops: new Map
57423
57422
  };
57423
+ const memoryChannels = {};
57424
+ const permissions = {};
57425
+ const enabledChannels = [];
57426
+ if (this.config.ssh) {
57427
+ memoryChannels.ssh = { memoryFile: `${this.config.ssh.chatDir}/memory.json`, maxMessages: 50 };
57428
+ enabledChannels.push("ssh");
57429
+ }
57430
+ if (this.config.telegram) {
57431
+ memoryChannels.telegram = { memoryFile: "/root/.telegram-memory.json", maxMessages: 50 };
57432
+ enabledChannels.push("telegram");
57433
+ }
57434
+ if (this.config.api) {
57435
+ memoryChannels.api = { memoryFile: "/root/.api-memory.json", maxMessages: 100 };
57436
+ enabledChannels.push("api");
57437
+ }
57438
+ for (const channel of enabledChannels) {
57439
+ permissions[channel] = { canRead: enabledChannels.filter((c) => c !== channel) };
57440
+ }
57424
57441
  this.memory = createPermissionMemory({
57425
- channels: {
57426
- ssh: { memoryFile: `${this.config.ssh.chatDir}/memory.json`, maxMessages: 50 },
57427
- telegram: { memoryFile: "/root/.telegram-memory.json", maxMessages: 50 },
57428
- api: { memoryFile: "/root/.api-memory.json", maxMessages: 100 }
57429
- },
57430
- permissions: {
57431
- ssh: { canRead: ["telegram", "api"] },
57432
- telegram: { canRead: ["ssh", "api"] },
57433
- api: { canRead: ["ssh", "telegram"] }
57434
- }
57442
+ channels: memoryChannels,
57443
+ permissions
57435
57444
  });
57436
57445
  this.router = createChannelRouter({
57437
57446
  announcement: {
57438
57447
  serverName: this.config.node.name,
57439
57448
  hostname: this.config.node.hostname,
57440
57449
  packageName: "@ebowwa/stack",
57441
- version: "0.1.0"
57450
+ version: "0.1.1"
57442
57451
  }
57443
57452
  });
57444
57453
  this.client = new GLMClient;
@@ -57621,10 +57630,15 @@ Prompt: ${prompt.slice(0, 100)}...`;
57621
57630
  await this.router.start();
57622
57631
  this.startAPI();
57623
57632
  console.log("[Stack] Running!");
57624
- console.log(` - SSH: echo 'msg' > ${this.config.ssh.chatDir}/in`);
57633
+ if (this.state.channels.ssh) {
57634
+ console.log(` - SSH: echo 'msg' > ${this.config.ssh.chatDir}/in`);
57635
+ }
57625
57636
  if (this.state.channels.telegram) {
57626
57637
  console.log(" - Telegram: enabled");
57627
57638
  }
57639
+ if (this.state.api.enabled) {
57640
+ console.log(` - API: :${this.state.api.port}`);
57641
+ }
57628
57642
  console.log(" - Commands: /ralph start|list|stop, /status, /memory <cmd>");
57629
57643
  await new Promise(() => {});
57630
57644
  }
@@ -57640,17 +57654,22 @@ Prompt: ${prompt.slice(0, 100)}...`;
57640
57654
  }
57641
57655
  }
57642
57656
  async function main() {
57643
- const stack = new Stack({
57644
- ssh: {
57645
- chatDir: process.env.SSH_CHAT_DIR || "/root/.ssh-chat",
57646
- pollInterval: 500
57647
- },
57648
- telegram: {
57649
- botToken: process.env.TELEGRAM_BOT_TOKEN,
57650
- allowedChats: process.env.TELEGRAM_CHAT_ID ? [parseInt(process.env.TELEGRAM_CHAT_ID, 10)] : undefined
57651
- },
57657
+ const config = {
57658
+ ...process.env.SSH_CHAT_DIR ? {
57659
+ ssh: {
57660
+ chatDir: process.env.SSH_CHAT_DIR,
57661
+ pollInterval: parseInt(process.env.SSH_POLL_INTERVAL || "500", 10)
57662
+ }
57663
+ } : {},
57664
+ ...process.env.TELEGRAM_BOT_TOKEN ? {
57665
+ telegram: {
57666
+ botToken: process.env.TELEGRAM_BOT_TOKEN,
57667
+ allowedChats: process.env.TELEGRAM_CHAT_ID ? [parseInt(process.env.TELEGRAM_CHAT_ID, 10)] : undefined
57668
+ }
57669
+ } : {},
57652
57670
  api: {
57653
- port: parseInt(process.env.API_PORT || "8911", 10)
57671
+ port: parseInt(process.env.API_PORT || "8911", 10),
57672
+ host: process.env.API_HOST
57654
57673
  },
57655
57674
  ralph: {
57656
57675
  worktreesDir: process.env.WORKTREES_DIR || "/root/worktrees",
@@ -57660,7 +57679,8 @@ async function main() {
57660
57679
  name: process.env.NODE_NAME || "stack",
57661
57680
  hostname: process.env.HOSTNAME || "localhost"
57662
57681
  }
57663
- });
57682
+ };
57683
+ const stack = new Stack(config);
57664
57684
  process.on("SIGINT", async () => {
57665
57685
  await stack.stop();
57666
57686
  process.exit(0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ebowwa/stack",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Full-stack daemon orchestrator combining unified-router (cross-channel) and node-agent (Ralph orchestration)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/index.ts CHANGED
@@ -94,7 +94,7 @@ interface RalphLoopInfo {
94
94
  // ============================================================
95
95
 
96
96
  export class Stack {
97
- private config: Required<StackConfig>;
97
+ private config: StackConfig;
98
98
  private state: StackState;
99
99
  private router: ReturnType<typeof createChannelRouter>;
100
100
  private memory: ReturnType<typeof createPermissionMemory>;
@@ -104,34 +104,50 @@ export class Stack {
104
104
  private abortController: AbortController | null = null;
105
105
 
106
106
  constructor(config: StackConfig) {
107
+ // Only set defaults for non-channel config
107
108
  this.config = {
108
- ssh: config.ssh ?? { chatDir: "/root/.ssh-chat" },
109
- telegram: config.telegram ?? {},
109
+ ...config,
110
110
  api: config.api ?? { port: 8911 },
111
111
  ralph: config.ralph ?? { worktreesDir: "/root/worktrees", repoUrl: "" },
112
112
  ai: config.ai ?? { model: "GLM-4.7", temperature: 0.7, maxTokens: 4096 },
113
113
  node: config.node ?? { name: "stack", hostname: "localhost" },
114
+ // ssh and telegram remain undefined if not provided
114
115
  };
115
116
 
116
117
  this.state = {
117
118
  started: new Date(),
118
119
  channels: { ssh: false, telegram: false },
119
- api: { enabled: !!this.config.api },
120
+ api: { enabled: !!this.config.api, port: this.config.api?.port },
120
121
  ralphLoops: new Map(),
121
122
  };
122
123
 
123
- // Initialize shared memory
124
+ // Build memory channels dynamically based on enabled channels
125
+ const memoryChannels: Record<string, { memoryFile: string; maxMessages: number }> = {};
126
+ const permissions: Record<string, { canRead: string[] }> = {};
127
+ const enabledChannels: string[] = [];
128
+
129
+ if (this.config.ssh) {
130
+ memoryChannels.ssh = { memoryFile: `${this.config.ssh.chatDir}/memory.json`, maxMessages: 50 };
131
+ enabledChannels.push("ssh");
132
+ }
133
+ if (this.config.telegram) {
134
+ memoryChannels.telegram = { memoryFile: "/root/.telegram-memory.json", maxMessages: 50 };
135
+ enabledChannels.push("telegram");
136
+ }
137
+ if (this.config.api) {
138
+ memoryChannels.api = { memoryFile: "/root/.api-memory.json", maxMessages: 100 };
139
+ enabledChannels.push("api");
140
+ }
141
+
142
+ // Set up cross-channel permissions for enabled channels
143
+ for (const channel of enabledChannels) {
144
+ permissions[channel] = { canRead: enabledChannels.filter(c => c !== channel) };
145
+ }
146
+
147
+ // Initialize shared memory (empty if no channels)
124
148
  this.memory = createPermissionMemory({
125
- channels: {
126
- ssh: { memoryFile: `${this.config.ssh.chatDir}/memory.json`, maxMessages: 50 },
127
- telegram: { memoryFile: "/root/.telegram-memory.json", maxMessages: 50 },
128
- api: { memoryFile: "/root/.api-memory.json", maxMessages: 100 },
129
- },
130
- permissions: {
131
- ssh: { canRead: ["telegram", "api"] },
132
- telegram: { canRead: ["ssh", "api"] },
133
- api: { canRead: ["ssh", "telegram"] },
134
- },
149
+ channels: memoryChannels,
150
+ permissions,
135
151
  });
136
152
 
137
153
  // Initialize router
@@ -140,7 +156,7 @@ export class Stack {
140
156
  serverName: this.config.node.name,
141
157
  hostname: this.config.node.hostname,
142
158
  packageName: "@ebowwa/stack",
143
- version: "0.1.0",
159
+ version: "0.1.1",
144
160
  },
145
161
  });
146
162
 
@@ -376,7 +392,7 @@ export class Stack {
376
392
 
377
393
  this.abortController = new AbortController();
378
394
 
379
- // Register channels
395
+ // Register channels (only if configured)
380
396
  await this.registerSSH();
381
397
  await this.registerTelegram();
382
398
 
@@ -390,10 +406,15 @@ export class Stack {
390
406
  this.startAPI();
391
407
 
392
408
  console.log("[Stack] Running!");
393
- console.log(` - SSH: echo 'msg' > ${this.config.ssh.chatDir}/in`);
409
+ if (this.state.channels.ssh) {
410
+ console.log(` - SSH: echo 'msg' > ${this.config.ssh!.chatDir}/in`);
411
+ }
394
412
  if (this.state.channels.telegram) {
395
413
  console.log(" - Telegram: enabled");
396
414
  }
415
+ if (this.state.api.enabled) {
416
+ console.log(` - API: :${this.state.api.port}`);
417
+ }
397
418
  console.log(" - Commands: /ralph start|list|stop, /status, /memory <cmd>");
398
419
 
399
420
  // Keep running
@@ -420,17 +441,26 @@ export class Stack {
420
441
  // ============================================================
421
442
 
422
443
  async function main() {
423
- const stack = new Stack({
424
- ssh: {
425
- chatDir: process.env.SSH_CHAT_DIR || "/root/.ssh-chat",
426
- pollInterval: 500,
427
- },
428
- telegram: {
429
- botToken: process.env.TELEGRAM_BOT_TOKEN,
430
- allowedChats: process.env.TELEGRAM_CHAT_ID ? [parseInt(process.env.TELEGRAM_CHAT_ID, 10)] : undefined,
431
- },
444
+ // Build config - only enable channels when explicitly configured
445
+ const config: StackConfig = {
446
+ // SSH only enabled if SSH_CHAT_DIR is set
447
+ ...(process.env.SSH_CHAT_DIR ? {
448
+ ssh: {
449
+ chatDir: process.env.SSH_CHAT_DIR,
450
+ pollInterval: parseInt(process.env.SSH_POLL_INTERVAL || "500", 10),
451
+ }
452
+ } : {}),
453
+ // Telegram only enabled if bot token is set
454
+ ...(process.env.TELEGRAM_BOT_TOKEN ? {
455
+ telegram: {
456
+ botToken: process.env.TELEGRAM_BOT_TOKEN,
457
+ allowedChats: process.env.TELEGRAM_CHAT_ID ? [parseInt(process.env.TELEGRAM_CHAT_ID, 10)] : undefined,
458
+ }
459
+ } : {}),
460
+ // API enabled by default
432
461
  api: {
433
462
  port: parseInt(process.env.API_PORT || "8911", 10),
463
+ host: process.env.API_HOST,
434
464
  },
435
465
  ralph: {
436
466
  worktreesDir: process.env.WORKTREES_DIR || "/root/worktrees",
@@ -440,7 +470,9 @@ async function main() {
440
470
  name: process.env.NODE_NAME || "stack",
441
471
  hostname: process.env.HOSTNAME || "localhost",
442
472
  },
443
- });
473
+ };
474
+
475
+ const stack = new Stack(config);
444
476
 
445
477
  // Handle shutdown
446
478
  process.on("SIGINT", async () => {