@ikon85/agent-workflow-kit 0.26.1 → 0.27.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.
Files changed (33) hide show
  1. package/.agents/skills/ask-matt/SKILL.md +1 -2
  2. package/.agents/skills/board-to-waves/SKILL.md +2 -2
  3. package/.agents/skills/improve-codebase-architecture/SKILL.md +0 -2
  4. package/.agents/skills/setup-workflow/board-sync.md +11 -0
  5. package/.claude/skills/ask-matt/SKILL.md +1 -2
  6. package/.claude/skills/board-to-waves/SKILL.md +2 -2
  7. package/.claude/skills/improve-codebase-architecture/SKILL.md +0 -2
  8. package/.claude/skills/setup-pre-commit/SKILL.md +3 -0
  9. package/.claude/skills/setup-pre-commit/scripts/pre-commit.template.sh +6 -0
  10. package/.claude/skills/setup-workflow/board-sync.md +11 -0
  11. package/.claude/skills/skill-manifest.json +1 -9
  12. package/PROVENANCE.md +5 -4
  13. package/README.md +39 -17
  14. package/agent-workflow-kit.package.json +297 -49
  15. package/docs/agents/board-sync.md +3 -0
  16. package/docs/workflow.html +259 -0
  17. package/docs/workflow.png +0 -0
  18. package/package.json +1 -1
  19. package/scripts/board-sync.py +18 -13
  20. package/scripts/board_config.py +7 -0
  21. package/scripts/build-kit.mjs +2 -1
  22. package/scripts/build-kit.test.mjs +44 -1
  23. package/scripts/test_board_sync_wave_title.py +108 -0
  24. package/scripts/test_skill_precommit_template.py +30 -0
  25. package/src/commands/init.mjs +12 -1
  26. package/src/commands/update.mjs +2 -1
  27. package/src/lib/bundle.mjs +12 -6
  28. package/src/lib/manifest.mjs +13 -3
  29. package/src/lib/updateReconcile.mjs +22 -8
  30. package/.agents/skills/zoom-out/SKILL.md +0 -7
  31. package/.agents/skills/zoom-out/THIRD-PARTY-NOTICES.md +0 -29
  32. package/.claude/skills/zoom-out/SKILL.md +0 -7
  33. package/.claude/skills/zoom-out/THIRD-PARTY-NOTICES.md +0 -29
