halfcycle 0.3.40 → 0.4.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "halfcycle",
3
- "version": "0.3.40",
3
+ "version": "0.4.0",
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/README.md CHANGED
@@ -42,7 +42,7 @@ A method document cannot fix that, because a document cannot interrupt you. This
42
42
 
43
43
  Credit where it is due, and it is due. GStack, Matt Pocock's skills, GitHub Spec Kit, BMAD, OpenSpec and claude-flow are genuinely good, and between them they taught this whole category that the bottleneck is discipline rather than model intelligence. We took two things from them deliberately and say so: the one-question-at-a-time interrogation shape, and an install that is one command and then stays out of your way.
44
44
 
45
- The objection this usually meets is that it must be too much for a small project. It would be, if there were one setting. A folder you download has exactly one, so whoever wrote it had to choose who to disappoint, and it is usually the small project that gets buried and quietly drops the process in week three. This reads the work instead and sizes itself to it, which is the section further down.
45
+ The objection this usually meets is that it must be too much for a small project. It would be, if there were one setting. A folder you download has exactly one, so whoever wrote it had to choose who to disappoint, and it is usually the small project that gets buried and quietly drops the process in week three. Halfcycle sizes each piece of work with a diagnostic before it starts instead, and records which design documents it includes and which it skips, which is the section further down.
46
46
 
47
47
  Writing the process down was never the hard part. What a folder you download structurally cannot have is these three things.
48
48
 
@@ -148,14 +148,12 @@ This matters enough to be specific about.
148
148
 
149
149
  **Your own Halfcycle credential lives outside this repository, in a file named `env` under your home directory — never in anything you'd commit.** Installing writes it. Opening or closing a phase rewrites it, to record which phase is open, and the credential in it is also renewed there automatically to keep your connection current. Uninstalling with `--remove-credential` deletes it. Nothing else changes it.
150
150
 
151
- **What the checks receive is the shape of a change, not its contents.** File paths, structural shapes, environment variable names and how they are used, the tables a write touches, route signatures, outbound host names. There is no file body and no diff in the request.
151
+ **What the checks receive is the shape of a change and short excerpts of the code being edited — never a whole file and never a diff.** File paths, structural shapes, environment variable names and how they are used, the tables a write touches, route signatures, outbound host names. There is no file body and no diff in the request.
152
152
 
153
- **Source excerpts are off, at both ends, for every engagement today.** The wire format does have a field for them, so the honest version of this is a conditional statement rather than a flat one, and it rests on three things rather than on our good intentions: your runner does not attach an excerpt unless you turn a flag on, and that flag is off by default; anything that does arrive for an engagement that has not opted in is stripped on our side before the checks or any model see it; and there is no way to opt in today, because nothing in the product can set that flag. If that ever changes, our privacy policy changes with it, and it is the policy — not this paragraph — that states the guarantee.
153
+ **Short excerpts of the code being edited are sent to Halfcycle to run its checks, under the terms you accepted at sign-in.** Our privacy policy, not this paragraph, states how we handle what you send.
154
154
 
155
155
  **What the readiness audit submits, and what it never carries.** `halfcycle_submit_findings` is how your session sends the audit's answers: a probe's status, a count, a repo-relative path, a short name. Never a file body, a diff or a source excerpt — the wire carries no field for prose, so a path or a name is the most it can carry. What Halfcycle keeps is what your session submitted, the judgement it reached, and which account and machine sign-in the submission came from; the documents themselves never reach it.
156
156
 
157
- **A promise, for the day a check does need to read something you wrote:** what you send it will be read and not kept: the finding and its evidence persist, the source does not, and training or benchmarking on it is foreclosed. It is written here now, labelled as a commitment rather than a feature, so the promise is public before the mechanism is.
158
-
159
157
  **Nothing method-shaped is left behind.** The runbooks, templates and question sets reach the session that asks for them, scoped to the step you are on, and are never at rest in your repository.
160
158
 
161
159
  ## What you keep
@@ -14820,7 +14820,7 @@ function readMcpServerUrl() {
14820
14820
  }
