agent-standup 0.20.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/LICENSE +21 -0
- package/README.md +322 -0
- package/dist/bin/standup-hook.js +296 -0
- package/dist/bin/standup.js +3351 -0
- package/dist/chunk-4TIZQTUZ.js +19195 -0
- package/dist/chunk-N7G677FC.js +1042 -0
- package/dist/chunk-VBXNDGOD.js +203 -0
- package/dist/hook-scripts/http.js +1265 -0
- package/dist/live-R6WH7ER7.js +326 -0
- package/dist/plugin/.claude-plugin/plugin.json +9 -0
- package/dist/plugin/.mcp.json +8 -0
- package/dist/plugin/hooks/hooks.json +35 -0
- package/dist/plugin/skills/setup-agent-standup/SKILL.md +53 -0
- package/dist/run-init-VVQPJOTB.js +407 -0
- package/package.json +88 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
// src/lib/interventions/types.ts
|
|
2
|
+
var INTERVENTION_LEVELS = ["nothing", "nudge", "block-overridable", "hard-block"];
|
|
3
|
+
var INTERVENTION_TIMINGS = ["immediate", "digest"];
|
|
4
|
+
var BLOCKING_LEVELS = /* @__PURE__ */ new Set([
|
|
5
|
+
"block-overridable",
|
|
6
|
+
"hard-block"
|
|
7
|
+
]);
|
|
8
|
+
function isBlockingLevel(level) {
|
|
9
|
+
return BLOCKING_LEVELS.has(level);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// src/lib/interventions/capture.ts
|
|
13
|
+
var INTERVENTION_OUTCOMES = ["silent", "nudged", "blocked", "overridden"];
|
|
14
|
+
var MAX_CAPTURED_COMMAND = 200;
|
|
15
|
+
function truncateCommand(command, limit = MAX_CAPTURED_COMMAND) {
|
|
16
|
+
if (command.length <= limit) return command;
|
|
17
|
+
return `${command.slice(0, limit)}\u2026[truncated]`;
|
|
18
|
+
}
|
|
19
|
+
function outcomeFor(finding, context) {
|
|
20
|
+
if (finding.level === "nothing") return "silent";
|
|
21
|
+
if (!isBlockingLevel(finding.level)) return "nudged";
|
|
22
|
+
if (context.overriddenEntryIds?.includes(finding.id) === true) return "overridden";
|
|
23
|
+
return context.blocked === false ? "nudged" : "blocked";
|
|
24
|
+
}
|
|
25
|
+
function buildCaptures(findings, context) {
|
|
26
|
+
return findings.map((finding) => {
|
|
27
|
+
const command = context.command === void 0 ? void 0 : truncateCommand(context.command);
|
|
28
|
+
const outcome = outcomeFor(finding, context);
|
|
29
|
+
const overrideReason = outcome === "overridden" ? context.overrideReason : void 0;
|
|
30
|
+
return {
|
|
31
|
+
entryId: finding.id,
|
|
32
|
+
sessionId: context.sessionId,
|
|
33
|
+
...context.rootSessionId === void 0 ? {} : { rootSessionId: context.rootSessionId },
|
|
34
|
+
...context.itemId === void 0 ? {} : { itemId: context.itemId },
|
|
35
|
+
outcome,
|
|
36
|
+
level: finding.level,
|
|
37
|
+
phase: finding.phase,
|
|
38
|
+
...context.tool === void 0 ? {} : { tool: context.tool },
|
|
39
|
+
...command === void 0 ? {} : { command },
|
|
40
|
+
message: finding.messages.plain,
|
|
41
|
+
...overrideReason === void 0 || overrideReason === "" ? {} : { overrideReason }
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// src/lib/build-constants.ts
|
|
47
|
+
var HOOK_VARIANTS = ["cli", "http"];
|
|
48
|
+
function isHookVariant(value) {
|
|
49
|
+
return typeof value === "string" && HOOK_VARIANTS.includes(value);
|
|
50
|
+
}
|
|
51
|
+
var HOOK_PROTOCOL = Object.freeze({
|
|
52
|
+
cli: Object.freeze({ current: 1, minSupported: 1 }),
|
|
53
|
+
http: Object.freeze({ current: 1, minSupported: 1 })
|
|
54
|
+
});
|
|
55
|
+
var SHIPPED_HOOK_PROTOCOL_VERSION = 1;
|
|
56
|
+
|
|
57
|
+
// src/lib/telemetry/contract.ts
|
|
58
|
+
var MAX_COMMAND_CHARS = 4096;
|
|
59
|
+
var MAX_PATHS = 64;
|
|
60
|
+
var MAX_PATH_CHARS = 256;
|
|
61
|
+
var MAX_TOOL_CHARS = 200;
|
|
62
|
+
var MAX_SESSION_ID_CHARS = 128;
|
|
63
|
+
var MAX_BATCH_SIZE = 500;
|
|
64
|
+
var TRUNCATION_MARKER = "\u2026[truncated]";
|
|
65
|
+
function capText(value, limit) {
|
|
66
|
+
if (value.length <= limit) return value;
|
|
67
|
+
if (limit <= TRUNCATION_MARKER.length) return value.slice(0, limit);
|
|
68
|
+
return value.slice(0, limit - TRUNCATION_MARKER.length) + TRUNCATION_MARKER;
|
|
69
|
+
}
|
|
70
|
+
function capPaths(paths) {
|
|
71
|
+
return paths.slice(0, MAX_PATHS).map((path) => capText(path, MAX_PATH_CHARS));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/lib/interventions/scoring.ts
|
|
75
|
+
var INTERVENTION_SCORE_MEANINGS = Object.freeze({
|
|
76
|
+
5: "I would have gone down the wrong path and wasted a lot of tokens, or done something incorrect, if not for this nudge",
|
|
77
|
+
4: "Saved me some time/tokens or got me somewhere quicker, but I wasn't about to do anything dangerous anyway",
|
|
78
|
+
3: "Neutral \u2014 it helped, but I could probably have figured it out myself",
|
|
79
|
+
2: "Didn't help; the nudge was incorrect or misleading and I wasted more time because of it",
|
|
80
|
+
1: "Actively wrong or harmful \u2014 a block I had to route around, a stumbling block that took too long to work around. Please remove"
|
|
81
|
+
});
|
|
82
|
+
var MIN_INTERVENTION_SCORE = 1;
|
|
83
|
+
var MAX_INTERVENTION_SCORE = 5;
|
|
84
|
+
function isValidInterventionScore(value) {
|
|
85
|
+
return typeof value === "number" && Number.isInteger(value) && value >= MIN_INTERVENTION_SCORE && value <= MAX_INTERVENTION_SCORE;
|
|
86
|
+
}
|
|
87
|
+
function isHumanOrAgentTestimony(population) {
|
|
88
|
+
return population !== "derived";
|
|
89
|
+
}
|
|
90
|
+
function emptyDistribution() {
|
|
91
|
+
return { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0 };
|
|
92
|
+
}
|
|
93
|
+
var SCALE_POINTS = [5, 4, 3, 2, 1];
|
|
94
|
+
function summariseScores(firings) {
|
|
95
|
+
const byEntry = /* @__PURE__ */ new Map();
|
|
96
|
+
for (const firing of firings) {
|
|
97
|
+
if (!isValidInterventionScore(firing.score)) continue;
|
|
98
|
+
const bucket = byEntry.get(firing.entryId) ?? {
|
|
99
|
+
scores: [],
|
|
100
|
+
notes: [],
|
|
101
|
+
testimony: [],
|
|
102
|
+
derived: []
|
|
103
|
+
};
|
|
104
|
+
bucket.scores.push(firing.score);
|
|
105
|
+
if (isHumanOrAgentTestimony(firing.population ?? "person")) {
|
|
106
|
+
bucket.testimony.push(firing.score);
|
|
107
|
+
} else {
|
|
108
|
+
bucket.derived.push(firing.score);
|
|
109
|
+
}
|
|
110
|
+
if (firing.note !== void 0 && firing.note.trim() !== "") {
|
|
111
|
+
bucket.notes.push(firing.note.trim());
|
|
112
|
+
}
|
|
113
|
+
byEntry.set(firing.entryId, bucket);
|
|
114
|
+
}
|
|
115
|
+
const summaries = [];
|
|
116
|
+
for (const [entryId, bucket] of byEntry) {
|
|
117
|
+
const distribution = emptyDistribution();
|
|
118
|
+
let total = 0;
|
|
119
|
+
for (const score of bucket.scores) {
|
|
120
|
+
distribution[score] += 1;
|
|
121
|
+
total += score;
|
|
122
|
+
}
|
|
123
|
+
const count = bucket.scores.length;
|
|
124
|
+
summaries.push({
|
|
125
|
+
entryId,
|
|
126
|
+
count,
|
|
127
|
+
mean: total / count,
|
|
128
|
+
distribution,
|
|
129
|
+
removalSignals: distribution[1],
|
|
130
|
+
unhelpful: distribution[1] + distribution[2],
|
|
131
|
+
notes: bucket.notes,
|
|
132
|
+
testimony: summarisePopulation(bucket.testimony),
|
|
133
|
+
derived: summarisePopulation(bucket.derived)
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
return summaries.sort((a, b) => a.entryId.localeCompare(b.entryId));
|
|
137
|
+
}
|
|
138
|
+
function summarisePopulation(scores) {
|
|
139
|
+
if (scores.length === 0) return null;
|
|
140
|
+
const distribution = emptyDistribution();
|
|
141
|
+
let total = 0;
|
|
142
|
+
for (const score of scores) {
|
|
143
|
+
distribution[score] += 1;
|
|
144
|
+
total += score;
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
count: scores.length,
|
|
148
|
+
mean: total / scores.length,
|
|
149
|
+
distribution,
|
|
150
|
+
removalSignals: distribution[1],
|
|
151
|
+
unhelpful: distribution[1] + distribution[2]
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
var DEFAULT_REVIEW_THRESHOLD = 3;
|
|
155
|
+
var DEFAULT_REVIEW_MEAN = 2.5;
|
|
156
|
+
function flagEntriesForReview(summaries, options = {}) {
|
|
157
|
+
const threshold = options.threshold ?? DEFAULT_REVIEW_THRESHOLD;
|
|
158
|
+
const meanAtOrBelow = options.meanAtOrBelow ?? DEFAULT_REVIEW_MEAN;
|
|
159
|
+
const flagged = [];
|
|
160
|
+
for (const summary of summaries) {
|
|
161
|
+
if (summary.count < threshold) continue;
|
|
162
|
+
const reasons = [];
|
|
163
|
+
if (summary.mean <= meanAtOrBelow) {
|
|
164
|
+
reasons.push(`mean ${summary.mean.toFixed(2)} over ${summary.count} ratings`);
|
|
165
|
+
}
|
|
166
|
+
if (summary.removalSignals > 0) {
|
|
167
|
+
reasons.push(
|
|
168
|
+
summary.removalSignals === 1 ? "1 rater asked for it to be removed" : `${summary.removalSignals} raters asked for it to be removed`
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
if (reasons.length === 0) continue;
|
|
172
|
+
flagged.push({ entryId: summary.entryId, summary, reason: reasons.join("; ") });
|
|
173
|
+
}
|
|
174
|
+
return flagged.sort((a, b) => a.summary.mean - b.summary.mean);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export {
|
|
178
|
+
HOOK_VARIANTS,
|
|
179
|
+
isHookVariant,
|
|
180
|
+
HOOK_PROTOCOL,
|
|
181
|
+
SHIPPED_HOOK_PROTOCOL_VERSION,
|
|
182
|
+
MAX_COMMAND_CHARS,
|
|
183
|
+
MAX_PATHS,
|
|
184
|
+
MAX_TOOL_CHARS,
|
|
185
|
+
MAX_SESSION_ID_CHARS,
|
|
186
|
+
MAX_BATCH_SIZE,
|
|
187
|
+
TRUNCATION_MARKER,
|
|
188
|
+
capText,
|
|
189
|
+
capPaths,
|
|
190
|
+
INTERVENTION_LEVELS,
|
|
191
|
+
INTERVENTION_TIMINGS,
|
|
192
|
+
isBlockingLevel,
|
|
193
|
+
INTERVENTION_OUTCOMES,
|
|
194
|
+
MAX_CAPTURED_COMMAND,
|
|
195
|
+
buildCaptures,
|
|
196
|
+
INTERVENTION_SCORE_MEANINGS,
|
|
197
|
+
MIN_INTERVENTION_SCORE,
|
|
198
|
+
MAX_INTERVENTION_SCORE,
|
|
199
|
+
isValidInterventionScore,
|
|
200
|
+
SCALE_POINTS,
|
|
201
|
+
summariseScores,
|
|
202
|
+
flagEntriesForReview
|
|
203
|
+
};
|