ashral 0.1.1 → 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.
package/dist/cli.js CHANGED
@@ -5,6 +5,9 @@ const commander_1 = require("commander");
5
5
  const runSession_1 = require("./runner/runSession");
6
6
  const claudeAdapter_1 = require("./adapters/claudeAdapter");
7
7
  const ntfyNotifier_1 = require("./notifications/ntfyNotifier");
8
+ const firebaseNotifier_1 = require("./notifications/firebaseNotifier");
9
+ const multiNotifier_1 = require("./notifications/multiNotifier");
10
+ const loadEnv_1 = require("./config/loadEnv");
8
11
  // ── ANSI helpers ─────────────────────────────────────────────────────────────
9
12
  const DIM = '\x1b[2m';
10
13
  const RESET = '\x1b[0m';
@@ -29,10 +32,13 @@ function makeEventHandler(sessionName, notifier) {
29
32
  switch (event.type) {
30
33
  case 'status_changed': {
31
34
  process.stderr.write(`\n${tag} ${ts} ${CYAN}status${RESET} ${event.from} → ${event.to}\n`);
32
- if (!notifier)
35
+ if (!notifier) {
36
+ process.stderr.write(`${tag} ${ts} ${DIM}(no notifier configured)${RESET}\n`);
33
37
  break;
38
+ }
34
39
  // Notify when Claude needs the user's attention
35
40
  if (event.to === 'waiting_for_input') {
41
+ process.stderr.write(`${tag} ${ts} ${YELLOW}notify${RESET} sending push notification...\n`);
36
42
  notifier.send({
37
43
  title: `Ashral - ${label}`,
38
44
  body: 'Claude is waiting for your input.',
@@ -40,6 +46,7 @@ function makeEventHandler(sessionName, notifier) {
40
46
  });
41
47
  }
42
48
  else if (event.to === 'approval_required') {
49
+ process.stderr.write(`${tag} ${ts} ${YELLOW}notify${RESET} sending push notification...\n`);
43
50
  notifier.send({
44
51
  title: `Ashral - ${label} [approval]`,
45
52
  body: 'Claude needs your approval before continuing.',
@@ -47,6 +54,7 @@ function makeEventHandler(sessionName, notifier) {
47
54
  });
48
55
  }
49
56
  else if (event.to === 'error') {
57
+ process.stderr.write(`${tag} ${ts} ${YELLOW}notify${RESET} sending push notification...\n`);
50
58
  notifier.send({
51
59
  title: `Ashral - ${label} [error]`,
52
60
  body: 'Claude encountered an error.',
@@ -68,15 +76,52 @@ function makeEventHandler(sessionName, notifier) {
68
76
  };
69
77
  }
70
78
  // ── Notifier setup ────────────────────────────────────────────────────────────
71
- // Resolves a notifier from --notify-url flag or ASHRAL_NTFY_URL env var.
72
- // Returns null (silent) if neither is set.
73
- function resolveNotifier(flagUrl) {
74
- const url = flagUrl ?? process.env.ASHRAL_NTFY_URL;
75
- if (!url)
76
- return null;
77
- return new ntfyNotifier_1.NtfyNotifier(url);
79
+ // Builds ALL configured notifiers and fans out to them in parallel via MultiNotifier.
80
+ // Firebase and ntfy are independent both fire when both are configured.
81
+ //
82
+ // Config (set in ~/.ashral/.env):
83
+ // ASHRAL_FIREBASE_SERVICE_ACCOUNT path to service account JSON, or the JSON string itself
84
+ // ASHRAL_FCM_TOKEN FCM device registration token
85
+ // ASHRAL_NTFY_URL e.g. https://ntfy.sh/your-topic
86
+ function resolveNotifier(ntfyFlagUrl) {
87
+ const active = [];
88
+ const labels = [];
89
+ // ── Firebase ──────────────────────────────────────────────────────────────
90
+ const serviceAccount = process.env.ASHRAL_FIREBASE_SERVICE_ACCOUNT;
91
+ const deviceToken = process.env.ASHRAL_FCM_TOKEN;
92
+ if (serviceAccount && deviceToken) {
93
+ try {
94
+ active.push(new firebaseNotifier_1.FirebaseNotifier({ serviceAccount, deviceToken }));
95
+ labels.push('Firebase');
96
+ }
97
+ catch (err) {
98
+ const msg = err instanceof Error ? err.message : String(err);
99
+ process.stderr.write(`[ashral] Firebase init failed: ${msg}\n`);
100
+ }
101
+ }
102
+ else {
103
+ if (!serviceAccount)
104
+ process.stderr.write(`[ashral] ${DIM}ASHRAL_FIREBASE_SERVICE_ACCOUNT not set${RESET}\n`);
105
+ if (!deviceToken)
106
+ process.stderr.write(`[ashral] ${DIM}ASHRAL_FCM_TOKEN not set${RESET}\n`);
107
+ }
108
+ // ── ntfy ──────────────────────────────────────────────────────────────────
109
+ const ntfyUrl = ntfyFlagUrl ?? process.env.ASHRAL_NTFY_URL;
110
+ if (ntfyUrl) {
111
+ active.push(new ntfyNotifier_1.NtfyNotifier(ntfyUrl));
112
+ labels.push('ntfy');
113
+ }
114
+ else {
115
+ process.stderr.write(`[ashral] ${DIM}ASHRAL_NTFY_URL not set${RESET}\n`);
116
+ }
117
+ if (active.length === 0)
118
+ return { notifier: null, labels: [] };
119
+ if (active.length === 1)
120
+ return { notifier: active[0], labels };
121
+ return { notifier: new multiNotifier_1.MultiNotifier(active), labels };
78
122
  }
79
123
  // ── CLI definition ────────────────────────────────────────────────────────────
124
+ (0, loadEnv_1.loadEnvFile)();
80
125
  const program = new commander_1.Command();
81
126
  program
82
127
  .name('ashral')
@@ -93,12 +138,16 @@ runCmd
93
138
  .action(async (options, command) => {
94
139
  const passthroughArgs = command.args;
95
140
  const adapter = new claudeAdapter_1.ClaudeAdapter();
96
- const notifier = resolveNotifier(options.notifyUrl);
141
+ const { notifier, labels } = resolveNotifier(options.notifyUrl);
142
+ process.stderr.write('\n');
97
143
  if (options.name) {
98
- process.stderr.write(`\n[ashral] Starting session: ${options.name}\n`);
144
+ process.stderr.write(`[ashral] Starting session: ${options.name}\n`);
145
+ }
146
+ if (labels.length > 0) {
147
+ process.stderr.write(`[ashral] Push notifications active: ${labels.join(' + ')}\n`);
99
148
  }
100
- if (notifier) {
101
- process.stderr.write(`[ashral] Push notifications enabled.\n`);
149
+ else {
150
+ process.stderr.write(`[ashral] Push notifications: none configured\n`);
102
151
  }
103
152
  process.stderr.write('\n');
104
153
  try {
@@ -115,5 +164,23 @@ runCmd
115
164
  process.exit(1);
116
165
  }
117
166
  });
167
+ // ── notify test ───────────────────────────────────────────────────────────────
168
+ program
169
+ .command('notify:test')
170
+ .description('Send a test notification to all configured providers')
171
+ .action(async () => {
172
+ const { notifier, labels } = resolveNotifier(undefined);
173
+ if (!notifier) {
174
+ process.stderr.write('[ashral] No notifiers configured. Check ~/.ashral/.env\n');
175
+ process.exit(1);
176
+ }
177
+ process.stderr.write(`[ashral] Sending test notification via: ${labels.join(' + ')}\n`);
178
+ await notifier.send({
179
+ title: 'Ashral test',
180
+ body: 'If you see this, notifications are working.',
181
+ priority: 'high',
182
+ });
183
+ process.stderr.write('[ashral] Done.\n');
184
+ });
118
185
  program.parse(process.argv);
119
186
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Loads .env files in priority order (later files do NOT override earlier ones):
3
+ * 1. ~/.ashral/.env — global user config, credentials live here
4
+ * 2. <cwd>/.env — project-level overrides
5
+ *
6
+ * This means Firebase credentials set once in ~/.ashral/.env work from any directory.
7
+ */
8
+ export declare function loadEnvFile(): void;
9
+ //# sourceMappingURL=loadEnv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadEnv.d.ts","sourceRoot":"","sources":["../../src/config/loadEnv.ts"],"names":[],"mappings":"AAuCA;;;;;;GAMG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAGlC"}
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadEnvFile = loadEnvFile;
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ const os_1 = require("os");
7
+ function stripWrappingQuotes(value) {
8
+ if ((value.startsWith('"') && value.endsWith('"')) ||
9
+ (value.startsWith("'") && value.endsWith("'"))) {
10
+ return value.slice(1, -1);
11
+ }
12
+ return value;
13
+ }
14
+ function loadFile(envPath) {
15
+ if (!(0, fs_1.existsSync)(envPath))
16
+ return;
17
+ const content = (0, fs_1.readFileSync)(envPath, 'utf-8');
18
+ for (const rawLine of content.split(/\r?\n/)) {
19
+ const line = rawLine.trim();
20
+ if (!line || line.startsWith('#'))
21
+ continue;
22
+ const exportPrefix = line.startsWith('export ') ? 'export '.length : 0;
23
+ const normalized = line.slice(exportPrefix);
24
+ const separatorIndex = normalized.indexOf('=');
25
+ if (separatorIndex <= 0)
26
+ continue;
27
+ const key = normalized.slice(0, separatorIndex).trim();
28
+ const value = stripWrappingQuotes(normalized.slice(separatorIndex + 1).trim());
29
+ if (!key || process.env[key] !== undefined)
30
+ continue;
31
+ process.env[key] = value;
32
+ }
33
+ }
34
+ /**
35
+ * Loads .env files in priority order (later files do NOT override earlier ones):
36
+ * 1. ~/.ashral/.env — global user config, credentials live here
37
+ * 2. <cwd>/.env — project-level overrides
38
+ *
39
+ * This means Firebase credentials set once in ~/.ashral/.env work from any directory.
40
+ */
41
+ function loadEnvFile() {
42
+ loadFile((0, path_1.join)((0, os_1.homedir)(), '.ashral', '.env'));
43
+ loadFile((0, path_1.resolve)(process.cwd(), '.env'));
44
+ }
45
+ //# sourceMappingURL=loadEnv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadEnv.js","sourceRoot":"","sources":["../../src/config/loadEnv.ts"],"names":[],"mappings":";;AA8CA,kCAGC;AAjDD,2BAA8C;AAC9C,+BAAqC;AACrC,2BAA6B;AAE7B,SAAS,mBAAmB,CAAC,KAAa;IACxC,IACE,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC9C,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAC9C,CAAC;QACD,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,QAAQ,CAAC,OAAe;IAC/B,IAAI,CAAC,IAAA,eAAU,EAAC,OAAO,CAAC;QAAE,OAAO;IAEjC,MAAM,OAAO,GAAG,IAAA,iBAAY,EAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAE/C,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAE5B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAE5C,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QACvE,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAC5C,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAE/C,IAAI,cAAc,IAAI,CAAC;YAAE,SAAS;QAElC,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,IAAI,EAAE,CAAC;QACvD,MAAM,KAAK,GAAG,mBAAmB,CAAC,UAAU,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAE/E,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS;YAAE,SAAS;QACrD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAC3B,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,WAAW;IACzB,QAAQ,CAAC,IAAA,WAAI,EAAC,IAAA,YAAO,GAAE,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7C,QAAQ,CAAC,IAAA,cAAO,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { type ServiceAccount } from 'firebase-admin/app';
2
+ import type { Notifier, NotificationPayload } from './notifier';
3
+ export interface FirebaseNotifierConfig {
4
+ /**
5
+ * Path to a Firebase service account JSON file,
6
+ * OR the JSON content as a string,
7
+ * OR a parsed service account object.
8
+ */
9
+ serviceAccount: string | ServiceAccount;
10
+ /** FCM device registration token for the target phone */
11
+ deviceToken: string;
12
+ }
13
+ export declare class FirebaseNotifier implements Notifier {
14
+ private readonly deviceToken;
15
+ constructor(config: FirebaseNotifierConfig);
16
+ send(payload: NotificationPayload): Promise<void>;
17
+ private parseServiceAccount;
18
+ }
19
+ //# sourceMappingURL=firebaseNotifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firebaseNotifier.d.ts","sourceRoot":"","sources":["../../src/notifications/firebaseNotifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEvF,OAAO,KAAK,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAiChE,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,cAAc,EAAE,MAAM,GAAG,cAAc,CAAC;IACxC,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,gBAAiB,YAAW,QAAQ;IAC/C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;gBAEzB,MAAM,EAAE,sBAAsB;IAcpC,IAAI,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAqCvD,OAAO,CAAC,mBAAmB;CAW5B"}
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FirebaseNotifier = void 0;
4
+ const app_1 = require("firebase-admin/app");
5
+ const messaging_1 = require("firebase-admin/messaging");
6
+ // FCM message-level delivery priority (wakes up the device)
7
+ const ANDROID_MESSAGE_PRIORITY = {
8
+ low: 'normal',
9
+ normal: 'high',
10
+ high: 'high',
11
+ urgent: 'high',
12
+ };
13
+ // Android notification display priority (controls heads-up / sound)
14
+ const ANDROID_NOTIFICATION_PRIORITY = {
15
+ low: 'default',
16
+ normal: 'high',
17
+ high: 'high',
18
+ urgent: 'max',
19
+ };
20
+ // APNs interrupt level for iOS
21
+ const APNS_INTERRUPT_LEVEL = {
22
+ low: 'passive',
23
+ normal: 'active',
24
+ high: 'time-sensitive',
25
+ urgent: 'time-sensitive',
26
+ };
27
+ class FirebaseNotifier {
28
+ constructor(config) {
29
+ this.deviceToken = config.deviceToken;
30
+ // Initialise the Admin SDK once — safe to call from multiple sessions
31
+ if ((0, app_1.getApps)().length === 0) {
32
+ const sa = typeof config.serviceAccount === 'string'
33
+ ? this.parseServiceAccount(config.serviceAccount)
34
+ : config.serviceAccount;
35
+ (0, app_1.initializeApp)({ credential: (0, app_1.cert)(sa) });
36
+ }
37
+ }
38
+ async send(payload) {
39
+ const priority = payload.priority ?? 'normal';
40
+ try {
41
+ const messageId = await (0, messaging_1.getMessaging)().send({
42
+ token: this.deviceToken,
43
+ notification: {
44
+ title: payload.title,
45
+ body: payload.body,
46
+ },
47
+ android: {
48
+ // High priority wakes the device even in Doze mode
49
+ priority: ANDROID_MESSAGE_PRIORITY[priority],
50
+ notification: {
51
+ // No channelId — let FCM create the default channel automatically,
52
+ // same as the Firebase Console test does.
53
+ sound: 'default',
54
+ priority: ANDROID_NOTIFICATION_PRIORITY[priority],
55
+ defaultSound: true,
56
+ },
57
+ },
58
+ apns: {
59
+ payload: {
60
+ aps: {
61
+ sound: 'default',
62
+ interruptionLevel: APNS_INTERRUPT_LEVEL[priority],
63
+ },
64
+ },
65
+ },
66
+ });
67
+ process.stderr.write(`[ashral] Firebase sent OK — messageId: ${messageId}\n`);
68
+ }
69
+ catch (err) {
70
+ const msg = err instanceof Error ? err.message : String(err);
71
+ process.stderr.write(`[ashral] Firebase error: ${msg}\n`);
72
+ }
73
+ }
74
+ parseServiceAccount(input) {
75
+ // Accept either a file path or raw JSON string
76
+ if (input.trim().startsWith('{')) {
77
+ return JSON.parse(input);
78
+ }
79
+ // It's a file path — read synchronously (only at startup, not on each send)
80
+ const { readFileSync } = require('fs');
81
+ const content = readFileSync(input, 'utf-8');
82
+ return JSON.parse(content);
83
+ }
84
+ }
85
+ exports.FirebaseNotifier = FirebaseNotifier;
86
+ //# sourceMappingURL=firebaseNotifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firebaseNotifier.js","sourceRoot":"","sources":["../../src/notifications/firebaseNotifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { Notifier, NotificationPayload } from './notifier';
2
+ /**
3
+ * Fans out a single send() call to every configured notifier in parallel.
4
+ * One failing notifier never blocks the others.
5
+ */
6
+ export declare class MultiNotifier implements Notifier {
7
+ private readonly notifiers;
8
+ constructor(notifiers: Notifier[]);
9
+ send(payload: NotificationPayload): Promise<void>;
10
+ }
11
+ //# sourceMappingURL=multiNotifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multiNotifier.d.ts","sourceRoot":"","sources":["../../src/notifications/multiNotifier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEhE;;;GAGG;AACH,qBAAa,aAAc,YAAW,QAAQ;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAa;gBAE3B,SAAS,EAAE,QAAQ,EAAE;IAI3B,IAAI,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;CAGxD"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MultiNotifier = void 0;
4
+ /**
5
+ * Fans out a single send() call to every configured notifier in parallel.
6
+ * One failing notifier never blocks the others.
7
+ */
8
+ class MultiNotifier {
9
+ constructor(notifiers) {
10
+ this.notifiers = notifiers;
11
+ }
12
+ async send(payload) {
13
+ await Promise.allSettled(this.notifiers.map((n) => n.send(payload)));
14
+ }
15
+ }
16
+ exports.MultiNotifier = MultiNotifier;
17
+ //# sourceMappingURL=multiNotifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multiNotifier.js","sourceRoot":"","sources":["../../src/notifications/multiNotifier.ts"],"names":[],"mappings":";;;AAEA;;;GAGG;AACH,MAAa,aAAa;IAGxB,YAAY,SAAqB;QAC/B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,OAA4B;QACrC,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACvE,CAAC;CACF;AAVD,sCAUC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ashral",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Control center for AI coding agents",
5
5
  "main": "dist/cli.js",
6
6
  "bin": {
@@ -20,6 +20,7 @@
20
20
  },
21
21
  "dependencies": {
22
22
  "commander": "^12.1.0",
23
+ "firebase-admin": "^13.7.0",
23
24
  "node-pty": "^1.0.0"
24
25
  },
25
26
  "devDependencies": {