roster-cli 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/sources/plugin-cache.js +2 -1
- package/dist/usage.js +25 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -155,10 +155,10 @@ Once installed:
|
|
|
155
155
|
(`ROSTER_DRIFT_DISABLE=1` to opt out). By default it watches
|
|
156
156
|
`.claude/agents` plus, in a plugin-layout repo (one with a top-level
|
|
157
157
|
`.claude-plugin/plugin.json`), the root `agents/` dir; override with
|
|
158
|
-
`ROSTER_DRIFT_DIR` (colon-separated dir list). The advisory
|
|
159
|
-
Claude's session context
|
|
160
|
-
|
|
161
|
-
session.
|
|
158
|
+
`ROSTER_DRIFT_DIR` (colon-separated dir list). The advisory is injected
|
|
159
|
+
into Claude's session context along with a relay directive, so Claude
|
|
160
|
+
surfaces it to you in its first response of the session. Advisory only —
|
|
161
|
+
never blocks a session.
|
|
162
162
|
|
|
163
163
|
## Contributing
|
|
164
164
|
|
|
@@ -145,7 +145,8 @@ export const pluginCacheSource = {
|
|
|
145
145
|
const sourceLabel = `plugin:${plugin.name}@${plugin.version}`;
|
|
146
146
|
return Promise.all(files.map(async (filePath) => {
|
|
147
147
|
const raw = await readFile(filePath, 'utf8');
|
|
148
|
-
|
|
148
|
+
const agent = parseAgentMarkdown(raw, filePath, sourceLabel);
|
|
149
|
+
return { ...agent, pluginName: plugin.name };
|
|
149
150
|
}));
|
|
150
151
|
}));
|
|
151
152
|
return agentLists.flat();
|
package/dist/usage.js
CHANGED
|
@@ -64,13 +64,24 @@ function parseArgs(argv) {
|
|
|
64
64
|
}
|
|
65
65
|
/**
|
|
66
66
|
* Pure join between observed invocation counts and a roster's agent names.
|
|
67
|
-
* - unused: in the roster, but zero observed invocations
|
|
68
|
-
*
|
|
67
|
+
* - unused: in the roster, but zero observed invocations (directly, or via an
|
|
68
|
+
* alias key such as the `<plugin>:<name>` form transcripts record for
|
|
69
|
+
* plugin-sourced subagents).
|
|
70
|
+
* - ghosts: observed invocations for a subagent_type that isn't in the roster
|
|
71
|
+
* and isn't a known alias of a roster name.
|
|
72
|
+
*
|
|
73
|
+
* `aliases` maps an observed count key (e.g. `sshworld:implementor`) to the
|
|
74
|
+
* canonical bare roster name (e.g. `implementor`). Omitting it preserves the
|
|
75
|
+
* prior exact-match-only behavior.
|
|
69
76
|
*/
|
|
70
|
-
export function computeJoin(counts, rosterNames) {
|
|
77
|
+
export function computeJoin(counts, rosterNames, aliases = {}) {
|
|
71
78
|
const rosterSet = new Set(rosterNames);
|
|
72
|
-
const unused = rosterNames.filter((name) =>
|
|
73
|
-
|
|
79
|
+
const unused = rosterNames.filter((name) => {
|
|
80
|
+
if (counts[name])
|
|
81
|
+
return false;
|
|
82
|
+
return !Object.keys(counts).some((key) => aliases[key] === name);
|
|
83
|
+
});
|
|
84
|
+
const ghosts = Object.keys(counts).filter((name) => !rosterSet.has(name) && !(name in aliases && rosterSet.has(aliases[name])));
|
|
74
85
|
return { unused, ghosts };
|
|
75
86
|
}
|
|
76
87
|
async function findJsonlFiles(root) {
|
|
@@ -148,6 +159,7 @@ async function countAgentInvocations(filePath, cutoff, counts) {
|
|
|
148
159
|
}
|
|
149
160
|
async function loadRosterNames(user, plugin) {
|
|
150
161
|
const names = new Set();
|
|
162
|
+
const aliases = {};
|
|
151
163
|
if (user) {
|
|
152
164
|
const agents = await sources.user.load();
|
|
153
165
|
for (const agent of agents)
|
|
@@ -155,10 +167,14 @@ async function loadRosterNames(user, plugin) {
|
|
|
155
167
|
}
|
|
156
168
|
if (plugin) {
|
|
157
169
|
const agents = await sources['plugin-cache'].load();
|
|
158
|
-
for (const agent of agents)
|
|
170
|
+
for (const agent of agents) {
|
|
159
171
|
names.add(agent.name);
|
|
172
|
+
if (agent.pluginName) {
|
|
173
|
+
aliases[`${agent.pluginName}:${agent.name}`] = agent.name;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
160
176
|
}
|
|
161
|
-
return [...names];
|
|
177
|
+
return { names: [...names], aliases };
|
|
162
178
|
}
|
|
163
179
|
function renderHuman(days, counts, unused, ghosts) {
|
|
164
180
|
const lines = [];
|
|
@@ -209,8 +225,8 @@ export async function run(argv) {
|
|
|
209
225
|
let unused = [];
|
|
210
226
|
let ghosts = [];
|
|
211
227
|
if (parsed.user || parsed.plugin) {
|
|
212
|
-
const rosterNames = await loadRosterNames(parsed.user, parsed.plugin);
|
|
213
|
-
const joined = computeJoin(counts, rosterNames);
|
|
228
|
+
const { names: rosterNames, aliases } = await loadRosterNames(parsed.user, parsed.plugin);
|
|
229
|
+
const joined = computeJoin(counts, rosterNames, aliases);
|
|
214
230
|
unused = joined.unused;
|
|
215
231
|
ghosts = joined.ghosts;
|
|
216
232
|
}
|