14821
14821
  function readExcerptConfig() {
14822
14822
  const raw = process.env["HALFCYCLE_SOURCE_EXCERPTS"];
14823
- const enabled = (raw ?? "").trim().toLowerCase() === "true";
14823
+ const enabled = (raw ?? "").trim().toLowerCase() !== "false";
14824
14824
  const readCap = (name, fallback) => {
14825
14825
  const v = process.env[name];
14826
14826
  if (v === void 0)
@@ -15701,8 +15701,10 @@ async function attempt(url2, token, request, fetchFn, retry) {
15701
15701
  import { spawnSync } from "node:child_process";
15702
15702
  import { readFileSync } from "node:fs";
15703
15703
  import { relative } from "node:path";
15704
+ var COLOR_AWARE_SUBCOMMANDS = /* @__PURE__ */ new Set(["diff", "show", "log"]);
15704
15705
  function git(args2, cwd, timeoutMs) {
15705
- const result = spawnSync("git", args2, {
15706
+ const argv = COLOR_AWARE_SUBCOMMANDS.has(args2[0] ?? "") ? [args2[0], "--no-color", ...args2.slice(1)] : args2;
15707
+ const result = spawnSync("git", argv, {
15706
15708
  cwd,
15707
15709
  encoding: "utf-8",
15708
15710
  ...timeoutMs === void 0 ? {} : { timeout: timeoutMs }
@@ -16816,13 +16818,21 @@ function produceExcerpts(diffContent, descriptors, caps) {
16816
16818
  const excerpts = [];
16817
16819
  const seen = /* @__PURE__ */ new Set();
16818
16820
  const lines = diffContent.split("\n");
16819
- let lineNo = 0;
16821
+ let newLineNo;
16820
16822
  for (const raw of lines) {
16821
- if (raw.startsWith("-") && !raw.startsWith("---"))
16823
+ const hunk = /^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/.exec(raw);
16824
+ if (hunk) {
16825
+ newLineNo = Number.parseInt(hunk[1], 10);
16826
+ continue;
16827
+ }
16828
+ if (newLineNo === void 0)
16829
+ continue;
16830
+ if (raw.startsWith("\\"))
16822
16831
  continue;
16823
- if (raw.startsWith("+++") || raw.startsWith("---"))
16832
+ if (raw.startsWith("-"))
16824
16833
  continue;
16825
- lineNo += 1;
16834
+ const lineNo = newLineNo;
16835
+ newLineNo += 1;
16826
16836
  if (!raw.startsWith("+"))
16827
16837
  continue;
16828
16838
  const text = raw.slice(1).trim();
@@ -17092,7 +17102,10 @@ async function runCi() {
17092
17102
  };
17093
17103
  });
17094
17104
  const context = loadChangeSetContext(repoRoot);
17095
- const changeSet = buildChangeSet(fileDiffEntries, { ...context, excerpts: readExcerptConfig() });
17105
+ const changeSet = buildChangeSet(fileDiffEntries, {
17106
+ ...context,
17107
+ excerpts: { enabled: false, ...EXCERPT_DEFAULTS }
17108
+ });
17096
17109
  const configResult = readConfig();
17097
17110
  if (!configResult.config) {
17098
17111
  const oidc = readActionsOidcEnv();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "halfcycle",
3
- "version": "0.3.40",
3
+ "version": "0.4.0",
4
4
  "description": "Your coding agents are the engineers. Halfcycle is the rest of the team: product owner, architect, planner and independent reviewer for Claude Code.",
5
5
  "keywords": [
6
6
  "claude",
@@ -44,7 +44,8 @@
44
44
  "scripts": {
45
45
  "build": "tsc -p tsconfig.json && node scripts/bundle-entries.mjs && node scripts/vendor-runner-bin.mjs",
46
46
  "typecheck": "tsc --noEmit -p tsconfig.test.json",
47
- "test": "tsc -p tsconfig.test.json && node --test \"dist-test/test/\"*.test.js"
47
+ "build:test": "tsc -p tsconfig.test.json",
48
+ "test": "node -e \"const{existsSync,readdirSync}=require('fs');const d='dist-test/test';if(!existsSync(d)||!readdirSync(d).some(f=>f.endsWith('.test.js'))){console.error('dist-test/test has no compiled *.test.js files — run pnpm run build:test first');process.exit(1)}\" && node --test \"dist-test/test/\"*.test.js"
48
49
  },
49
50
  "dependencies": {
50
51
  "zod": "^4.4.3"