@@ -40,8 +40,8 @@ export const HELPER_FILES = [
40
40
  { path: 'scripts/wrapup-land.py', kind: 'script', mode: 0o755 },
41
41
  // Deterministic release preparation and its manifest-derived local/CI guard.
42
42
  // Both are invoked through package scripts by /kit-release.
43
- { path: 'scripts/kit-release.mjs', kind: 'script', mode: 0o644 },
44
- { path: 'scripts/release-delta-guard.mjs', kind: 'script', mode: 0o644 },
43
+ { path: 'scripts/kit-release.mjs', kind: 'script', mode: 0o644, installRole: 'maintainer' },
44
+ { path: 'scripts/release-delta-guard.mjs', kind: 'script', mode: 0o644, installRole: 'maintainer' },
45
45
  // Neutral publish/readback parity and externally reconstructable release state.
46
46
  // /kit-release uses these after merge; downstream update/consumer flows reuse
47
47
  // the parity primitive rather than growing a second registry/GitHub comparison.
@@ -161,7 +161,7 @@ const SURFACE_DIR = { claude: '.claude/skills', codex: '.agents/skills' };
161
161
  export function publishableSkills(manifest) {
162
162
  return Object.entries(manifest.skills)
163
163
  .filter(([, e]) => e.publish)
164
- .map(([name, e]) => ({ name, surfaces: e.surfaces }));
164
+ .map(([name, e]) => ({ name, surfaces: e.surfaces, installRole: e.installRole ?? 'consumer' }));
165
165
  }
166
166
 
167
167
  async function walk(dir) {
@@ -188,17 +188,23 @@ async function walk(dir) {
188
188
  */
189
189
  export async function collectBundle(repoRoot, manifest) {
190
190
  const files = [];
191
- for (const { name, surfaces } of publishableSkills(manifest)) {
191
+ for (const { name, surfaces, installRole } of publishableSkills(manifest)) {
192
192
  for (const surface of surfaces) {
193
193
  const base = join(SURFACE_DIR[surface], name);
194
194
  for (const abs of await walk(join(repoRoot, base))) {
195
195
  const rel = relative(repoRoot, abs);
196
- files.push({ src: rel, dest: rel, kind: 'skill', ownerSkill: name, surface, mode: 0o644 });
196
+ files.push({
197
+ src: rel, dest: rel, kind: 'skill', ownerSkill: name, surface,
198
+ installRole, mode: 0o644,
199
+ });
197
200
  }
198
201
  }
199
202
  }
200
203
  for (const h of HELPER_FILES) {
201
- files.push({ src: h.path, dest: h.path, kind: h.kind, mode: h.mode });
204
+ files.push({
205
+ src: h.path, dest: h.path, kind: h.kind,
206
+ installRole: h.installRole ?? 'consumer', mode: h.mode,
207
+ });
202
208
  }
203
209
  return { files, stubs: STUB_TARGETS };
204
210
  }
@@ -4,12 +4,15 @@ import { writeAtomic } from './atomicWrite.mjs';
4
4
  // Two manifests (Codex R1#9 / R3#1):
5
5
  // - package manifest (shipped with the kit): the desired-state file list.
6
6
  // - consumer manifest (agent-workflow-kit.json in the target repo root): installed state.
7
- // Both model every file kind:
7
+ // Package entries model every file kind and install role:
8
8
  // { path, kind: 'skill'|'script'|'hook'|'template'|'doc', ownerSkill?, surface?,
9
- // sha256, mode, origin: 'kit' }
9
+ // installRole: 'consumer'|'maintainer', sha256, mode, origin: 'kit' }
10
+ // Consumer manifests record their top-level installRole and retain the role on
11
+ // every installed entry, including edited legacy maintainer files kept in place.
10
12
 
11
13
  export const CONSUMER_MANIFEST_NAME = 'agent-workflow-kit.json';
12
14
  export const PACKAGE_MANIFEST_NAME = 'agent-workflow-kit.package.json';
15
+ export const CONSUMER_INSTALL_ROLE = 'consumer';
13
16
 
14
17
  /**
15
18
  * Parse a JSON manifest, or null if the file does not exist. A corrupt file
@@ -47,7 +50,14 @@ export async function writeManifest(path, obj) {
47
50
  }
48
51
 
49
52
  export function emptyConsumerManifest(kitVersion) {
50
- return { kitVersion, installed: [] };
53
+ return { kitVersion, installRole: CONSUMER_INSTALL_ROLE, installed: [] };
54
+ }
55
+
56
+ /** Package entries without a role predate role-aware installs and remain consumer-owned. */
57
+ export function filesForInstallRole(manifest, installRole = CONSUMER_INSTALL_ROLE) {
58
+ return (manifest?.files ?? []).filter(
59
+ (entry) => (entry.installRole ?? CONSUMER_INSTALL_ROLE) === installRole,
60
+ );
51
61
  }
52
62
 
53
63
  /** Map a manifest's file list (under `key`) by `path` for quick lookup. */
@@ -5,6 +5,7 @@ import { lineDiff, writeAtomic } from './atomicWrite.mjs';
5
5
  import { hookReferenced } from './settings.mjs';
6
6
  import {
7
7
  CONSUMER_MANIFEST_NAME, PACKAGE_MANIFEST_NAME, emptyConsumerManifest,
8
+ CONSUMER_INSTALL_ROLE, filesForInstallRole,
8
9
  indexByPath, readManifest, writeManifest,
9
10
  } from './manifest.mjs';
10
11
 
@@ -18,11 +19,13 @@ export async function reconcile({ kitRoot, consumerRoot, decide = () => false, d
18
19
  if (!consumer) throw new Error('not initialised — run `init` first');
19
20
 
20
21
  const installedIdx = indexByPath(consumer, 'installed');
21
- const pkgIdx = indexByPath(pkg, 'files');
22
+ const packageIdx = indexByPath(pkg, 'files');
23
+ const installable = filesForInstallRole(pkg);
24
+ const pkgIdx = indexByPath({ files: installable }, 'files');
22
25
  const result = emptyResult();
23
26
  const nextInstalled = [];
24
27
 
25
- for (const file of pkg.files) {
28
+ for (const file of installable) {
26
29
  const dest = join(consumerRoot, file.path);
27
30
  const prior = installedIdx.get(file.path);
28
31
  const current = (await exists(dest)) ? await sha256File(dest) : null;
@@ -41,12 +44,12 @@ export async function reconcile({ kitRoot, consumerRoot, decide = () => false, d
41
44
  } else if (userEdited && upstreamChanged) {
42
45
  const incoming = await readFile(join(kitRoot, file.path), 'utf8');
43
46
  result.conflicts.push({ path: file.path, diff: lineDiff(await readFile(dest, 'utf8'), incoming) });
44
- nextInstalled.push(prior);
47
+ nextInstalled.push(withInstallRole(prior));
45
48
  } else if (userEdited) {
46
- nextInstalled.push(prior);
49
+ nextInstalled.push(withInstallRole(prior));
47
50
  result.userModified.push(file.path);
48
51
  } else {
49
- nextInstalled.push(prior);
52
+ nextInstalled.push(withInstallRole(prior));
50
53
  result.unchanged.push(file.path);
51
54
  }
52
55
  }
@@ -58,7 +61,11 @@ export async function reconcile({ kitRoot, consumerRoot, decide = () => false, d
58
61
  const userEdited = current !== null && current !== prior.installedSha256;
59
62
  const referenced = prior.kind === 'hook' && (await hookReferenced(consumerRoot, prior.path));
60
63
  if (userEdited || referenced || !(await decide('delete', prior.path))) {
61
- nextInstalled.push(prior);
64
+ const packageEntry = packageIdx.get(prior.path);
65
+ nextInstalled.push(withInstallRole(
66
+ prior,
67
+ packageEntry?.installRole ?? prior.installRole ?? CONSUMER_INSTALL_ROLE,
68
+ ));
62
69
  result.keptDeleted.push(prior.path);
63
70
  } else {
64
71
  if (!dryRun && current !== null) await rm(dest);
@@ -66,6 +73,9 @@ export async function reconcile({ kitRoot, consumerRoot, decide = () => false, d
66
73
  }
67
74
  }
68
75
 
76
+ result.manifestChanged = consumer.installRole !== CONSUMER_INSTALL_ROLE ||
77
+ nextInstalled.some((next) => installedIdx.get(next.path)?.installRole !== next.installRole);
78
+
69
79
  if (!dryRun) {
70
80
  await writeManifest(join(consumerRoot, CONSUMER_MANIFEST_NAME), {
71
81
  ...emptyConsumerManifest(pkg.kitVersion), installed: nextInstalled,
@@ -77,13 +87,17 @@ export async function reconcile({ kitRoot, consumerRoot, decide = () => false, d
77
87
  function emptyResult() {
78
88
  return {
79
89
  unchanged: [], updated: [], conflicts: [], userModified: [],
80
- added: [], deleted: [], keptDeleted: [],
90
+ added: [], deleted: [], keptDeleted: [], manifestChanged: false,
81
91
  };
82
92
  }
83
93
 
84
94
  function entry(file, installedSha256) {
85
95
  return {
86
96
  path: file.path, kind: file.kind, ownerSkill: file.ownerSkill, surface: file.surface,
87
- installedSha256, origin: 'kit',
97
+ installedSha256, origin: 'kit', installRole: CONSUMER_INSTALL_ROLE,
88
98
  };
89
99
  }
100
+
101
+ function withInstallRole(installed, installRole = CONSUMER_INSTALL_ROLE) {
102
+ return { ...installed, installRole };
103
+ }
@@ -1,7 +0,0 @@
1
- ---
2
- name: zoom-out
3
- description: "Tell the agent to zoom out and give broader context or a higher-level perspective. Use when you're unfamiliar with a section of code or need to understand how it fits into the bigger picture."
4
- disable-model-invocation: true
5
- ---
6
-
7
- I don't know this area of code well. Go up a layer of abstraction. Give me a map of all the relevant modules and callers, using the project's domain glossary vocabulary. (For a full refactor/deepening pass with an HTML report and grilling loop, use `improve-codebase-architecture` instead.)
@@ -1,29 +0,0 @@
1
- # Third-Party Notices
2
-
3
- This skill is adapted from **Matt Pocock's skills**
4
- (https://github.com/mattpocock/skills), `skills/engineering/zoom-out` @ 2bf7005, Copyright (c) 2026 Matt Pocock,
5
- used under the MIT License. Locally adapted (fork-and-own); see PROVENANCE.md.
6
-
7
- ```
8
- MIT License
9
-
10
- Copyright (c) 2026 Matt Pocock
11
-
12
- Permission is hereby granted, free of charge, to any person obtaining a copy
13
- of this software and associated documentation files (the "Software"), to deal
14
- in the Software without restriction, including without limitation the rights
15
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
- copies of the Software, and to permit persons to whom the Software is
17
- furnished to do so, subject to the following conditions:
18
-
19
- The above copyright notice and this permission notice shall be included in all
20
- copies or substantial portions of the Software.
21
-
22
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
- SOFTWARE.
29
- ```
@@ -1,7 +0,0 @@
1
- ---
2
- name: zoom-out
3
- description: Tell the agent to zoom out and give broader context or a higher-level perspective. Use when you're unfamiliar with a section of code or need to understand how it fits into the bigger picture.
4
- disable-model-invocation: true
5
- ---
6
-
7
- I don't know this area of code well. Go up a layer of abstraction. Give me a map of all the relevant modules and callers, using the project's domain glossary vocabulary. (For a full refactor/deepening pass with an HTML report and grilling loop, use `improve-codebase-architecture` instead.)
@@ -1,29 +0,0 @@
1
- # Third-Party Notices
2
-
3
- This skill is adapted from **Matt Pocock's skills**
4
- (https://github.com/mattpocock/skills), `skills/engineering/zoom-out` @ 2bf7005, Copyright (c) 2026 Matt Pocock,
5
- used under the MIT License. Locally adapted (fork-and-own); see PROVENANCE.md.
6
-
7
- ```
8
- MIT License
9
-
10
- Copyright (c) 2026 Matt Pocock
11
-
12
- Permission is hereby granted, free of charge, to any person obtaining a copy
13
- of this software and associated documentation files (the "Software"), to deal
14
- in the Software without restriction, including without limitation the rights
15
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
- copies of the Software, and to permit persons to whom the Software is
17
- furnished to do so, subject to the following conditions:
18
-
19
- The above copyright notice and this permission notice shall be included in all
20
- copies or substantial portions of the Software.
21
-
22
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
- SOFTWARE.
29
- ```