@brainervirus/workit-core 1.0.1 → 1.0.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/package.json CHANGED
@@ -1,16 +1,22 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-core",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "private": false,
5
- "description": "Workit — workflow rails for agentic coding: specs, plans, YouTrack, CI-gated commits (shared core)",
5
+ "description": "Workit shared core — task, policy, evidence, review, decision, worker, and writer state for agentic coding workflows",
6
6
  "keywords": [
7
- "agent",
7
+ "agentic-coding",
8
+ "ai-agents",
9
+ "codex",
8
10
  "cursor",
9
11
  "mcp",
10
12
  "opencode",
11
- "workflow",
12
- "youTrack"
13
+ "pi",
14
+ "policy-engine",
15
+ "task-management",
16
+ "typescript",
17
+ "workflow"
13
18
  ],
19
+ "homepage": "https://github.com/BrainerVirus/workit#readme",
14
20
  "bugs": {
15
21
  "url": "https://github.com/BrainerVirus/workit/issues"
16
22
  },
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env bun
2
- // AR-16: path-gated releases. Replaces message-only commit analysis: a
3
- // releasable commit counts only when it touches a PRODUCT PATH (any of the
4
- // four package dirs). Tooling-only merges produce no release at all.
2
+ // AR-16: path-gated releases. A releasable commit counts only when it touches
3
+ // a PRODUCT PATH (any of the four package dirs). Tooling-only merges produce no
4
+ // release at all. A payload change typed docs/chore still publishes as patch —
5
+ // skills and metadata live in the tarball, so installed users must receive
6
+ // them; merge-backs and the release's own manifest sync never do.
5
7
  import { execFileSync } from "node:child_process";
6
8
  import { resolve } from "node:path";
7
9
 
@@ -15,6 +17,9 @@ export const RELEASE_PACKAGES = [
15
17
  "workit-pi",
16
18
  ] as const;
17
19
 
20
+ /** The release pipeline's own version-sync commit: never a release trigger. */
21
+ const RELEASE_SYNC = /^chore\(release\): sync manifests\b/;
22
+
18
23
  const g = (root: string, args: string[]): string =>
19
24
  execFileSync("git", args, { cwd: root, encoding: "utf8" }).trim();
20
25
 
@@ -64,9 +69,10 @@ const commitsSince = (root: string, from: string): { message: string; files: str
64
69
  }));
65
70
  };
66
71
 
67
- export function analyzeReleaseScope(
68
- root = process.cwd(),
69
- ): { level: Level | null; productPkgs: string[] } {
72
+ export function analyzeReleaseScope(root = process.cwd()): {
73
+ level: Level | null;
74
+ productPkgs: string[];
75
+ } {
70
76
  const from = latestTag(root);
71
77
  if (from === null) {
72
78
  return { level: "minor", productPkgs: [...RELEASE_PACKAGES] };
@@ -74,18 +80,27 @@ export function analyzeReleaseScope(
74
80
  const commits = commitsSince(root, from);
75
81
  const levels: Level[] = [];
76
82
  const pkgs = new Set<string>();
83
+ let payloadOnly = false;
77
84
  for (const { message, files } of commits) {
78
- const touched = files.filter((f) => RELEASE_PACKAGES.some((p) => f.startsWith(`packages/${p}/`)));
85
+ const subject = (message.split("\n")[0] ?? "").trim();
86
+ if (RELEASE_SYNC.test(subject)) continue;
87
+ const touched = files.filter((f) =>
88
+ RELEASE_PACKAGES.some((p) => f.startsWith(`packages/${p}/`)),
89
+ );
79
90
  if (touched.length === 0) continue;
80
91
  const lvl = subjectLevel(message);
81
92
  if (lvl) levels.push(lvl);
93
+ else if (!subject.startsWith("Merge ")) payloadOnly = true;
82
94
  for (const f of touched) {
83
95
  const pkg = RELEASE_PACKAGES.find((p) => f.startsWith(`packages/${p}/`));
84
96
  if (pkg) pkgs.add(pkg);
85
97
  }
86
98
  }
87
- if (levels.length === 0) return { level: null, productPkgs: [...pkgs] };
88
- const level = levels.reduce<Level>((best, l) => (LEVEL_RANK[l] > LEVEL_RANK[best] ? l : best), "patch");
99
+ if (levels.length === 0) return { level: payloadOnly ? "patch" : null, productPkgs: [...pkgs] };
100
+ const level = levels.reduce<Level>(
101
+ (best, l) => (LEVEL_RANK[l] > LEVEL_RANK[best] ? l : best),
102
+ "patch",
103
+ );
89
104
  return { level, productPkgs: [...pkgs] };
90
105
  }
91
106
 
@@ -31,3 +31,8 @@ selects requirements; do not wait for a rule that can only exist after assess.
31
31
 
32
32
  PR merged per settings, or a status brief (frontier state, next action) when
33
33
  blocked on the human. Record evidence for fixes, findings for blockers.
34
+
35
+ A squash merge creates a new commit on the base branch, so the pre-merge
36
+ candidate identity changes: re-record verification and review evidence against
37
+ the merged commit before `task.close`, or the close will report unsatisfied
38
+ requirements.
@@ -20,11 +20,14 @@ selects requirements; do not wait for a rule that can only exist after assess.
20
20
  blockers. Never trust memory across an interruption.
21
21
  2. Classify the steering:
22
22
  - same-task: fold into scope (reassess if facts changed), continue.
23
- - new-task: `task.start` + `policy.assess`; the parked task waits.
23
+ - new-task: `task.pause` the parked lead task, then `task.start` +
24
+ `policy.assess` for the new one. Keep exactly one active lead per
25
+ session: external actions bind to that single active task, and a second
26
+ active lead makes writer authority ambiguous.
24
27
  - quick-question: answer from the parked state, then resume.
25
28
  3. Handle it with the same rigor as the parked work (no drive-by edits).
26
29
  4. Re-anchor: one-line resume brief (where we were, what changed, what
27
- is next) before touching the parked work again.
30
+ is next), then `task.resume` the parked task before touching it again.
28
31
 
29
32
  ## Completion
30
33