halfcycle 0.3.30 → 0.3.31
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/.claude-plugin/plugin.json +1 -1
- package/bin/bin.bundle.mjs +71 -29
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "halfcycle",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.31",
|
|
4
4
|
"description": "Halfcycle Method bundle — resolution-stub slash commands, remote method-delivery registration, and governance-hook wiring for a Halfcycle engagement repo. It ships NO worker role files: a project's roles are authored from that project's own recorded decisions at orchestration kickoff (FX-2, W3-F-27).",
|
|
5
5
|
"commands": [
|
|
6
6
|
{
|
package/bin/bin.bundle.mjs
CHANGED
|
@@ -15147,21 +15147,49 @@ function emitBlock(reason) {
|
|
|
15147
15147
|
process.stdout.write(JSON.stringify({ decision: "block", reason }) + "\n");
|
|
15148
15148
|
process.exit(0);
|
|
15149
15149
|
}
|
|
15150
|
-
function
|
|
15151
|
-
|
|
15150
|
+
function nonBlockingReply(event, text) {
|
|
15151
|
+
if (event === "PostToolUse") {
|
|
15152
|
+
return JSON.stringify({
|
|
15153
|
+
systemMessage: text,
|
|
15154
|
+
hookSpecificOutput: { hookEventName: event, additionalContext: text }
|
|
15155
|
+
});
|
|
15156
|
+
}
|
|
15157
|
+
return JSON.stringify({ systemMessage: text });
|
|
15152
15158
|
}
|
|
15153
|
-
function
|
|
15154
|
-
|
|
15159
|
+
function hookReply(event) {
|
|
15160
|
+
const queued = [];
|
|
15161
|
+
return {
|
|
15162
|
+
notice(text) {
|
|
15163
|
+
queued.push(text);
|
|
15164
|
+
},
|
|
15165
|
+
block(reason) {
|
|
15166
|
+
const carried = queued.splice(0);
|
|
15167
|
+
return emitBlock(carried.length === 0 ? reason : [reason, ...carried].join("\n"));
|
|
15168
|
+
},
|
|
15169
|
+
flush() {
|
|
15170
|
+
if (queued.length === 0)
|
|
15171
|
+
return;
|
|
15172
|
+
const text = queued.splice(0).join("\n");
|
|
15173
|
+
const code = process.exitCode;
|
|
15174
|
+
if (code !== void 0 && code !== null && Number(code) !== 0) {
|
|
15175
|
+
writeSync(2, `${text}
|
|
15155
15176
|
`);
|
|
15156
|
-
|
|
15157
|
-
|
|
15158
|
-
|
|
15177
|
+
return;
|
|
15178
|
+
}
|
|
15179
|
+
process.stdout.write(`${nonBlockingReply(event, text)}
|
|
15159
15180
|
`);
|
|
15181
|
+
}
|
|
15182
|
+
};
|
|
15160
15183
|
}
|
|
15161
|
-
function
|
|
15162
|
-
|
|
15163
|
-
|
|
15164
|
-
|
|
15184
|
+
function infraWarningText(message) {
|
|
15185
|
+
return `[Halfcycle] WARNING: Guard service unavailable \u2014 ${message}. Session continues (fail-open).`;
|
|
15186
|
+
}
|
|
15187
|
+
function localFaultText(message) {
|
|
15188
|
+
return `[Halfcycle] WARNING: Local fault \u2014 ${message}. The guard service was not contacted. Session continues (fail-open).`;
|
|
15189
|
+
}
|
|
15190
|
+
function contractFaultText(message) {
|
|
15191
|
+
return `[Halfcycle] WARNING: Guard response could not be understood \u2014 ${message}
|
|
15192
|
+
This is not a service outage: the guard service answered. The suspect is this repository's own installed halfcycle runner, which is out of date with what the service now sends. Update it: run "npx halfcycle" in this repository, then retry. Session continues (fail-open).`;
|
|
15165
15193
|
}
|
|
15166
15194
|
var UNCONFIGURED_EXIT_TOOL_USE = 2;
|
|
15167
15195
|
var UNCONFIGURED_EXIT_STOP_FAMILY = 1;
|
|
@@ -17212,6 +17240,11 @@ async function evaluateWithRefresh(opts) {
|
|
|
17212
17240
|
// dist/hooks/post-tool-use.js
|
|
17213
17241
|
var HANDLED_EDIT_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
|
|
17214
17242
|
async function runPostToolUse() {
|
|
17243
|
+
const reply = hookReply("PostToolUse");
|
|
17244
|
+
await evaluateEdit(reply);
|
|
17245
|
+
reply.flush();
|
|
17246
|
+
}
|
|
17247
|
+
async function evaluateEdit(reply) {
|
|
17215
17248
|
let input;
|
|
17216
17249
|
try {
|
|
17217
17250
|
const raw = await readStdin();
|
|
@@ -17228,7 +17261,7 @@ async function runPostToolUse() {
|
|
|
17228
17261
|
return;
|
|
17229
17262
|
const repoRootResult = getRepoRoot(process.cwd());
|
|
17230
17263
|
if (!repoRootResult.ok) {
|
|
17231
|
-
|
|
17264
|
+
reply.notice(localFaultText(`Could not find git repo root: ${repoRootResult.message}`));
|
|
17232
17265
|
return;
|
|
17233
17266
|
}
|
|
17234
17267
|
const repoRoot = repoRootResult.value;
|
|
@@ -17280,10 +17313,10 @@ async function runPostToolUse() {
|
|
|
17280
17313
|
return;
|
|
17281
17314
|
}
|
|
17282
17315
|
if (failure.kind === "contract") {
|
|
17283
|
-
|
|
17316
|
+
reply.notice(contractFaultText(failure.message));
|
|
17284
17317
|
return;
|
|
17285
17318
|
}
|
|
17286
|
-
|
|
17319
|
+
reply.notice(infraWarningText(failure.reason));
|
|
17287
17320
|
return;
|
|
17288
17321
|
}
|
|
17289
17322
|
const telemetryConfig = readTelemetryConfig();
|
|
@@ -17311,25 +17344,25 @@ async function runPostToolUse() {
|
|
|
17311
17344
|
}, {
|
|
17312
17345
|
warn: (msg) => process.stderr.write(msg + "\n")
|
|
17313
17346
|
});
|
|
17314
|
-
actOnEnvelope2(clientResult.envelope);
|
|
17347
|
+
actOnEnvelope2(clientResult.envelope, reply);
|
|
17315
17348
|
}
|
|
17316
|
-
function actOnEnvelope2(envelope) {
|
|
17349
|
+
function actOnEnvelope2(envelope, reply) {
|
|
17317
17350
|
const notRun = notRunReport(envelope.notRun);
|
|
17318
17351
|
const notRunBlock = notRun ? `
|
|
17319
17352
|
${notRun}` : "";
|
|
17320
17353
|
if (envelope.guardsFired.length === 0) {
|
|
17321
17354
|
if (notRun)
|
|
17322
|
-
|
|
17355
|
+
reply.notice(notRun);
|
|
17323
17356
|
return;
|
|
17324
17357
|
}
|
|
17325
17358
|
if (envelope.blocking) {
|
|
17326
17359
|
const guardLines = envelope.guardsFired.map((g) => ` [${g.severity.toUpperCase()}] ${g.patternRef}: ${g.explanation}`).join("\n");
|
|
17327
17360
|
const reason = `Guard blocked: ${envelope.explanation}
|
|
17328
17361
|
${guardLines}${notRunBlock}`;
|
|
17329
|
-
|
|
17362
|
+
reply.block(reason);
|
|
17330
17363
|
} else {
|
|
17331
17364
|
const guardLines = envelope.guardsFired.map((g) => ` [${g.severity.toUpperCase()}] ${g.patternRef}: ${g.explanation}`).join("\n");
|
|
17332
|
-
|
|
17365
|
+
reply.notice(`[Halfcycle] Guard warning: ${envelope.explanation}
|
|
17333
17366
|
${guardLines}${notRunBlock}`);
|
|
17334
17367
|
}
|
|
17335
17368
|
}
|
|
@@ -17464,6 +17497,10 @@ function orphanSweep(repoRoot, refKnown, keepSessionId, now = Date.now()) {
|
|
|
17464
17497
|
}
|
|
17465
17498
|
|
|
17466
17499
|
// dist/hooks/session-diff.js
|
|
17500
|
+
var STOP_HOOK_EVENT = {
|
|
17501
|
+
stop: "Stop",
|
|
17502
|
+
"subagent-stop": "SubagentStop"
|
|
17503
|
+
};
|
|
17467
17504
|
function resolveDiffBase2(repoRoot, sessionId) {
|
|
17468
17505
|
const ref = readMarker(repoRoot, sessionId);
|
|
17469
17506
|
if (ref === null)
|
|
@@ -17495,9 +17532,14 @@ function collectDiff(repoRoot, base) {
|
|
|
17495
17532
|
};
|
|
17496
17533
|
}
|
|
17497
17534
|
async function runSessionDiff(input, kind) {
|
|
17535
|
+
const reply = hookReply(STOP_HOOK_EVENT[kind]);
|
|
17536
|
+
await evaluateSession(input, kind, reply);
|
|
17537
|
+
reply.flush();
|
|
17538
|
+
}
|
|
17539
|
+
async function evaluateSession(input, kind, reply) {
|
|
17498
17540
|
const repoRootResult = getRepoRoot(process.cwd());
|
|
17499
17541
|
if (!repoRootResult.ok) {
|
|
17500
|
-
|
|
17542
|
+
reply.notice(localFaultText(`Could not find git repo root: ${repoRootResult.message}`));
|
|
17501
17543
|
return;
|
|
17502
17544
|
}
|
|
17503
17545
|
const repoRoot = repoRootResult.value;
|
|
@@ -17507,7 +17549,7 @@ async function runSessionDiff(input, kind) {
|
|
|
17507
17549
|
const diffBase = base.kind;
|
|
17508
17550
|
const collected = collectDiff(repoRoot, base);
|
|
17509
17551
|
if (!collected.ok) {
|
|
17510
|
-
|
|
17552
|
+
reply.notice(localFaultText(`Could not get session diff: ${collected.message}`));
|
|
17511
17553
|
return;
|
|
17512
17554
|
}
|
|
17513
17555
|
const { getDiff } = collected;
|
|
@@ -17566,10 +17608,10 @@ async function runSessionDiff(input, kind) {
|
|
|
17566
17608
|
return;
|
|
17567
17609
|
}
|
|
17568
17610
|
if (failure.kind === "contract") {
|
|
17569
|
-
|
|
17611
|
+
reply.notice(contractFaultText(failure.message));
|
|
17570
17612
|
return;
|
|
17571
17613
|
}
|
|
17572
|
-
|
|
17614
|
+
reply.notice(infraWarningText(failure.reason));
|
|
17573
17615
|
return;
|
|
17574
17616
|
}
|
|
17575
17617
|
const telemetryConfig = readTelemetryConfig();
|
|
@@ -17595,28 +17637,28 @@ async function runSessionDiff(input, kind) {
|
|
|
17595
17637
|
warn: (msg) => process.stderr.write(msg + "\n")
|
|
17596
17638
|
});
|
|
17597
17639
|
writeDedupe(repoRoot, sessionId, { base: baseKey, digest });
|
|
17598
|
-
actOnEnvelope3(clientResult.envelope, kind, input.stop_hook_active === true);
|
|
17640
|
+
actOnEnvelope3(clientResult.envelope, kind, input.stop_hook_active === true, reply);
|
|
17599
17641
|
}
|
|
17600
|
-
function actOnEnvelope3(envelope, kind, neverBlock) {
|
|
17642
|
+
function actOnEnvelope3(envelope, kind, neverBlock, reply) {
|
|
17601
17643
|
const notRun = notRunReport(envelope.notRun);
|
|
17602
17644
|
const notRunBlock = notRun ? `
|
|
17603
17645
|
${notRun}` : "";
|
|
17604
17646
|
if (envelope.guardsFired.length === 0) {
|
|
17605
17647
|
if (notRun)
|
|
17606
|
-
|
|
17648
|
+
reply.notice(notRun);
|
|
17607
17649
|
return;
|
|
17608
17650
|
}
|
|
17609
17651
|
const where = kind === "stop" ? "session stop" : "session stop";
|
|
17610
17652
|
const guardLines = envelope.guardsFired.map((g) => ` [${g.severity.toUpperCase()}] ${g.patternRef}: ${g.explanation}`).join("\n");
|
|
17611
17653
|
if (envelope.blocking && !neverBlock) {
|
|
17612
|
-
|
|
17654
|
+
reply.block(`Guard blocked at ${where}: ${envelope.explanation}
|
|
17613
17655
|
${guardLines}${notRunBlock}`);
|
|
17614
17656
|
} else if (envelope.blocking && neverBlock) {
|
|
17615
|
-
|
|
17657
|
+
reply.notice(`[Halfcycle] Guard would block at ${where} but the stop was already continued (stop_hook_active) \u2014 surfacing as a warning:
|
|
17616
17658
|
${envelope.explanation}
|
|
17617
17659
|
${guardLines}${notRunBlock}`);
|
|
17618
17660
|
} else {
|
|
17619
|
-
|
|
17661
|
+
reply.notice(`[Halfcycle] Guard warning at ${where}: ${envelope.explanation}
|
|
17620
17662
|
${guardLines}${notRunBlock}`);
|
|
17621
17663
|
}
|
|
17622
17664
|
}
|
package/package.json
CHANGED