@phnx-labs/agents-cli 1.20.78 → 1.20.83
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 +595 -0
- package/README.md +26 -26
- package/dist/bin/agents +0 -0
- package/dist/commands/activity.d.ts +9 -0
- package/dist/commands/activity.js +153 -24
- package/dist/commands/apply.js +11 -4
- package/dist/commands/cli.js +1 -1
- package/dist/commands/commands.d.ts +1 -1
- package/dist/commands/commands.js +7 -6
- package/dist/commands/defaults.js +3 -11
- package/dist/commands/doctor.d.ts +66 -0
- package/dist/commands/doctor.js +596 -33
- package/dist/commands/events.js +1 -1
- package/dist/commands/exec.js +24 -5
- package/dist/commands/feed.d.ts +4 -0
- package/dist/commands/feed.js +87 -11
- package/dist/commands/harness.js +2 -2
- package/dist/commands/hooks.js +1 -1
- package/dist/commands/import.js +8 -4
- package/dist/commands/logs.js +6 -0
- package/dist/commands/menubar.js +12 -0
- package/dist/commands/models.js +1 -1
- package/dist/commands/packages.js +6 -6
- package/dist/commands/permissions.js +1 -1
- package/dist/commands/profiles.js +1 -1
- package/dist/commands/pull.d.ts +1 -1
- package/dist/commands/pull.js +4 -4
- package/dist/commands/repo.d.ts +78 -0
- package/dist/commands/repo.js +187 -11
- package/dist/commands/routines.d.ts +8 -1
- package/dist/commands/routines.js +241 -77
- package/dist/commands/rules.js +13 -12
- package/dist/commands/secrets.d.ts +3 -1
- package/dist/commands/secrets.js +100 -32
- package/dist/commands/sessions-inject.d.ts +7 -4
- package/dist/commands/sessions-inject.js +18 -18
- package/dist/commands/sessions-picker.js +32 -3
- package/dist/commands/sessions-resume.d.ts +16 -0
- package/dist/commands/sessions-resume.js +14 -13
- package/dist/commands/sessions.d.ts +115 -0
- package/dist/commands/sessions.js +189 -35
- package/dist/commands/set.d.ts +15 -0
- package/dist/commands/set.js +79 -0
- package/dist/commands/setup-fleet.d.ts +21 -0
- package/dist/commands/setup-fleet.js +201 -0
- package/dist/commands/setup-secrets.d.ts +20 -0
- package/dist/commands/setup-secrets.js +223 -0
- package/dist/commands/setup.js +17 -3
- package/dist/commands/skills.js +1 -1
- package/dist/commands/sync.js +7 -2
- package/dist/commands/teams-picker.js +0 -1
- package/dist/commands/teams.d.ts +33 -1
- package/dist/commands/teams.js +208 -44
- package/dist/commands/versions.js +10 -5
- package/dist/commands/view.d.ts +1 -0
- package/dist/commands/view.js +11 -0
- package/dist/index.js +52 -8
- package/dist/lib/acp/harnesses.js +0 -7
- package/dist/lib/activity.d.ts +156 -0
- package/dist/lib/activity.js +282 -0
- package/dist/lib/agents.d.ts +9 -2
- package/dist/lib/agents.js +72 -63
- package/dist/lib/browser/service.js +3 -0
- package/dist/lib/browser/types.d.ts +7 -0
- package/dist/lib/capabilities.js +6 -2
- package/dist/lib/crabbox/lease.js +2 -2
- package/dist/lib/crabbox/setup-copy.d.ts +4 -4
- package/dist/lib/crabbox/setup-copy.js +4 -4
- package/dist/lib/daemon.d.ts +18 -0
- package/dist/lib/daemon.js +47 -6
- package/dist/lib/devices/fleet.d.ts +1 -1
- package/dist/lib/devices/fleet.js +1 -1
- package/dist/lib/doctor-diff.d.ts +20 -0
- package/dist/lib/doctor-diff.js +6 -1
- package/dist/lib/drift.d.ts +31 -11
- package/dist/lib/drift.js +58 -7
- package/dist/lib/events.d.ts +8 -1
- package/dist/lib/events.js +10 -1
- package/dist/lib/exec.d.ts +7 -0
- package/dist/lib/exec.js +69 -11
- package/dist/lib/feed-post.d.ts +28 -1
- package/dist/lib/feed-post.js +110 -2
- package/dist/lib/fleet/apply.js +8 -1
- package/dist/lib/fleet/auth-sync.d.ts +18 -1
- package/dist/lib/fleet/auth-sync.js +25 -11
- package/dist/lib/fleet/remote-login.js +5 -0
- package/dist/lib/git.d.ts +14 -14
- package/dist/lib/git.js +41 -44
- package/dist/lib/hooks.d.ts +71 -0
- package/dist/lib/hooks.js +245 -95
- package/dist/lib/hosts/dispatch.d.ts +28 -1
- package/dist/lib/hosts/dispatch.js +33 -5
- package/dist/lib/hosts/option.js +2 -2
- package/dist/lib/hosts/passthrough.d.ts +22 -1
- package/dist/lib/hosts/passthrough.js +238 -13
- package/dist/lib/hosts/run-target.d.ts +2 -0
- package/dist/lib/hosts/run-target.js +1 -0
- package/dist/lib/hq/floor.d.ts +1 -1
- package/dist/lib/hq/floor.js +6 -1
- package/dist/lib/mcp.js +3 -71
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/install-menubar.d.ts +24 -0
- package/dist/lib/menubar/install-menubar.js +52 -2
- package/dist/lib/menubar/notify-desktop.d.ts +15 -0
- package/dist/lib/menubar/notify-desktop.js +41 -5
- package/dist/lib/merged-resources.d.ts +11 -0
- package/dist/{commands/resources.js → lib/merged-resources.js} +11 -19
- package/dist/lib/permissions.d.ts +0 -32
- package/dist/lib/permissions.js +4 -157
- package/dist/lib/picker.js +1 -1
- package/dist/lib/platform/process.d.ts +16 -5
- package/dist/lib/platform/process.js +54 -0
- package/dist/lib/plugins.d.ts +0 -8
- package/dist/lib/plugins.js +4 -110
- package/dist/lib/project-resources.js +4 -1
- package/dist/lib/refresh.d.ts +5 -3
- package/dist/lib/refresh.js +7 -5
- package/dist/lib/resources/commands.js +4 -1
- package/dist/lib/resources/mcp.js +0 -4
- package/dist/lib/resources/permissions.d.ts +1 -1
- package/dist/lib/resources/permissions.js +1 -5
- package/dist/lib/resources/rules.js +4 -1
- package/dist/lib/resources/skills.js +4 -1
- package/dist/lib/resources/subagents.js +4 -0
- package/dist/lib/resources/types.d.ts +1 -1
- package/dist/lib/routines.d.ts +33 -0
- package/dist/lib/routines.js +122 -0
- package/dist/lib/run-defaults.d.ts +1 -0
- package/dist/lib/run-defaults.js +9 -0
- package/dist/lib/runner.d.ts +0 -12
- package/dist/lib/runner.js +49 -10
- package/dist/lib/scheduler.js +16 -4
- 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/secrets/agent.d.ts +16 -0
- package/dist/lib/secrets/agent.js +105 -3
- package/dist/lib/secrets/audit.d.ts +46 -0
- package/dist/lib/secrets/audit.js +56 -0
- package/dist/lib/secrets/bundles.d.ts +11 -8
- package/dist/lib/secrets/bundles.js +31 -23
- package/dist/lib/secrets/index.d.ts +2 -1
- package/dist/lib/secrets/index.js +8 -2
- package/dist/lib/secrets/remote.d.ts +75 -2
- package/dist/lib/secrets/remote.js +139 -5
- package/dist/lib/secrets/sync.js +3 -3
- package/dist/lib/session/active.d.ts +128 -26
- package/dist/lib/session/active.js +192 -53
- package/dist/lib/session/actor-sidecar.d.ts +23 -0
- package/dist/lib/session/actor-sidecar.js +101 -0
- package/dist/lib/session/db.d.ts +4 -1
- package/dist/lib/session/db.js +65 -8
- package/dist/lib/session/discover.d.ts +4 -0
- package/dist/lib/session/discover.js +13 -0
- package/dist/lib/session/hook-sessions.d.ts +9 -0
- package/dist/lib/session/hook-sessions.js +57 -8
- package/dist/lib/session/pid-registry.d.ts +13 -0
- package/dist/lib/session/render.d.ts +2 -0
- package/dist/lib/session/render.js +1 -1
- package/dist/lib/session/types.d.ts +16 -0
- package/dist/lib/staleness/detectors/commands.js +2 -2
- package/dist/lib/staleness/detectors/permissions.js +1 -45
- package/dist/lib/staleness/writers/commands.js +4 -5
- package/dist/lib/staleness/writers/hooks.js +1 -1
- package/dist/lib/startup/command-registry.d.ts +1 -2
- package/dist/lib/startup/command-registry.js +2 -4
- package/dist/lib/state.js +57 -1
- package/dist/lib/subagents-registry.js +5 -12
- package/dist/lib/subagents.d.ts +0 -10
- package/dist/lib/subagents.js +0 -12
- package/dist/lib/teams/agents.d.ts +0 -2
- package/dist/lib/teams/agents.js +10 -27
- package/dist/lib/teams/index.d.ts +1 -1
- package/dist/lib/teams/index.js +1 -1
- package/dist/lib/types.d.ts +17 -9
- package/dist/lib/usage.d.ts +28 -5
- package/dist/lib/usage.js +271 -8
- package/dist/lib/versions.js +7 -1
- package/dist/lib/watchdog/watchdog.d.ts +1 -1
- package/dist/lib/watchdog/watchdog.js +25 -13
- package/package.json +1 -2
- package/dist/commands/check.d.ts +0 -15
- package/dist/commands/check.js +0 -180
- package/dist/commands/resources.d.ts +0 -5
package/dist/lib/session/db.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* SQLite-backed session index and full-text search.
|
|
3
3
|
*
|
|
4
4
|
* Stores session metadata and user-prompt text in a WAL-mode SQLite database
|
|
5
|
-
* at ~/.agents/sessions/sessions.db. Provides incremental upsert, scan-stamp
|
|
5
|
+
* at ~/.agents/.history/sessions/sessions.db. Provides incremental upsert, scan-stamp
|
|
6
6
|
* ledger (mtime/size tracking to skip unchanged files), FTS5 search with
|
|
7
7
|
* BM25 ranking, and label-first search for /rename'd sessions.
|
|
8
8
|
*/
|
|
@@ -13,10 +13,11 @@ import { parseSession } from './parse.js';
|
|
|
13
13
|
import { extractRecentDirectoriesTouched, extractTodoProgressFromEvents } from './state.js';
|
|
14
14
|
import { getSessionsDir, getSessionsDbPath } from '../state.js';
|
|
15
15
|
import { machineForSessionFile } from './origin-machine.js';
|
|
16
|
+
import { loadSessionActorIndex, readSessionActorRecord } from './actor-sidecar.js';
|
|
16
17
|
const SESSIONS_DIR = getSessionsDir();
|
|
17
18
|
const DB_PATH = getSessionsDbPath();
|
|
18
19
|
/** Current schema version; bumped when migrations are added. */
|
|
19
|
-
const SCHEMA_VERSION =
|
|
20
|
+
const SCHEMA_VERSION = 20;
|
|
20
21
|
/**
|
|
21
22
|
* Canonicalize a file path for use as a scan_ledger key. The same physical
|
|
22
23
|
* session file is reachable via multiple aliases — `~/.claude/projects/x.jsonl`
|
|
@@ -63,6 +64,7 @@ CREATE TABLE IF NOT EXISTS sessions (
|
|
|
63
64
|
output_tokens INTEGER,
|
|
64
65
|
cost_usd REAL,
|
|
65
66
|
duration_ms INTEGER,
|
|
67
|
+
model TEXT,
|
|
66
68
|
file_path TEXT NOT NULL,
|
|
67
69
|
file_mtime_ms INTEGER,
|
|
68
70
|
file_size INTEGER,
|
|
@@ -77,7 +79,9 @@ CREATE TABLE IF NOT EXISTS sessions (
|
|
|
77
79
|
todos TEXT,
|
|
78
80
|
recent_directories_touched TEXT,
|
|
79
81
|
linear_project TEXT,
|
|
80
|
-
linear_project_url TEXT
|
|
82
|
+
linear_project_url TEXT,
|
|
83
|
+
actor TEXT,
|
|
84
|
+
initiated_by TEXT
|
|
81
85
|
);
|
|
82
86
|
CREATE INDEX IF NOT EXISTS idx_sessions_timestamp ON sessions(timestamp DESC);
|
|
83
87
|
CREATE INDEX IF NOT EXISTS idx_sessions_cwd ON sessions(cwd);
|
|
@@ -360,6 +364,25 @@ function migrateSchema(db, fromVersion) {
|
|
|
360
364
|
});
|
|
361
365
|
txn(rows);
|
|
362
366
|
}
|
|
367
|
+
if (fromVersion < 19) {
|
|
368
|
+
// v18 → v19: actor provenance (RUSH-2018) — who initiated the session and
|
|
369
|
+
// the actor's kind. Populated at write time from the resolved actor (the
|
|
370
|
+
// pid-registry/spawn path), not derivable from the transcript, so there is
|
|
371
|
+
// no ledger wipe here: a rescan can't backfill these, and forcing a full
|
|
372
|
+
// re-parse would be pure churn. Existing rows stay NULL until re-created.
|
|
373
|
+
const cols = db.prepare(`PRAGMA table_info(sessions)`).all();
|
|
374
|
+
if (!cols.some(c => c.name === 'actor'))
|
|
375
|
+
db.exec(`ALTER TABLE sessions ADD COLUMN actor TEXT`);
|
|
376
|
+
if (!cols.some(c => c.name === 'initiated_by'))
|
|
377
|
+
db.exec(`ALTER TABLE sessions ADD COLUMN initiated_by TEXT`);
|
|
378
|
+
}
|
|
379
|
+
if (fromVersion < 20) {
|
|
380
|
+
// v19 → v20: persist the transcript's model for the static session list.
|
|
381
|
+
const cols = db.prepare(`PRAGMA table_info(sessions)`).all();
|
|
382
|
+
if (!cols.some(c => c.name === 'model'))
|
|
383
|
+
db.exec(`ALTER TABLE sessions ADD COLUMN model TEXT`);
|
|
384
|
+
db.exec(`DELETE FROM scan_ledger; DELETE FROM dir_ledger;`);
|
|
385
|
+
}
|
|
363
386
|
}
|
|
364
387
|
/** Open (or return the cached) sessions database, applying migrations as needed. */
|
|
365
388
|
export function getDB() {
|
|
@@ -719,18 +742,20 @@ const upsertSessionStmt = (db) => db.prepare(`
|
|
|
719
742
|
id, short_id, agent, origin, routine_name, routine_run_id,
|
|
720
743
|
version, account, timestamp, last_activity,
|
|
721
744
|
project, cwd, git_branch, topic, label, message_count, token_count,
|
|
722
|
-
output_tokens, cost_usd, duration_ms,
|
|
745
|
+
output_tokens, cost_usd, duration_ms, model,
|
|
723
746
|
file_path, file_mtime_ms, file_size, scanned_at, is_team_origin,
|
|
724
747
|
pr_url, pr_number, worktree_slug, ticket_id, plan, todos,
|
|
725
|
-
recent_directories_touched, linear_project, linear_project_url, machine
|
|
748
|
+
recent_directories_touched, linear_project, linear_project_url, machine,
|
|
749
|
+
actor, initiated_by
|
|
726
750
|
) VALUES (
|
|
727
751
|
@id, @short_id, @agent, @origin, @routine_name, @routine_run_id,
|
|
728
752
|
@version, @account, @timestamp, @last_activity,
|
|
729
753
|
@project, @cwd, @git_branch, @topic, @label, @message_count, @token_count,
|
|
730
|
-
@output_tokens, @cost_usd, @duration_ms,
|
|
754
|
+
@output_tokens, @cost_usd, @duration_ms, @model,
|
|
731
755
|
@file_path, @file_mtime_ms, @file_size, @scanned_at, @is_team_origin,
|
|
732
756
|
@pr_url, @pr_number, @worktree_slug, @ticket_id, @plan, @todos,
|
|
733
|
-
@recent_directories_touched, @linear_project, @linear_project_url, @machine
|
|
757
|
+
@recent_directories_touched, @linear_project, @linear_project_url, @machine,
|
|
758
|
+
@actor, @initiated_by
|
|
734
759
|
)
|
|
735
760
|
ON CONFLICT(id) DO UPDATE SET
|
|
736
761
|
short_id = excluded.short_id,
|
|
@@ -760,6 +785,7 @@ const upsertSessionStmt = (db) => db.prepare(`
|
|
|
760
785
|
output_tokens = excluded.output_tokens,
|
|
761
786
|
cost_usd = excluded.cost_usd,
|
|
762
787
|
duration_ms = excluded.duration_ms,
|
|
788
|
+
model = excluded.model,
|
|
763
789
|
file_path = excluded.file_path,
|
|
764
790
|
file_mtime_ms = excluded.file_mtime_ms,
|
|
765
791
|
file_size = excluded.file_size,
|
|
@@ -780,7 +806,15 @@ const upsertSessionStmt = (db) => db.prepare(`
|
|
|
780
806
|
WHEN excluded.ticket_id IS NOT sessions.ticket_id THEN excluded.linear_project_url
|
|
781
807
|
ELSE COALESCE(excluded.linear_project_url, sessions.linear_project_url)
|
|
782
808
|
END,
|
|
783
|
-
machine = excluded.machine
|
|
809
|
+
machine = excluded.machine,
|
|
810
|
+
-- actor / initiated_by record who launched the session. COALESCE(existing,
|
|
811
|
+
-- incoming) keeps a stored owner (a rescan carries no actor -> excluded.actor
|
|
812
|
+
-- is NULL -> the stored value wins, never clobbered) BUT backfills a row that
|
|
813
|
+
-- was inserted NULL-first — e.g. an older scanner, or any scan that ran before
|
|
814
|
+
-- the actor sidecar landed — once the sidecar-join finally provides one. Plain
|
|
815
|
+
-- exclusion locked those rows to NULL forever (RUSH-2018/2019 fix).
|
|
816
|
+
actor = COALESCE(sessions.actor, excluded.actor),
|
|
817
|
+
initiated_by = COALESCE(sessions.initiated_by, excluded.initiated_by)
|
|
784
818
|
`);
|
|
785
819
|
function enrichCachedSessionMeta(meta) {
|
|
786
820
|
if (!meta.filePath)
|
|
@@ -838,6 +872,12 @@ function resolveMachine(meta) {
|
|
|
838
872
|
*/
|
|
839
873
|
export function upsertSession(meta, content, scan) {
|
|
840
874
|
meta = enrichCachedSessionMeta(meta);
|
|
875
|
+
// Join the durable sessionId -> actor sidecar (RUSH-2019) when the caller
|
|
876
|
+
// didn't already carry an actor, so a scanned transcript still attributes to a
|
|
877
|
+
// person. The ON CONFLICT COALESCEs actor/initiated_by, so this fills a fresh
|
|
878
|
+
// row AND backfills one indexed null-first (before its sidecar existed), while a
|
|
879
|
+
// rescan carrying no actor still keeps the stored owner.
|
|
880
|
+
const actorRec = meta.actor ? undefined : readSessionActorRecord(meta.id);
|
|
841
881
|
const db = getDB();
|
|
842
882
|
const { upsert, delText, insText, readLabel } = stmts(db);
|
|
843
883
|
const row = {
|
|
@@ -861,6 +901,7 @@ export function upsertSession(meta, content, scan) {
|
|
|
861
901
|
output_tokens: meta.outputTokens ?? null,
|
|
862
902
|
cost_usd: meta.costUsd ?? null,
|
|
863
903
|
duration_ms: meta.durationMs ?? null,
|
|
904
|
+
model: meta.model ?? null,
|
|
864
905
|
file_path: meta.filePath,
|
|
865
906
|
file_mtime_ms: scan?.fileMtimeMs ?? null,
|
|
866
907
|
file_size: scan?.fileSize ?? null,
|
|
@@ -876,6 +917,8 @@ export function upsertSession(meta, content, scan) {
|
|
|
876
917
|
linear_project: meta.linearProject ?? null,
|
|
877
918
|
linear_project_url: meta.linearProjectUrl ?? null,
|
|
878
919
|
machine: resolveMachine(meta),
|
|
920
|
+
actor: meta.actor ?? actorRec?.actor ?? null,
|
|
921
|
+
initiated_by: meta.initiatedBy ?? actorRec?.initiatedBy ?? null,
|
|
879
922
|
};
|
|
880
923
|
const txn = db.transaction(() => {
|
|
881
924
|
upsert.run(row);
|
|
@@ -894,6 +937,12 @@ export function upsertSessionsBatch(entries) {
|
|
|
894
937
|
const db = getDB();
|
|
895
938
|
const { upsert, delText, insText, readLabel } = stmts(db);
|
|
896
939
|
const now = Date.now();
|
|
940
|
+
// One directory read for the whole batch: join the durable sessionId -> actor
|
|
941
|
+
// sidecar (RUSH-2019) so scanned transcripts attribute to a person. Only used
|
|
942
|
+
// for entries whose meta carries no actor; the ON CONFLICT COALESCEs the column,
|
|
943
|
+
// so this fills fresh rows AND backfills null-first ones, never clobbering a
|
|
944
|
+
// stored owner on rescan.
|
|
945
|
+
const actorIndex = loadSessionActorIndex();
|
|
897
946
|
// Persist the Claude resumable-parse continuation (parser_state + content_text)
|
|
898
947
|
// alongside the stamp. On a full/incremental Claude parse the caller passes the
|
|
899
948
|
// serialized newState + accumulated user doc so the NEXT scan can resume from
|
|
@@ -972,6 +1021,7 @@ export function upsertSessionsBatch(entries) {
|
|
|
972
1021
|
output_tokens: meta.outputTokens ?? null,
|
|
973
1022
|
cost_usd: meta.costUsd ?? null,
|
|
974
1023
|
duration_ms: meta.durationMs ?? null,
|
|
1024
|
+
model: meta.model ?? null,
|
|
975
1025
|
file_path: meta.filePath,
|
|
976
1026
|
file_mtime_ms: scan?.fileMtimeMs ?? null,
|
|
977
1027
|
file_size: scan?.fileSize ?? null,
|
|
@@ -987,6 +1037,8 @@ export function upsertSessionsBatch(entries) {
|
|
|
987
1037
|
linear_project: meta.linearProject ?? null,
|
|
988
1038
|
linear_project_url: meta.linearProjectUrl ?? null,
|
|
989
1039
|
machine: resolveMachine(meta),
|
|
1040
|
+
actor: meta.actor ?? actorIndex.get(meta.id)?.actor ?? null,
|
|
1041
|
+
initiated_by: meta.initiatedBy ?? actorIndex.get(meta.id)?.initiatedBy ?? null,
|
|
990
1042
|
});
|
|
991
1043
|
delText.run(meta.id);
|
|
992
1044
|
insText.run(meta.id,
|
|
@@ -1157,6 +1209,7 @@ function rowToMeta(row) {
|
|
|
1157
1209
|
outputTokens: row.output_tokens ?? undefined,
|
|
1158
1210
|
costUsd: row.cost_usd ?? undefined,
|
|
1159
1211
|
durationMs: row.duration_ms ?? undefined,
|
|
1212
|
+
model: row.model ?? undefined,
|
|
1160
1213
|
version: row.version ?? undefined,
|
|
1161
1214
|
account: row.account ?? undefined,
|
|
1162
1215
|
topic: row.topic ?? undefined,
|
|
@@ -1172,6 +1225,10 @@ function rowToMeta(row) {
|
|
|
1172
1225
|
linearProject: row.linear_project ?? undefined,
|
|
1173
1226
|
linearProjectUrl: row.linear_project_url ?? undefined,
|
|
1174
1227
|
machine: row.machine ?? undefined,
|
|
1228
|
+
actor: row.actor ?? undefined,
|
|
1229
|
+
// Narrow the free-text column to the known kinds; an unexpected value maps
|
|
1230
|
+
// to undefined rather than being asserted as a valid kind.
|
|
1231
|
+
initiatedBy: row.initiated_by === 'human' || row.initiated_by === 'agent' ? row.initiated_by : undefined,
|
|
1175
1232
|
};
|
|
1176
1233
|
}
|
|
1177
1234
|
function parseJsonColumn(value) {
|
|
@@ -54,6 +54,7 @@ interface ClaudeSessionScan {
|
|
|
54
54
|
cwd?: string;
|
|
55
55
|
gitBranch?: string;
|
|
56
56
|
version?: string;
|
|
57
|
+
model?: string;
|
|
57
58
|
topic?: string;
|
|
58
59
|
messageCount: number;
|
|
59
60
|
tokenCount?: number;
|
|
@@ -93,6 +94,7 @@ interface CodexSessionScan {
|
|
|
93
94
|
cwd?: string;
|
|
94
95
|
gitBranch?: string;
|
|
95
96
|
version?: string;
|
|
97
|
+
model?: string;
|
|
96
98
|
topic?: string;
|
|
97
99
|
messageCount: number;
|
|
98
100
|
tokenCount?: number;
|
|
@@ -366,6 +368,7 @@ export interface ClaudeParseState {
|
|
|
366
368
|
cwd?: string;
|
|
367
369
|
gitBranch?: string;
|
|
368
370
|
version?: string;
|
|
371
|
+
model?: string;
|
|
369
372
|
topic?: string;
|
|
370
373
|
customTitle?: string;
|
|
371
374
|
aiTitle?: string;
|
|
@@ -424,6 +427,7 @@ export interface ClaudeParserState {
|
|
|
424
427
|
cwd?: string;
|
|
425
428
|
gitBranch?: string;
|
|
426
429
|
version?: string;
|
|
430
|
+
model?: string;
|
|
427
431
|
entrypoint?: string;
|
|
428
432
|
firstTsMs?: number;
|
|
429
433
|
topic?: string;
|
|
@@ -1000,6 +1000,7 @@ async function readClaudeMeta(filePath, sessionId, scanStamp, priorRow, account,
|
|
|
1000
1000
|
filePath,
|
|
1001
1001
|
gitBranch: scan.gitBranch,
|
|
1002
1002
|
version: scan.version,
|
|
1003
|
+
model: scan.model,
|
|
1003
1004
|
account,
|
|
1004
1005
|
topic: scan.topic,
|
|
1005
1006
|
label,
|
|
@@ -1030,6 +1031,7 @@ async function readClaudeMeta(filePath, sessionId, scanStamp, priorRow, account,
|
|
|
1030
1031
|
lastActivity: scan.lastActivity,
|
|
1031
1032
|
filePath,
|
|
1032
1033
|
account,
|
|
1034
|
+
model: scan.model,
|
|
1033
1035
|
label,
|
|
1034
1036
|
messageCount: scan.messageCount,
|
|
1035
1037
|
tokenCount: scan.tokenCount,
|
|
@@ -1327,6 +1329,7 @@ export async function readCodexMeta(filePath, resolveAccount, currentVersion, sc
|
|
|
1327
1329
|
filePath,
|
|
1328
1330
|
gitBranch: scan.gitBranch,
|
|
1329
1331
|
version: resolveSessionVersion('codex', filePath, scan.version, currentVersion),
|
|
1332
|
+
model: scan.model,
|
|
1330
1333
|
topic: scan.topic,
|
|
1331
1334
|
messageCount: scan.messageCount,
|
|
1332
1335
|
tokenCount: scan.tokenCount,
|
|
@@ -1545,6 +1548,7 @@ function readGeminiMeta(filePath, hashDir, projectMap, currentVersion) {
|
|
|
1545
1548
|
cwd,
|
|
1546
1549
|
filePath,
|
|
1547
1550
|
version: resolveSessionVersion('gemini', filePath, embeddedVersion, currentVersion),
|
|
1551
|
+
model: sessionModel,
|
|
1548
1552
|
topic,
|
|
1549
1553
|
messageCount,
|
|
1550
1554
|
tokenCount: sawTokenCount ? tokenCount : undefined,
|
|
@@ -2162,6 +2166,7 @@ function readHermesMeta(filePath) {
|
|
|
2162
2166
|
project: platform,
|
|
2163
2167
|
filePath,
|
|
2164
2168
|
version: model,
|
|
2169
|
+
model,
|
|
2165
2170
|
topic,
|
|
2166
2171
|
messageCount: messageCount || (typeof session.message_count === 'number' ? session.message_count : undefined),
|
|
2167
2172
|
};
|
|
@@ -2260,6 +2265,7 @@ async function readDroidMeta(filePath, currentVersion) {
|
|
|
2260
2265
|
cwd,
|
|
2261
2266
|
filePath,
|
|
2262
2267
|
version: resolveSessionVersion('droid', filePath, undefined, currentVersion),
|
|
2268
|
+
model,
|
|
2263
2269
|
topic: scan.topic,
|
|
2264
2270
|
messageCount: scan.messageCount,
|
|
2265
2271
|
tokenCount,
|
|
@@ -2403,6 +2409,7 @@ export function initClaudeParseState() {
|
|
|
2403
2409
|
cwd: undefined,
|
|
2404
2410
|
gitBranch: undefined,
|
|
2405
2411
|
version: undefined,
|
|
2412
|
+
model: undefined,
|
|
2406
2413
|
topic: undefined,
|
|
2407
2414
|
customTitle: undefined,
|
|
2408
2415
|
aiTitle: undefined,
|
|
@@ -2587,6 +2594,8 @@ export function applyClaudeLine(state, parsed) {
|
|
|
2587
2594
|
// Per-assistant-message cost: each event carries its own model, so we
|
|
2588
2595
|
// multiply that event's raw token directions by that model's price.
|
|
2589
2596
|
const model = parsed.message?.model;
|
|
2597
|
+
if (typeof model === 'string' && model)
|
|
2598
|
+
state.model = model;
|
|
2590
2599
|
if (model && usageObj && typeof usageObj === 'object') {
|
|
2591
2600
|
const eventCost = costOfUsage({
|
|
2592
2601
|
model,
|
|
@@ -2619,6 +2628,7 @@ export function finalizeClaudeScan(state) {
|
|
|
2619
2628
|
cwd: state.cwd,
|
|
2620
2629
|
gitBranch: state.gitBranch,
|
|
2621
2630
|
version: state.version,
|
|
2631
|
+
model: state.model,
|
|
2622
2632
|
topic: resolvedTopic,
|
|
2623
2633
|
entrypoint: state.entrypoint,
|
|
2624
2634
|
messageCount: state.messageCount,
|
|
@@ -2684,6 +2694,7 @@ export function serializeClaudeParserState(state, offset) {
|
|
|
2684
2694
|
cwd: state.cwd,
|
|
2685
2695
|
gitBranch: state.gitBranch,
|
|
2686
2696
|
version: state.version,
|
|
2697
|
+
model: state.model,
|
|
2687
2698
|
entrypoint: state.entrypoint,
|
|
2688
2699
|
firstTsMs: state.firstTsMs,
|
|
2689
2700
|
topic: state.topic,
|
|
@@ -2744,6 +2755,7 @@ export function hydrateClaudeParseState(prior) {
|
|
|
2744
2755
|
cwd: prior.cwd,
|
|
2745
2756
|
gitBranch: prior.gitBranch,
|
|
2746
2757
|
version: prior.version,
|
|
2758
|
+
model: prior.model,
|
|
2747
2759
|
topic: prior.topic,
|
|
2748
2760
|
customTitle: prior.customTitle,
|
|
2749
2761
|
aiTitle: prior.aiTitle,
|
|
@@ -3098,6 +3110,7 @@ export function finalizeCodexScan(state) {
|
|
|
3098
3110
|
cwd: state.cwd,
|
|
3099
3111
|
gitBranch: state.gitBranch,
|
|
3100
3112
|
version: state.version,
|
|
3113
|
+
model: state.model,
|
|
3101
3114
|
topic: state.topic,
|
|
3102
3115
|
messageCount: state.messageCount,
|
|
3103
3116
|
tokenCount: state.tokenCount,
|
|
@@ -14,6 +14,15 @@ export interface HookSessionIndex {
|
|
|
14
14
|
byTerminalId: Map<string, HookSessionRecord>;
|
|
15
15
|
byPid: Map<number, HookSessionRecord>;
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Read the deployed hook's record for one specific pid, or undefined if absent /
|
|
19
|
+
* corrupt / not fresh. `startedAtMs` (the live process's known start, when the
|
|
20
|
+
* caller has it) rejects a stale record left by a PRIOR process at a reused pid:
|
|
21
|
+
* the hook writes its record AFTER the agent boots, so a record whose `ts`
|
|
22
|
+
* predates the current process's start belongs to a dead predecessor. `ts` is
|
|
23
|
+
* Unix SECONDS (the hook stamps `date +%s`); `startedAtMs` is millis.
|
|
24
|
+
*/
|
|
25
|
+
export declare function readStateSessionRecord(pid: number, startedAtMs?: number): HookSessionRecord | undefined;
|
|
17
26
|
/**
|
|
18
27
|
* Scan the hook state dir once and index every record by launch_id, terminal_id,
|
|
19
28
|
* and pid. Returns empty maps if the dir is absent. Newest-by-`ts` wins a key
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Read-only view of the SessionStart hook's live-session state files.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
4
|
+
* Two on-disk sources carry a non-Claude agent's authoritative id (whose id we
|
|
5
|
+
* can't know at spawn), both read here:
|
|
6
|
+
* 1. The `@agents/session-tracker` hook writes
|
|
7
|
+
* `~/.agents/.cache/terminals/sessions/<pid>.json` with the id plus the join
|
|
8
|
+
* keys `launch_id` / `terminal_id`. Rich schema, but this package is NOT
|
|
9
|
+
* deployed on the fleet — its dir is empty there. Scanned into the index by
|
|
10
|
+
* {@link loadHookSessionIndex}.
|
|
11
|
+
* 2. The ACTUALLY-DEPLOYED SessionStart hook writes
|
|
12
|
+
* `~/.agents/.cache/state/sessions/<pid>.json` ({@link readStateSessionRecord})
|
|
13
|
+
* — `{session_id,cwd,pid,ts}`, keyed purely by pid. This is the real fleet id
|
|
14
|
+
* source for every agent; read targeted per-pid, never scanned (RUSH-2007).
|
|
15
|
+
* Both see agents `ag run` did NOT launch (you typing `claude` in a terminal).
|
|
11
16
|
*
|
|
12
17
|
* This module lets `sessions --active` reconcile a `ps`-discovered pid to that
|
|
13
18
|
* authoritative id. It is deliberately a small hand-rolled reader — the CLI does
|
|
@@ -23,12 +28,56 @@
|
|
|
23
28
|
*/
|
|
24
29
|
import fs from 'fs';
|
|
25
30
|
import path from 'path';
|
|
26
|
-
import { getTerminalsDir } from '../state.js';
|
|
31
|
+
import { getTerminalsDir, getRuntimeStateDir } from '../state.js';
|
|
27
32
|
function hookSessionsDir() {
|
|
28
33
|
// Sibling of the pid-registry's by-pid/ dir. The hook hardcodes this same path
|
|
29
34
|
// (packages/session-tracker/src/hook.sh); we read it, never move it.
|
|
30
35
|
return path.join(getTerminalsDir(), 'sessions');
|
|
31
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* The path the ACTUALLY-DEPLOYED SessionStart hook writes:
|
|
39
|
+
* `~/.agents/.cache/state/sessions/<pid>.json`, carrying `{session_id,cwd,pid,ts}`
|
|
40
|
+
* for EVERY agent (claude/codex/gemini/kimi/grok/antigravity). This is the fleet's
|
|
41
|
+
* real id source; the `terminals/sessions/` path above belongs to the separate
|
|
42
|
+
* `@agents/session-tracker` package, which is not deployed (its dir is empty on the
|
|
43
|
+
* fleet), so a non-Claude tmux session's id resolved ONLY through the index above
|
|
44
|
+
* never landed (RUSH-2007). These records are keyed purely by pid — no
|
|
45
|
+
* launch_id/terminal_id/agent — so they join only on pid. The dir is an unpruned
|
|
46
|
+
* graveyard (thousands of dead-pid files), so this is a TARGETED per-pid read on
|
|
47
|
+
* demand, never a full-dir scan folded into {@link loadHookSessionIndex}.
|
|
48
|
+
*/
|
|
49
|
+
function stateSessionRecordPath(pid) {
|
|
50
|
+
return path.join(getRuntimeStateDir(), 'sessions', `${pid}.json`);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Read the deployed hook's record for one specific pid, or undefined if absent /
|
|
54
|
+
* corrupt / not fresh. `startedAtMs` (the live process's known start, when the
|
|
55
|
+
* caller has it) rejects a stale record left by a PRIOR process at a reused pid:
|
|
56
|
+
* the hook writes its record AFTER the agent boots, so a record whose `ts`
|
|
57
|
+
* predates the current process's start belongs to a dead predecessor. `ts` is
|
|
58
|
+
* Unix SECONDS (the hook stamps `date +%s`); `startedAtMs` is millis.
|
|
59
|
+
*/
|
|
60
|
+
export function readStateSessionRecord(pid, startedAtMs) {
|
|
61
|
+
if (!pid || pid < 1)
|
|
62
|
+
return undefined;
|
|
63
|
+
let rec;
|
|
64
|
+
try {
|
|
65
|
+
rec = parseRecord(fs.readFileSync(stateSessionRecordPath(pid), 'utf8'));
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return undefined; // absent (the common case) or unreadable
|
|
69
|
+
}
|
|
70
|
+
if (!rec)
|
|
71
|
+
return undefined;
|
|
72
|
+
if (startedAtMs !== undefined && typeof rec.ts === 'number') {
|
|
73
|
+
// Allow a small skew: the hook fires just after exec, and ts is second-
|
|
74
|
+
// granular so it can floor to just before a sub-second process start.
|
|
75
|
+
const SKEW_MS = 5_000;
|
|
76
|
+
if (rec.ts * 1000 < startedAtMs - SKEW_MS)
|
|
77
|
+
return undefined; // reused-pid graveyard record
|
|
78
|
+
}
|
|
79
|
+
return rec;
|
|
80
|
+
}
|
|
32
81
|
function parseRecord(raw) {
|
|
33
82
|
try {
|
|
34
83
|
const o = JSON.parse(raw);
|
|
@@ -4,6 +4,19 @@ export interface PidSessionEntry {
|
|
|
4
4
|
/** The launch session id. Present for agents launched with a known id (Claude). */
|
|
5
5
|
sessionId?: string;
|
|
6
6
|
cwd?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Resolved actor id (`resolveActor().id`) stamped at spawn — who initiated this
|
|
9
|
+
* run. A tailnet login/email for a resolved human, or `UNRESOLVED@<host>` when
|
|
10
|
+
* it can't be determined. Read back by the active-sessions path to surface an
|
|
11
|
+
* `owner` per session (RUSH-2018), so a co-located fleet shows who launched what.
|
|
12
|
+
*/
|
|
13
|
+
actor?: string;
|
|
14
|
+
/**
|
|
15
|
+
* The actor's kind (`resolveActor().kind`): `'human'` for a person-initiated
|
|
16
|
+
* run, `'agent'` for one an agent spawned. Pairs with {@link actor} the same way
|
|
17
|
+
* `AGENTS_ACTOR` / `AGENTS_ACTOR_KIND` do on the exec env.
|
|
18
|
+
*/
|
|
19
|
+
initiatedBy?: 'human' | 'agent';
|
|
7
20
|
/**
|
|
8
21
|
* The launch id minted by `ag run` and exported to the child as
|
|
9
22
|
* `AGENT_LAUNCH_ID`. The agent's SessionStart hook records the SAME id in its
|
|
@@ -64,6 +64,8 @@ export interface SessionStats {
|
|
|
64
64
|
}
|
|
65
65
|
/** Compute aggregate statistics (turns, tools, tokens, duration) from session events. */
|
|
66
66
|
export declare function computeSummaryStats(events: SessionEvent[]): SessionStats;
|
|
67
|
+
/** Strip the 'claude-' prefix and date suffix from a model identifier. */
|
|
68
|
+
export declare function shortenModel(model: string): string;
|
|
67
69
|
/** Format a duration in milliseconds as a human-readable string (e.g. '12 min', '2h 30min'). */
|
|
68
70
|
export declare function formatDuration(ms: number): string;
|
|
69
71
|
/**
|
|
@@ -220,7 +220,7 @@ export function computeSummaryStats(events) {
|
|
|
220
220
|
};
|
|
221
221
|
}
|
|
222
222
|
/** Strip the 'claude-' prefix and date suffix from a model identifier. */
|
|
223
|
-
function shortenModel(model) {
|
|
223
|
+
export function shortenModel(model) {
|
|
224
224
|
return model.replace(/^claude-/, '').replace(/-\d{8}$/, '');
|
|
225
225
|
}
|
|
226
226
|
/** Format a token count as a human-readable string (e.g. 67.5K, 1.2M). */
|
|
@@ -119,6 +119,8 @@ export interface SessionMeta {
|
|
|
119
119
|
costUsd?: number;
|
|
120
120
|
/** Wall-clock duration in ms (lastTs − firstTs), persisted at scan time. */
|
|
121
121
|
durationMs?: number;
|
|
122
|
+
/** Underlying LLM model observed in the transcript, when the agent records one. */
|
|
123
|
+
model?: string;
|
|
122
124
|
version?: string;
|
|
123
125
|
account?: string;
|
|
124
126
|
topic?: string;
|
|
@@ -190,6 +192,20 @@ export interface SessionMeta {
|
|
|
190
192
|
* undefined for sessions obtained outside that path.
|
|
191
193
|
*/
|
|
192
194
|
machine?: string;
|
|
195
|
+
/**
|
|
196
|
+
* Resolved actor id (`resolveActor().id`) who initiated this session — a
|
|
197
|
+
* tailnet login/email for a resolved human, or `UNRESOLVED@<host>`. Persisted
|
|
198
|
+
* write-once at session creation and preserved across content rescans (kept
|
|
199
|
+
* out of the DB upsert's ON CONFLICT set). Undefined for rows created before
|
|
200
|
+
* actor stamping. RUSH-2018.
|
|
201
|
+
*/
|
|
202
|
+
actor?: string;
|
|
203
|
+
/**
|
|
204
|
+
* The actor's kind (`resolveActor().kind`): `'human'` for a person-initiated
|
|
205
|
+
* run, `'agent'` for one an agent spawned. Pairs with {@link actor}, same
|
|
206
|
+
* split as `AGENTS_ACTOR` / `AGENTS_ACTOR_KIND` on the exec env. RUSH-2018.
|
|
207
|
+
*/
|
|
208
|
+
initiatedBy?: 'human' | 'agent';
|
|
193
209
|
/**
|
|
194
210
|
* True only for rows pulled from another machine over the live cross-machine
|
|
195
211
|
* fan-out (`remote-list.ts`) — their transcript is on that peer's disk, so
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import * as fs from 'fs';
|
|
8
8
|
import * as path from 'path';
|
|
9
|
-
import { AGENTS, agentConfigDirName } from '../../agents.js';
|
|
9
|
+
import { AGENTS, MANAGED_AGENT_IDS, agentConfigDirName } from '../../agents.js';
|
|
10
10
|
import { shouldInstallCommandAsSkill, listCommandSkillsInVersion } from '../../command-skills.js';
|
|
11
11
|
import { lazyAgentMap } from '../writers/lazy-map.js';
|
|
12
12
|
function buildCommandsDetector(agent) {
|
|
@@ -34,7 +34,7 @@ function buildCommandsDetector(agent) {
|
|
|
34
34
|
// agents with their own slash-command runtime (nativeCommandRuntime) opt out.
|
|
35
35
|
export const commandsDetectors = lazyAgentMap(() => {
|
|
36
36
|
const m = {};
|
|
37
|
-
for (const id of
|
|
37
|
+
for (const id of MANAGED_AGENT_IDS) {
|
|
38
38
|
const cfg = AGENTS[id];
|
|
39
39
|
if (cfg.capabilities.commands === false && (!cfg.commandsSubdir || cfg.commandsSubdir === '') && cfg.nativeCommandRuntime)
|
|
40
40
|
continue;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* reports the permission GROUP names that have been applied.
|
|
4
4
|
*
|
|
5
5
|
* For claude/opencode the detector intersects with discovered groups (a group
|
|
6
|
-
* is "applied" if any of its allow/deny rules are present). For Codex /
|
|
6
|
+
* is "applied" if any of its allow/deny rules are present). For Codex /
|
|
7
7
|
* Antigravity / Grok the on-disk format is lossy — once any group has been
|
|
8
8
|
* applied the storage doesn't carry per-group provenance back, so we report
|
|
9
9
|
* "all known groups applied" when any permission artifact is present. This
|
|
@@ -100,29 +100,6 @@ function buildOpenCodeDetector() {
|
|
|
100
100
|
},
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
|
-
function buildGeminiDetector() {
|
|
104
|
-
return {
|
|
105
|
-
kind: 'permissions',
|
|
106
|
-
agent: 'gemini',
|
|
107
|
-
list({ versionHome }) {
|
|
108
|
-
const settingsPath = path.join(versionHome, '.gemini', 'settings.json');
|
|
109
|
-
if (!fs.existsSync(settingsPath))
|
|
110
|
-
return [];
|
|
111
|
-
try {
|
|
112
|
-
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
113
|
-
const core = settings?.tools?.core;
|
|
114
|
-
const exclude = settings?.tools?.exclude;
|
|
115
|
-
const hasCore = Array.isArray(core) && core.length > 0;
|
|
116
|
-
const hasExclude = Array.isArray(exclude) && exclude.length > 0;
|
|
117
|
-
if (hasCore || hasExclude) {
|
|
118
|
-
return discoverPermissionGroups().map(g => g.name);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
catch { /* parse fail */ }
|
|
122
|
-
return [];
|
|
123
|
-
},
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
103
|
function buildAntigravityDetector() {
|
|
127
104
|
return {
|
|
128
105
|
kind: 'permissions',
|
|
@@ -312,25 +289,6 @@ function buildCopilotDetector() {
|
|
|
312
289
|
},
|
|
313
290
|
};
|
|
314
291
|
}
|
|
315
|
-
function buildForgeDetector() {
|
|
316
|
-
return {
|
|
317
|
-
kind: 'permissions',
|
|
318
|
-
agent: 'forge',
|
|
319
|
-
list({ versionHome }) {
|
|
320
|
-
const permissionsPath = path.join(versionHome, '.forge', 'permissions.yaml');
|
|
321
|
-
if (!fs.existsSync(permissionsPath))
|
|
322
|
-
return [];
|
|
323
|
-
try {
|
|
324
|
-
const config = yaml.parse(fs.readFileSync(permissionsPath, 'utf-8'));
|
|
325
|
-
if (config && Array.isArray(config.policies) && config.policies.length > 0) {
|
|
326
|
-
return discoverPermissionGroups().map(g => g.name);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
catch { /* parse fail */ }
|
|
330
|
-
return [];
|
|
331
|
-
},
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
292
|
function buildHermesDetector() {
|
|
335
293
|
return {
|
|
336
294
|
kind: 'permissions',
|
|
@@ -355,7 +313,6 @@ const handlers = {
|
|
|
355
313
|
claude: buildClaudeDetector,
|
|
356
314
|
codex: buildCodexDetector,
|
|
357
315
|
opencode: buildOpenCodeDetector,
|
|
358
|
-
gemini: buildGeminiDetector,
|
|
359
316
|
antigravity: buildAntigravityDetector,
|
|
360
317
|
grok: buildGrokDetector,
|
|
361
318
|
goose: buildGooseDetector,
|
|
@@ -365,7 +322,6 @@ const handlers = {
|
|
|
365
322
|
kiro: buildKiroDetector,
|
|
366
323
|
openclaw: buildOpenClawDetector,
|
|
367
324
|
copilot: buildCopilotDetector,
|
|
368
|
-
forge: buildForgeDetector,
|
|
369
325
|
hermes: buildHermesDetector,
|
|
370
326
|
};
|
|
371
327
|
export const permissionsDetectors = lazyAgentMap(() => {
|
|
@@ -11,15 +11,14 @@
|
|
|
11
11
|
*
|
|
12
12
|
* - native command file — `{agentDir}/<commandsSubdir>/<name>.md` (or .toml
|
|
13
13
|
* when the agent's format is toml). Standard path for Claude, Codex
|
|
14
|
-
* < 0.117.0,
|
|
15
|
-
* Antigravity.
|
|
14
|
+
* < 0.117.0, Cursor, OpenCode, Copilot, Amp, Kiro, Roo, Antigravity.
|
|
16
15
|
*
|
|
17
16
|
* Source resolution is `resolveCommandSource` (user → system → extras —
|
|
18
17
|
* project layer intentionally excluded).
|
|
19
18
|
*/
|
|
20
19
|
import * as fs from 'fs';
|
|
21
20
|
import * as path from 'path';
|
|
22
|
-
import { AGENTS, agentConfigDirName } from '../../agents.js';
|
|
21
|
+
import { AGENTS, MANAGED_AGENT_IDS, agentConfigDirName } from '../../agents.js';
|
|
23
22
|
import { supports } from '../../capabilities.js';
|
|
24
23
|
import { safeJoin } from '../../paths.js';
|
|
25
24
|
import { markdownToToml } from '../../convert.js';
|
|
@@ -83,7 +82,7 @@ function buildCommandsWriter(agent) {
|
|
|
83
82
|
// Built lazily on first access — see lazy-map.ts for the cycle rationale.
|
|
84
83
|
//
|
|
85
84
|
// Registration covers two cases:
|
|
86
|
-
// - native commands (claude, codex < 0.117.0,
|
|
85
|
+
// - native commands (claude, codex < 0.117.0, grok, etc.) — `commands` cap
|
|
87
86
|
// - commands-as-skills (kimi, codex >= 0.117.0)
|
|
88
87
|
//
|
|
89
88
|
// Agents that have skills but use a NATIVE non-file slash-command system
|
|
@@ -92,7 +91,7 @@ function buildCommandsWriter(agent) {
|
|
|
92
91
|
// commands, so there's nothing to write and nothing to convert.
|
|
93
92
|
export const commandsWriters = lazyAgentMap(() => {
|
|
94
93
|
const m = {};
|
|
95
|
-
for (const id of
|
|
94
|
+
for (const id of MANAGED_AGENT_IDS) {
|
|
96
95
|
const cfg = AGENTS[id];
|
|
97
96
|
if (cfg.capabilities.commands === false && (!cfg.skillsDir || cfg.skillsDir === ''))
|
|
98
97
|
continue;
|
|
@@ -90,7 +90,7 @@ function buildHooksWriter(agent) {
|
|
|
90
90
|
// registerHooksForGrok — file copy alone only sees top-level available.hooks
|
|
91
91
|
// names (RUSH-1353). Copilot/Kiro/Goose load managed *.json under their
|
|
92
92
|
// hooks dirs the same way.
|
|
93
|
-
if (agent === 'claude' || agent === 'codex' || agent === '
|
|
93
|
+
if (agent === 'claude' || agent === 'codex' || agent === 'antigravity' || agent === 'kimi' || agent === 'droid' || agent === 'copilot' || agent === 'kiro' || agent === 'goose' || agent === 'cursor' || agent === 'grok' || agent === 'hermes') {
|
|
94
94
|
registerHooksToSettings(agent, versionHome);
|
|
95
95
|
}
|
|
96
96
|
return { synced };
|
|
@@ -25,7 +25,6 @@ export type Registrar = (program: Command) => void;
|
|
|
25
25
|
export type ModuleLoader = () => Promise<Registrar>;
|
|
26
26
|
export declare const loadView: ModuleLoader;
|
|
27
27
|
export declare const loadInspect: ModuleLoader;
|
|
28
|
-
export declare const loadResources: ModuleLoader;
|
|
29
28
|
export declare const loadFeedback: ModuleLoader;
|
|
30
29
|
export declare const loadCommands: ModuleLoader;
|
|
31
30
|
export declare const loadHooks: ModuleLoader;
|
|
@@ -48,13 +47,13 @@ export declare const loadMonitors: ModuleLoader;
|
|
|
48
47
|
export declare const loadRun: ModuleLoader;
|
|
49
48
|
export declare const loadFork: ModuleLoader;
|
|
50
49
|
export declare const loadDefaults: ModuleLoader;
|
|
50
|
+
export declare const loadSet: ModuleLoader;
|
|
51
51
|
export declare const loadModels: ModuleLoader;
|
|
52
52
|
export declare const loadPrune: ModuleLoader;
|
|
53
53
|
export declare const loadTrash: ModuleLoader;
|
|
54
54
|
export declare const loadRestore: ModuleLoader;
|
|
55
55
|
export declare const loadDoctor: ModuleLoader;
|
|
56
56
|
export declare const loadApply: ModuleLoader;
|
|
57
|
-
export declare const loadCheck: ModuleLoader;
|
|
58
57
|
export declare const loadStatus: ModuleLoader;
|
|
59
58
|
export declare const loadProfiles: ModuleLoader;
|
|
60
59
|
export declare const loadHarness: ModuleLoader;
|