@inceptionstack/roundhouse 0.5.8 → 0.5.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inceptionstack/roundhouse",
3
- "version": "0.5.8",
3
+ "version": "0.5.10",
4
4
  "type": "module",
5
5
  "description": "Multi-platform chat gateway that routes messages through a configured AI agent",
6
6
  "license": "MIT",
@@ -105,9 +105,23 @@ export async function cronAdd(store: CronStore, positional: string[], flags: Rec
105
105
  }
106
106
 
107
107
  export async function cronList(store: CronStore, _positional: string[], flags: Record<string, string>): Promise<void> {
108
- const jobs = await store.listJobs();
108
+ let jobs = await store.listJobs();
109
+
110
+ // Hide completed one-shot jobs unless --all flag is set
111
+ if (!flags.all) {
112
+ const filtered: typeof jobs = [];
113
+ for (const j of jobs) {
114
+ if (j.schedule.type === "once") {
115
+ const state = await store.getState(j.id);
116
+ if (state.totalRuns > 0) continue;
117
+ }
118
+ filtered.push(j);
119
+ }
120
+ jobs = filtered;
121
+ }
122
+
109
123
  if (jobs.length === 0) {
110
- console.log("No cron jobs configured.");
124
+ console.log("No active cron jobs.");
111
125
  return;
112
126
  }
113
127
  if (flags.json) {
@@ -6,8 +6,8 @@
6
6
  */
7
7
 
8
8
  import { getAgentFactory } from "../agents/registry";
9
- // TODO: route through TransportAdapter.notify() when multi-transport lands
10
9
  import { sendTelegramToMany } from "../transports/telegram/notify";
10
+ import { sendIpc } from "../ipc";
11
11
  import { CronStore, generateRunId } from "./store";
12
12
  import { buildTemplateContext, renderTemplate } from "./template";
13
13
  import type { CronJobConfig, CronRunRecord } from "./types";
@@ -20,6 +20,7 @@ export class CronRunner {
20
20
  constructor(
21
21
  private store: CronStore,
22
22
  private agentConfig?: GatewayConfig["agent"],
23
+ private notifyFn?: (text: string) => Promise<void>,
23
24
  ) {}
24
25
 
25
26
  async runJob(
@@ -127,10 +128,9 @@ export class CronRunner {
127
128
  }
128
129
 
129
130
  private async notify(job: CronJobConfig, record: CronRunRecord): Promise<void> {
131
+ // Apply onlyOn filter if configured (for both routes)
130
132
  const tg = job.notify?.telegram;
131
- if (!tg?.chatIds?.length) return;
132
-
133
- if (!shouldNotify(tg.onlyOn, record.status)) return;
133
+ if (tg?.onlyOn && !shouldNotify(tg.onlyOn, record.status)) return;
134
134
 
135
135
  const icon = runStatusIcon(record.status);
136
136
  const dur = `${(record.durationMs / 1000).toFixed(1)}s`;
@@ -145,6 +145,27 @@ export class CronRunner {
145
145
  body = `${header}\nError: ${record.error.slice(0, NOTIFY_MAX_ERROR_CHARS)}`;
146
146
  }
147
147
 
148
- await sendTelegramToMany(tg.chatIds, body);
148
+ // Route 1: Explicit Telegram chat IDs configured on the job
149
+ if (tg?.chatIds?.length) {
150
+ await sendTelegramToMany(tg.chatIds, body);
151
+ return;
152
+ }
153
+
154
+ // Route 2: Direct callback from gateway (no loopback socket)
155
+ if (this.notifyFn) {
156
+ try {
157
+ await this.notifyFn(body);
158
+ } catch (err) {
159
+ console.warn(`[cron] ${job.id} notify callback failed:`, (err as Error).message);
160
+ }
161
+ return;
162
+ }
163
+
164
+ // Route 3: Fallback to IPC (for CLI-triggered runs outside gateway)
165
+ try {
166
+ await sendIpc({ type: "notify", text: body });
167
+ } catch {
168
+ console.warn(`[cron] ${job.id} IPC notify failed (gateway not running?)`);
169
+ }
149
170
  }
150
171
  }
@@ -41,9 +41,9 @@ export class CronSchedulerService {
41
41
  private lastHeartbeatAt = 0; // 0 = fires on first tick after startup (intentional catch-up)
42
42
  private tickMs: number;
43
43
 
44
- constructor(private opts?: { tickMs?: number; agentConfig?: GatewayConfig["agent"]; notifyChatIds?: number[] }) {
44
+ constructor(private opts?: { tickMs?: number; agentConfig?: GatewayConfig["agent"]; notifyChatIds?: number[]; notifyFn?: (text: string) => Promise<void> }) {
45
45
  this.store = new CronStore();
46
- this.runner = new CronRunner(this.store, this.opts?.agentConfig);
46
+ this.runner = new CronRunner(this.store, this.opts?.agentConfig, this.opts?.notifyFn);
47
47
  this.queue = new PQueue({ concurrency: 1 });
48
48
  this.tickMs = this.opts?.tickMs ?? TICK_MS;
49
49
  }
@@ -88,10 +88,19 @@ export class CronSchedulerService {
88
88
 
89
89
  async listJobs(): Promise<Array<{ job: CronJobConfig; state: CronJobState }>> {
90
90
  await this.reload();
91
- return this.jobs.map((job) => ({
92
- job,
93
- state: this.states.get(job.id) ?? emptyState(job.id),
94
- }));
91
+ return this.jobs
92
+ .filter((job) => {
93
+ // Hide completed one-shot jobs (already fired, won't run again)
94
+ if (job.schedule.type === "once") {
95
+ const state = this.states.get(job.id);
96
+ if (state && state.totalRuns > 0) return false;
97
+ }
98
+ return true;
99
+ })
100
+ .map((job) => ({
101
+ job,
102
+ state: this.states.get(job.id) ?? emptyState(job.id),
103
+ }));
95
104
  }
96
105
 
97
106
  async trigger(jobId: string): Promise<void> {
@@ -325,6 +325,12 @@ export class Gateway {
325
325
  this.cronScheduler = new CronSchedulerService({
326
326
  agentConfig: this.config.agent,
327
327
  notifyChatIds: this.config.chat.notifyChatIds,
328
+ notifyFn: async (text: string) => {
329
+ const chatIds = this.config.chat.notifyChatIds;
330
+ if (chatIds?.length && this.transport) {
331
+ await this.transport.notify(chatIds, text);
332
+ }
333
+ },
328
334
  });
329
335
  try {
330
336
  await this.cronScheduler.start();
@@ -52,3 +52,117 @@ Users can also manage jobs via Telegram:
52
52
  - `/crons trigger <id>` — run now
53
53
  - `/crons pause <id>` — disable
54
54
  - `/crons resume <id>` — enable
55
+
56
+ ## roundhouse message
57
+
58
+ Send a message to the user via all active transports (Telegram, etc.) without spawning an agent turn.
59
+
60
+ **Usage:**
61
+ ```bash
62
+ roundhouse message "Hello from the server!"
63
+ roundhouse message --session main "Targeted to primary chat"
64
+ ```
65
+
66
+ ## Git & GitHub (gh CLI)
67
+
68
+ Use `gh` CLI for all GitHub operations. It handles authentication automatically.
69
+
70
+ **Common patterns:**
71
+ ```bash
72
+ # Push branches
73
+ git push origin <branch>
74
+
75
+ # Create PRs
76
+ gh pr create --base main --head <branch> --title "..." --body "..."
77
+
78
+ # Merge PRs
79
+ gh pr merge <number> --squash --admin
80
+
81
+ # Check CI status
82
+ gh pr checks <number>
83
+ gh run list --limit 5
84
+
85
+ # Create releases / tags
86
+ git tag v1.2.3 && git push origin v1.2.3
87
+ ```
88
+
89
+ **Prefer `gh` over raw git for:**
90
+ - PR creation and merging
91
+ - CI/workflow status checks
92
+ - Release creation
93
+ - Repository settings
94
+
95
+ ## mcporter (MCP Server CLI)
96
+
97
+ Call tools from configured MCP servers (AWS APIs, docs, infrastructure).
98
+
99
+ ```bash
100
+ mcporter list # show available servers
101
+ mcporter list <server> --schema # show tools + parameters
102
+ mcporter call <server>.<tool> key=val # call a tool
103
+ ```
104
+
105
+ **Examples:**
106
+ ```bash
107
+ mcporter call 'aws-mcp.sts_GetCallerIdentity()'
108
+ mcporter call aws-mcp.s3_ListBuckets
109
+ mcporter call 'aws-documentation.search(query: "Lambda timeout")'
110
+ ```
111
+
112
+ > Ensure PATH includes `~/.local/bin` for `mcporter`/`uvx` discovery.
113
+
114
+ ## playwright-cli (Browser Automation)
115
+
116
+ Headless browser automation for testing web UIs, scraping, screenshots.
117
+
118
+ **Core workflow:** open → snapshot → interact → close
119
+
120
+ ```bash
121
+ playwright-cli open "https://example.com" # launch + navigate
122
+ playwright-cli snapshot # accessibility tree with [ref=eN]
123
+ playwright-cli click e5 # click element by ref
124
+ playwright-cli fill e3 "search query" # type into input
125
+ playwright-cli screenshot # save viewport PNG
126
+ playwright-cli close # close browser
127
+ ```
128
+
129
+ **Other commands:**
130
+ ```bash
131
+ playwright-cli requests # list network requests
132
+ playwright-cli request <index> # show request details
133
+ playwright-cli cookie-list # list cookies
134
+ playwright-cli eval "document.title" # run JS in page
135
+ playwright-cli pdf # save page as PDF
136
+ ```
137
+
138
+ **Use for:** E2E testing, visual verification, form automation, web scraping.
139
+ **NOT for:** API-only testing (use curl), static file reading.
140
+
141
+ ## codex exec
142
+
143
+ Delegate tasks to Codex CLI (architecture design, parallel research, code review).
144
+
145
+ ```bash
146
+ codex exec "Design a retry mechanism with exponential backoff for this module"
147
+ ```
148
+
149
+ Good for: brainstorming, getting a second opinion, architecture decisions, reducing bikeshedding.
150
+
151
+ ## Memory Management
152
+
153
+ Durable state files the agent can read and update:
154
+
155
+ - `~/MEMORY.md` — stable facts, preferences, project context (edit existing entries, don't append duplicates)
156
+ - `~/daily/YYYY-MM-DD/front-page.md` — today's work log, decisions, open loops
157
+ - `~/daily/YYYY-MM-DD/articles/` — detailed write-ups for durable topics
158
+
159
+ ## AWS CLI
160
+
161
+ Full AWS access via instance role (us-east-1). No credentials needed.
162
+
163
+ ```bash
164
+ aws sts get-caller-identity
165
+ aws s3 ls
166
+ aws logs tail /aws/lambda/<name> --since 1h
167
+ aws cloudformation describe-stacks --stack-name <name>
168
+ ```