@raidiant/notifai 10.1.6 → 11.0.1
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/CHANGELOG.md +56 -0
- package/README.md +28 -16
- package/dist/claude-wake.d.ts +1 -2
- package/dist/claude-wake.js +15 -61
- package/dist/claude-wake.js.map +1 -1
- package/dist/cli-bin.js +3 -14
- package/dist/cli-bin.js.map +1 -1
- package/dist/cli-contract.d.ts +12 -0
- package/dist/cli-contract.js +19 -0
- package/dist/cli-contract.js.map +1 -0
- package/dist/cli-release.d.ts +0 -1
- package/dist/cli-release.js +5 -21
- package/dist/cli-release.js.map +1 -1
- package/dist/client.d.ts +2 -2
- package/dist/codex-wake.d.ts +1 -1
- package/dist/codex-wake.js +8 -36
- package/dist/codex-wake.js.map +1 -1
- package/dist/command-session.js +2 -1
- package/dist/command-session.js.map +1 -1
- package/dist/commands-acknowledge.d.ts +13 -0
- package/dist/commands-acknowledge.js +67 -0
- package/dist/commands-acknowledge.js.map +1 -0
- package/dist/commands-ask.d.ts +63 -0
- package/dist/commands-ask.js +407 -0
- package/dist/commands-ask.js.map +1 -0
- package/dist/commands-close.d.ts +6 -0
- package/dist/commands-close.js +197 -0
- package/dist/commands-close.js.map +1 -0
- package/dist/commands-config.js +2 -2
- package/dist/commands-config.js.map +1 -1
- package/dist/commands-core.js +2 -2
- package/dist/commands-core.js.map +1 -1
- package/dist/commands-doctor.js +89 -134
- package/dist/commands-doctor.js.map +1 -1
- package/dist/commands-harness-context.d.ts +0 -1
- package/dist/commands-harness-context.js +2 -4
- package/dist/commands-harness-context.js.map +1 -1
- package/dist/commands-hook-diagnostics.d.ts +27 -0
- package/dist/commands-hook-diagnostics.js +97 -0
- package/dist/commands-hook-diagnostics.js.map +1 -0
- package/dist/commands-hook-install.d.ts +26 -0
- package/dist/commands-hook-install.js +549 -0
- package/dist/commands-hook-install.js.map +1 -0
- package/dist/commands-hook-run.d.ts +29 -0
- package/dist/commands-hook-run.js +517 -0
- package/dist/commands-hook-run.js.map +1 -0
- package/dist/commands-init.d.ts +2 -7
- package/dist/commands-init.js +59 -92
- package/dist/commands-init.js.map +1 -1
- package/dist/commands-send.js +35 -3
- package/dist/commands-send.js.map +1 -1
- package/dist/commands-skill.js +5 -5
- package/dist/commands-skill.js.map +1 -1
- package/dist/commands-update.js +17 -31
- package/dist/commands-update.js.map +1 -1
- package/dist/commands.d.ts +11 -6
- package/dist/commands.js +9 -4
- package/dist/commands.js.map +1 -1
- package/dist/config-schema.js +2 -2
- package/dist/config-schema.js.map +1 -1
- package/dist/config.d.ts +14 -4
- package/dist/config.js +35 -9
- package/dist/config.js.map +1 -1
- package/dist/file-lock.d.ts +3 -0
- package/dist/file-lock.js +33 -17
- package/dist/file-lock.js.map +1 -1
- package/dist/guidance-content.js +30 -15
- package/dist/guidance-content.js.map +1 -1
- package/dist/harnesses.d.ts +2 -2
- package/dist/harnesses.js +10 -2
- package/dist/harnesses.js.map +1 -1
- package/dist/hook-acknowledgements.d.ts +42 -0
- package/dist/hook-acknowledgements.js +316 -0
- package/dist/hook-acknowledgements.js.map +1 -0
- package/dist/hook-adapter.js +7 -4
- package/dist/hook-adapter.js.map +1 -1
- package/dist/hook-events.d.ts +6 -0
- package/dist/hook-events.js +22 -0
- package/dist/hook-events.js.map +1 -0
- package/dist/hook-gates.d.ts +7 -0
- package/dist/hook-gates.js +21 -0
- package/dist/hook-gates.js.map +1 -0
- package/dist/hook-lifecycle.d.ts +93 -0
- package/dist/{hooks.js → hook-lifecycle.js} +61 -1359
- package/dist/hook-lifecycle.js.map +1 -0
- package/dist/hook-project-sessions.d.ts +28 -0
- package/dist/hook-project-sessions.js +141 -0
- package/dist/hook-project-sessions.js.map +1 -0
- package/dist/hook-question-lock.d.ts +7 -0
- package/dist/hook-question-lock.js +173 -0
- package/dist/hook-question-lock.js.map +1 -0
- package/dist/hook-question-retirement.d.ts +57 -0
- package/dist/hook-question-retirement.js +261 -0
- package/dist/hook-question-retirement.js.map +1 -0
- package/dist/hook-question-state.d.ts +45 -0
- package/dist/hook-question-state.js +196 -0
- package/dist/hook-question-state.js.map +1 -0
- package/dist/hook-session-state.d.ts +31 -0
- package/dist/hook-session-state.js +249 -0
- package/dist/hook-session-state.js.map +1 -0
- package/dist/{hooks.d.ts → hook-types.d.ts} +17 -236
- package/dist/hook-types.js +4 -0
- package/dist/hook-types.js.map +1 -0
- package/dist/install-hooks.d.ts +72 -60
- package/dist/install-hooks.js +292 -211
- package/dist/install-hooks.js.map +1 -1
- package/dist/interactive.d.ts +3 -16
- package/dist/interactive.js +19 -95
- package/dist/interactive.js.map +1 -1
- package/dist/local-path.d.ts +7 -0
- package/dist/local-path.js +27 -0
- package/dist/local-path.js.map +1 -0
- package/dist/node-floor.js +3 -10
- package/dist/node-floor.js.map +1 -1
- package/dist/npm-invocation.d.ts +34 -0
- package/dist/npm-invocation.js +53 -0
- package/dist/npm-invocation.js.map +1 -0
- package/dist/openclaw-plugin.d.ts +12 -3
- package/dist/openclaw-plugin.js +42 -16
- package/dist/openclaw-plugin.js.map +1 -1
- package/dist/opencode-plugin.d.ts +2 -2
- package/dist/opencode-plugin.js +4 -6
- package/dist/opencode-plugin.js.map +1 -1
- package/dist/program.js +11 -13
- package/dist/program.js.map +1 -1
- package/dist/project-enablement.d.ts +6 -0
- package/dist/project-enablement.js +11 -27
- package/dist/project-enablement.js.map +1 -1
- package/dist/question-settlement-process.d.ts +1 -1
- package/dist/readiness.d.ts +3 -3
- package/dist/readiness.js +14 -6
- package/dist/readiness.js.map +1 -1
- package/dist/send.d.ts +8 -4
- package/dist/send.js +145 -26
- package/dist/send.js.map +1 -1
- package/dist/session-activation.d.ts +3 -1
- package/dist/session-activation.js +16 -0
- package/dist/session-activation.js.map +1 -1
- package/dist/skill-source/manifest.json +4 -4
- package/dist/skill-source/notifai/SKILL.md +67 -63
- package/dist/skill-source/notifai/references/harness-setup.md +62 -28
- package/dist/ui/config-view.d.ts +0 -2
- package/dist/ui/config-view.js +1 -5
- package/dist/ui/config-view.js.map +1 -1
- package/dist/ui/theme.d.ts +0 -3
- package/dist/ui/theme.js +0 -1
- package/dist/ui/theme.js.map +1 -1
- package/dist/version.d.ts +22 -0
- package/dist/version.js +51 -0
- package/dist/version.js.map +1 -0
- package/dist/wake-support.d.ts +8 -0
- package/dist/wake-support.js +38 -0
- package/dist/wake-support.js.map +1 -0
- package/package.json +2 -2
- package/dist/cli-update-contract.d.ts +0 -7
- package/dist/cli-update-contract.js +0 -10
- package/dist/cli-update-contract.js.map +0 -1
- package/dist/commands-hooks.d.ts +0 -160
- package/dist/commands-hooks.js +0 -1798
- package/dist/commands-hooks.js.map +0 -1
- package/dist/hooks.js.map +0 -1
package/dist/commands-doctor.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { NOTIFICATION_CONTRACT_FINGERPRINT, PLATFORMS, SHIPPED_CLI_CAPABILITIES, } from '@raidiant/notifai-protocol';
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
|
-
import path from 'node:path';
|
|
4
3
|
import { inspectClaudeInbox, systemClaudeWakeAdapters } from './claude-wake.js';
|
|
5
4
|
import { ApiCallError } from './client.js';
|
|
6
5
|
import { inspectCodexResume } from './codex-wake.js';
|
|
7
6
|
import {} from './config.js';
|
|
8
|
-
import {
|
|
7
|
+
import { HARNESS_LABELS, HERMES_QUESTION_ROUTING_UNAVAILABLE, isHookInstallableHarness, questionRoutingCapability, } from './harnesses.js';
|
|
9
8
|
import { hookAdapterTargetsArtifact, inspectHookAdapter, isNpxAdapterTarget, } from './hook-adapter.js';
|
|
10
|
-
import { readLiveProjectSessionPointers, readProjectSessionPointer,
|
|
11
|
-
import {
|
|
9
|
+
import { readLiveProjectSessionPointers, readProjectSessionPointer, } from './hook-project-sessions.js';
|
|
10
|
+
import { readSessionState } from './hook-session-state.js';
|
|
11
|
+
import { NON_ROUTING_BLOCKING_STOP_TIMEOUT_SECONDS, QUESTION_STOP_TIMEOUT_SECONDS, codexCoexistenceNotes, codexHomeNote, codexRepresentationProblems, codexTrustProblems, detectedHarnesses, findInstallations, findLegacyProjectInstallations, handlerEvent, } from './install-hooks.js';
|
|
12
12
|
import { inferInvocationContext } from './invocation-context.js';
|
|
13
13
|
import { firstBlocker, readinessJson, } from './readiness.js';
|
|
14
14
|
import { packageVersion } from './release.js';
|
|
@@ -17,12 +17,14 @@ import { deviceInstallRemedy, readyCompanionDevices } from './commands-devices.j
|
|
|
17
17
|
import { setupAccessUrl } from './setup-destinations.js';
|
|
18
18
|
import { claudeSessionPid, resolveActiveHarness, } from './commands-harness-context.js';
|
|
19
19
|
import { stopShapeProblems } from './commands-hook-shape.js';
|
|
20
|
-
import {
|
|
20
|
+
import { CODEX_FRESH_SESSION_USER_ACTION, CODEX_HOOK_APPROVAL_USER_ACTION, CODEX_STOP_DEFINITION_NOT_SINGULAR_PROBLEM, CODEX_STALE_STOP_DEFINITION_PROBLEM, activeQuestionRouteProblems, hookActivationAdvice, } from './commands-hook-diagnostics.js';
|
|
21
|
+
import { HOOK_EVENTS, requiredHookEvents } from './hook-events.js';
|
|
21
22
|
import { cliBinReadiness, inspectCliInstallations } from './cli-bin.js';
|
|
22
23
|
import { latestPublishedCliVersion, newerPublishedCli, shouldConsultCliRegistry, thisCliVersion, } from './cli-release.js';
|
|
23
24
|
import { SETUP_PROOF_STALE_MS, observedCompanionReceipt, readSetupProof, setupProofProject, setupProofIsStale, setupProofApplies, } from './commands-setup-proof.js';
|
|
24
25
|
import { skillReadiness } from './commands-skill.js';
|
|
25
26
|
import { projectBinding, projectEnabled } from './project-enablement.js';
|
|
27
|
+
import { CLI_UPDATE_AVAILABLE, SERVICE_UPDATE_IN_PROGRESS } from './cli-contract.js';
|
|
26
28
|
// ---------------------------------------------------------------------------
|
|
27
29
|
// doctor
|
|
28
30
|
// ---------------------------------------------------------------------------
|
|
@@ -84,7 +86,7 @@ async function compatibilityCheck(client, deps) {
|
|
|
84
86
|
status: 'optional-gap',
|
|
85
87
|
detail: scheduled
|
|
86
88
|
? 'Update Notifai soon to keep sending notifications.'
|
|
87
|
-
:
|
|
89
|
+
: CLI_UPDATE_AVAILABLE,
|
|
88
90
|
technical,
|
|
89
91
|
remedy: {
|
|
90
92
|
by: 'user-here',
|
|
@@ -98,7 +100,7 @@ async function compatibilityCheck(client, deps) {
|
|
|
98
100
|
id: 'contract',
|
|
99
101
|
title: 'Notifai update',
|
|
100
102
|
status: 'optional-gap',
|
|
101
|
-
detail:
|
|
103
|
+
detail: SERVICE_UPDATE_IN_PROGRESS,
|
|
102
104
|
technical,
|
|
103
105
|
remedy: {
|
|
104
106
|
by: 'user-here',
|
|
@@ -117,7 +119,7 @@ async function compatibilityCheck(client, deps) {
|
|
|
117
119
|
id: 'contract',
|
|
118
120
|
title: 'Notifai update',
|
|
119
121
|
status: 'optional-gap',
|
|
120
|
-
detail:
|
|
122
|
+
detail: SERVICE_UPDATE_IN_PROGRESS,
|
|
121
123
|
technical,
|
|
122
124
|
remedy: {
|
|
123
125
|
by: 'user-here',
|
|
@@ -139,7 +141,7 @@ async function compatibilityCheck(client, deps) {
|
|
|
139
141
|
id: 'contract',
|
|
140
142
|
title: 'Notifai update',
|
|
141
143
|
status: 'optional-gap',
|
|
142
|
-
detail:
|
|
144
|
+
detail: SERVICE_UPDATE_IN_PROGRESS,
|
|
143
145
|
technical: {
|
|
144
146
|
error: err instanceof ApiCallError
|
|
145
147
|
? { code: err.code, status: err.status }
|
|
@@ -168,13 +170,8 @@ function projectReadiness(deps, config) {
|
|
|
168
170
|
return {
|
|
169
171
|
id: 'project',
|
|
170
172
|
title: 'Project identity',
|
|
171
|
-
status: '
|
|
172
|
-
detail: `"${inferred}"
|
|
173
|
-
remedy: {
|
|
174
|
-
by: 'cli',
|
|
175
|
-
summary: 'make the inferred Project identity explicit for every checkout',
|
|
176
|
-
command: 'notifai init',
|
|
177
|
-
},
|
|
173
|
+
status: 'ready',
|
|
174
|
+
detail: `"${inferred}" (inferred from Git or the current directory)`,
|
|
178
175
|
};
|
|
179
176
|
}
|
|
180
177
|
return {
|
|
@@ -514,7 +511,7 @@ async function applyRegistryRecommendation(deps, json, states) {
|
|
|
514
511
|
if (contract === undefined || contract.status === 'gap')
|
|
515
512
|
return;
|
|
516
513
|
contract.status = 'optional-gap';
|
|
517
|
-
contract.detail =
|
|
514
|
+
contract.detail = CLI_UPDATE_AVAILABLE;
|
|
518
515
|
contract.remedy = {
|
|
519
516
|
by: 'user-here',
|
|
520
517
|
summary: 'update Notifai',
|
|
@@ -707,7 +704,7 @@ export function remedyLine(state) {
|
|
|
707
704
|
* a remedy.
|
|
708
705
|
*/
|
|
709
706
|
function hookStates(deps) {
|
|
710
|
-
const installations = findInstallations(deps.
|
|
707
|
+
const installations = findInstallations(deps.env, deps.hookAdapterHome, deps.hookPlatform);
|
|
711
708
|
const { active, contested } = resolveActiveHarness(deps.env, deps.cwd, (deps.now ?? Date.now)());
|
|
712
709
|
const config = loadLoggedConfig(deps, { cwd: deps.cwd, env: deps.env });
|
|
713
710
|
const settings = {
|
|
@@ -787,7 +784,7 @@ function hookStates(deps) {
|
|
|
787
784
|
'hooks (adapter)': 'Hook adapter',
|
|
788
785
|
'hooks (trust)': 'Codex hook trust',
|
|
789
786
|
'hooks (stop shape)': 'Turn-end hook shape',
|
|
790
|
-
'hooks (
|
|
787
|
+
'hooks (legacy project install)': 'Leftover project hook install',
|
|
791
788
|
'hooks (codex representation)': 'Codex hook representation',
|
|
792
789
|
'hooks (question admission)': 'Question admission',
|
|
793
790
|
'hooks (fired)': 'Hooks have run here',
|
|
@@ -808,13 +805,14 @@ function hookStates(deps) {
|
|
|
808
805
|
: 'gap',
|
|
809
806
|
detail: check.detail,
|
|
810
807
|
...(check.technical === undefined ? {} : { technical: check.technical }),
|
|
811
|
-
...(check.ok
|
|
808
|
+
...(check.ok || (check.reportOnly === true && check.remedy === undefined)
|
|
812
809
|
? {}
|
|
813
810
|
: {
|
|
814
811
|
remedy: {
|
|
815
812
|
// The check's own remedy when it has one; the generic reinstall
|
|
816
813
|
// line was wrong exactly where it mattered (an unfired pointer
|
|
817
|
-
// needs a prompt, not `hooks install`).
|
|
814
|
+
// needs a prompt, not `hooks install`). A report-only capability
|
|
815
|
+
// with no remedy is intentionally absent, not repairable.
|
|
818
816
|
...(check.remedy ?? {
|
|
819
817
|
summary: 'the detail above names what to change',
|
|
820
818
|
command: 'notifai hooks install',
|
|
@@ -828,7 +826,7 @@ function hookStates(deps) {
|
|
|
828
826
|
}
|
|
829
827
|
function hookChecks(deps) {
|
|
830
828
|
const checks = [];
|
|
831
|
-
const installations = findInstallations(deps.
|
|
829
|
+
const installations = findInstallations(deps.env, deps.hookAdapterHome, deps.hookPlatform);
|
|
832
830
|
// Not having hooks is a setup someone chose, not a fault: `send` works
|
|
833
831
|
// without them. A setup that cannot work is what deserves to go red.
|
|
834
832
|
if (installations.length === 0) {
|
|
@@ -842,9 +840,7 @@ function hookChecks(deps) {
|
|
|
842
840
|
checks.push({
|
|
843
841
|
name: 'hooks',
|
|
844
842
|
ok: true,
|
|
845
|
-
detail: installations
|
|
846
|
-
.map((i) => `${i.harness} ${i.global ? 'global' : 'project'} (${i.file})`)
|
|
847
|
-
.join(', '),
|
|
843
|
+
detail: installations.map((i) => `${i.harness} (${i.file})`).join(', '),
|
|
848
844
|
});
|
|
849
845
|
const wired = new Set(installations.map((installation) => installation.harness));
|
|
850
846
|
const unwired = detectedHarnesses(deps.cwd, deps.env).filter((harness) => !wired.has(harness));
|
|
@@ -973,9 +969,8 @@ function hookChecks(deps) {
|
|
|
973
969
|
checks.push({
|
|
974
970
|
name: 'hooks (adapter)',
|
|
975
971
|
ok: false,
|
|
976
|
-
//
|
|
977
|
-
//
|
|
978
|
-
reportOnly: active === null && installations.every((installation) => installation.global),
|
|
972
|
+
// The adapter is one Machine-level file every harness runs through, so
|
|
973
|
+
// a defect in it is always this machine's to fix and always fixable.
|
|
979
974
|
detail: adapterProblems.join('; '),
|
|
980
975
|
...(adapterMismatch
|
|
981
976
|
? { technical: { effective_cli_artifact: effectiveArtifact, registered_target: sharedAdapter.target } }
|
|
@@ -1008,38 +1003,38 @@ function hookChecks(deps) {
|
|
|
1008
1003
|
},
|
|
1009
1004
|
}),
|
|
1010
1005
|
});
|
|
1011
|
-
const shapeProblems = installations.flatMap((installation) => stopShapeProblems(installation, deps.hookPlatform).map((problem) => `${problem} — run \`notifai hooks install --harness ${installation.harness}
|
|
1006
|
+
const shapeProblems = installations.flatMap((installation) => stopShapeProblems(installation, deps.hookPlatform).map((problem) => `${problem} — run \`notifai hooks install --harness ${installation.harness}\``));
|
|
1012
1007
|
checks.push({
|
|
1013
1008
|
name: 'hooks (stop shape)',
|
|
1014
1009
|
ok: shapeProblems.length === 0,
|
|
1015
1010
|
detail: shapeProblems.length === 0
|
|
1016
|
-
? `every installed Stop handler declares the shape its harness
|
|
1011
|
+
? `every installed Stop handler declares the shape its harness and host need: Claude Code async on POSIX and blocking on Windows, Codex blocking, each with an explicit ${QUESTION_STOP_TIMEOUT_SECONDS}s full-window budget; non-routing blocking hosts ${NON_ROUTING_BLOCKING_STOP_TIMEOUT_SECONDS}s`
|
|
1017
1012
|
: shapeProblems.join('; '),
|
|
1018
1013
|
});
|
|
1019
|
-
// Project
|
|
1020
|
-
//
|
|
1021
|
-
//
|
|
1022
|
-
//
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
installations: installations.filter((i) => i.harness === harness),
|
|
1030
|
-
}))
|
|
1031
|
-
.filter((entry) => entry.installations.some((installation) => installation.global) &&
|
|
1032
|
-
entry.installations.some((installation) => !installation.global));
|
|
1033
|
-
if (duplicated.length > 0) {
|
|
1014
|
+
// A Project-scoped definition an older build wrote still fires beside the
|
|
1015
|
+
// Machine one, so each event runs twice and the Project copy keeps serving a
|
|
1016
|
+
// definition no install refreshes. Notifai no longer creates these and never
|
|
1017
|
+
// accepts one as a working route: it is a gap with an exact removal command.
|
|
1018
|
+
const legacy = findLegacyProjectInstallations(deps.cwd, deps.env, deps.hookAdapterHome, deps.hookPlatform);
|
|
1019
|
+
if (legacy.length > 0) {
|
|
1020
|
+
const harnesses = [...new Set(legacy.map((installation) => installation.harness))];
|
|
1021
|
+
const command = harnesses
|
|
1022
|
+
.map((harness) => `notifai hooks install --harness ${harness}`)
|
|
1023
|
+
.join(' && ');
|
|
1034
1024
|
checks.push({
|
|
1035
|
-
name: 'hooks (
|
|
1025
|
+
name: 'hooks (legacy project install)',
|
|
1036
1026
|
ok: false,
|
|
1037
|
-
detail:
|
|
1038
|
-
.map((
|
|
1039
|
-
.join('
|
|
1027
|
+
detail: `${legacy
|
|
1028
|
+
.map((installation) => `${installation.harness} (${installation.file})`)
|
|
1029
|
+
.join(', ')} — Notifai installs for this machine only, and a leftover Project copy fires beside it. Run \`${command}\` to remove it`,
|
|
1030
|
+
remedy: {
|
|
1031
|
+
by: 'cli',
|
|
1032
|
+
summary: 'remove the leftover Project-scoped Notifai hooks',
|
|
1033
|
+
command,
|
|
1034
|
+
},
|
|
1040
1035
|
});
|
|
1041
1036
|
}
|
|
1042
|
-
const representationProblems = codexRepresentationProblems(deps.
|
|
1037
|
+
const representationProblems = codexRepresentationProblems(deps.env, deps.hookPlatform);
|
|
1043
1038
|
if (representationProblems.length > 0) {
|
|
1044
1039
|
checks.push({
|
|
1045
1040
|
name: 'hooks (codex representation)',
|
|
@@ -1048,7 +1043,7 @@ function hookChecks(deps) {
|
|
|
1048
1043
|
});
|
|
1049
1044
|
}
|
|
1050
1045
|
else {
|
|
1051
|
-
const coexistence = codexCoexistenceNotes(deps.
|
|
1046
|
+
const coexistence = codexCoexistenceNotes(deps.env, deps.hookPlatform);
|
|
1052
1047
|
if (coexistence.length > 0) {
|
|
1053
1048
|
checks.push({
|
|
1054
1049
|
name: 'hooks (codex representation)',
|
|
@@ -1062,48 +1057,33 @@ function hookChecks(deps) {
|
|
|
1062
1057
|
checks.push({ name: 'hooks (codex home)', ok: true, detail: codexHome });
|
|
1063
1058
|
}
|
|
1064
1059
|
if (active !== null && activeInstallations.length > 0) {
|
|
1065
|
-
//
|
|
1066
|
-
//
|
|
1067
|
-
//
|
|
1068
|
-
const
|
|
1069
|
-
? deps.cwd
|
|
1070
|
-
: readSessionState(active.sessionId, deps.env).activation_cwd ?? deps.cwd;
|
|
1071
|
-
const admissionDeps = activationCwd === deps.cwd ? deps : { ...deps, cwd: activationCwd };
|
|
1072
|
-
const admissionInstallations = activationCwd === deps.cwd
|
|
1073
|
-
? installations
|
|
1074
|
-
: findInstallations(activationCwd, deps.env, deps.hookAdapterHome, deps.hookPlatform);
|
|
1075
|
-
const admissionProblems = activeQuestionRouteProblems(admissionDeps, active, admissionInstallations);
|
|
1060
|
+
// One Machine installation per harness means the inventory no longer
|
|
1061
|
+
// depends on which checkout activated the session, so admission reads the
|
|
1062
|
+
// same installations doctor already listed.
|
|
1063
|
+
const admissionProblems = activeQuestionRouteProblems(deps, active, installations);
|
|
1076
1064
|
checks.push({
|
|
1077
1065
|
name: 'hooks (question admission)',
|
|
1078
1066
|
ok: admissionProblems.length === 0,
|
|
1079
1067
|
detail: admissionProblems.length === 0
|
|
1080
1068
|
? `the active ${active.label} route is exact, current, singular, trusted where applicable, and bounded by a live owner`
|
|
1081
1069
|
: admissionProblems.join('; '),
|
|
1082
|
-
...(admissionProblems.
|
|
1070
|
+
...(admissionProblems.includes(CODEX_STOP_DEFINITION_NOT_SINGULAR_PROBLEM)
|
|
1083
1071
|
? {
|
|
1084
1072
|
remedy: {
|
|
1085
1073
|
by: 'cli',
|
|
1086
|
-
summary:
|
|
1074
|
+
summary: 'restore exactly one current Codex Stop definition',
|
|
1087
1075
|
command: 'notifai hooks install --harness codex',
|
|
1088
1076
|
},
|
|
1089
1077
|
}
|
|
1090
|
-
: admissionProblems.includes(
|
|
1078
|
+
: admissionProblems.includes(CODEX_STALE_STOP_DEFINITION_PROBLEM)
|
|
1091
1079
|
? {
|
|
1092
1080
|
remedy: {
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1081
|
+
summary: 'start one fresh Codex session so it loads the current trusted Stop definition',
|
|
1082
|
+
command: 'notifai doctor',
|
|
1083
|
+
user_action: CODEX_FRESH_SESSION_USER_ACTION,
|
|
1096
1084
|
},
|
|
1097
1085
|
}
|
|
1098
|
-
:
|
|
1099
|
-
? {
|
|
1100
|
-
remedy: {
|
|
1101
|
-
summary: 'start one fresh Codex session so it loads the current trusted Stop definition',
|
|
1102
|
-
command: 'notifai doctor',
|
|
1103
|
-
user_action: CODEX_FRESH_SESSION_USER_ACTION,
|
|
1104
|
-
},
|
|
1105
|
-
}
|
|
1106
|
-
: {}),
|
|
1086
|
+
: {}),
|
|
1107
1087
|
});
|
|
1108
1088
|
}
|
|
1109
1089
|
// Which route this judges, and which remedy it prints, must both belong to
|
|
@@ -1122,7 +1102,7 @@ function hookChecks(deps) {
|
|
|
1122
1102
|
const firedState = firedPointer === null ? null : readSessionState(firedPointer.sessionId, deps.env);
|
|
1123
1103
|
const promptFired = firedState?.last_prompt_at !== undefined;
|
|
1124
1104
|
const stopFired = firedState?.last_stop_at !== undefined;
|
|
1125
|
-
const fired = firedPointer !== null && promptFired
|
|
1105
|
+
const fired = firedPointer !== null && promptFired;
|
|
1126
1106
|
// Installations for other harnesses are irrelevant to the active one, and an
|
|
1127
1107
|
// active harness with none of its own has nothing to activate: say that
|
|
1128
1108
|
// instead of advising a prompt in some other harness. When the environment
|
|
@@ -1142,14 +1122,15 @@ function hookChecks(deps) {
|
|
|
1142
1122
|
checks.push({
|
|
1143
1123
|
name: 'hooks (fired)',
|
|
1144
1124
|
ok: fired,
|
|
1145
|
-
//
|
|
1146
|
-
//
|
|
1147
|
-
//
|
|
1125
|
+
// UserPromptSubmit proves that this exact session reached the installed
|
|
1126
|
+
// lifecycle path. A historical Stop is only telemetry: requiring one made
|
|
1127
|
+
// a first-turn question impossible even after the current Stop definition,
|
|
1128
|
+
// trust, shape, and continuation owner had all been proven above.
|
|
1148
1129
|
reportOnly: true,
|
|
1149
1130
|
detail: fired
|
|
1150
1131
|
? active === null
|
|
1151
|
-
?
|
|
1152
|
-
: `the active ${active.label} session has run UserPromptSubmit and Stop`
|
|
1132
|
+
? `a session in this directory has run UserPromptSubmit and is ready for this turn's Stop${stopFired ? '; an earlier Stop was also observed' : ''}`
|
|
1133
|
+
: `the active ${active.label} session has run UserPromptSubmit and is ready for this turn's Stop${stopFired ? '; an earlier Stop was also observed' : ''}`
|
|
1153
1134
|
: firedPointer === null
|
|
1154
1135
|
? `no ${contested.length > 1
|
|
1155
1136
|
? `session pointer for any harness whose markers are present here (${contested
|
|
@@ -1158,14 +1139,14 @@ function hookChecks(deps) {
|
|
|
1158
1139
|
: active === null
|
|
1159
1140
|
? 'session pointer'
|
|
1160
1141
|
: `${active.label} session pointer`} from the last 24 hours — ${activationAdvice}`
|
|
1161
|
-
: `the routed session has fired
|
|
1142
|
+
: `the routed session has not fired UserPromptSubmit — send one prompt, then check again`,
|
|
1162
1143
|
...(fired
|
|
1163
1144
|
? {}
|
|
1164
1145
|
: {
|
|
1165
1146
|
remedy: {
|
|
1166
1147
|
summary: firedPointer === null
|
|
1167
1148
|
? `send one ${active === null || contested.length > 1 ? '' : `${active.label} `}prompt in a session here, then re-check`
|
|
1168
|
-
: '
|
|
1149
|
+
: 'send one prompt in the routed session, then re-check',
|
|
1169
1150
|
command: 'notifai doctor',
|
|
1170
1151
|
},
|
|
1171
1152
|
}),
|
|
@@ -1177,37 +1158,36 @@ function hookChecks(deps) {
|
|
|
1177
1158
|
checks.push({
|
|
1178
1159
|
name: 'hooks (answer continuation)',
|
|
1179
1160
|
ok: continuationHarnesses.length > 0 &&
|
|
1180
|
-
continuationHarnesses.every((harness) =>
|
|
1161
|
+
continuationHarnesses.every((harness) => questionRoutingCapability(harness, deps.hookPlatform ?? process.platform)
|
|
1162
|
+
.stopContinuation !== 'unsupported'),
|
|
1181
1163
|
reportOnly: active === null,
|
|
1182
1164
|
detail: continuationHarnesses.length === 0
|
|
1183
1165
|
? active === null
|
|
1184
1166
|
? 'no installed harness route to assess'
|
|
1185
1167
|
: `the active ${active.label} session has no matching continuation adapter`
|
|
1186
1168
|
: continuationHarnesses
|
|
1187
|
-
.map((harness) => `${harness}: ${
|
|
1169
|
+
.map((harness) => `${harness}: ${questionRoutingCapability(harness, deps.hookPlatform ?? process.platform).deliveryContract}`)
|
|
1188
1170
|
.join('; '),
|
|
1189
1171
|
});
|
|
1190
1172
|
const wakeRoute = wakeRouteCheck(deps, active, activeInstallations);
|
|
1191
1173
|
if (wakeRoute !== null)
|
|
1192
1174
|
checks.push(wakeRoute);
|
|
1193
|
-
const stray = codexStrayWorktreeCheck(deps);
|
|
1194
|
-
if (stray !== null)
|
|
1195
|
-
checks.push(stray);
|
|
1196
1175
|
return checks;
|
|
1197
1176
|
}
|
|
1198
1177
|
/**
|
|
1199
|
-
* Whether an answer arriving after this turn
|
|
1200
|
-
*
|
|
1201
|
-
*
|
|
1178
|
+
* Whether an answer arriving after this turn's ordinary continuation returns
|
|
1179
|
+
* could start another turn in this exact session without a new User prompt.
|
|
1180
|
+
* This is a named optional capability, separate from the held Stop
|
|
1181
|
+
* continuation that already makes Question Routing usable.
|
|
1202
1182
|
*
|
|
1203
1183
|
* Read-only, and deliberately so: nothing here connects to a socket, takes a
|
|
1204
1184
|
* lock, or sends a message. A diagnostic that wakes the agent it is diagnosing
|
|
1205
1185
|
* would be its own bug report.
|
|
1206
1186
|
*
|
|
1207
|
-
* Everything it can report negatively is
|
|
1208
|
-
*
|
|
1209
|
-
*
|
|
1210
|
-
*
|
|
1187
|
+
* Everything it can report negatively is optional rather than a routing
|
|
1188
|
+
* failure: a held continuation can still return the answer, or the accepted
|
|
1189
|
+
* journal can replay it at the session's next turn. What it buys is that the
|
|
1190
|
+
* direct-wake capability and its limits have an explicit name.
|
|
1211
1191
|
*
|
|
1212
1192
|
* It never asks for `crossSessionInbound`. The poster is the session's own
|
|
1213
1193
|
* hook child and takes the privileged own-child path, verified to be delivered
|
|
@@ -1219,9 +1199,19 @@ function wakeRouteCheck(deps, active, activeInstallations) {
|
|
|
1219
1199
|
if (active === null || activeInstallations.length === 0)
|
|
1220
1200
|
return null;
|
|
1221
1201
|
if (active.harness === 'claude-code') {
|
|
1202
|
+
const platform = deps.hookPlatform ?? process.platform;
|
|
1203
|
+
if (platform === 'win32') {
|
|
1204
|
+
return {
|
|
1205
|
+
name: 'hooks (wake route)',
|
|
1206
|
+
ok: false,
|
|
1207
|
+
reportOnly: true,
|
|
1208
|
+
technical: { held_stop_continuation: true },
|
|
1209
|
+
detail: 'direct inbox wake is unavailable on Windows; the held Stop still returns the answer to this same Agent Session without another User prompt',
|
|
1210
|
+
};
|
|
1211
|
+
}
|
|
1222
1212
|
const readiness = inspectClaudeInbox({
|
|
1223
1213
|
pid: deps.claudeSourcePid ?? claudeSessionPid(deps.env),
|
|
1224
|
-
platform
|
|
1214
|
+
platform,
|
|
1225
1215
|
readDescriptor: deps.claudeWake?.readDescriptor ?? systemClaudeWakeAdapters(deps.env).readDescriptor,
|
|
1226
1216
|
socketExists: (socketPath) => existsSync(socketPath),
|
|
1227
1217
|
});
|
|
@@ -1243,6 +1233,7 @@ function wakeRouteCheck(deps, active, activeInstallations) {
|
|
|
1243
1233
|
name: 'hooks (wake route)',
|
|
1244
1234
|
ok: readiness.state === 'ready',
|
|
1245
1235
|
reportOnly: true,
|
|
1236
|
+
technical: { held_stop_continuation: true },
|
|
1246
1237
|
detail: readiness.state === 'ready'
|
|
1247
1238
|
? `the held Codex turn continues from its own hook, and after it returns ${readiness.lockDirectory} can prove a stopped thread unowned before resuming it`
|
|
1248
1239
|
: `the held Codex turn still continues from its own hook, but after it returns nothing can be resumed: ${readiness.reason}. Answers wait for the next turn`,
|
|
@@ -1250,40 +1241,4 @@ function wakeRouteCheck(deps, active, activeInstallations) {
|
|
|
1250
1241
|
}
|
|
1251
1242
|
return null;
|
|
1252
1243
|
}
|
|
1253
|
-
/**
|
|
1254
|
-
* A Codex hooks file sitting in a worktree, which Codex will never read.
|
|
1255
|
-
*
|
|
1256
|
-
* `settingsFile` now writes to the main repository, so this only fires for a
|
|
1257
|
-
* file an older build left behind — but that file is indistinguishable from a
|
|
1258
|
-
* working install if you go looking, and it is exactly what made this bug take
|
|
1259
|
-
* a day to find. Omitted entirely when there is nothing to say.
|
|
1260
|
-
*/
|
|
1261
|
-
function codexStrayWorktreeCheck(deps) {
|
|
1262
|
-
const layer = codexLayerDir(deps.cwd);
|
|
1263
|
-
if (layer === null)
|
|
1264
|
-
return null;
|
|
1265
|
-
const root = codexProjectRoot(deps.cwd);
|
|
1266
|
-
const project = inspectCodexLayer(codexLayerPaths(false, deps.cwd, deps.env));
|
|
1267
|
-
if (project.jsonEvents.length === 0 && project.tomlEvents.length === 0)
|
|
1268
|
-
return null;
|
|
1269
|
-
const strayJson = path.join(path.dirname(layer), '.codex', 'hooks.json');
|
|
1270
|
-
const strayToml = path.join(path.dirname(layer), '.codex', 'config.toml');
|
|
1271
|
-
const problems = [];
|
|
1272
|
-
if (!existsSync(layer)) {
|
|
1273
|
-
problems.push(`${layer} is missing, so Codex never looks for project hooks here`);
|
|
1274
|
-
}
|
|
1275
|
-
if (existsSync(strayJson) && path.resolve(strayJson) !== path.resolve(project.paths.hooksJson)) {
|
|
1276
|
-
problems.push(`${strayJson} is never read — Codex reads ${project.writeTarget} instead`);
|
|
1277
|
-
}
|
|
1278
|
-
if (existsSync(strayToml) && path.resolve(strayToml) !== path.resolve(project.paths.configToml)) {
|
|
1279
|
-
problems.push(`${strayToml} is never read — Codex reads ${project.writeTarget} instead`);
|
|
1280
|
-
}
|
|
1281
|
-
return {
|
|
1282
|
-
name: 'hooks (codex worktree)',
|
|
1283
|
-
ok: problems.length === 0,
|
|
1284
|
-
detail: problems.length === 0
|
|
1285
|
-
? `worktree wired to the main repository at ${root}`
|
|
1286
|
-
: `${problems.join('; ')}. Re-run \`notifai hooks install\` to fix.`,
|
|
1287
|
-
};
|
|
1288
|
-
}
|
|
1289
1244
|
//# sourceMappingURL=commands-doctor.js.map
|