aether-colony 5.2.1 → 5.3.1

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 (143) hide show
  1. package/.aether/aether-utils.sh +35 -0
  2. package/.aether/agents/aether-ambassador.md +140 -0
  3. package/.aether/agents/aether-archaeologist.md +108 -0
  4. package/.aether/agents/aether-architect.md +133 -0
  5. package/.aether/agents/aether-auditor.md +144 -0
  6. package/.aether/agents/aether-builder.md +184 -0
  7. package/.aether/agents/aether-chaos.md +115 -0
  8. package/.aether/agents/aether-chronicler.md +122 -0
  9. package/.aether/agents/aether-gatekeeper.md +116 -0
  10. package/.aether/agents/aether-includer.md +117 -0
  11. package/.aether/agents/aether-keeper.md +177 -0
  12. package/.aether/agents/aether-measurer.md +128 -0
  13. package/.aether/agents/aether-oracle.md +137 -0
  14. package/.aether/agents/aether-probe.md +133 -0
  15. package/.aether/agents/aether-queen.md +286 -0
  16. package/.aether/agents/aether-route-setter.md +130 -0
  17. package/.aether/agents/aether-sage.md +106 -0
  18. package/.aether/agents/aether-scout.md +101 -0
  19. package/.aether/agents/aether-surveyor-disciplines.md +391 -0
  20. package/.aether/agents/aether-surveyor-nest.md +329 -0
  21. package/.aether/agents/aether-surveyor-pathogens.md +264 -0
  22. package/.aether/agents/aether-surveyor-provisions.md +334 -0
  23. package/.aether/agents/aether-tracker.md +137 -0
  24. package/.aether/agents/aether-watcher.md +174 -0
  25. package/.aether/agents/aether-weaver.md +130 -0
  26. package/.aether/commands/claude/archaeology.md +334 -0
  27. package/.aether/commands/claude/build.md +65 -0
  28. package/.aether/commands/claude/chaos.md +336 -0
  29. package/.aether/commands/claude/colonize.md +259 -0
  30. package/.aether/commands/claude/continue.md +60 -0
  31. package/.aether/commands/claude/council.md +507 -0
  32. package/.aether/commands/claude/data-clean.md +81 -0
  33. package/.aether/commands/claude/dream.md +268 -0
  34. package/.aether/commands/claude/entomb.md +498 -0
  35. package/.aether/commands/claude/export-signals.md +57 -0
  36. package/.aether/commands/claude/feedback.md +96 -0
  37. package/.aether/commands/claude/flag.md +151 -0
  38. package/.aether/commands/claude/flags.md +169 -0
  39. package/.aether/commands/claude/focus.md +76 -0
  40. package/.aether/commands/claude/help.md +154 -0
  41. package/.aether/commands/claude/history.md +140 -0
  42. package/.aether/commands/claude/import-signals.md +71 -0
  43. package/.aether/commands/claude/init.md +505 -0
  44. package/.aether/commands/claude/insert-phase.md +105 -0
  45. package/.aether/commands/claude/interpret.md +278 -0
  46. package/.aether/commands/claude/lay-eggs.md +210 -0
  47. package/.aether/commands/claude/maturity.md +113 -0
  48. package/.aether/commands/claude/memory-details.md +77 -0
  49. package/.aether/commands/claude/migrate-state.md +171 -0
  50. package/.aether/commands/claude/oracle.md +642 -0
  51. package/.aether/commands/claude/organize.md +232 -0
  52. package/.aether/commands/claude/patrol.md +620 -0
  53. package/.aether/commands/claude/pause-colony.md +233 -0
  54. package/.aether/commands/claude/phase.md +115 -0
  55. package/.aether/commands/claude/pheromones.md +156 -0
  56. package/.aether/commands/claude/plan.md +693 -0
  57. package/.aether/commands/claude/preferences.md +65 -0
  58. package/.aether/commands/claude/quick.md +100 -0
  59. package/.aether/commands/claude/redirect.md +76 -0
  60. package/.aether/commands/claude/resume-colony.md +197 -0
  61. package/.aether/commands/claude/resume.md +388 -0
  62. package/.aether/commands/claude/run.md +231 -0
  63. package/.aether/commands/claude/seal.md +774 -0
  64. package/.aether/commands/claude/skill-create.md +286 -0
  65. package/.aether/commands/claude/status.md +410 -0
  66. package/.aether/commands/claude/swarm.md +349 -0
  67. package/.aether/commands/claude/tunnels.md +426 -0
  68. package/.aether/commands/claude/update.md +132 -0
  69. package/.aether/commands/claude/verify-castes.md +143 -0
  70. package/.aether/commands/claude/watch.md +239 -0
  71. package/.aether/commands/opencode/archaeology.md +331 -0
  72. package/.aether/commands/opencode/build.md +1168 -0
  73. package/.aether/commands/opencode/chaos.md +329 -0
  74. package/.aether/commands/opencode/colonize.md +195 -0
  75. package/.aether/commands/opencode/continue.md +1436 -0
  76. package/.aether/commands/opencode/council.md +437 -0
  77. package/.aether/commands/opencode/data-clean.md +77 -0
  78. package/.aether/commands/opencode/dream.md +260 -0
  79. package/.aether/commands/opencode/entomb.md +377 -0
  80. package/.aether/commands/opencode/export-signals.md +54 -0
  81. package/.aether/commands/opencode/feedback.md +99 -0
  82. package/.aether/commands/opencode/flag.md +149 -0
  83. package/.aether/commands/opencode/flags.md +167 -0
  84. package/.aether/commands/opencode/focus.md +73 -0
  85. package/.aether/commands/opencode/help.md +157 -0
  86. package/.aether/commands/opencode/history.md +136 -0
  87. package/.aether/commands/opencode/import-signals.md +68 -0
  88. package/.aether/commands/opencode/init.md +518 -0
  89. package/.aether/commands/opencode/insert-phase.md +111 -0
  90. package/.aether/commands/opencode/interpret.md +272 -0
  91. package/.aether/commands/opencode/lay-eggs.md +213 -0
  92. package/.aether/commands/opencode/maturity.md +108 -0
  93. package/.aether/commands/opencode/memory-details.md +83 -0
  94. package/.aether/commands/opencode/migrate-state.md +165 -0
  95. package/.aether/commands/opencode/oracle.md +593 -0
  96. package/.aether/commands/opencode/organize.md +226 -0
  97. package/.aether/commands/opencode/patrol.md +626 -0
  98. package/.aether/commands/opencode/pause-colony.md +203 -0
  99. package/.aether/commands/opencode/phase.md +113 -0
  100. package/.aether/commands/opencode/pheromones.md +162 -0
  101. package/.aether/commands/opencode/plan.md +684 -0
  102. package/.aether/commands/opencode/preferences.md +71 -0
  103. package/.aether/commands/opencode/quick.md +91 -0
  104. package/.aether/commands/opencode/redirect.md +84 -0
  105. package/.aether/commands/opencode/resume-colony.md +190 -0
  106. package/.aether/commands/opencode/resume.md +394 -0
  107. package/.aether/commands/opencode/run.md +237 -0
  108. package/.aether/commands/opencode/seal.md +452 -0
  109. package/.aether/commands/opencode/skill-create.md +63 -0
  110. package/.aether/commands/opencode/status.md +307 -0
  111. package/.aether/commands/opencode/swarm.md +15 -0
  112. package/.aether/commands/opencode/tunnels.md +400 -0
  113. package/.aether/commands/opencode/update.md +127 -0
  114. package/.aether/commands/opencode/verify-castes.md +139 -0
  115. package/.aether/commands/opencode/watch.md +227 -0
  116. package/.aether/docs/command-playbooks/build-full.md +1 -1
  117. package/.aether/docs/command-playbooks/build-prep.md +10 -3
  118. package/.aether/docs/command-playbooks/build-verify.md +51 -0
  119. package/.aether/docs/command-playbooks/continue-advance.md +115 -6
  120. package/.aether/docs/command-playbooks/continue-verify.md +32 -0
  121. package/.aether/utils/clash-detect.sh +239 -0
  122. package/.aether/utils/hooks/clash-pre-tool-use.js +99 -0
  123. package/.aether/utils/merge-driver-lockfile.sh +35 -0
  124. package/.aether/utils/midden.sh +534 -0
  125. package/.aether/utils/pheromone.sh +1376 -108
  126. package/.aether/utils/queen.sh +2 -4
  127. package/.aether/utils/state-api.sh +25 -4
  128. package/.aether/utils/swarm.sh +1 -1
  129. package/.aether/utils/worktree.sh +189 -0
  130. package/CHANGELOG.md +26 -0
  131. package/README.md +161 -161
  132. package/bin/cli.js +103 -61
  133. package/bin/lib/banner.js +14 -0
  134. package/bin/lib/init.js +8 -7
  135. package/bin/lib/interactive-setup.js +251 -0
  136. package/bin/npx-entry.js +21 -0
  137. package/bin/npx-install.js +9 -167
  138. package/bin/validate-package.sh +23 -0
  139. package/package.json +2 -2
  140. package/.aether/docs/plans/pheromone-display-plan.md +0 -257
  141. package/.aether/schemas/example-prompt-builder.xml +0 -234
  142. package/.aether/scripts/incident-test-add.sh +0 -47
  143. package/.aether/scripts/weekly-audit.sh +0 -79
