@phnx-labs/agents-cli 1.21.2 → 1.21.3
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 +34 -0
- package/dist/bin/agents +0 -0
- package/dist/commands/computer-actions.d.ts +4 -0
- package/dist/commands/computer-actions.js +34 -0
- package/dist/commands/computer.js +4 -2
- package/dist/commands/perf.d.ts +16 -0
- package/dist/commands/perf.js +11 -1
- package/dist/commands/projects.d.ts +11 -1
- package/dist/commands/projects.js +16 -2
- package/dist/commands/sessions-picker.js +17 -2
- package/dist/commands/sessions.d.ts +5 -0
- package/dist/commands/sessions.js +14 -0
- package/dist/index.js +8 -0
- package/dist/lib/browser/service.js +13 -0
- package/dist/lib/computer/dispatch.d.ts +3 -1
- package/dist/lib/computer/dispatch.js +10 -2
- package/dist/lib/event-stream.d.ts +2 -0
- package/dist/lib/event-stream.js +3 -0
- package/dist/lib/events.d.ts +3 -1
- package/dist/lib/events.js +4 -2
- package/dist/lib/git.d.ts +14 -0
- package/dist/lib/git.js +36 -0
- package/dist/lib/hooks/profile.js +1 -14
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/percentile.d.ts +12 -0
- package/dist/lib/percentile.js +24 -0
- package/dist/lib/perf/db.d.ts +1 -2
- package/dist/lib/perf/db.js +2 -14
- package/dist/lib/plugins.js +12 -1
- package/dist/lib/resources.d.ts +16 -0
- package/dist/lib/resources.js +25 -14
- package/dist/lib/routines.js +1 -14
- package/dist/lib/runner.js +8 -1
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/session/db.d.ts +16 -1
- package/dist/lib/session/db.js +227 -4
- package/dist/lib/session/discover.d.ts +28 -0
- package/dist/lib/session/discover.js +42 -1
- package/dist/lib/session/highlights.d.ts +24 -4
- package/dist/lib/session/highlights.js +52 -7
- package/dist/lib/session/parse.js +19 -3
- package/dist/lib/session/prompt.d.ts +19 -0
- package/dist/lib/session/prompt.js +43 -0
- package/dist/lib/session/types.d.ts +42 -0
- package/dist/lib/types.d.ts +14 -0
- package/package.json +1 -1
|
@@ -9,7 +9,7 @@ import * as fs from 'fs';
|
|
|
9
9
|
import { truncate } from '../format.js';
|
|
10
10
|
import * as path from 'path';
|
|
11
11
|
import Database from '../sqlite.js';
|
|
12
|
-
import { isSyntheticUserMessage } from './prompt.js';
|
|
12
|
+
import { isSyntheticUserMessage, extractSlashCommandName, extractSlashCommandFromToolInput } from './prompt.js';
|
|
13
13
|
/**
|
|
14
14
|
* Largest session file we will load into memory. Above this we throw a clean
|
|
15
15
|
* error instead of OOMing or hitting V8's ERR_STRING_TOO_LONG. Aligns with
|
|
@@ -379,6 +379,14 @@ export function parseClaudeContent(content) {
|
|
|
379
379
|
};
|
|
380
380
|
if (isLocal)
|
|
381
381
|
event._local = true;
|
|
382
|
+
// SlashCommand: the MODEL invoking a slash command programmatically
|
|
383
|
+
// (distinct from the <command-name> wrapper below, which is the
|
|
384
|
+
// USER typing one) — see prompt.ts's extractSlashCommandFromToolInput.
|
|
385
|
+
if (toolName === 'SlashCommand') {
|
|
386
|
+
const slashCommand = extractSlashCommandFromToolInput(toolInput);
|
|
387
|
+
if (slashCommand)
|
|
388
|
+
event.slashCommand = slashCommand;
|
|
389
|
+
}
|
|
382
390
|
events.push(event);
|
|
383
391
|
}
|
|
384
392
|
}
|
|
@@ -403,13 +411,21 @@ export function parseClaudeContent(content) {
|
|
|
403
411
|
// Simple user text
|
|
404
412
|
const text = contentBlocks.trim();
|
|
405
413
|
if (text) {
|
|
406
|
-
|
|
414
|
+
const event = {
|
|
407
415
|
type: 'message',
|
|
408
416
|
agent: 'claude',
|
|
409
417
|
timestamp,
|
|
410
418
|
role: 'user',
|
|
411
419
|
content: text,
|
|
412
|
-
}
|
|
420
|
+
};
|
|
421
|
+
// The USER typing a slash command — Claude injects a <command-name>
|
|
422
|
+
// wrapper as the message content (see prompt.ts's
|
|
423
|
+
// extractSlashCommandName; distinct from the SlashCommand tool-use
|
|
424
|
+
// above, which is the model invoking one programmatically).
|
|
425
|
+
const slashCommand = extractSlashCommandName(text);
|
|
426
|
+
if (slashCommand)
|
|
427
|
+
event.slashCommand = slashCommand;
|
|
428
|
+
events.push(event);
|
|
413
429
|
}
|
|
414
430
|
}
|
|
415
431
|
else if (Array.isArray(contentBlocks)) {
|
|
@@ -12,6 +12,25 @@
|
|
|
12
12
|
* own scaffolding at parse time simply never reach here.
|
|
13
13
|
*/
|
|
14
14
|
export declare function isSyntheticUserMessage(raw: string | undefined): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Extract the invoked slash-command name from a raw `role=user` message, or
|
|
17
|
+
* undefined when the message carries no `<command-name>` wrapper. Used by
|
|
18
|
+
* `parseClaudeContent` to populate `SessionEvent.slashCommand`.
|
|
19
|
+
*
|
|
20
|
+
* Normalizes a leading `/` onto the result: current Claude Code wraps the
|
|
21
|
+
* name WITH the slash already (`/recap`), but the wrapper predates that and
|
|
22
|
+
* older transcripts carry the bare name (`recap`) — normalizing here means
|
|
23
|
+
* every consumer sees one consistent `/name` shape regardless of vintage.
|
|
24
|
+
*/
|
|
25
|
+
export declare function extractSlashCommandName(raw: string | undefined): string | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Extract the invoked slash-command name from the `SlashCommand` tool's input
|
|
28
|
+
* — the MODEL invoking a command programmatically, not the user typing it.
|
|
29
|
+
* The tool's `command` field carries the full invocation text (name plus any
|
|
30
|
+
* args, e.g. `/code:commit fix the bug`); only the leading command token is
|
|
31
|
+
* the name, matching {@link extractSlashCommandName}'s shape.
|
|
32
|
+
*/
|
|
33
|
+
export declare function extractSlashCommandFromToolInput(toolInput: Record<string, any> | undefined): string | undefined;
|
|
15
34
|
export declare const HEADLESS_PLAN_MODE_PREFIX = "You are running in HEADLESS PLAN MODE.";
|
|
16
35
|
/** Strip framework noise from a raw session prompt, returning only meaningful user text. */
|
|
17
36
|
export declare function cleanSessionPrompt(raw: string): string;
|
|
@@ -63,6 +63,49 @@ export function isSyntheticUserMessage(raw) {
|
|
|
63
63
|
return false;
|
|
64
64
|
return SYNTHETIC_USER_MESSAGE_PATTERNS.some(pattern => pattern.test(raw));
|
|
65
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* The `<command-name>` wrapper Claude injects into a `role=user` message when
|
|
68
|
+
* a typed slash command is invoked, e.g.:
|
|
69
|
+
* <command-message>recap</command-message>
|
|
70
|
+
* <command-name>/recap</command-name>
|
|
71
|
+
* Captures the name INCLUDING its leading slash (`/recap`), matching how the
|
|
72
|
+
* `SlashCommand` tool's own `command` input is formatted (see
|
|
73
|
+
* `extractSlashCommandFromToolInput`) so both sources land on the same shape.
|
|
74
|
+
*/
|
|
75
|
+
const COMMAND_NAME_WRAPPER_RE = /<command-name>\s*([^<]*?)\s*<\/command-name>/i;
|
|
76
|
+
/**
|
|
77
|
+
* Extract the invoked slash-command name from a raw `role=user` message, or
|
|
78
|
+
* undefined when the message carries no `<command-name>` wrapper. Used by
|
|
79
|
+
* `parseClaudeContent` to populate `SessionEvent.slashCommand`.
|
|
80
|
+
*
|
|
81
|
+
* Normalizes a leading `/` onto the result: current Claude Code wraps the
|
|
82
|
+
* name WITH the slash already (`/recap`), but the wrapper predates that and
|
|
83
|
+
* older transcripts carry the bare name (`recap`) — normalizing here means
|
|
84
|
+
* every consumer sees one consistent `/name` shape regardless of vintage.
|
|
85
|
+
*/
|
|
86
|
+
export function extractSlashCommandName(raw) {
|
|
87
|
+
if (!raw)
|
|
88
|
+
return undefined;
|
|
89
|
+
const m = raw.match(COMMAND_NAME_WRAPPER_RE);
|
|
90
|
+
const name = m?.[1]?.trim();
|
|
91
|
+
if (!name)
|
|
92
|
+
return undefined;
|
|
93
|
+
return name.startsWith('/') ? name : `/${name}`;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Extract the invoked slash-command name from the `SlashCommand` tool's input
|
|
97
|
+
* — the MODEL invoking a command programmatically, not the user typing it.
|
|
98
|
+
* The tool's `command` field carries the full invocation text (name plus any
|
|
99
|
+
* args, e.g. `/code:commit fix the bug`); only the leading command token is
|
|
100
|
+
* the name, matching {@link extractSlashCommandName}'s shape.
|
|
101
|
+
*/
|
|
102
|
+
export function extractSlashCommandFromToolInput(toolInput) {
|
|
103
|
+
const command = toolInput?.command;
|
|
104
|
+
if (typeof command !== 'string')
|
|
105
|
+
return undefined;
|
|
106
|
+
const name = command.trim().split(/\s+/)[0];
|
|
107
|
+
return name || undefined;
|
|
108
|
+
}
|
|
66
109
|
// Prefix prepended to every Claude-in-plan-mode team spawn prompt.
|
|
67
110
|
// Ends at a blank line before the real user task.
|
|
68
111
|
export const HEADLESS_PLAN_MODE_PREFIX = 'You are running in HEADLESS PLAN MODE.';
|
|
@@ -52,6 +52,15 @@ export interface SessionEvent {
|
|
|
52
52
|
hookName?: string;
|
|
53
53
|
/** Lifecycle event the hook fired on (SessionStart, PreToolUse, …). */
|
|
54
54
|
hookEvent?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Slash-command invocation name (e.g. `/recap`, `/code:commit`), captured
|
|
57
|
+
* two ways in a Claude transcript: a `role=user` message whose content is
|
|
58
|
+
* the `<command-name>` wrapper Claude injects for a typed slash command
|
|
59
|
+
* (`parseClaudeContent`, see `prompt.ts`'s `extractSlashCommandName`), or a
|
|
60
|
+
* `tool_use` event for the `SlashCommand` tool (a command the MODEL invoked
|
|
61
|
+
* programmatically, not the user). Undefined for every other event.
|
|
62
|
+
*/
|
|
63
|
+
slashCommand?: string;
|
|
55
64
|
}
|
|
56
65
|
/** A displayable file attachment discovered in a session transcript. */
|
|
57
66
|
export interface SessionAttachment {
|
|
@@ -186,6 +195,39 @@ export interface SessionMeta {
|
|
|
186
195
|
todos?: TodoProgress;
|
|
187
196
|
/** Most-recent unique directories changed or used as a shell working directory. */
|
|
188
197
|
recentDirectoriesTouched?: string[];
|
|
198
|
+
/**
|
|
199
|
+
* Skills invoked during the session (structurally identical to
|
|
200
|
+
* session/highlights.ts's SkillUse — declared inline here rather than
|
|
201
|
+
* imported, to avoid a circular import: highlights.ts imports SessionEvent
|
|
202
|
+
* from this file). Populated by discover.ts's incremental Claude
|
|
203
|
+
* accumulator (ClaudeParseState.skillEvents, run through extractSkills at
|
|
204
|
+
* finalize) so session/db.ts's upsertSessionsBatch can write
|
|
205
|
+
* session_resource_usage rows WITHOUT re-parsing the whole transcript —
|
|
206
|
+
* the same reason meta.todos/recentDirectoriesTouched are pre-computed by
|
|
207
|
+
* the caller for claude/codex instead of left to db.ts's re-parse path.
|
|
208
|
+
*/
|
|
209
|
+
skillsUsed?: Array<{
|
|
210
|
+
name: string;
|
|
211
|
+
count: number;
|
|
212
|
+
}>;
|
|
213
|
+
/** Sibling of {@link skillsUsed} for slash-command invocations (SessionEvent.slashCommand). */
|
|
214
|
+
slashCommandsUsed?: Array<{
|
|
215
|
+
name: string;
|
|
216
|
+
count: number;
|
|
217
|
+
}>;
|
|
218
|
+
/**
|
|
219
|
+
* Whether this session emitted at least one `browser.navigate` /
|
|
220
|
+
* `browser.screenshot` event, computed at scan time from a sessionId-scoped
|
|
221
|
+
* read of the events log (events.ts `query({ sessionId })`) rather than a
|
|
222
|
+
* transcript re-scan — see `detectToolUsage` in session/db.ts. `undefined`
|
|
223
|
+
* means a legacy row this scanner hasn't computed the field for yet (never
|
|
224
|
+
* collapsed to `false`, so a consumer — e.g. sessions-picker.ts's
|
|
225
|
+
* `classifySessionTool` — knows to fall back to a transcript-derived guess
|
|
226
|
+
* instead of trusting a false negative).
|
|
227
|
+
*/
|
|
228
|
+
usedBrowser?: boolean;
|
|
229
|
+
/** Sibling of {@link usedBrowser} for `computer.action` events. */
|
|
230
|
+
usedComputer?: boolean;
|
|
189
231
|
/** Linear project containing ticketId, resolved lazily and cached in SQLite. */
|
|
190
232
|
linearProject?: string;
|
|
191
233
|
/** Browser URL for linearProject. */
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -605,6 +605,20 @@ export interface DiscoveredPlugin {
|
|
|
605
605
|
* (e.g. workflow-scoped) — those default to the user marketplace on sync.
|
|
606
606
|
*/
|
|
607
607
|
marketplace?: string;
|
|
608
|
+
/**
|
|
609
|
+
* Absolute path to the DotAgents repo root containing this plugin — the
|
|
610
|
+
* grandparent of `root` (`<repo>/plugins/<name>` → `<repo>`), true for every
|
|
611
|
+
* marketplace kind (user/system/extra/project). DotAgents repos are
|
|
612
|
+
* git-tracked (plugins.ts), so this pairs with {@link snapshotSha}.
|
|
613
|
+
*/
|
|
614
|
+
repoRoot: string;
|
|
615
|
+
/**
|
|
616
|
+
* Short HEAD sha of `repoRoot`'s git checkout, lazily resolved (a getter,
|
|
617
|
+
* not computed at discovery time) and memoized per repoRoot
|
|
618
|
+
* (`git.ts` `resolveSnapshotSha`) — see `ResolvedResource.snapshotSha` for
|
|
619
|
+
* the identical rationale. `undefined` when `repoRoot` isn't a git repo.
|
|
620
|
+
*/
|
|
621
|
+
readonly snapshotSha: string | undefined;
|
|
608
622
|
}
|
|
609
623
|
/**
|
|
610
624
|
* Identifies one DotAgents repo that contributes a plugin marketplace. Each
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phnx-labs/agents-cli",
|
|
3
|
-
"version": "1.21.
|
|
3
|
+
"version": "1.21.3",
|
|
4
4
|
"description": "One CLI for all your AI coding agents - versions, config, cloud dispatch, sessions, and teams (now with first-class Grok Build CLI support)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|