ashral 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.
- package/dist/adapters/claudeAdapter.d.ts.map +1 -1
- package/dist/adapters/claudeAdapter.js +4 -1
- package/dist/adapters/claudeAdapter.js.map +1 -1
- package/dist/cli.js +79 -12
- package/dist/cli.js.map +1 -1
- package/dist/config/loadEnv.d.ts +9 -0
- package/dist/config/loadEnv.d.ts.map +1 -0
- package/dist/config/loadEnv.js +45 -0
- package/dist/config/loadEnv.js.map +1 -0
- package/dist/notifications/firebaseNotifier.d.ts +19 -0
- package/dist/notifications/firebaseNotifier.d.ts.map +1 -0
- package/dist/notifications/firebaseNotifier.js +86 -0
- package/dist/notifications/firebaseNotifier.js.map +1 -0
- package/dist/notifications/multiNotifier.d.ts +11 -0
- package/dist/notifications/multiNotifier.d.ts.map +1 -0
- package/dist/notifications/multiNotifier.js +17 -0
- package/dist/notifications/multiNotifier.js.map +1 -0
- package/package.json +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claudeAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/claudeAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAyDtD,qBAAa,aAAc,SAAQ,WAAW;IAC5C,QAAQ,CAAC,SAAS,YAAY;IAE9B,UAAU,CAAC,eAAe,EAAE,MAAM,EAAE,GAAG,cAAc;
|
|
1
|
+
{"version":3,"file":"claudeAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/claudeAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAyDtD,qBAAa,aAAc,SAAQ,WAAW;IAC5C,QAAQ,CAAC,SAAS,YAAY;IAE9B,UAAU,CAAC,eAAe,EAAE,MAAM,EAAE,GAAG,cAAc;IAWrD,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,GAAG,aAAa,GAAG,IAAI;IAqB7E,OAAO,CAAC,OAAO;CAGhB"}
|
|
@@ -56,8 +56,11 @@ class ClaudeAdapter extends baseAdapter_1.BaseAdapter {
|
|
|
56
56
|
this.agentName = 'claude';
|
|
57
57
|
}
|
|
58
58
|
getCommand(passthroughArgs) {
|
|
59
|
+
// On Windows, npm CLIs are installed as .cmd wrappers — node-pty needs the
|
|
60
|
+
// explicit extension since it doesn't go through the shell to resolve it.
|
|
61
|
+
const command = process.platform === 'win32' ? 'claude.cmd' : 'claude';
|
|
59
62
|
return {
|
|
60
|
-
command
|
|
63
|
+
command,
|
|
61
64
|
args: passthroughArgs,
|
|
62
65
|
// No extra env needed — claude picks up the caller's environment
|
|
63
66
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claudeAdapter.js","sourceRoot":"","sources":["../../src/adapters/claudeAdapter.ts"],"names":[],"mappings":";;;AAAA,+CAAiE;AAGjE,oEAAoE;AACpE,MAAM,OAAO,GAAG,mDAAmD,CAAC;AAEpE,SAAS,SAAS,CAAC,GAAW;IAC5B,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AAClC,CAAC;AAED;;;;;GAKG;AAEH,4EAA4E;AAC5E,MAAM,iBAAiB,GAAG;IACxB,iBAAiB;IACjB,aAAa;IACb,WAAW;IACX,WAAW;IACX,UAAU;IACV,yBAAyB;IACzB,eAAe;CAChB,CAAC;AAEF,uDAAuD;AACvD,MAAM,gBAAgB,GAAG;IACvB,SAAS,EAAgB,uBAAuB;IAChD,SAAS,EAAgB,0FAA0F;IACnH,gBAAgB,EAAS,sDAAsD;IAC/E,iBAAiB,EAAQ,iDAAiD;IAC1E,iBAAiB,EAAS,qDAAqD;IAC/E,sBAAsB;IACtB,0BAA0B;IAC1B,cAAc;CACf,CAAC;AAEF,gCAAgC;AAChC,MAAM,gBAAgB,GAAG;IACvB,iCAAiC;IACjC,qCAAqC;IACrC,6BAA6B;IAC7B,iBAAiB;CAClB,CAAC;AAEF,+BAA+B;AAC/B,MAAM,cAAc,GAAG;IACrB,WAAW;IACX,cAAc;IACd,qBAAqB;IACrB,oBAAoB;IACpB,oBAAoB;IACpB,4BAA4B;CAC7B,CAAC;AAEF,MAAa,aAAc,SAAQ,yBAAW;IAA9C;;QACW,cAAS,GAAG,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"claudeAdapter.js","sourceRoot":"","sources":["../../src/adapters/claudeAdapter.ts"],"names":[],"mappings":";;;AAAA,+CAAiE;AAGjE,oEAAoE;AACpE,MAAM,OAAO,GAAG,mDAAmD,CAAC;AAEpE,SAAS,SAAS,CAAC,GAAW;IAC5B,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AAClC,CAAC;AAED;;;;;GAKG;AAEH,4EAA4E;AAC5E,MAAM,iBAAiB,GAAG;IACxB,iBAAiB;IACjB,aAAa;IACb,WAAW;IACX,WAAW;IACX,UAAU;IACV,yBAAyB;IACzB,eAAe;CAChB,CAAC;AAEF,uDAAuD;AACvD,MAAM,gBAAgB,GAAG;IACvB,SAAS,EAAgB,uBAAuB;IAChD,SAAS,EAAgB,0FAA0F;IACnH,gBAAgB,EAAS,sDAAsD;IAC/E,iBAAiB,EAAQ,iDAAiD;IAC1E,iBAAiB,EAAS,qDAAqD;IAC/E,sBAAsB;IACtB,0BAA0B;IAC1B,cAAc;CACf,CAAC;AAEF,gCAAgC;AAChC,MAAM,gBAAgB,GAAG;IACvB,iCAAiC;IACjC,qCAAqC;IACrC,6BAA6B;IAC7B,iBAAiB;CAClB,CAAC;AAEF,+BAA+B;AAC/B,MAAM,cAAc,GAAG;IACrB,WAAW;IACX,cAAc;IACd,qBAAqB;IACrB,oBAAoB;IACpB,oBAAoB;IACpB,4BAA4B;CAC7B,CAAC;AAEF,MAAa,aAAc,SAAQ,yBAAW;IAA9C;;QACW,cAAS,GAAG,QAAQ,CAAC;IAqChC,CAAC;IAnCC,UAAU,CAAC,eAAyB;QAClC,2EAA2E;QAC3E,0EAA0E;QAC1E,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC;QACvE,OAAO;YACL,OAAO;YACP,IAAI,EAAE,eAAe;YACrB,iEAAiE;SAClE,CAAC;IACJ,CAAC;IAED,YAAY,CAAC,GAAW,EAAE,aAA4B;QACpD,2DAA2D;QAC3D,IAAI,aAAa,KAAK,WAAW;YAAE,OAAO,IAAI,CAAC;QAE/C,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;QAE5B,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,iBAAiB,CAAC;YAAE,OAAO,mBAAmB,CAAC;QACtE,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC;YAAE,OAAO,OAAO,CAAC;QACvD,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,gBAAgB,CAAC;YAAE,OAAO,mBAAmB,CAAC;QAErE,+DAA+D;QAC/D,IACE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,gBAAgB,CAAC;YACpC,CAAC,aAAa,KAAK,mBAAmB,IAAI,aAAa,KAAK,mBAAmB,CAAC,EAChF,CAAC;YACD,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,OAAO,CAAC,IAAY,EAAE,QAAkB;QAC9C,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5C,CAAC;CACF;AAtCD,sCAsCC"}
|
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
|
-
//
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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(
|
|
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
|
-
|
|
101
|
-
process.stderr.write(`[ashral] Push notifications
|
|
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":";;;AACA,yCAAoC;AACpC,oDAAiD;AACjD,4DAAyD;AACzD,+DAA4D;
|
|
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.
|
|
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": {
|