aisnitch 0.2.2 → 0.2.4
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 +314 -666
- package/dist/cli/index.cjs +431 -63
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +431 -63
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +199 -74
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -2
- package/dist/index.d.ts +14 -2
- package/dist/index.js +199 -74
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -482,15 +482,24 @@ var BaseAdapter = class {
|
|
|
482
482
|
cwd: data.cwd ?? context.cwd
|
|
483
483
|
}
|
|
484
484
|
});
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
485
|
+
let published;
|
|
486
|
+
try {
|
|
487
|
+
published = await this.publishEventImplementation(event, {
|
|
488
|
+
cwd: context.cwd,
|
|
489
|
+
env: context.env,
|
|
490
|
+
hookPayload: context.hookPayload,
|
|
491
|
+
pid: context.pid,
|
|
492
|
+
sessionId,
|
|
493
|
+
source: context.source,
|
|
494
|
+
transcriptPath: context.transcriptPath
|
|
495
|
+
});
|
|
496
|
+
} catch (error) {
|
|
497
|
+
logger.error(
|
|
498
|
+
{ error, eventType: type, adapter: this.name, sessionId },
|
|
499
|
+
"\u{1F4D6} Failed to publish event \u2014 swallowing to prevent daemon crash"
|
|
500
|
+
);
|
|
501
|
+
published = false;
|
|
502
|
+
}
|
|
494
503
|
if (published) {
|
|
495
504
|
this.eventsEmitted += 1;
|
|
496
505
|
}
|
|
@@ -5618,22 +5627,40 @@ var AdapterRegistry = class {
|
|
|
5618
5627
|
}
|
|
5619
5628
|
/**
|
|
5620
5629
|
* Starts every adapter enabled in the current AISnitch config.
|
|
5630
|
+
* 📖 Each adapter is started independently — one failure does not prevent
|
|
5631
|
+
* the others from starting.
|
|
5621
5632
|
*/
|
|
5622
5633
|
async startAll(config) {
|
|
5623
5634
|
for (const adapter of this.list()) {
|
|
5624
5635
|
if (config.adapters[adapter.name]?.enabled !== true) {
|
|
5625
5636
|
continue;
|
|
5626
5637
|
}
|
|
5627
|
-
|
|
5638
|
+
try {
|
|
5639
|
+
await adapter.start();
|
|
5640
|
+
} catch (error) {
|
|
5641
|
+
logger.error(
|
|
5642
|
+
{ error, adapter: adapter.name },
|
|
5643
|
+
`\u{1F4D6} Failed to start adapter "${adapter.name}" \u2014 skipping`
|
|
5644
|
+
);
|
|
5645
|
+
}
|
|
5628
5646
|
}
|
|
5629
5647
|
}
|
|
5630
5648
|
/**
|
|
5631
5649
|
* Stops every adapter in reverse registration order.
|
|
5650
|
+
* 📖 Each adapter is stopped independently — one failure does not prevent
|
|
5651
|
+
* the others from being stopped.
|
|
5632
5652
|
*/
|
|
5633
5653
|
async stopAll() {
|
|
5634
5654
|
const adapters = this.list().reverse();
|
|
5635
5655
|
for (const adapter of adapters) {
|
|
5636
|
-
|
|
5656
|
+
try {
|
|
5657
|
+
await adapter.stop();
|
|
5658
|
+
} catch (error) {
|
|
5659
|
+
logger.warn(
|
|
5660
|
+
{ error, adapter: adapter.name },
|
|
5661
|
+
`\u{1F4D6} Error stopping adapter "${adapter.name}" \u2014 continuing`
|
|
5662
|
+
);
|
|
5663
|
+
}
|
|
5637
5664
|
}
|
|
5638
5665
|
}
|
|
5639
5666
|
};
|
|
@@ -6596,8 +6623,16 @@ var EventBus = class {
|
|
|
6596
6623
|
},
|
|
6597
6624
|
"Published event"
|
|
6598
6625
|
);
|
|
6599
|
-
|
|
6600
|
-
|
|
6626
|
+
try {
|
|
6627
|
+
this.emitter.emit("event", parsedEvent.data);
|
|
6628
|
+
} catch (error) {
|
|
6629
|
+
logger.warn({ error, eventType: parsedEvent.data.type }, "\u{1F4D6} Error in EventBus global subscriber");
|
|
6630
|
+
}
|
|
6631
|
+
try {
|
|
6632
|
+
this.emitter.emit(`event:${parsedEvent.data.type}`, parsedEvent.data);
|
|
6633
|
+
} catch (error) {
|
|
6634
|
+
logger.warn({ error, eventType: parsedEvent.data.type }, "\u{1F4D6} Error in EventBus typed subscriber");
|
|
6635
|
+
}
|
|
6601
6636
|
return true;
|
|
6602
6637
|
}
|
|
6603
6638
|
/**
|
|
@@ -6744,7 +6779,7 @@ var import_ws = require("ws");
|
|
|
6744
6779
|
|
|
6745
6780
|
// src/package-info.ts
|
|
6746
6781
|
var AISNITCH_PACKAGE_NAME = "aisnitch";
|
|
6747
|
-
var AISNITCH_VERSION = "0.2.
|
|
6782
|
+
var AISNITCH_VERSION = "0.2.3";
|
|
6748
6783
|
var AISNITCH_DESCRIPTION = "Universal bridge for AI coding tool activity \u2014 capture, normalize, stream.";
|
|
6749
6784
|
function getPackageScaffoldInfo() {
|
|
6750
6785
|
return {
|
|
@@ -6878,6 +6913,7 @@ var WSServer = class {
|
|
|
6878
6913
|
});
|
|
6879
6914
|
socket.on("error", (error) => {
|
|
6880
6915
|
logger.warn({ error }, "WebSocket consumer error");
|
|
6916
|
+
this.consumers.delete(socket);
|
|
6881
6917
|
});
|
|
6882
6918
|
const welcomeMessage = {
|
|
6883
6919
|
type: "welcome",
|
|
@@ -7032,10 +7068,17 @@ var HTTPReceiver = class {
|
|
|
7032
7068
|
}
|
|
7033
7069
|
async handleRequest(request, response, options) {
|
|
7034
7070
|
this.requestCount += 1;
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7071
|
+
let requestUrl;
|
|
7072
|
+
try {
|
|
7073
|
+
requestUrl = new URL(
|
|
7074
|
+
request.url ?? "/",
|
|
7075
|
+
`http://${this.host}:${this.port ?? options.port}`
|
|
7076
|
+
);
|
|
7077
|
+
} catch {
|
|
7078
|
+
this.invalidRequestCount += 1;
|
|
7079
|
+
this.sendJson(response, 400, { error: "malformed request url" });
|
|
7080
|
+
return;
|
|
7081
|
+
}
|
|
7039
7082
|
if (request.method === "GET" && requestUrl.pathname === "/health") {
|
|
7040
7083
|
this.sendJson(response, 200, options.getHealthSnapshot());
|
|
7041
7084
|
return;
|
|
@@ -7380,26 +7423,32 @@ var Pipeline = class {
|
|
|
7380
7423
|
await adapter.handleHook(payload);
|
|
7381
7424
|
});
|
|
7382
7425
|
}
|
|
7426
|
+
try {
|
|
7427
|
+
this.wsPort = await this.wsServer.start({
|
|
7428
|
+
port: resolvedWsPort,
|
|
7429
|
+
eventBus: this.eventBus,
|
|
7430
|
+
activeTools
|
|
7431
|
+
});
|
|
7432
|
+
this.httpPort = await this.httpReceiver.start({
|
|
7433
|
+
port: resolvedHttpPort,
|
|
7434
|
+
onHook: async (tool, payload) => {
|
|
7435
|
+
await this.handleHook(tool, payload);
|
|
7436
|
+
},
|
|
7437
|
+
getHealthSnapshot: () => this.getHealthSnapshot()
|
|
7438
|
+
});
|
|
7439
|
+
this.socketPath = await this.udsServer.start({
|
|
7440
|
+
socketPath,
|
|
7441
|
+
onEvent: async (event) => {
|
|
7442
|
+
await this.publishEvent(event);
|
|
7443
|
+
}
|
|
7444
|
+
});
|
|
7445
|
+
await this.adapterRegistry.startAll(config);
|
|
7446
|
+
} catch (error) {
|
|
7447
|
+
logger.error({ error }, "\u{1F4D6} Pipeline start failed \u2014 rolling back already-started components");
|
|
7448
|
+
await this.rollbackPartialStart();
|
|
7449
|
+
throw error;
|
|
7450
|
+
}
|
|
7383
7451
|
this.startedAt = Date.now();
|
|
7384
|
-
this.wsPort = await this.wsServer.start({
|
|
7385
|
-
port: resolvedWsPort,
|
|
7386
|
-
eventBus: this.eventBus,
|
|
7387
|
-
activeTools
|
|
7388
|
-
});
|
|
7389
|
-
this.httpPort = await this.httpReceiver.start({
|
|
7390
|
-
port: resolvedHttpPort,
|
|
7391
|
-
onHook: async (tool, payload) => {
|
|
7392
|
-
await this.handleHook(tool, payload);
|
|
7393
|
-
},
|
|
7394
|
-
getHealthSnapshot: () => this.getHealthSnapshot()
|
|
7395
|
-
});
|
|
7396
|
-
this.socketPath = await this.udsServer.start({
|
|
7397
|
-
socketPath,
|
|
7398
|
-
onEvent: async (event) => {
|
|
7399
|
-
await this.publishEvent(event);
|
|
7400
|
-
}
|
|
7401
|
-
});
|
|
7402
|
-
await this.adapterRegistry.startAll(config);
|
|
7403
7452
|
logger.info(this.getStatus(), "Core pipeline started");
|
|
7404
7453
|
return this.getStatus();
|
|
7405
7454
|
}
|
|
@@ -7407,10 +7456,25 @@ var Pipeline = class {
|
|
|
7407
7456
|
* Stops every pipeline component in reverse dependency order.
|
|
7408
7457
|
*/
|
|
7409
7458
|
async stop() {
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
|
|
7413
|
-
|
|
7459
|
+
const stopSafely = async (label, fn) => {
|
|
7460
|
+
try {
|
|
7461
|
+
await fn();
|
|
7462
|
+
} catch (error) {
|
|
7463
|
+
logger.warn({ error }, `\u{1F4D6} Error while stopping ${label} \u2014 continuing shutdown`);
|
|
7464
|
+
}
|
|
7465
|
+
};
|
|
7466
|
+
await stopSafely("adapter registry", async () => {
|
|
7467
|
+
await this.adapterRegistry?.stopAll();
|
|
7468
|
+
});
|
|
7469
|
+
await stopSafely("HTTP receiver", async () => {
|
|
7470
|
+
await this.httpReceiver.stop();
|
|
7471
|
+
});
|
|
7472
|
+
await stopSafely("UDS server", async () => {
|
|
7473
|
+
await this.udsServer.stop();
|
|
7474
|
+
});
|
|
7475
|
+
await stopSafely("WebSocket server", async () => {
|
|
7476
|
+
await this.wsServer.stop();
|
|
7477
|
+
});
|
|
7414
7478
|
this.eventBus.unsubscribeAll();
|
|
7415
7479
|
this.adapterRegistry = null;
|
|
7416
7480
|
this.enabledTools.clear();
|
|
@@ -7427,11 +7491,50 @@ var Pipeline = class {
|
|
|
7427
7491
|
registerHookHandler(tool, handler) {
|
|
7428
7492
|
this.hookHandlers.set(tool, handler);
|
|
7429
7493
|
}
|
|
7494
|
+
/**
|
|
7495
|
+
* 📖 Rolls back any components that were successfully started before a
|
|
7496
|
+
* failure occurred, preventing orphaned servers or leaking resources.
|
|
7497
|
+
*/
|
|
7498
|
+
async rollbackPartialStart() {
|
|
7499
|
+
const stopSafe = async (label, fn) => {
|
|
7500
|
+
try {
|
|
7501
|
+
await fn();
|
|
7502
|
+
} catch (error) {
|
|
7503
|
+
logger.warn({ error }, `\u{1F4D6} Error rolling back ${label}`);
|
|
7504
|
+
}
|
|
7505
|
+
};
|
|
7506
|
+
await stopSafe("adapter registry", async () => {
|
|
7507
|
+
await this.adapterRegistry?.stopAll();
|
|
7508
|
+
});
|
|
7509
|
+
await stopSafe("UDS server", async () => {
|
|
7510
|
+
await this.udsServer.stop();
|
|
7511
|
+
});
|
|
7512
|
+
await stopSafe("HTTP receiver", async () => {
|
|
7513
|
+
await this.httpReceiver.stop();
|
|
7514
|
+
});
|
|
7515
|
+
await stopSafe("WebSocket server", async () => {
|
|
7516
|
+
await this.wsServer.stop();
|
|
7517
|
+
});
|
|
7518
|
+
this.adapterRegistry = null;
|
|
7519
|
+
this.enabledTools.clear();
|
|
7520
|
+
this.hookHandlers.clear();
|
|
7521
|
+
}
|
|
7430
7522
|
/**
|
|
7431
7523
|
* Publishes an event after best-effort context enrichment.
|
|
7524
|
+
* 📖 If enrichment fails, the original event is published un-enriched
|
|
7525
|
+
* rather than being dropped entirely.
|
|
7432
7526
|
*/
|
|
7433
7527
|
async publishEvent(event, context = {}) {
|
|
7434
|
-
|
|
7528
|
+
let enrichedEvent;
|
|
7529
|
+
try {
|
|
7530
|
+
enrichedEvent = await this.contextDetector.enrich(event, context);
|
|
7531
|
+
} catch (error) {
|
|
7532
|
+
logger.warn(
|
|
7533
|
+
{ error, eventId: event.id },
|
|
7534
|
+
"\u{1F4D6} Context enrichment failed \u2014 publishing un-enriched event"
|
|
7535
|
+
);
|
|
7536
|
+
enrichedEvent = event;
|
|
7537
|
+
}
|
|
7435
7538
|
return this.eventBus.publish(enrichedEvent);
|
|
7436
7539
|
}
|
|
7437
7540
|
/**
|
|
@@ -7467,6 +7570,16 @@ var Pipeline = class {
|
|
|
7467
7570
|
};
|
|
7468
7571
|
}
|
|
7469
7572
|
async handleHook(tool, payload) {
|
|
7573
|
+
try {
|
|
7574
|
+
await this.handleHookInner(tool, payload);
|
|
7575
|
+
} catch (error) {
|
|
7576
|
+
logger.error(
|
|
7577
|
+
{ error, tool },
|
|
7578
|
+
"\u{1F4D6} Unhandled error in hook handler \u2014 swallowing to prevent daemon crash"
|
|
7579
|
+
);
|
|
7580
|
+
}
|
|
7581
|
+
}
|
|
7582
|
+
async handleHookInner(tool, payload) {
|
|
7470
7583
|
if (!this.enabledTools.has(tool)) {
|
|
7471
7584
|
logger.debug({ tool }, "Ignoring hook for disabled tool");
|
|
7472
7585
|
return;
|
|
@@ -8642,18 +8755,22 @@ function parseSocketPayload(data) {
|
|
|
8642
8755
|
return parsedEvent.success ? parsedEvent.data : null;
|
|
8643
8756
|
}
|
|
8644
8757
|
function parseUnknownPayload(data) {
|
|
8645
|
-
|
|
8646
|
-
|
|
8647
|
-
|
|
8648
|
-
|
|
8649
|
-
|
|
8650
|
-
|
|
8651
|
-
|
|
8652
|
-
|
|
8653
|
-
|
|
8654
|
-
|
|
8758
|
+
try {
|
|
8759
|
+
if (typeof data === "string") {
|
|
8760
|
+
return JSON.parse(data);
|
|
8761
|
+
}
|
|
8762
|
+
if (Array.isArray(data)) {
|
|
8763
|
+
return JSON.parse(Buffer.concat(data).toString("utf8"));
|
|
8764
|
+
}
|
|
8765
|
+
if (data instanceof ArrayBuffer) {
|
|
8766
|
+
return JSON.parse(
|
|
8767
|
+
Buffer.from(new Uint8Array(data)).toString("utf8")
|
|
8768
|
+
);
|
|
8769
|
+
}
|
|
8770
|
+
return JSON.parse(Buffer.from(data).toString("utf8"));
|
|
8771
|
+
} catch {
|
|
8772
|
+
return null;
|
|
8655
8773
|
}
|
|
8656
|
-
return JSON.parse(Buffer.from(data).toString("utf8"));
|
|
8657
8774
|
}
|
|
8658
8775
|
|
|
8659
8776
|
// src/tui/hooks/useKeyBinds.ts
|
|
@@ -9381,16 +9498,20 @@ function ManagedDaemonApp({
|
|
|
9381
9498
|
}
|
|
9382
9499
|
function parseSocketPayload2(data) {
|
|
9383
9500
|
let parsedPayload;
|
|
9384
|
-
|
|
9385
|
-
|
|
9386
|
-
|
|
9387
|
-
|
|
9388
|
-
|
|
9389
|
-
|
|
9390
|
-
|
|
9391
|
-
|
|
9392
|
-
|
|
9393
|
-
|
|
9501
|
+
try {
|
|
9502
|
+
if (typeof data === "string") {
|
|
9503
|
+
parsedPayload = JSON.parse(data);
|
|
9504
|
+
} else if (Array.isArray(data)) {
|
|
9505
|
+
parsedPayload = JSON.parse(Buffer.concat(data).toString("utf8"));
|
|
9506
|
+
} else if (data instanceof ArrayBuffer) {
|
|
9507
|
+
parsedPayload = JSON.parse(
|
|
9508
|
+
Buffer.from(new Uint8Array(data)).toString("utf8")
|
|
9509
|
+
);
|
|
9510
|
+
} else {
|
|
9511
|
+
parsedPayload = JSON.parse(Buffer.from(data).toString("utf8"));
|
|
9512
|
+
}
|
|
9513
|
+
} catch {
|
|
9514
|
+
return null;
|
|
9394
9515
|
}
|
|
9395
9516
|
if (typeof parsedPayload === "object" && parsedPayload !== null && "type" in parsedPayload && parsedPayload.type === "welcome") {
|
|
9396
9517
|
return null;
|
|
@@ -9461,18 +9582,22 @@ async function attachWebSocketMonitor(url, output) {
|
|
|
9461
9582
|
};
|
|
9462
9583
|
}
|
|
9463
9584
|
function parseSocketMessage(data) {
|
|
9464
|
-
|
|
9465
|
-
|
|
9466
|
-
|
|
9467
|
-
|
|
9468
|
-
|
|
9469
|
-
|
|
9470
|
-
|
|
9471
|
-
|
|
9472
|
-
|
|
9473
|
-
|
|
9585
|
+
try {
|
|
9586
|
+
if (typeof data === "string") {
|
|
9587
|
+
return JSON.parse(data);
|
|
9588
|
+
}
|
|
9589
|
+
if (Array.isArray(data)) {
|
|
9590
|
+
return JSON.parse(Buffer.concat(data).toString("utf8"));
|
|
9591
|
+
}
|
|
9592
|
+
if (data instanceof ArrayBuffer) {
|
|
9593
|
+
return JSON.parse(
|
|
9594
|
+
Buffer.from(new Uint8Array(data)).toString("utf8")
|
|
9595
|
+
);
|
|
9596
|
+
}
|
|
9597
|
+
return JSON.parse(Buffer.from(data).toString("utf8"));
|
|
9598
|
+
} catch {
|
|
9599
|
+
return null;
|
|
9474
9600
|
}
|
|
9475
|
-
return JSON.parse(Buffer.from(data).toString("utf8"));
|
|
9476
9601
|
}
|
|
9477
9602
|
function isWelcomeMessage(payload) {
|
|
9478
9603
|
if (typeof payload !== "object" || payload === null) {
|