@walwal-harness/cli 7.1.47 → 7.1.48

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/CHANGELOG.md CHANGED
@@ -4,7 +4,7 @@ docmeta:
4
4
  title: walwal-harness CHANGELOG
5
5
  type: output
6
6
  createdAt: 2026-05-07T00:00:00Z
7
- updatedAt: 2026-05-07T00:00:00Z
7
+ updatedAt: 2026-06-05T00:00:00Z
8
8
  source:
9
9
  producer: agent
10
10
  skillId: harness-release
@@ -31,6 +31,11 @@ docmeta:
31
31
 
32
32
  ## Unreleased
33
33
 
34
+ ## 7.1.48 — Auto-managed `.harness` `.gitignore` + runtime untrack on init (2026-06-05)
35
+ - `walwal-harness init` now writes/refreshes a marked managed block in the project-root `.gitignore` so machine-specific harness runtime/local state is never committed and never pollutes teammates' diffs. Ignored: live conductor `progress.json`/`progress.log`/`handoff.json`/`events.jsonl`, the `todos/` live queue (`state.json` + `events.jsonl`), `actions/`, `ops/`, `activity/`, `logs/`, `archive/` migration backups, and the `dashboard/` visualization tooling. Durable team knowledge stays tracked: `conventions/`, `gotchas/`, `documents/`, `memories/`, `memory.md`, `shared/`, `config.json`, `HARNESS.md`, `.bundle-version`.
36
+ - Init also best-effort `git rm --cached`s any of those runtime paths committed before the ignore block existed (files stay on disk), fixing the "`.gitignore` added but already-tracked files keep showing as changes" case.
37
+ - Canonical ignore list now lives in `assets/templates/gitignore-append.txt` as a single source of truth, consumed by both `bin/init.js` and `scripts/harness-dashboard-up.sh` (the dashboard launcher defers to init's managed block instead of appending its own narrow one).
38
+
34
39
  ## 7.1.38 — CEO approval authority for routine operations (2026-05-31)
35
40
 
36
41
  - CEO now has explicit authority to approve reversible routine operations without Owner confirmation, including mission consolidation/supersede cleanup, monitoring cadence, briefing templates, local cron/launchd/wake automation, dashboard refresh, and Telegram/dashboard notifications that use already configured credentials.
@@ -1,6 +1,26 @@
1
- # walwal-harness dashboard runtime
2
- .harness/dashboard/apps/harness-dashboard/node_modules/
3
- .harness/dashboard/apps/harness-dashboard/.next/
4
- .harness/dashboard/apps/harness-dashboard/.turbo/
5
- .harness/dashboard/apps/harness-dashboard/tsconfig.tsbuildinfo
6
- .harness/dashboard/.download/
1
+ # >>> walwal-harness managed (local/runtime state — do not edit between markers) >>>
2
+ # Auto-managed by `walwal-harness init` (refreshed on every init).
3
+ # Edit the package template assets/templates/gitignore-append.txt, not this block.
4
+ #
5
+ # SHARED with teammates (kept in git): .harness/{conventions,gotchas,documents,
6
+ # memories,shared}/ .harness/{memory.md,config.json,HARNESS.md,.bundle-version}
7
+ # Everything listed below is machine-specific runtime or local tooling — never shared.
8
+ #
9
+ # Live conductor todo-queue + transition log (heartbeats churn each tick; embeds local paths)
10
+ .harness/todos/state.json
11
+ .harness/todos/events.jsonl
12
+ # Live conductor / handoff / event state (rewritten every run)
13
+ .harness/progress.json
14
+ .harness/progress.log
15
+ .harness/handoff.json
16
+ .harness/events.jsonl
17
+ # Active-sprint, service-ops, activity heatmap & logs runtime
18
+ .harness/actions/
19
+ .harness/ops/
20
+ .harness/activity/
21
+ .harness/logs/
22
+ # Migration & pre-harness backup snapshots (local-only)
23
+ .harness/archive/
24
+ # Brick Office dashboard — local visualization tool + per-env data & build artifacts
25
+ .harness/dashboard/
26
+ # <<< walwal-harness managed <<<
package/bin/init.js CHANGED
@@ -853,6 +853,102 @@ function ensureHarnessEnv() {
853
853
  log('.env: HARNESS_BASE_PORT placeholder added — CEO/CXX must choose an available value before starting services');
854
854
  }
855
855
 
856
+ // ── .gitignore management ───────────────────────────────────────────────────
857
+ // Keep the host project's root .gitignore in sync with the harness's local/runtime
858
+ // state so high-churn conductor files, backups, and dashboard tooling never get
859
+ // committed (and pollute teammates' diffs). The canonical entry list ships in
860
+ // assets/templates/gitignore-append.txt — single source of truth, also consumed by
861
+ // scripts/harness-dashboard-up.sh.
862
+ const GITIGNORE_MARKER_BEGIN = '# >>> walwal-harness managed';
863
+ const GITIGNORE_MARKER_END = '# <<< walwal-harness managed';
864
+
865
+ function readGitignoreBlock() {
866
+ const tplPath = path.join(PKG_ROOT, 'assets', 'templates', 'gitignore-append.txt');
867
+ if (!fileExists(tplPath)) return null;
868
+ const block = fs.readFileSync(tplPath, 'utf8').replace(/\s+$/, '');
869
+ return block || null;
870
+ }
871
+
872
+ // Non-comment, non-empty lines of the managed block = the local/runtime pathspecs.
873
+ function localPathsFromBlock(block) {
874
+ return block
875
+ .split('\n')
876
+ .map((l) => l.trim())
877
+ .filter((l) => l && !l.startsWith('#'));
878
+ }
879
+
880
+ // Write or refresh the marked managed block in the project-root .gitignore.
881
+ // Idempotent: an existing block is replaced in place; everything else is preserved.
882
+ function ensureProjectGitignore() {
883
+ const block = readGitignoreBlock();
884
+ if (!block) {
885
+ log(' → .gitignore: skipped (managed template missing)');
886
+ return;
887
+ }
888
+ const gitignorePath = path.join(PROJECT_ROOT, '.gitignore');
889
+ const original = fileExists(gitignorePath) ? fs.readFileSync(gitignorePath, 'utf8') : '';
890
+ const lines = original.length ? original.split('\n') : [];
891
+
892
+ const beginLine = lines.findIndex((l) => l.startsWith(GITIGNORE_MARKER_BEGIN));
893
+ let next;
894
+ if (beginLine !== -1) {
895
+ let endLine = lines.findIndex((l, i) => i >= beginLine && l.startsWith(GITIGNORE_MARKER_END));
896
+ if (endLine === -1) endLine = lines.length - 1; // tolerate a truncated block
897
+ next = [...lines.slice(0, beginLine), ...block.split('\n'), ...lines.slice(endLine + 1)].join('\n');
898
+ } else {
899
+ const head = original.replace(/\n*$/, '');
900
+ next = (head ? head + '\n\n' : '') + block + '\n';
901
+ }
902
+ if (!next.endsWith('\n')) next += '\n';
903
+ if (next !== original) {
904
+ fs.writeFileSync(gitignorePath, next);
905
+ log(beginLine !== -1
906
+ ? ' → .gitignore: refreshed walwal-harness managed block'
907
+ : ' → .gitignore: added walwal-harness runtime/local ignore block');
908
+ }
909
+ }
910
+
911
+ // Best-effort: a project that committed runtime state before the ignore block existed
912
+ // keeps showing churn until those paths leave the index. Drop them from tracking
913
+ // (files stay on disk). Never fail init over git: a non-repo / missing-git / odd state
914
+ // is a quiet no-op.
915
+ function gitUntrackLocalState() {
916
+ const block = readGitignoreBlock();
917
+ if (!block) return;
918
+ try {
919
+ const inside = execSync('git rev-parse --is-inside-work-tree', {
920
+ cwd: PROJECT_ROOT, stdio: ['ignore', 'pipe', 'ignore'],
921
+ }).toString().trim();
922
+ if (inside !== 'true') return;
923
+ } catch {
924
+ return; // not a git repo / git unavailable
925
+ }
926
+
927
+ const removed = [];
928
+ for (const rel of localPathsFromBlock(block)) {
929
+ let tracked = '';
930
+ try {
931
+ tracked = execSync(`git ls-files -- ${shellQuote(rel)}`, {
932
+ cwd: PROJECT_ROOT, stdio: ['ignore', 'pipe', 'ignore'],
933
+ }).toString().trim();
934
+ } catch {
935
+ continue;
936
+ }
937
+ if (!tracked) continue;
938
+ try {
939
+ execSync(`git rm -r --cached --quiet --ignore-unmatch -- ${shellQuote(rel)}`, {
940
+ cwd: PROJECT_ROOT, stdio: ['ignore', 'ignore', 'ignore'],
941
+ });
942
+ removed.push(rel);
943
+ } catch {
944
+ // leave it tracked; non-fatal
945
+ }
946
+ }
947
+ if (removed.length) {
948
+ log(` → git: untracked ${removed.length} now-ignored runtime path(s), kept on disk (${removed.join(', ')})`);
949
+ }
950
+ }
951
+
856
952
  function ensureStructuredRuntimeFiles({ dryRun = false } = {}) {
857
953
  const todosDir = path.join(HARNESS_DIR, 'todos');
858
954
  const statePath = path.join(todosDir, 'state.json');
@@ -2621,6 +2717,8 @@ function main() {
2621
2717
  console.log('');
2622
2718
 
2623
2719
  scaffoldHarness();
2720
+ ensureProjectGitignore();
2721
+ gitUntrackLocalState();
2624
2722
  installSkills();
2625
2723
  installScripts();
2626
2724
  ensureWakeScheduler();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@walwal-harness/cli",
3
- "version": "7.1.47",
3
+ "version": "7.1.48",
4
4
  "description": "Company-style AI agent harness for Claude and Codex. Installs commands, CXX agents, skills, HR-Resource hiring pool, and project-local .harness runtime state.",
5
5
  "bin": {
6
6
  "walwal-harness": "bin/init.js"
@@ -53,22 +53,27 @@ fi
53
53
 
54
54
  ensure_gitignore() {
55
55
  local gitignore="${HARNESS_ROOT}/.gitignore"
56
- local marker="# walwal-harness dashboard runtime"
56
+ # `walwal-harness init` owns the canonical managed block (covers .harness/dashboard/
57
+ # plus all other runtime/local state). If it's already present, nothing to add.
58
+ local managed_marker="# >>> walwal-harness managed"
59
+ if [[ -f "$gitignore" ]] && grep -Fq "$managed_marker" "$gitignore"; then
60
+ return
61
+ fi
62
+ # Prefer the package's canonical template (single source of truth shared with init.js);
63
+ # fall back to a dashboard-only block for older packages that lack the template.
64
+ local tpl="${PACKAGE_ROOT}/assets/templates/gitignore-append.txt"
57
65
  local block
58
- block="$(cat <<'EOF'
66
+ if [[ -f "$tpl" ]]; then
67
+ block="$(cat "$tpl")"
68
+ else
69
+ block="$(cat <<'EOF'
59
70
  # walwal-harness dashboard runtime
60
- .harness/dashboard/apps/harness-dashboard/node_modules/
61
- .harness/dashboard/apps/harness-dashboard/.next/
62
- .harness/dashboard/apps/harness-dashboard/.turbo/
63
- .harness/dashboard/apps/harness-dashboard/tsconfig.tsbuildinfo
64
- .harness/dashboard/.download/
71
+ .harness/dashboard/
65
72
  EOF
66
73
  )"
67
- if [[ -f "$gitignore" ]] && grep -Fq "$marker" "$gitignore"; then
68
- return
69
74
  fi
70
75
  mkdir -p "$(dirname "$gitignore")"
71
- if [[ -s "$gitignore" ]] && [[ "$(tail -c 1 "$gitignore" 2>/dev/null || true)" != "" ]]; then
76
+ if [[ -f "$gitignore" ]] && [[ -s "$gitignore" ]] && [[ "$(tail -c 1 "$gitignore" 2>/dev/null || true)" != "" ]]; then
72
77
  printf '\n' >> "$gitignore"
73
78
  fi
74
79
  printf '%s\n' "$block" >> "$gitignore"