@@ -0,0 +1,239 @@
1
+ #!/bin/bash
2
+ # Clash detection utility -- detects file conflicts across git worktrees.
3
+ #
4
+ # When multiple agents work in parallel worktrees, they could accidentally
5
+ # edit the same file from different worktrees. This script checks for that.
6
+ #
7
+ # Usage: clash-detect --file <path> [--worktree <path>]
8
+ # Returns JSON: {ok:true, result:{conflict:false}} or
9
+ # {ok:true, result:{conflict:true, conflicting_worktrees:[...]}}
10
+ #
11
+ # Environment:
12
+ # AETHER_ROOT - repo root (auto-detected if not set)
13
+ # WORKTREE_DIR - current worktree path (to exclude self from checks)
14
+ #
15
+ # When sourced by aether-utils.sh, provides _clash_detect function.
16
+ # When run directly, executes _clash_detect with provided arguments.
17
+
18
+ # Only set strict mode when run directly (not sourced)
19
+ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
20
+ set -uo pipefail
21
+ fi
22
+
23
+ # Set AETHER_ROOT if not already set (e.g., when sourced)
24
+ : "${AETHER_ROOT:=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
25
+
26
+ # Fallback error constant for standalone execution (when not sourced by aether-utils.sh)
27
+ : "${E_VALIDATION_FAILED:=E_VALIDATION_FAILED}"
28
+
29
+ # Allowlist of path patterns that bypass clash detection (branch-local state)
30
+ # These files live in .aether/data/ and are unique per worktree/branch
31
+ _CLASH_ALLOWLIST=(
32
+ ".aether/data/"
33
+ )
34
+
35
+ # Check if a file path matches the allowlist
36
+ _clash_is_allowlisted() {
37
+ local file="$1"
38
+ for pattern in "${_CLASH_ALLOWLIST[@]}"; do
39
+ if [[ "$file" == "$pattern"* ]]; then
40
+ return 0
41
+ fi
42
+ done
43
+ return 1
44
+ }
45
+
46
+ # Normalize a path for comparison on macOS (handles /var vs /private/var)
47
+ _clash_normalize_path() {
48
+ local p="$1"
49
+ if [[ -z "$p" ]]; then
50
+ echo ""
51
+ return
52
+ fi
53
+ if command -v realpath >/dev/null 2>&1; then
54
+ realpath "$p" 2>/dev/null && return
55
+ fi
56
+ (cd "$p" 2>/dev/null && pwd) || echo "$p"
57
+ }
58
+
59
+ # JSON output helpers (standalone, for direct execution mode)
60
+ _clash_json_ok() {
61
+ echo "{\"ok\":true,\"result\":$1}"
62
+ }
63
+
64
+ _clash_json_err() {
65
+ echo "{\"ok\":false,\"error\":$1}" >&2
66
+ exit 1
67
+ }
68
+
69
+ # Bridge: use aether-utils JSON helpers when sourced, standalone when direct
70
+ _cok() {
71
+ if type json_ok &>/dev/null; then
72
+ json_ok "$1"
73
+ else
74
+ _clash_json_ok "$1"
75
+ fi
76
+ }
77
+
78
+ _cerr() {
79
+ if type json_err &>/dev/null; then
80
+ json_err "${2:-$E_UNKNOWN}" "$1"
81
+ else
82
+ _clash_json_err "\"$1\""
83
+ fi
84
+ }
85
+
86
+ # Main clash detection logic
87
+ _clash_detect() {
88
+ local file=""
89
+ local worktree="${WORKTREE_DIR:-}"
90
+
91
+ while [[ $# -gt 0 ]]; do
92
+ case "$1" in
93
+ --file) file="${2:-}"; shift 2 ;;
94
+ --worktree) worktree="${2:-}"; shift 2 ;;
95
+ *) shift ;;
96
+ esac
97
+ done
98
+
99
+ if [[ -z "$file" ]]; then
100
+ _cerr "Usage: clash-detect --file <path> [--worktree <path>]" "$E_VALIDATION_FAILED"
101
+ fi
102
+
103
+ # Allowlisted files never clash (branch-local state)
104
+ if _clash_is_allowlisted "$file"; then
105
+ _cok '{"conflict":false}'
106
+ return
107
+ fi
108
+
109
+ # Verify we're in a git repo
110
+ if ! git -C "$AETHER_ROOT" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
111
+ _cok '{"conflict":false}'
112
+ return
113
+ fi
114
+
115
+ # Normalize the current worktree path for comparison
116
+ if [[ -n "$worktree" ]]; then
117
+ worktree="$(_clash_normalize_path "$worktree")" || worktree=""
118
+ fi
119
+
120
+ # Enumerate all worktrees
121
+ local conflicting=()
122
+ while IFS= read -r line; do
123
+ local wt_path
124
+ wt_path=$(echo "$line" | awk '{print $1}')
125
+ [[ -z "$wt_path" ]] && continue
126
+
127
+ local abs_wt_path
128
+ abs_wt_path="$(_clash_normalize_path "$wt_path")" || continue
129
+
130
+ # Skip if this is the current worktree (self-check)
131
+ if [[ -n "$worktree" && "$abs_wt_path" == "$worktree" ]]; then
132
+ continue
133
+ fi
134
+
135
+ # Check if this worktree has uncommitted changes to the target file
136
+ local file_status
137
+ file_status=$(git -C "$abs_wt_path" status --porcelain -- "$file" 2>/dev/null) || continue
138
+
139
+ if [[ -n "$file_status" ]]; then
140
+ local branch_name
141
+ branch_name=$(git -C "$abs_wt_path" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
142
+ conflicting+=("\"$branch_name\"")
143
+ fi
144
+ done < <(git -C "$AETHER_ROOT" worktree list 2>/dev/null | tail -n +2)
145
+
146
+ if [[ ${#conflicting[@]} -eq 0 ]]; then
147
+ _cok '{"conflict":false}'
148
+ else
149
+ local conflict_list
150
+ conflict_list=$(printf '%s,' "${conflicting[@]}")
151
+ conflict_list="[${conflict_list%,}]"
152
+ _cok "{\"conflict\":true,\"conflicting_worktrees\":$conflict_list}"
153
+ fi
154
+ }
155
+
156
+ # _clash_setup
157
+ # Install or uninstall the clash detection PreToolUse hook.
158
+ #
159
+ # Usage: clash-setup [--install] [--uninstall]
160
+ # Returns JSON: {ok:true, result:{hook_installed:true/false}}
161
+ #
162
+ # Environment:
163
+ # CLASH_SETTINGS_PATH - path to settings.json (default: .claude/settings.json)
164
+ _clash_setup() {
165
+ local action=""
166
+ local settings_path="${CLASH_SETTINGS_PATH:-$AETHER_ROOT/.claude/settings.json}"
167
+
168
+ while [[ $# -gt 0 ]]; do
169
+ case "$1" in
170
+ --install) action="install"; shift ;;
171
+ --uninstall) action="uninstall"; shift ;;
172
+ *) shift ;;
173
+ esac
174
+ done
175
+
176
+ if [[ -z "$action" ]]; then
177
+ _cerr "Usage: clash-setup [--install] [--uninstall]" "$E_VALIDATION_FAILED"
178
+ fi
179
+
180
+ # Ensure settings file exists
181
+ if [[ ! -f "$settings_path" ]]; then
182
+ echo '{}' > "$settings_path" 2>/dev/null || {
183
+ _cerr "Cannot create settings file at $settings_path" "$E_FILE_NOT_FOUND"
184
+ }
185
+ fi
186
+
187
+ # Read current settings
188
+ local settings
189
+ settings=$(cat "$settings_path" 2>/dev/null) || settings='{}'
190
+
191
+ local hook_command='node .aether/utils/hooks/clash-pre-tool-use.js'
192
+ local hook_entry="{\"type\":\"command\",\"command\":\"$hook_command\",\"timeout\":5}"
193
+
194
+ if [[ "$action" == "install" ]]; then
195
+ # Check if hook already exists in PreToolUse
196
+ if echo "$settings" | jq -e '.hooks.PreToolUse[]?.hooks[]?.command' 2>/dev/null \
197
+ | grep -q "clash-pre-tool-use"; then
198
+ # Already installed
199
+ _cok '{"hook_installed":true}'
200
+ return
201
+ fi
202
+
203
+ # Add the hook to PreToolUse array
204
+ settings=$(echo "$settings" | jq --arg entry "$hook_entry" '
205
+ if .hooks.PreToolUse then
206
+ .hooks.PreToolUse += [{"matcher": "Edit|Write", "hooks": [($entry | fromjson)]}]
207
+ else
208
+ .hooks.PreToolUse = [{"matcher": "Edit|Write", "hooks": [($entry | fromjson)]}]
209
+ end
210
+ ' 2>/dev/null)
211
+
212
+ if [[ $? -ne 0 ]] || [[ -z "$settings" ]]; then
213
+ _cerr "Failed to update settings file" "$E_UNKNOWN"
214
+ fi
215
+
216
+ echo "$settings" > "$settings_path"
217
+
218
+ _cok '{"hook_installed":true}'
219
+
220
+ elif [[ "$action" == "uninstall" ]]; then
221
+ # Remove the hook from PreToolUse
222
+ settings=$(echo "$settings" | jq '
223
+ if .hooks.PreToolUse then
224
+ .hooks.PreToolUse = [.hooks.PreToolUse[] |
225
+ select(.hooks[]?.command | . != "node .aether/utils/hooks/clash-pre-tool-use.js")
226
+ ]
227
+ end
228
+ ' 2>/dev/null)
229
+
230
+ echo "$settings" > "$settings_path"
231
+
232
+ _cok '{"hook_installed":false}'
233
+ fi
234
+ }
235
+
236
+ # Run if executed directly (not sourced)
237
+ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
238
+ _clash_detect "$@"
239
+ fi
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env node
2
+ // Clash Detection PreToolUse Hook
3
+ //
4
+ // Runs before Edit/Write tool calls in Claude Code.
5
+ // Checks if any other active git worktree has uncommitted changes to the
6
+ // same file, preventing agents from silently overwriting each other's work.
7
+ //
8
+ // Exit codes:
9
+ // 0 - Allow the operation
10
+ // 2 - Block the operation (conflict detected)
11
+ //
12
+ // Design principle: fail-open. If the hook errors for any reason,
13
+ // the operation is allowed. The goal is safety guidance, not blocking work.
14
+
15
+ const { execSync } = require('child_process');
16
+ const path = require('path');
17
+
18
+ // Files that are branch-local state and never clash across worktrees
19
+ const ALLOWLIST = [
20
+ '.aether/data/',
21
+ ];
22
+
23
+ // Timeout for clash-detect subprocess (ms)
24
+ const DETECT_TIMEOUT = 5000;
25
+
26
+ let input = '';
27
+ const stdinTimeout = setTimeout(() => process.exit(0), 3000);
28
+ process.stdin.setEncoding('utf8');
29
+ process.stdin.on('data', chunk => input += chunk);
30
+ process.stdin.on('end', () => {
31
+ clearTimeout(stdinTimeout);
32
+ try {
33
+ const data = JSON.parse(input);
34
+ const toolName = data.tool_name;
35
+
36
+ // Only check Edit and Write operations
37
+ if (toolName !== 'Edit' && toolName !== 'Write') {
38
+ process.exit(0);
39
+ }
40
+
41
+ // Extract file path
42
+ const filePath = data.tool_input?.file_path || '';
43
+ if (!filePath) {
44
+ process.exit(0);
45
+ }
46
+
47
+ // Check allowlist (branch-local state files never clash)
48
+ if (ALLOWLIST.some(pattern => filePath.includes(pattern))) {
49
+ process.exit(0);
50
+ }
51
+
52
+ // Find the clash-detect script
53
+ // It lives at .aether/utils/clash-detect.sh relative to the repo root
54
+ const cwd = data.cwd || process.cwd();
55
+ const repoClashDetect = path.join(cwd, '.aether', 'utils', 'clash-detect.sh');
56
+
57
+ // Extract just the relative file path for clash-detect
58
+ const relPath = path.relative(cwd, filePath);
59
+
60
+ // Determine which clash-detect to use: repo-local or PATH
61
+ const fs = require('fs');
62
+ const clashDetect = fs.existsSync(repoClashDetect) ? repoClashDetect : 'clash-detect';
63
+
64
+ // Run clash-detect
65
+ try {
66
+ const cmd = clashDetect === 'clash-detect'
67
+ ? `clash-detect --file "${relPath}"`
68
+ : `bash "${clashDetect}" --file "${relPath}"`;
69
+ const result = execSync(cmd, {
70
+ timeout: DETECT_TIMEOUT,
71
+ encoding: 'utf8',
72
+ cwd: cwd,
73
+ stdio: ['pipe', 'pipe', 'pipe'],
74
+ });
75
+
76
+ const parsed = JSON.parse(result.trim());
77
+ if (parsed.ok && parsed.result?.conflict) {
78
+ const worktrees = (parsed.result.conflicting_worktrees || []).join(', ');
79
+ const output = {
80
+ decision: 'block',
81
+ reason: `File "${relPath}" has uncommitted changes in worktree(s): ${worktrees}. ` +
82
+ 'Coordinate with the other agent or wait for their changes to be committed.',
83
+ };
84
+ process.stderr.write(JSON.stringify(output) + '\n');
85
+ process.exit(2);
86
+ }
87
+
88
+ // No conflict -- allow
89
+ process.exit(0);
90
+ } catch (err) {
91
+ // Fail-open: if clash-detect fails, allow the operation
92
+ // This prevents the hook from blocking all work when something goes wrong
93
+ process.exit(0);
94
+ }
95
+ } catch (e) {
96
+ // Fail-open on any parsing or unexpected error
97
+ process.exit(0);
98
+ }
99
+ });
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env bash
2
+ # Merge Driver: npm lockfile auto-merge
3
+ #
4
+ # Resolves package-lock.json merge conflicts by keeping "ours" (the branch
5
+ # being merged into). Lockfiles are deterministic outputs of package.json,
6
+ # so the correct resolution is always to regenerate from the target branch's
7
+ # package.json, which effectively means keeping "ours".
8
+ #
9
+ # Usage: merge-driver-lockfile.sh %O %A %B
10
+ # %O = ancestor (base version)
11
+ # %A = ours (current branch, the version we want to keep)
12
+ # %B = theirs (incoming branch)
13
+ #
14
+ # Git merge driver contract:
15
+ # Exit 0 = conflict resolved (merge continues)
16
+ # Exit non-zero = conflict unresolved
17
+ #
18
+ # This driver is configured via:
19
+ # git config merge.lockfile.name "npm lockfile auto-merge"
20
+ # git config merge.lockfile.driver "bash .aether/utils/merge-driver-lockfile.sh %O %A %B"
21
+
22
+ set -euo pipefail
23
+
24
+ ANCESTOR="${1:-}"
25
+ OURS="${2:-}"
26
+ THEIRS="${3:-}"
27
+
28
+ # Strategy: keep "ours" unchanged.
29
+ # The "ours" file already contains the correct content on disk.
30
+ # We do nothing -- git considers the file resolved when we exit 0.
31
+ #
32
+ # Log for debugging (to stderr so it does not pollute merge output)
33
+ echo "[aether] merge-driver: resolved package-lock.json conflict (kept ours)" >&2
34
+
35
+ exit 0