noctrace 0.7.3 → 0.7.5
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/bin/noctrace.js +30 -32
- package/dist/client/assets/index-9-y1oErw.js +30 -0
- package/dist/client/assets/{index-iQItZcUN.css → index-DyjeNSzP.css} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/server/shared/parser.js +6 -0
- package/dist/server/shared/reliability.js +186 -0
- package/package.json +1 -1
- package/dist/client/assets/index-CLA0rrye.js +0 -30
package/bin/noctrace.js
CHANGED
|
@@ -8,25 +8,37 @@ const NOCTRACE_PORT = 4117;
|
|
|
8
8
|
const NOCTRACE_BASE_URL = `http://localhost:${NOCTRACE_PORT}`;
|
|
9
9
|
const HOOKS_ENDPOINT = `${NOCTRACE_BASE_URL}/api/hooks`;
|
|
10
10
|
|
|
11
|
-
/**
|
|
12
|
-
* The curl command used as the hook body.
|
|
13
|
-
* Reads the hook event JSON from stdin and POSTs it to noctrace.
|
|
14
|
-
* `--data-raw "$(cat)"` captures all of stdin and sends it as the request body.
|
|
15
|
-
*/
|
|
16
|
-
const HOOK_COMMAND = `curl -s -X POST ${HOOKS_ENDPOINT} -H 'Content-Type: application/json' --data-raw "$(cat)"`;
|
|
17
|
-
|
|
18
11
|
/**
|
|
19
12
|
* The set of Claude Code hook event names noctrace subscribes to.
|
|
20
13
|
*/
|
|
21
14
|
const HOOK_EVENT_NAMES = [
|
|
22
15
|
'PostToolUse',
|
|
16
|
+
'PostToolUseFailure',
|
|
23
17
|
'SubagentStart',
|
|
24
18
|
'SubagentStop',
|
|
25
19
|
'Stop',
|
|
26
20
|
'PreCompact',
|
|
27
21
|
'PostCompact',
|
|
22
|
+
'SessionStart',
|
|
23
|
+
'SessionEnd',
|
|
24
|
+
'PermissionRequest',
|
|
25
|
+
'PermissionDenied',
|
|
26
|
+
'WorktreeCreate',
|
|
27
|
+
'WorktreeRemove',
|
|
28
28
|
];
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Check if a hook entry array contains a noctrace hook (either old command-type or new http-type).
|
|
32
|
+
*/
|
|
33
|
+
function hasNoctraceHook(entry) {
|
|
34
|
+
return Array.isArray(entry.hooks) &&
|
|
35
|
+
entry.hooks.some(
|
|
36
|
+
(h) =>
|
|
37
|
+
(h.type === 'command' && typeof h.command === 'string' && h.command.includes(HOOKS_ENDPOINT)) ||
|
|
38
|
+
(h.type === 'http' && h.url === HOOKS_ENDPOINT),
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
30
42
|
/**
|
|
31
43
|
* Read and parse ~/.claude/settings.json.
|
|
32
44
|
* Returns an empty object if the file doesn't exist yet.
|
|
@@ -51,9 +63,8 @@ async function writeSettings(settingsPath, settings) {
|
|
|
51
63
|
|
|
52
64
|
/**
|
|
53
65
|
* Install noctrace hooks into ~/.claude/settings.json.
|
|
54
|
-
* For each hook event name, adds
|
|
55
|
-
*
|
|
56
|
-
* Skips events that already have a noctrace hook registered.
|
|
66
|
+
* For each hook event name, adds an HTTP hook pointing at the noctrace endpoint.
|
|
67
|
+
* Detects both old command-type and new http-type hooks to avoid duplicates.
|
|
57
68
|
*/
|
|
58
69
|
async function installHooks() {
|
|
59
70
|
const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
|
|
@@ -69,14 +80,8 @@ async function installHooks() {
|
|
|
69
80
|
|
|
70
81
|
const existing = settings.hooks[eventName];
|
|
71
82
|
|
|
72
|
-
// Check whether a noctrace hook is already registered
|
|
73
|
-
const alreadyInstalled = existing.some(
|
|
74
|
-
(entry) =>
|
|
75
|
-
Array.isArray(entry.hooks) &&
|
|
76
|
-
entry.hooks.some(
|
|
77
|
-
(h) => h.type === 'command' && typeof h.command === 'string' && h.command.includes(HOOKS_ENDPOINT),
|
|
78
|
-
),
|
|
79
|
-
);
|
|
83
|
+
// Check whether a noctrace hook is already registered (either old command or new http format)
|
|
84
|
+
const alreadyInstalled = existing.some(hasNoctraceHook);
|
|
80
85
|
|
|
81
86
|
if (alreadyInstalled) {
|
|
82
87
|
skipped.push(eventName);
|
|
@@ -85,8 +90,8 @@ async function installHooks() {
|
|
|
85
90
|
|
|
86
91
|
existing.push({
|
|
87
92
|
hooks: [{
|
|
88
|
-
type: '
|
|
89
|
-
|
|
93
|
+
type: 'http',
|
|
94
|
+
url: HOOKS_ENDPOINT,
|
|
90
95
|
async: true,
|
|
91
96
|
}],
|
|
92
97
|
});
|
|
@@ -108,8 +113,8 @@ async function installHooks() {
|
|
|
108
113
|
|
|
109
114
|
/**
|
|
110
115
|
* Remove noctrace hooks from ~/.claude/settings.json.
|
|
111
|
-
*
|
|
112
|
-
*
|
|
116
|
+
* Removes both old command-type and new http-type hooks.
|
|
117
|
+
* Iterates all hook event keys (not just HOOK_EVENT_NAMES) to clean up orphaned entries.
|
|
113
118
|
*/
|
|
114
119
|
async function uninstallHooks() {
|
|
115
120
|
const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
|
|
@@ -122,20 +127,13 @@ async function uninstallHooks() {
|
|
|
122
127
|
|
|
123
128
|
const removed = [];
|
|
124
129
|
|
|
125
|
-
|
|
130
|
+
// Iterate ALL hook event keys (not just current HOOK_EVENT_NAMES) to clean up orphaned old entries
|
|
131
|
+
for (const eventName of Object.keys(settings.hooks)) {
|
|
126
132
|
const existing = settings.hooks[eventName];
|
|
127
133
|
if (!Array.isArray(existing)) continue;
|
|
128
134
|
|
|
129
135
|
const before = existing.length;
|
|
130
|
-
settings.hooks[eventName] = existing.filter(
|
|
131
|
-
(entry) =>
|
|
132
|
-
!(
|
|
133
|
-
Array.isArray(entry.hooks) &&
|
|
134
|
-
entry.hooks.some(
|
|
135
|
-
(h) => h.type === 'command' && typeof h.command === 'string' && h.command.includes(HOOKS_ENDPOINT),
|
|
136
|
-
)
|
|
137
|
-
),
|
|
138
|
-
);
|
|
136
|
+
settings.hooks[eventName] = existing.filter((entry) => !hasNoctraceHook(entry));
|
|
139
137
|
|
|
140
138
|
if (settings.hooks[eventName].length < before) {
|
|
141
139
|
removed.push(eventName);
|