@raidiant/notifai 9.3.0 → 10.1.0
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 +40 -0
- package/README.md +1 -1
- package/dist/client.d.ts +3 -1
- package/dist/client.js +2 -0
- package/dist/client.js.map +1 -1
- package/dist/commands-agent-sessions.d.ts +6 -0
- package/dist/commands-agent-sessions.js +51 -0
- package/dist/commands-agent-sessions.js.map +1 -0
- package/dist/commands-auth.js +4 -4
- package/dist/commands-auth.js.map +1 -1
- package/dist/commands-config.js +11 -4
- package/dist/commands-config.js.map +1 -1
- package/dist/commands-core.d.ts +5 -0
- package/dist/commands-core.js +2 -0
- package/dist/commands-core.js.map +1 -1
- package/dist/commands-doctor.js +121 -40
- package/dist/commands-doctor.js.map +1 -1
- package/dist/commands-harness-context.d.ts +15 -2
- package/dist/commands-harness-context.js +40 -1
- package/dist/commands-harness-context.js.map +1 -1
- package/dist/commands-hooks.d.ts +4 -3
- package/dist/commands-hooks.js +139 -16
- package/dist/commands-hooks.js.map +1 -1
- package/dist/commands-init.js +10 -5
- package/dist/commands-init.js.map +1 -1
- package/dist/commands-send-support.js +18 -1
- package/dist/commands-send-support.js.map +1 -1
- package/dist/commands-send.js +2 -2
- package/dist/commands-send.js.map +1 -1
- package/dist/commands-sounds.d.ts +12 -0
- package/dist/commands-sounds.js +35 -0
- package/dist/commands-sounds.js.map +1 -0
- package/dist/commands.d.ts +2 -0
- package/dist/commands.js +2 -0
- package/dist/commands.js.map +1 -1
- package/dist/config-schema.js +5 -2
- package/dist/config-schema.js.map +1 -1
- package/dist/config.d.ts +3 -4
- package/dist/config.js +5 -2
- package/dist/config.js.map +1 -1
- package/dist/credentials.js +4 -1
- package/dist/credentials.js.map +1 -1
- package/dist/harnesses.d.ts +49 -7
- package/dist/harnesses.js +110 -24
- package/dist/harnesses.js.map +1 -1
- package/dist/hooks.d.ts +2 -2
- package/dist/hooks.js +2 -2
- package/dist/hooks.js.map +1 -1
- package/dist/install-hooks.d.ts +10 -11
- package/dist/install-hooks.js +18 -13
- package/dist/install-hooks.js.map +1 -1
- package/dist/interactive.js +20 -23
- package/dist/interactive.js.map +1 -1
- package/dist/invocation-context.d.ts +2 -2
- package/dist/openclaw-plugin.d.ts +49 -0
- package/dist/openclaw-plugin.js +350 -0
- package/dist/openclaw-plugin.js.map +1 -0
- package/dist/orca-session-title.d.ts +10 -0
- package/dist/orca-session-title.js +98 -0
- package/dist/orca-session-title.js.map +1 -0
- package/dist/program.d.ts +3 -1
- package/dist/program.js +37 -13
- package/dist/program.js.map +1 -1
- package/dist/send.js +11 -14
- package/dist/send.js.map +1 -1
- package/dist/session-activation.js +1 -1
- package/dist/session-activation.js.map +1 -1
- package/dist/session-labels.d.ts +18 -2
- package/dist/session-labels.js +79 -8
- package/dist/session-labels.js.map +1 -1
- package/dist/sound-ref.d.ts +23 -0
- package/dist/sound-ref.js +28 -0
- package/dist/sound-ref.js.map +1 -0
- package/dist/ui/help.d.ts +4 -5
- package/dist/ui/help.js +5 -6
- package/dist/ui/help.js.map +1 -1
- package/package.json +3 -3
- package/src/client.test.ts +12 -0
- package/src/client.ts +8 -0
- package/src/commands-agent-sessions.ts +72 -0
- package/src/commands-auth.ts +4 -3
- package/src/commands-config.ts +10 -4
- package/src/commands-core.ts +6 -0
- package/src/commands-doctor.ts +143 -38
- package/src/commands-harness-context.ts +56 -2
- package/src/commands-hooks.ts +180 -20
- package/src/commands-init.ts +10 -4
- package/src/commands-send-support.ts +23 -1
- package/src/commands-send.ts +2 -2
- package/src/commands-sounds.test.ts +106 -0
- package/src/commands-sounds.ts +49 -0
- package/src/commands.test.ts +529 -17
- package/src/commands.ts +5 -0
- package/src/config-schema.test.ts +1 -0
- package/src/config-schema.ts +5 -2
- package/src/config.test.ts +42 -20
- package/src/config.ts +6 -5
- package/src/credentials.test.ts +20 -0
- package/src/credentials.ts +4 -1
- package/src/fixtures/hermes-0.20.6-classic-cli-local.json +50 -0
- package/src/fixtures/openclaw-2026.7.1-2-agent-local.json +57 -0
- package/src/harness-integration.test.ts +294 -0
- package/src/harnesses.test.ts +115 -8
- package/src/harnesses.ts +133 -30
- package/src/hooks.test.ts +4 -3
- package/src/hooks.ts +4 -4
- package/src/install-hooks.test.ts +213 -4
- package/src/install-hooks.ts +38 -30
- package/src/interactive.test.ts +31 -0
- package/src/interactive.ts +20 -26
- package/src/invocation-context.ts +2 -2
- package/src/openclaw-plugin.ts +409 -0
- package/src/orca-session-title.test.ts +54 -0
- package/src/orca-session-title.ts +103 -0
- package/src/program.test.ts +27 -0
- package/src/program.ts +47 -12
- package/src/send.ts +10 -19
- package/src/session-activation.ts +1 -1
- package/src/session-labels.test.ts +58 -9
- package/src/session-labels.ts +95 -12
- package/src/skill.test.ts +14 -3
- package/src/sound-ref.test.ts +31 -0
- package/src/sound-ref.ts +34 -0
- package/src/ui/config-view.test.ts +1 -0
- package/src/ui/help.test.ts +16 -0
- package/src/ui/help.ts +6 -7
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { hookHostPlatform } from './hook-adapter.js';
|
|
3
|
+
import { harnessAccountHome } from './install-hooks.js';
|
|
4
|
+
import { MISSING_LIFECYCLE_GUIDANCE_CONTEXT, WORKER_ACTIVATION_CONTEXT, } from './session-activation.js';
|
|
5
|
+
/**
|
|
6
|
+
* The OpenClaw adapter.
|
|
7
|
+
*
|
|
8
|
+
* OpenClaw's extension point is an in-process Gateway plugin, not a command
|
|
9
|
+
* hook. The generated module shells out to the same `notifai hook <event>`
|
|
10
|
+
* commands every other harness invokes, so presence, activation, and
|
|
11
|
+
* retirement stay in the CLI.
|
|
12
|
+
*
|
|
13
|
+
* before_prompt_build -> session-start / subagent-start (first owner/worker)
|
|
14
|
+
* message_received -> user-prompt-submit (User is present)
|
|
15
|
+
* agent_end -> stop (the turn ended)
|
|
16
|
+
* session_end -> session-end (retire local state)
|
|
17
|
+
* resolve_exec_env -> NOTIFAI_ACTIVE_* markers (exact Source Context)
|
|
18
|
+
*
|
|
19
|
+
* `command:stop` is a User abort and is deliberately not wired. Asynchronous
|
|
20
|
+
* ask is unsupported until a live continuation probe.
|
|
21
|
+
*/
|
|
22
|
+
export const OPENCLAW_PLUGIN_MARKER = '// notifai managed openclaw plugin';
|
|
23
|
+
export const OPENCLAW_PLUGIN_ID = 'notifai';
|
|
24
|
+
export const OPENCLAW_PLUGIN_FILENAME = 'index.js';
|
|
25
|
+
export const OPENCLAW_PLUGIN_MANIFEST = 'openclaw.plugin.json';
|
|
26
|
+
export const OPENCLAW_PLUGIN_PACKAGE = 'package.json';
|
|
27
|
+
const OPENCLAW_ADAPTER_VERSION = 1;
|
|
28
|
+
export const OPENCLAW_EVENTS = [
|
|
29
|
+
['SessionStart', 'session-start'],
|
|
30
|
+
['SubagentStart', 'subagent-start'],
|
|
31
|
+
['UserPromptSubmit', 'user-prompt-submit'],
|
|
32
|
+
['Stop', 'stop'],
|
|
33
|
+
['SessionEnd', 'session-end'],
|
|
34
|
+
];
|
|
35
|
+
export function openclawStateDir(env = process.env, platform = process.platform) {
|
|
36
|
+
const override = env['OPENCLAW_STATE_DIR'];
|
|
37
|
+
if (override !== undefined && override !== '')
|
|
38
|
+
return override;
|
|
39
|
+
const homeOverride = env['OPENCLAW_HOME'];
|
|
40
|
+
if (homeOverride !== undefined && homeOverride !== '') {
|
|
41
|
+
return path.join(homeOverride, '.openclaw');
|
|
42
|
+
}
|
|
43
|
+
return path.join(harnessAccountHome(env, platform), '.openclaw');
|
|
44
|
+
}
|
|
45
|
+
export function openclawConfigPath(env = process.env, platform = process.platform) {
|
|
46
|
+
const override = env['OPENCLAW_CONFIG_PATH'];
|
|
47
|
+
if (override !== undefined && override !== '')
|
|
48
|
+
return override;
|
|
49
|
+
return path.join(openclawStateDir(env, platform), 'openclaw.json');
|
|
50
|
+
}
|
|
51
|
+
export function openclawPluginDir(global, cwd, env = process.env, platform = process.platform) {
|
|
52
|
+
return global
|
|
53
|
+
? path.join(openclawStateDir(env, platform), 'extensions', OPENCLAW_PLUGIN_ID)
|
|
54
|
+
: path.join(cwd, '.openclaw', 'extensions', OPENCLAW_PLUGIN_ID);
|
|
55
|
+
}
|
|
56
|
+
export function openclawPluginPath(global, cwd, env = process.env, platform = process.platform) {
|
|
57
|
+
return path.join(openclawPluginDir(global, cwd, env, platform), OPENCLAW_PLUGIN_FILENAME);
|
|
58
|
+
}
|
|
59
|
+
export function openclawPluginManifest() {
|
|
60
|
+
return `${JSON.stringify({
|
|
61
|
+
id: OPENCLAW_PLUGIN_ID,
|
|
62
|
+
name: 'Notifai',
|
|
63
|
+
description: 'Notifai lifecycle activation, Source Context, and session observation.',
|
|
64
|
+
activation: { onStartup: true },
|
|
65
|
+
configSchema: { type: 'object', additionalProperties: false },
|
|
66
|
+
}, null, 2)}\n`;
|
|
67
|
+
}
|
|
68
|
+
export function openclawPluginPackage() {
|
|
69
|
+
return `${JSON.stringify({
|
|
70
|
+
name: 'notifai-openclaw',
|
|
71
|
+
version: '1.0.0',
|
|
72
|
+
type: 'module',
|
|
73
|
+
openclaw: { extensions: [`./${OPENCLAW_PLUGIN_FILENAME}`] },
|
|
74
|
+
}, null, 2)}\n`;
|
|
75
|
+
}
|
|
76
|
+
export function openclawPluginSource(options) {
|
|
77
|
+
const { adapterPath, timeoutSeconds } = options;
|
|
78
|
+
const win32 = hookHostPlatform(options.platform) === 'win32';
|
|
79
|
+
const nodeConstant = win32
|
|
80
|
+
? `const NODE = ${JSON.stringify(options.nodePath ?? process.execPath)}\n`
|
|
81
|
+
: '';
|
|
82
|
+
const spawnArguments = win32
|
|
83
|
+
? 'NODE, [ADAPTER, "hook", event, "--owner", "notifai", "--harness", "openclaw"]'
|
|
84
|
+
: 'ADAPTER, ["hook", event, "--owner", "notifai", "--harness", "openclaw"]';
|
|
85
|
+
const windowsHide = win32 ? '\n windowsHide: true,' : '';
|
|
86
|
+
return `${OPENCLAW_PLUGIN_MARKER}
|
|
87
|
+
// Generated by \`notifai hooks install --harness openclaw\`. Edits are lost on
|
|
88
|
+
// the next install; change the CLI instead, which is where the logic lives.
|
|
89
|
+
import { spawn } from "node:child_process"
|
|
90
|
+
|
|
91
|
+
${nodeConstant}const ADAPTER = ${JSON.stringify(adapterPath)}
|
|
92
|
+
const TIMEOUT_MS = ${timeoutSeconds * 1000}
|
|
93
|
+
const ADAPTER_VERSION = ${OPENCLAW_ADAPTER_VERSION}
|
|
94
|
+
const MISSING_LIFECYCLE_GUIDANCE_CONTEXT = ${JSON.stringify(MISSING_LIFECYCLE_GUIDANCE_CONTEXT)}
|
|
95
|
+
const WORKER_ACTIVATION_CONTEXT = ${JSON.stringify(WORKER_ACTIVATION_CONTEXT)}
|
|
96
|
+
|
|
97
|
+
function runHook(event, envelope) {
|
|
98
|
+
return new Promise((resolve) => {
|
|
99
|
+
let child
|
|
100
|
+
try {
|
|
101
|
+
child = spawn(${spawnArguments}, {
|
|
102
|
+
env: process.env,
|
|
103
|
+
shell: false,${windowsHide}
|
|
104
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
105
|
+
})
|
|
106
|
+
} catch {
|
|
107
|
+
resolve(null)
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let stdout = ""
|
|
112
|
+
let settled = false
|
|
113
|
+
const finish = (value) => {
|
|
114
|
+
if (settled) return
|
|
115
|
+
settled = true
|
|
116
|
+
clearTimeout(timer)
|
|
117
|
+
resolve(value)
|
|
118
|
+
}
|
|
119
|
+
const timer = setTimeout(() => {
|
|
120
|
+
child.kill("SIGTERM")
|
|
121
|
+
finish(null)
|
|
122
|
+
}, TIMEOUT_MS)
|
|
123
|
+
|
|
124
|
+
child.stdout?.setEncoding("utf-8")
|
|
125
|
+
child.stdout?.on("data", (chunk) => {
|
|
126
|
+
stdout += chunk
|
|
127
|
+
})
|
|
128
|
+
child.stderr?.resume()
|
|
129
|
+
child.on("error", () => finish(null))
|
|
130
|
+
child.on("close", () => finish(stdout))
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
child.stdin?.end(JSON.stringify(envelope))
|
|
134
|
+
} catch {
|
|
135
|
+
finish(null)
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function sessionKeyOf(event, ctx) {
|
|
141
|
+
const key = ctx?.sessionKey ?? event?.sessionKey ?? event?.context?.sessionKey
|
|
142
|
+
return typeof key === "string" ? key.trim() : ""
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function workspaceDirOf(event, ctx) {
|
|
146
|
+
const dir = ctx?.workspaceDir ?? event?.workspaceDir ?? event?.context?.workspaceDir
|
|
147
|
+
return typeof dir === "string" && dir.length > 0 ? dir : process.cwd()
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function isWorkerSession(sessionKey, ctx) {
|
|
151
|
+
if (sessionKey === "") return true
|
|
152
|
+
if (sessionKey.includes(":subagent:")) return true
|
|
153
|
+
if (sessionKey.includes(":acp:")) return true
|
|
154
|
+
if (ctx?.targetKind === "acp" || ctx?.dispatchKind === "acp") return true
|
|
155
|
+
if (typeof ctx?.parentSessionKey === "string" && ctx.parentSessionKey.length > 0) return true
|
|
156
|
+
return false
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function isUserMessage(event, ctx) {
|
|
160
|
+
const from = event?.from ?? event?.context?.from ?? ctx?.senderId
|
|
161
|
+
if (typeof from !== "string" || from.trim().length === 0) return false
|
|
162
|
+
const trigger = ctx?.trigger ?? event?.trigger
|
|
163
|
+
if (trigger === "cron" || trigger === "heartbeat") return false
|
|
164
|
+
return true
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function register(api) {
|
|
168
|
+
const activated = new Set()
|
|
169
|
+
api.on("before_prompt_build", async (event, ctx) => {
|
|
170
|
+
const sessionKey = sessionKeyOf(event, ctx)
|
|
171
|
+
if (sessionKey === "") return { prependContext: WORKER_ACTIVATION_CONTEXT }
|
|
172
|
+
if (activated.has(sessionKey)) return
|
|
173
|
+
const worker = isWorkerSession(sessionKey, ctx)
|
|
174
|
+
const resolved = await runHook(worker ? "subagent-start" : "session-start", {
|
|
175
|
+
session_id: sessionKey,
|
|
176
|
+
cwd: workspaceDirOf(event, ctx),
|
|
177
|
+
hook_event_name: worker ? "SubagentStart" : "SessionStart",
|
|
178
|
+
})
|
|
179
|
+
const context = typeof resolved === "string" && resolved.trim().length > 0
|
|
180
|
+
? resolved.trim()
|
|
181
|
+
: worker ? WORKER_ACTIVATION_CONTEXT : MISSING_LIFECYCLE_GUIDANCE_CONTEXT
|
|
182
|
+
activated.add(sessionKey)
|
|
183
|
+
return { prependContext: context }
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
api.on("message_received", async (event, ctx) => {
|
|
187
|
+
if (!isUserMessage(event, ctx)) return
|
|
188
|
+
const sessionKey = sessionKeyOf(event, ctx)
|
|
189
|
+
if (sessionKey === "") return
|
|
190
|
+
await runHook("user-prompt-submit", {
|
|
191
|
+
session_id: sessionKey,
|
|
192
|
+
cwd: workspaceDirOf(event, ctx),
|
|
193
|
+
hook_event_name: "UserPromptSubmit",
|
|
194
|
+
})
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
api.on("agent_end", async (event, ctx) => {
|
|
198
|
+
const sessionKey = sessionKeyOf(event, ctx)
|
|
199
|
+
if (sessionKey === "") return
|
|
200
|
+
await runHook("stop", {
|
|
201
|
+
session_id: sessionKey,
|
|
202
|
+
cwd: workspaceDirOf(event, ctx),
|
|
203
|
+
hook_event_name: "Stop",
|
|
204
|
+
})
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
api.on("session_end", async (event, ctx) => {
|
|
208
|
+
const sessionKey = sessionKeyOf(event, ctx)
|
|
209
|
+
if (sessionKey === "") return
|
|
210
|
+
activated.delete(sessionKey)
|
|
211
|
+
await runHook("session-end", {
|
|
212
|
+
session_id: sessionKey,
|
|
213
|
+
cwd: workspaceDirOf(event, ctx),
|
|
214
|
+
hook_event_name: "SessionEnd",
|
|
215
|
+
})
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
api.on("resolve_exec_env", (event, ctx) => {
|
|
219
|
+
const sessionKey = sessionKeyOf(event, ctx)
|
|
220
|
+
if (sessionKey === "") return
|
|
221
|
+
return {
|
|
222
|
+
NOTIFAI_ACTIVE_HARNESS: "openclaw",
|
|
223
|
+
NOTIFAI_ACTIVE_SESSION_ID: sessionKey,
|
|
224
|
+
}
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export default {
|
|
229
|
+
id: ${JSON.stringify(OPENCLAW_PLUGIN_ID)},
|
|
230
|
+
name: "Notifai",
|
|
231
|
+
register,
|
|
232
|
+
}
|
|
233
|
+
`;
|
|
234
|
+
}
|
|
235
|
+
export function isOurOpenclawPlugin(contents) {
|
|
236
|
+
return contents.includes(OPENCLAW_PLUGIN_MARKER);
|
|
237
|
+
}
|
|
238
|
+
export function openclawPluginTarget(contents) {
|
|
239
|
+
if (!isOurOpenclawPlugin(contents))
|
|
240
|
+
return null;
|
|
241
|
+
const adapter = /^const ADAPTER = (".*")$/m.exec(contents)?.[1];
|
|
242
|
+
const node = /^const NODE = (".*")$/m.exec(contents)?.[1];
|
|
243
|
+
const version = Number(/^const ADAPTER_VERSION = (\d+)$/m.exec(contents)?.[1] ?? 0);
|
|
244
|
+
const timeoutMs = Number(/^const TIMEOUT_MS = (\d+)$/m.exec(contents)?.[1] ?? Number.NaN);
|
|
245
|
+
if (adapter === undefined)
|
|
246
|
+
return null;
|
|
247
|
+
try {
|
|
248
|
+
return {
|
|
249
|
+
adapter: JSON.parse(adapter),
|
|
250
|
+
current: version === OPENCLAW_ADAPTER_VERSION,
|
|
251
|
+
...(Number.isFinite(timeoutMs) ? { timeoutSeconds: timeoutMs / 1000 } : {}),
|
|
252
|
+
...(node === undefined ? {} : { nodePath: JSON.parse(node) }),
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
export function parseOpenclawConfig(source) {
|
|
260
|
+
try {
|
|
261
|
+
const parsed = JSON.parse(source);
|
|
262
|
+
if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
263
|
+
return parsed;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
const stripped = source
|
|
268
|
+
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
269
|
+
.replace(/^\s*\/\/.*$/gm, '')
|
|
270
|
+
.replace(/,(\s*[}\]])/g, '$1');
|
|
271
|
+
const parsed = JSON.parse(stripped);
|
|
272
|
+
if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
273
|
+
return parsed;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
throw new Error('OpenClaw config is not a JSON object');
|
|
277
|
+
}
|
|
278
|
+
export function mergeOpenclawNotifaiEntry(config, pluginDir, global) {
|
|
279
|
+
const plugins = config.plugins !== null && typeof config.plugins === 'object' && !Array.isArray(config.plugins)
|
|
280
|
+
? { ...config.plugins }
|
|
281
|
+
: {};
|
|
282
|
+
const entries = plugins.entries !== null && typeof plugins.entries === 'object' && !Array.isArray(plugins.entries)
|
|
283
|
+
? { ...plugins.entries }
|
|
284
|
+
: {};
|
|
285
|
+
const existing = entries[OPENCLAW_PLUGIN_ID] !== null &&
|
|
286
|
+
typeof entries[OPENCLAW_PLUGIN_ID] === 'object' &&
|
|
287
|
+
!Array.isArray(entries[OPENCLAW_PLUGIN_ID])
|
|
288
|
+
? { ...entries[OPENCLAW_PLUGIN_ID] }
|
|
289
|
+
: {};
|
|
290
|
+
const hooks = existing.hooks !== null && typeof existing.hooks === 'object' && !Array.isArray(existing.hooks)
|
|
291
|
+
? { ...existing.hooks }
|
|
292
|
+
: {};
|
|
293
|
+
entries[OPENCLAW_PLUGIN_ID] = {
|
|
294
|
+
...existing,
|
|
295
|
+
enabled: true,
|
|
296
|
+
hooks: { ...hooks, allowConversationAccess: true },
|
|
297
|
+
};
|
|
298
|
+
plugins.entries = entries;
|
|
299
|
+
if (!global) {
|
|
300
|
+
const load = plugins.load !== null && typeof plugins.load === 'object' && !Array.isArray(plugins.load)
|
|
301
|
+
? { ...plugins.load }
|
|
302
|
+
: {};
|
|
303
|
+
const paths = Array.isArray(load.paths) ? [...load.paths] : [];
|
|
304
|
+
if (!paths.includes(pluginDir))
|
|
305
|
+
paths.push(pluginDir);
|
|
306
|
+
load.paths = paths;
|
|
307
|
+
plugins.load = load;
|
|
308
|
+
}
|
|
309
|
+
return { ...config, plugins };
|
|
310
|
+
}
|
|
311
|
+
export function removeOpenclawNotifaiEntry(config, pluginDir) {
|
|
312
|
+
const plugins = config.plugins !== null && typeof config.plugins === 'object' && !Array.isArray(config.plugins)
|
|
313
|
+
? { ...config.plugins }
|
|
314
|
+
: {};
|
|
315
|
+
const entries = plugins.entries !== null && typeof plugins.entries === 'object' && !Array.isArray(plugins.entries)
|
|
316
|
+
? { ...plugins.entries }
|
|
317
|
+
: {};
|
|
318
|
+
delete entries[OPENCLAW_PLUGIN_ID];
|
|
319
|
+
if (Object.keys(entries).length > 0)
|
|
320
|
+
plugins.entries = entries;
|
|
321
|
+
else
|
|
322
|
+
delete plugins.entries;
|
|
323
|
+
const load = plugins.load !== null && typeof plugins.load === 'object' && !Array.isArray(plugins.load)
|
|
324
|
+
? { ...plugins.load }
|
|
325
|
+
: {};
|
|
326
|
+
if (Array.isArray(load.paths)) {
|
|
327
|
+
const paths = load.paths.filter((value) => value !== pluginDir);
|
|
328
|
+
if (paths.length > 0)
|
|
329
|
+
load.paths = paths;
|
|
330
|
+
else
|
|
331
|
+
delete load.paths;
|
|
332
|
+
}
|
|
333
|
+
if (Object.keys(load).length > 0)
|
|
334
|
+
plugins.load = load;
|
|
335
|
+
else
|
|
336
|
+
delete plugins.load;
|
|
337
|
+
if (Object.keys(plugins).length > 0)
|
|
338
|
+
return { ...config, plugins };
|
|
339
|
+
const next = { ...config };
|
|
340
|
+
delete next.plugins;
|
|
341
|
+
return next;
|
|
342
|
+
}
|
|
343
|
+
/** Config-directory presence is not ownership. These files mean OpenClaw is actually configured. */
|
|
344
|
+
export function openclawHasGlobalEvidence(exists, env = process.env, platform = process.platform) {
|
|
345
|
+
const state = openclawStateDir(env, platform);
|
|
346
|
+
return (exists(openclawConfigPath(env, platform)) ||
|
|
347
|
+
exists(path.join(state, 'agents')) ||
|
|
348
|
+
exists(path.join(state, 'workspace')));
|
|
349
|
+
}
|
|
350
|
+
//# sourceMappingURL=openclaw-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openclaw-plugin.js","sourceRoot":"","sources":["../src/openclaw-plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type OrcaSessionTitleLookup = (env: NodeJS.ProcessEnv) => string | undefined;
|
|
2
|
+
export type OrcaCommand = (executable: string, args: readonly string[]) => string | null;
|
|
3
|
+
/**
|
|
4
|
+
* Read the User-facing task name assigned to this exact Orca worktree.
|
|
5
|
+
*
|
|
6
|
+
* The environment contributes only an opaque selector. Orca must return that
|
|
7
|
+
* exact id and its matching path before its display name becomes trusted; no
|
|
8
|
+
* path component or identifier is ever promoted into an Agent Session label.
|
|
9
|
+
*/
|
|
10
|
+
export declare function readOrcaSessionTitle(env: NodeJS.ProcessEnv, command?: OrcaCommand): string | undefined;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
const runOrcaCommand = (executable, args) => {
|
|
4
|
+
try {
|
|
5
|
+
return execFileSync(executable, args, {
|
|
6
|
+
encoding: 'utf8',
|
|
7
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
8
|
+
timeout: 2_000,
|
|
9
|
+
maxBuffer: 512 * 1024,
|
|
10
|
+
windowsHide: true,
|
|
11
|
+
}).trim();
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
function containsControlCharacter(value) {
|
|
18
|
+
return Array.from(value).some((character) => {
|
|
19
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
20
|
+
return codePoint < 32 || codePoint === 127;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function worktreePathFromId(value) {
|
|
24
|
+
if (value.length === 0 || value.length > 4_096 || containsControlCharacter(value))
|
|
25
|
+
return null;
|
|
26
|
+
const separator = value.indexOf('::');
|
|
27
|
+
if (separator <= 0)
|
|
28
|
+
return null;
|
|
29
|
+
const repoId = value.slice(0, separator);
|
|
30
|
+
const worktreePath = value.slice(separator + 2);
|
|
31
|
+
if (!/^[A-Za-z0-9._-]+$/u.test(repoId) || worktreePath.length === 0)
|
|
32
|
+
return null;
|
|
33
|
+
return path.posix.isAbsolute(worktreePath) || path.win32.isAbsolute(worktreePath)
|
|
34
|
+
? worktreePath
|
|
35
|
+
: null;
|
|
36
|
+
}
|
|
37
|
+
function orcaExecutable(env) {
|
|
38
|
+
const configured = env['ORCA_CLI_COMMAND']?.trim();
|
|
39
|
+
if (configured !== undefined && configured.length > 0) {
|
|
40
|
+
return containsControlCharacter(configured) ? null : configured;
|
|
41
|
+
}
|
|
42
|
+
return env['ORCA_DEV_REPO_ROOT'] === undefined ? 'orca' : 'orca-dev';
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Read the User-facing task name assigned to this exact Orca worktree.
|
|
46
|
+
*
|
|
47
|
+
* The environment contributes only an opaque selector. Orca must return that
|
|
48
|
+
* exact id and its matching path before its display name becomes trusted; no
|
|
49
|
+
* path component or identifier is ever promoted into an Agent Session label.
|
|
50
|
+
*/
|
|
51
|
+
export function readOrcaSessionTitle(env, command = runOrcaCommand) {
|
|
52
|
+
if (env['TERM_PROGRAM'] !== 'Orca')
|
|
53
|
+
return undefined;
|
|
54
|
+
const worktreeId = env['ORCA_WORKTREE_ID'];
|
|
55
|
+
if (worktreeId === undefined)
|
|
56
|
+
return undefined;
|
|
57
|
+
const expectedPath = worktreePathFromId(worktreeId);
|
|
58
|
+
if (expectedPath === null)
|
|
59
|
+
return undefined;
|
|
60
|
+
const executable = orcaExecutable(env);
|
|
61
|
+
if (executable === null)
|
|
62
|
+
return undefined;
|
|
63
|
+
let output;
|
|
64
|
+
try {
|
|
65
|
+
output = command(executable, [
|
|
66
|
+
'worktree',
|
|
67
|
+
'show',
|
|
68
|
+
'--worktree',
|
|
69
|
+
`id:${worktreeId}`,
|
|
70
|
+
'--json',
|
|
71
|
+
]);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
if (output === null || output === '')
|
|
77
|
+
return undefined;
|
|
78
|
+
let parsed;
|
|
79
|
+
try {
|
|
80
|
+
parsed = JSON.parse(output);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
86
|
+
return undefined;
|
|
87
|
+
const response = parsed;
|
|
88
|
+
const worktree = response.result?.worktree;
|
|
89
|
+
if (response.ok !== true ||
|
|
90
|
+
worktree?.id !== worktreeId ||
|
|
91
|
+
worktree.path !== expectedPath ||
|
|
92
|
+
typeof worktree.displayName !== 'string' ||
|
|
93
|
+
worktree.displayName.trim().length === 0) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
return worktree.displayName;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=orca-session-title.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orca-session-title.js","sourceRoot":"","sources":["../src/orca-session-title.ts"],"names":[],"mappings":"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"}
|
package/dist/program.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import { acknowledgeCommand, askCommand, accessStatusCommand, authStatusCommand, capabilitiesCommand, closeCommand, configExplainCommand, configSetCommand, configShowCommand, configUnsetCommand, devicesCommand, doctorCommand, guidanceSetCommand, guidanceShowCommand, guidanceUnsetCommand, hookRunCommand, hooksInstallCommand, hooksUninstallCommand, initCommand, loginCommand, logoutCommand, projectDisableCommand, projectEnableCommand, projectStatusCommand, logsCommand, repliesCommand, sendCommand, statusCommand, type CommandDeps } from './commands.js';
|
|
2
|
+
import { acknowledgeCommand, askCommand, accessStatusCommand, agentSessionRenameCommand, authStatusCommand, capabilitiesCommand, closeCommand, configExplainCommand, configSetCommand, configShowCommand, configUnsetCommand, devicesCommand, doctorCommand, guidanceSetCommand, guidanceShowCommand, guidanceUnsetCommand, hookRunCommand, hooksInstallCommand, hooksUninstallCommand, initCommand, loginCommand, logoutCommand, projectDisableCommand, projectEnableCommand, projectStatusCommand, logsCommand, repliesCommand, sendCommand, soundsCommand, statusCommand, type CommandDeps } from './commands.js';
|
|
3
3
|
/**
|
|
4
4
|
* Every command implementation the tree dispatches to, injectable so a test
|
|
5
5
|
* can parse real argv and assert the exact flags a command would receive —
|
|
@@ -14,10 +14,12 @@ declare const defaultRunners: {
|
|
|
14
14
|
authStatus: typeof authStatusCommand;
|
|
15
15
|
accessStatus: typeof accessStatusCommand;
|
|
16
16
|
devices: typeof devicesCommand;
|
|
17
|
+
sounds: typeof soundsCommand;
|
|
17
18
|
capabilities: typeof capabilitiesCommand;
|
|
18
19
|
projectEnable: typeof projectEnableCommand;
|
|
19
20
|
projectDisable: typeof projectDisableCommand;
|
|
20
21
|
projectStatus: typeof projectStatusCommand;
|
|
22
|
+
agentSessionRename: typeof agentSessionRenameCommand;
|
|
21
23
|
send: typeof sendCommand;
|
|
22
24
|
replies: typeof repliesCommand;
|
|
23
25
|
acknowledge: typeof acknowledgeCommand;
|
package/dist/program.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
-
import { acknowledgeCommand, askCommand, accessStatusCommand, authStatusCommand, capabilitiesCommand, closeCommand, configExplainCommand, configSetCommand, configShowCommand, configUnsetCommand, devicesCommand, doctorCommand, guidanceSetCommand, guidanceShowCommand, guidanceUnsetCommand, hookDefersDiagnosticsUntilAfterCleanup, hookRunCommand, hooksInstallCommand, hooksUninstallCommand, initCommand, loginCommand, logoutCommand, projectDisableCommand, projectEnableCommand, projectStatusCommand, logsCommand, repliesCommand, reportAskFailure, sendCommand, statusCommand, } from './commands.js';
|
|
3
|
+
import { acknowledgeCommand, askCommand, accessStatusCommand, agentSessionRenameCommand, authStatusCommand, capabilitiesCommand, closeCommand, configExplainCommand, configSetCommand, configShowCommand, configUnsetCommand, devicesCommand, doctorCommand, guidanceSetCommand, guidanceShowCommand, guidanceUnsetCommand, hookDefersDiagnosticsUntilAfterCleanup, hookRunCommand, hooksInstallCommand, hooksUninstallCommand, initCommand, loginCommand, logoutCommand, projectDisableCommand, projectEnableCommand, projectStatusCommand, logsCommand, repliesCommand, reportAskFailure, sendCommand, soundsCommand, statusCommand, } from './commands.js';
|
|
4
4
|
import { packageVersion } from './release.js';
|
|
5
|
-
import {
|
|
5
|
+
import { HOOK_INSTALLABLE_HARNESSES } from './harnesses.js';
|
|
6
6
|
import { GROUP, SEND_GROUP, helpConfiguration, rootHelpFooter } from './ui/help.js';
|
|
7
7
|
import { readStdinWithTimeout } from './hook-input.js';
|
|
8
8
|
import { argvFlagNames } from './logging.js';
|
|
@@ -46,10 +46,12 @@ const defaultRunners = {
|
|
|
46
46
|
authStatus: authStatusCommand,
|
|
47
47
|
accessStatus: accessStatusCommand,
|
|
48
48
|
devices: devicesCommand,
|
|
49
|
+
sounds: soundsCommand,
|
|
49
50
|
capabilities: capabilitiesCommand,
|
|
50
51
|
projectEnable: projectEnableCommand,
|
|
51
52
|
projectDisable: projectDisableCommand,
|
|
52
53
|
projectStatus: projectStatusCommand,
|
|
54
|
+
agentSessionRename: agentSessionRenameCommand,
|
|
53
55
|
send: sendCommand,
|
|
54
56
|
replies: repliesCommand,
|
|
55
57
|
acknowledge: acknowledgeCommand,
|
|
@@ -126,11 +128,12 @@ export function buildProgram(deps, options = {}) {
|
|
|
126
128
|
/**
|
|
127
129
|
* Bare `notifai`.
|
|
128
130
|
*
|
|
129
|
-
* At a human terminal this opens the interactive app
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
131
|
+
* At a human terminal this opens the interactive app, which enters `init`
|
|
132
|
+
* when the machine is not yet paired and otherwise offers daily actions.
|
|
133
|
+
* Anywhere else it prints help exactly as before. The check is the same one
|
|
134
|
+
* every other prompt in this CLI is gated on — stdin and stdout both TTYs,
|
|
135
|
+
* not CI, `NOTIFAI_NO_INPUT` unset — because an agent that reaches a prompt
|
|
136
|
+
* does not fail, it hangs for ever waiting on a stdin nobody is typing into.
|
|
134
137
|
*/
|
|
135
138
|
/**
|
|
136
139
|
* An unrecognised subcommand reaches the root as an excess argument, and
|
|
@@ -198,9 +201,21 @@ export function buildProgram(deps, options = {}) {
|
|
|
198
201
|
project.command('status').description('Show lifecycle enablement for this Project').option('--json').action((opts) => {
|
|
199
202
|
exit(runners.projectStatus(deps, opts.json === true));
|
|
200
203
|
});
|
|
204
|
+
const session = program
|
|
205
|
+
.command('session')
|
|
206
|
+
.helpGroup(GROUP.agent)
|
|
207
|
+
.summary('Inspect or rename the current Agent Session')
|
|
208
|
+
.description('Operate on the exact Agent Session owned by the active harness');
|
|
209
|
+
session
|
|
210
|
+
.command('rename <label>')
|
|
211
|
+
.description('Rename this exact Agent Session; agents use this only after its job changes completely enough that the old label would mislead')
|
|
212
|
+
.option('--json', 'machine-readable output')
|
|
213
|
+
.action(async (label, opts) => {
|
|
214
|
+
exit(await runners.agentSessionRename(deps, label, opts));
|
|
215
|
+
});
|
|
201
216
|
program
|
|
202
217
|
.command('login')
|
|
203
|
-
.helpGroup(GROUP.
|
|
218
|
+
.helpGroup(GROUP.advanced)
|
|
204
219
|
.summary('Sign in and pair this machine')
|
|
205
220
|
.description('Pair this machine with your Notifai account via browser approval')
|
|
206
221
|
.option('--name <name>', 'machine name shown in the dashboard (default: hostname)')
|
|
@@ -246,6 +261,15 @@ export function buildProgram(deps, options = {}) {
|
|
|
246
261
|
.action(async (opts) => {
|
|
247
262
|
exit(await runners.devices(deps, opts));
|
|
248
263
|
});
|
|
264
|
+
program
|
|
265
|
+
.command('sounds')
|
|
266
|
+
.helpGroup(GROUP.daily)
|
|
267
|
+
.summary('List shipped and Account custom sounds')
|
|
268
|
+
.description('List the sounds --sound and the saved sound key accept: shipped names and this Account\'s custom sounds')
|
|
269
|
+
.option('--json', 'machine-readable output')
|
|
270
|
+
.action(async (opts) => {
|
|
271
|
+
exit(await runners.sounds(deps, opts));
|
|
272
|
+
});
|
|
249
273
|
program
|
|
250
274
|
.command('capabilities')
|
|
251
275
|
.helpGroup(GROUP.advanced)
|
|
@@ -289,7 +313,7 @@ export function buildProgram(deps, options = {}) {
|
|
|
289
313
|
.option('--choice <label>', 'with --reply, ask a closed question; repeat the flag once per answer (2-6)', (v, all = []) => [...all, v])
|
|
290
314
|
.option('--multi', 'with --choice, several answers may be selected')
|
|
291
315
|
.optionsGroup(SEND_GROUP.advanced)
|
|
292
|
-
.option('--sound <sound>', 'override saved sound: default | done | attention | alert | none')
|
|
316
|
+
.option('--sound <sound>', 'override saved sound: default | done | attention | alert | none, or a custom name or id from notifai sounds')
|
|
293
317
|
.option('--level <level>', 'Apple-only interruption level: passive | active | time_sensitive (unsupported with --platform android)')
|
|
294
318
|
.option('--wait <seconds>', 'how long to wait for provider outcomes', (v) => Number(v))
|
|
295
319
|
.option('--no-wait', 'return immediately after acceptance')
|
|
@@ -330,7 +354,7 @@ export function buildProgram(deps, options = {}) {
|
|
|
330
354
|
flags.wait = wait;
|
|
331
355
|
exit(await runners.send(deps, flags));
|
|
332
356
|
});
|
|
333
|
-
send.addHelpText('after', `\nKind is required, and it selects the sound the notification arrives with: done rings the completion chime, failed the most insistent tone, blocked and question a distinct attention tone, update
|
|
357
|
+
send.addHelpText('after', `\nKind is required, and it selects the sound the notification arrives with: done rings the completion chime, failed the most insistent tone, blocked and question a distinct attention tone, update Device default.\nAn explicit --sound or saved sound preference outranks that default. --sound accepts a shipped name, an Account custom sound name or id from \`notifai sounds\`, or none. --level is Apple-only; Android attention is owned by kind, product channels, and device settings.\n`);
|
|
334
358
|
program
|
|
335
359
|
.command('replies [request_id]')
|
|
336
360
|
.helpGroup(GROUP.agent)
|
|
@@ -449,7 +473,7 @@ export function buildProgram(deps, options = {}) {
|
|
|
449
473
|
.option('--owner <name>', 'internal ownership marker')
|
|
450
474
|
.option('--harness <name>', 'internal harness output adapter')
|
|
451
475
|
.action(async (event, opts) => {
|
|
452
|
-
const harness =
|
|
476
|
+
const harness = HOOK_INSTALLABLE_HARNESSES.find((candidate) => candidate === opts.harness);
|
|
453
477
|
exit(await runners.hookRun(deps, event, () => readStdinWithTimeout(), harness));
|
|
454
478
|
});
|
|
455
479
|
const hooks = program
|
|
@@ -460,7 +484,7 @@ export function buildProgram(deps, options = {}) {
|
|
|
460
484
|
hooks
|
|
461
485
|
.command('install')
|
|
462
486
|
.description('Wire this harness to route registered questions to your devices')
|
|
463
|
-
.option('--harness <name>', 'claude-code | codex | cursor | opencode (default: every detected harness)')
|
|
487
|
+
.option('--harness <name>', 'claude-code | codex | cursor | opencode | openclaw (default: every detected harness)')
|
|
464
488
|
.option('--global', 'install for every project instead of just this one')
|
|
465
489
|
.action((opts) => {
|
|
466
490
|
exit(runners.hooksInstall(deps, opts));
|
|
@@ -468,7 +492,7 @@ export function buildProgram(deps, options = {}) {
|
|
|
468
492
|
hooks
|
|
469
493
|
.command('uninstall')
|
|
470
494
|
.description('Remove the hooks this CLI installed')
|
|
471
|
-
.option('--harness <name>', 'claude-code | codex | cursor | opencode (default: detected)')
|
|
495
|
+
.option('--harness <name>', 'claude-code | codex | cursor | opencode | openclaw (default: detected)')
|
|
472
496
|
.option('--global', 'remove the machine-wide install')
|
|
473
497
|
.action((opts) => {
|
|
474
498
|
exit(runners.hooksUninstall(deps, opts));
|