@tech-leads-club/harness-toolkit 0.10.0 → 0.10.2
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/dist/compact-before.mjs +21 -21
- package/dist/doctor.mjs +23 -23
- package/dist/init-project.mjs +24 -24
- package/dist/install-runtime.mjs +21 -21
- package/dist/lessons-cli.mjs +21 -21
- package/dist/obs-cli.mjs +23 -23
- package/dist/prompt-submit.mjs +66 -66
- package/dist/refresh-model-prices.mjs +22 -22
- package/dist/response-after.mjs +21 -21
- package/dist/run.mjs +22 -22
- package/dist/session-end.mjs +23 -23
- package/dist/session-start.mjs +25 -25
- package/dist/shim.mjs +21 -21
- package/dist/ship-gate.mjs +22 -22
- package/dist/stop.mjs +25 -25
- package/dist/subagent-start.mjs +21 -21
- package/dist/subagent-stop.mjs +22 -22
- package/dist/support.mjs +23 -23
- package/dist/tlc-cli.mjs +37 -37
- package/dist/tool-after.mjs +22 -22
- package/dist/tool-before.mjs +23 -23
- package/dist/tool-failure.mjs +21 -21
- package/docs/concepts.md +38 -0
- package/docs/log.md +2 -0
- package/package.json +1 -1
- package/skills/harness-init/SKILL.md +13 -3
- package/src/core/rules/rules.trigger.ts +26 -10
- package/src/entrypoints/prompt-submit.ts +5 -2
|
@@ -27,13 +27,24 @@ export type TriggerContext = {
|
|
|
27
27
|
* every repository, or a rule copied between them silently stops firing. An operator who wants their own shape
|
|
28
28
|
* writes `command(<pattern>)`.
|
|
29
29
|
*/
|
|
30
|
-
|
|
30
|
+
type ShellShape = {
|
|
31
|
+
readonly prefix: readonly string[];
|
|
32
|
+
/**
|
|
33
|
+
* why this exists only on `gh pr create`: a draft is not yet open for review, so a rule gating `pr-open`
|
|
34
|
+
* has no work to demand proof of. It is also the only way a proof that itself depends on the pull request
|
|
35
|
+
* existing — `gh pr view`, for one — can ever run: open the draft, produce the proof against it, then
|
|
36
|
+
* `gh pr ready`, which keeps its own gate ([/decisions/ad-118.md](/decisions/ad-118.md)).
|
|
37
|
+
*/
|
|
38
|
+
readonly excludeIfAny?: readonly string[];
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const SHELL_SHAPES: Record<"pr-open" | "commit" | "push", readonly ShellShape[]> = {
|
|
31
42
|
"pr-open": [
|
|
32
|
-
["gh", "pr", "create"],
|
|
33
|
-
["gh", "pr", "ready"],
|
|
43
|
+
{ prefix: ["gh", "pr", "create"], excludeIfAny: ["--draft", "-d"] },
|
|
44
|
+
{ prefix: ["gh", "pr", "ready"] },
|
|
34
45
|
],
|
|
35
|
-
commit: [["git", "commit"]],
|
|
36
|
-
push: [["git", "push"]],
|
|
46
|
+
commit: [{ prefix: ["git", "commit"] }],
|
|
47
|
+
push: [{ prefix: ["git", "push"] }],
|
|
37
48
|
};
|
|
38
49
|
|
|
39
50
|
/**
|
|
@@ -53,8 +64,15 @@ function subCommands(command: string): string[][] {
|
|
|
53
64
|
}
|
|
54
65
|
|
|
55
66
|
/** why prefix rather than equality: `gh pr create --fill --base main` is the same act as `gh pr create`. */
|
|
56
|
-
function startsWithShape(words: readonly string[],
|
|
57
|
-
return
|
|
67
|
+
function startsWithShape(words: readonly string[], prefix: readonly string[]): boolean {
|
|
68
|
+
return prefix.every((token, index) => words[index] === token);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function matchesShape(words: readonly string[], shape: ShellShape): boolean {
|
|
72
|
+
if (!startsWithShape(words, shape.prefix)) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
return !shape.excludeIfAny?.some((flag) => words.includes(flag));
|
|
58
76
|
}
|
|
59
77
|
|
|
60
78
|
/**
|
|
@@ -82,9 +100,7 @@ export function triggerMatches(trigger: RuleTrigger, context: TriggerContext): b
|
|
|
82
100
|
return false;
|
|
83
101
|
}
|
|
84
102
|
const shapes = SHELL_SHAPES[trigger.kind];
|
|
85
|
-
return subCommands(context.command).some((words) =>
|
|
86
|
-
shapes.some((shape) => startsWithShape(words, shape)),
|
|
87
|
-
);
|
|
103
|
+
return subCommands(context.command).some((words) => shapes.some((shape) => matchesShape(words, shape)));
|
|
88
104
|
}
|
|
89
105
|
default: {
|
|
90
106
|
if (context.command === undefined) {
|
|
@@ -2,7 +2,7 @@ import type { HarnessEvent } from "../contracts/index.ts";
|
|
|
2
2
|
import { coreFacade } from "../core/index.ts";
|
|
3
3
|
import type { Handler, HandlerContext } from "./run.ts";
|
|
4
4
|
import { main } from "./run.ts";
|
|
5
|
-
import { currentGitSha, obsConfigFor } from "./support.ts";
|
|
5
|
+
import { currentGitSha, obsConfigFor, shaScopeRoot } from "./support.ts";
|
|
6
6
|
|
|
7
7
|
export const promptSubmitHandler: Handler = async (event: HarnessEvent, ctx: HandlerContext) => {
|
|
8
8
|
coreFacade.observability.recordFromEvent(event.projectDir, obsConfigFor(ctx.policy), event);
|
|
@@ -11,7 +11,10 @@ export const promptSubmitHandler: Handler = async (event: HarnessEvent, ctx: Han
|
|
|
11
11
|
coreFacade.untrusted.clearRecall(event.projectDir, event.sessionKey);
|
|
12
12
|
// why: every stop-time gate diffs against this, not against HEAD. A turn that commits moves HEAD past its
|
|
13
13
|
// own changes, and each gate then read an empty diff and skipped ([/decisions/ad-058.md](/decisions/ad-058.md)).
|
|
14
|
-
|
|
14
|
+
// why: the exact AD-114 divergence, now against turn_base_sha instead of a rule's proof sha — a worktree
|
|
15
|
+
// session recorded the main checkout's HEAD as the turn's start, so every gate diffing against it saw a
|
|
16
|
+
// whole untouched file read as "added this turn" ([/decisions/ad-117.md](/decisions/ad-117.md)).
|
|
17
|
+
const sha = await currentGitSha(shaScopeRoot(event));
|
|
15
18
|
if (sha) {
|
|
16
19
|
await coreFacade.handoff.patchHandoff(event.projectDir, event.provider, {
|
|
17
20
|
slice: { turn_base_sha: sha },
|