@lovrozagar/grunt 0.5.2 → 0.6.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 (157) hide show
  1. package/.agents/agents/grunt.md +2 -24
  2. package/.agents/agents/orchestrator.md +5 -50
  3. package/.agents/skills/ask/SKILL.md +5 -12
  4. package/.agents/skills/auto/SKILL.md +7 -12
  5. package/.agents/skills/browser/SKILL.md +4 -8
  6. package/.agents/skills/clasp/SKILL.md +11 -0
  7. package/.agents/skills/commit/SKILL.md +3 -1
  8. package/.agents/skills/commit-push/SKILL.md +2 -0
  9. package/.agents/skills/commit-push-deploy/SKILL.md +2 -0
  10. package/.agents/skills/commit-push-release/SKILL.md +2 -0
  11. package/.agents/skills/explain/SKILL.md +7 -13
  12. package/.agents/skills/google-workspace/SKILL.md +13 -0
  13. package/.agents/skills/handoff/SKILL.md +7 -11
  14. package/.agents/skills/implement-plan/SKILL.md +5 -109
  15. package/.agents/skills/listen/SKILL.md +15 -0
  16. package/.agents/skills/pickup/SKILL.md +6 -12
  17. package/.agents/skills/speak/SKILL.md +13 -0
  18. package/.agents/skills/tmp/SKILL.md +6 -10
  19. package/.agents/skills/write-plan/SKILL.md +5 -77
  20. package/.claude/agents/grunt.md +2 -26
  21. package/.claude/agents/orchestrator.md +12 -50
  22. package/.claude/skills/ask/SKILL.md +5 -12
  23. package/.claude/skills/auto/SKILL.md +7 -12
  24. package/.claude/skills/browser/SKILL.md +4 -8
  25. package/.claude/skills/clasp/SKILL.md +11 -0
  26. package/.claude/skills/commit/SKILL.md +3 -1
  27. package/.claude/skills/commit-push/SKILL.md +2 -0
  28. package/.claude/skills/commit-push-deploy/SKILL.md +2 -0
  29. package/.claude/skills/commit-push-release/SKILL.md +2 -0
  30. package/.claude/skills/explain/SKILL.md +7 -13
  31. package/.claude/skills/google-workspace/SKILL.md +13 -0
  32. package/.claude/skills/handoff/SKILL.md +7 -11
  33. package/.claude/skills/implement-plan/SKILL.md +5 -109
  34. package/.claude/skills/listen/SKILL.md +15 -0
  35. package/.claude/skills/pickup/SKILL.md +6 -12
  36. package/.claude/skills/speak/SKILL.md +13 -0
  37. package/.claude/skills/tmp/SKILL.md +6 -10
  38. package/.claude/skills/write-plan/SKILL.md +5 -77
  39. package/.codex/agents/grunt.toml +2 -26
  40. package/.codex/agents/orchestrator.toml +4 -50
  41. package/.grok/agents/grunt.md +2 -24
  42. package/.grok/agents/orchestrator.md +4 -48
  43. package/.grok/global-settings.toml +1 -3
  44. package/.grok/hooks/orchestrate-parent.js +190 -358
  45. package/.grok/skills/ask/SKILL.md +5 -12
  46. package/.grok/skills/auto/SKILL.md +7 -12
  47. package/.grok/skills/browser/SKILL.md +4 -8
  48. package/.grok/skills/clasp/SKILL.md +11 -0
  49. package/.grok/skills/commit/SKILL.md +3 -1
  50. package/.grok/skills/commit-push/SKILL.md +2 -0
  51. package/.grok/skills/commit-push-deploy/SKILL.md +2 -0
  52. package/.grok/skills/commit-push-release/SKILL.md +2 -0
  53. package/.grok/skills/explain/SKILL.md +7 -13
  54. package/.grok/skills/google-workspace/SKILL.md +13 -0
  55. package/.grok/skills/handoff/SKILL.md +7 -11
  56. package/.grok/skills/implement-plan/SKILL.md +5 -109
  57. package/.grok/skills/listen/SKILL.md +15 -0
  58. package/.grok/skills/pickup/SKILL.md +6 -12
  59. package/.grok/skills/speak/SKILL.md +13 -0
  60. package/.grok/skills/tmp/SKILL.md +6 -10
  61. package/.grok/skills/write-plan/SKILL.md +5 -77
  62. package/.rulesync/hooks.jsonc +1 -1
  63. package/.rulesync/mcp-policy.jsonc +0 -2
  64. package/.rulesync/reference/INDEX.md +30 -20
  65. package/.rulesync/reference/browser.md +13 -6
  66. package/.rulesync/reference/cascade.md +6 -86
  67. package/.rulesync/reference/clasp.md +21 -0
  68. package/.rulesync/reference/google-workspace.md +79 -0
  69. package/.rulesync/reference/hooks.md +7 -11
  70. package/.rulesync/reference/implementation-format.md +113 -0
  71. package/.rulesync/reference/law.md +5 -3
  72. package/.rulesync/reference/listen.md +80 -0
  73. package/.rulesync/reference/map.md +40 -36
  74. package/.rulesync/reference/output.md +3 -51
  75. package/.rulesync/reference/plan-format.md +4 -2
  76. package/.rulesync/reference/refs-map.md +12 -5
  77. package/.rulesync/reference/rtk.md +3 -2
  78. package/.rulesync/reference/scope.md +37 -0
  79. package/.rulesync/reference/setup.md +27 -0
  80. package/.rulesync/reference/skills-map.md +13 -12
  81. package/.rulesync/reference/speak.md +59 -0
  82. package/.rulesync/rules/CLAUDE.md +3 -49
  83. package/.rulesync/rules/overview.md +9 -47
  84. package/.rulesync/skills/ask/SKILL.md +5 -12
  85. package/.rulesync/skills/auto/SKILL.md +5 -12
  86. package/.rulesync/skills/browser/SKILL.md +4 -8
  87. package/.rulesync/skills/clasp/SKILL.md +9 -0
  88. package/.rulesync/skills/commit/SKILL.md +3 -1
  89. package/.rulesync/skills/commit-push/SKILL.md +2 -0
  90. package/.rulesync/skills/commit-push-deploy/SKILL.md +2 -0
  91. package/.rulesync/skills/commit-push-release/SKILL.md +2 -0
  92. package/.rulesync/skills/explain/SKILL.md +7 -14
  93. package/.rulesync/skills/google-workspace/SKILL.md +11 -0
  94. package/.rulesync/skills/handoff/SKILL.md +7 -11
  95. package/.rulesync/skills/implement-plan/SKILL.md +5 -119
  96. package/.rulesync/skills/listen/SKILL.md +13 -0
  97. package/.rulesync/skills/pickup/SKILL.md +6 -12
  98. package/.rulesync/skills/speak/SKILL.md +13 -0
  99. package/.rulesync/skills/tmp/SKILL.md +6 -10
  100. package/.rulesync/skills/write-plan/SKILL.md +5 -84
  101. package/.rulesync/subagents/grunt.md +2 -24
  102. package/.rulesync/subagents/orchestrator.md +14 -59
  103. package/AGENTS.md +9 -47
  104. package/CHANGELOG.md +67 -0
  105. package/CLAUDE.md +1 -49
  106. package/README.md +89 -80
  107. package/cli/grunt.mjs +21 -3
  108. package/cli/grunt.test.ts +47 -3
  109. package/cli/init.mjs +134 -234
  110. package/cli/init.test.ts +241 -58
  111. package/cli/prompt.mjs +9 -36
  112. package/cli/prompt.test.ts +14 -0
  113. package/package.json +10 -2
  114. package/scripts/browser.mjs +128 -7
  115. package/scripts/doctor.mjs +104 -10
  116. package/scripts/emit-gemini.mjs +2 -2
  117. package/scripts/emit-mcp-policy.mjs +1 -1
  118. package/scripts/gate-fat-tools.mjs +223 -173
  119. package/scripts/google-workspace.mjs +713 -0
  120. package/scripts/grunt-job.mjs +453 -69
  121. package/scripts/guarded-md.mjs +230 -0
  122. package/scripts/guarded-roots.mjs +1 -1
  123. package/scripts/interactive.mjs +15 -0
  124. package/scripts/listen.mjs +829 -0
  125. package/scripts/parse-need.mjs +21 -2
  126. package/scripts/persist-implementation.mjs +278 -0
  127. package/scripts/prompt.mjs +32 -0
  128. package/scripts/scrub-spawn-prompt.mjs +3 -50
  129. package/scripts/setup.mjs +746 -0
  130. package/scripts/speak.mjs +291 -0
  131. package/.agents/agents/implementer.md +0 -32
  132. package/.agents/agents/thinker.md +0 -29
  133. package/.agents/skills/cascade/SKILL.md +0 -28
  134. package/.agents/skills/parent/SKILL.md +0 -6
  135. package/.agents/skills/solo/SKILL.md +0 -25
  136. package/.claude/agents/implementer.md +0 -37
  137. package/.claude/agents/thinker.md +0 -36
  138. package/.claude/skills/cascade/SKILL.md +0 -28
  139. package/.claude/skills/parent/SKILL.md +0 -6
  140. package/.claude/skills/solo/SKILL.md +0 -25
  141. package/.codex/agents/implementer.toml +0 -26
  142. package/.codex/agents/thinker.toml +0 -26
  143. package/.grok/agents/implementer.md +0 -27
  144. package/.grok/agents/thinker.md +0 -27
  145. package/.grok/parent.md +0 -1
  146. package/.grok/roles/implementer.toml +0 -5
  147. package/.grok/roles/thinker.toml +0 -5
  148. package/.grok/skills/cascade/SKILL.md +0 -28
  149. package/.grok/skills/parent/SKILL.md +0 -6
  150. package/.grok/skills/solo/SKILL.md +0 -25
  151. package/.rulesync/grunt.config.jsonc +0 -7
  152. package/.rulesync/skills/cascade/SKILL.md +0 -28
  153. package/.rulesync/skills/parent/SKILL.md +0 -6
  154. package/.rulesync/skills/solo/SKILL.md +0 -25
  155. package/.rulesync/subagents/implementer.md +0 -49
  156. package/.rulesync/subagents/thinker.md +0 -49
  157. package/scripts/grunt-config.mjs +0 -50
@@ -0,0 +1,230 @@
1
+ /** Sentinel merge for AGENTS.md CLAUDE.md GEMINI.md. Copied into consumers. */
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+
5
+ export const GUARDED_ROOT_FILES = ["AGENTS.md", "CLAUDE.md", "GEMINI.md"];
6
+ export const SENTINEL_BEGIN = "<!-- grunt:begin -->";
7
+ export const SENTINEL_END = "<!-- grunt:end -->";
8
+ export const MAX_GUARDED_MARKDOWN_BYTES = 2 * 1024 * 1024;
9
+ const GRUNT_REGION_RE =
10
+ /(?:^|(?<=\n)|(?<=\r\n))[ \t]*<!-- grunt:begin -->[ \t]*\r?\n?[\s\S]*?(?:^|(?<=\n)|(?<=\r\n))[ \t]*<!-- grunt:end -->[ \t]*\r?\n?/g;
11
+ const GRUNT_INTERIOR_RE =
12
+ /(?:^|(?<=\n)|(?<=\r\n))[ \t]*<!-- grunt:begin -->[ \t]*\r?\n?([\s\S]*?)(?:^|(?<=\n)|(?<=\r\n))[ \t]*<!-- grunt:end -->/g;
13
+ const ORPHAN_END_RE = /(?:^|\r?\n)[ \t]*<!-- grunt:end -->[ \t]*(?=\r?\n|$)|<!-- grunt:end -->/g;
14
+ const BEGIN_LINE_RE = /^[ \t]*<!-- grunt:begin -->[ \t]*$/;
15
+ const END_LINE_RE = /^[ \t]*<!-- grunt:end -->[ \t]*$/;
16
+
17
+ function detectNewline(text) {
18
+ return String(text).includes("\r\n") ? "\r\n" : "\n";
19
+ }
20
+
21
+ function toNewline(text, nl) {
22
+ return String(text).replace(/\r\n/g, "\n").replace(/\n/g, nl);
23
+ }
24
+
25
+ function trimTrailingNewlines(text) {
26
+ return String(text).replace(/(?:\r?\n)+$/, "");
27
+ }
28
+
29
+ function normEq(a, b) {
30
+ return (
31
+ trimTrailingNewlines(String(a).replace(/\r\n/g, "\n")) ===
32
+ trimTrailingNewlines(String(b).replace(/\r\n/g, "\n"))
33
+ );
34
+ }
35
+
36
+ function cloneRe(re) {
37
+ return new RegExp(re.source, re.flags);
38
+ }
39
+
40
+ function inspectGuardedBuffer(buf) {
41
+ if (buf.length > MAX_GUARDED_MARKDOWN_BYTES) return "huge";
42
+ if (buf.includes(0)) return "binary";
43
+ return null;
44
+ }
45
+
46
+ export function extractUserMarkdown(text) {
47
+ let user = String(text).replace(cloneRe(GRUNT_REGION_RE), "");
48
+ const i = user.indexOf(SENTINEL_BEGIN);
49
+ if (i >= 0) user = user.slice(0, i);
50
+ user = user.replace(cloneRe(ORPHAN_END_RE), "");
51
+ return userRemainderIsBlank(user) ? "" : user;
52
+ }
53
+
54
+ function unwrapStackedMarkers(text) {
55
+ const lines = String(text).split(/\r?\n/);
56
+ let start = 0;
57
+ let end = lines.length;
58
+ while (start < end && BEGIN_LINE_RE.test(lines[start])) start++;
59
+ while (end > start && lines[end - 1] === "") end--;
60
+ while (end > start && END_LINE_RE.test(lines[end - 1])) {
61
+ end--;
62
+ while (end > start && lines[end - 1] === "") end--;
63
+ }
64
+ return lines.slice(start, end).join("\n");
65
+ }
66
+
67
+ export function extractGruntBody(text) {
68
+ const src = String(text);
69
+ const parts = [];
70
+ const re = cloneRe(GRUNT_INTERIOR_RE);
71
+ let m;
72
+ while ((m = re.exec(src))) {
73
+ parts.push(trimTrailingNewlines(unwrapStackedMarkers(m[1])));
74
+ }
75
+ if (parts.length) return parts.join("\n");
76
+ const i = src.indexOf(SENTINEL_BEGIN);
77
+ if (i >= 0) {
78
+ return trimTrailingNewlines(
79
+ unwrapStackedMarkers(src.slice(i + SENTINEL_BEGIN.length).replace(/^[ \t]*\r?\n/, "")),
80
+ );
81
+ }
82
+ if (!src.includes(SENTINEL_END)) return null;
83
+ return trimTrailingNewlines(unwrapStackedMarkers(src));
84
+ }
85
+
86
+ function userRemainderIsBlank(user) {
87
+ return String(user).replace(/\r\n/g, "\n").replace(/\n/g, "") === "";
88
+ }
89
+
90
+ export function composeGuardedMarkdown(gruntBody, userRemainder, nl = "\n") {
91
+ const raw = extractGruntBody(gruntBody) ?? gruntBody;
92
+ const body = toNewline(trimTrailingNewlines(raw), nl);
93
+ const block = `${SENTINEL_BEGIN}${nl}${body}${nl}${SENTINEL_END}${nl}`;
94
+ const user = extractUserMarkdown(userRemainder == null ? "" : String(userRemainder));
95
+ if (!user || userRemainderIsBlank(user)) return block;
96
+ return block + toNewline(user, nl);
97
+ }
98
+
99
+ export function mergeGuardedContent(existingText, gruntBody) {
100
+ const existing = existingText == null ? "" : String(existingText);
101
+ const nl =
102
+ existing.includes("\r\n") || String(gruntBody).includes("\r\n")
103
+ ? detectNewline(existing || gruntBody)
104
+ : "\n";
105
+ if (!existing) return composeGuardedMarkdown(gruntBody, "", nl);
106
+ const hadSentinel = existing.includes(SENTINEL_BEGIN) && existing.includes(SENTINEL_END);
107
+ const user = extractUserMarkdown(existing);
108
+ if (!hadSentinel && normEq(existing, gruntBody)) {
109
+ return composeGuardedMarkdown(gruntBody, "", nl);
110
+ }
111
+ return composeGuardedMarkdown(gruntBody, user, nl);
112
+ }
113
+
114
+ export function writeMergedGuardedFile(destPath, gruntBody) {
115
+ if (!fs.existsSync(destPath)) {
116
+ fs.writeFileSync(destPath, mergeGuardedContent("", gruntBody));
117
+ return;
118
+ }
119
+ const buf = fs.readFileSync(destPath);
120
+ if (inspectGuardedBuffer(buf)) return "aborted-unsafe";
121
+ fs.writeFileSync(destPath, mergeGuardedContent(buf.toString("utf8"), gruntBody));
122
+ }
123
+
124
+ export function guardedMarkdownDrift(destPath, gruntBody) {
125
+ if (!fs.existsSync(destPath)) return true;
126
+ const buf = fs.readFileSync(destPath);
127
+ if (inspectGuardedBuffer(buf)) return true;
128
+ const text = buf.toString("utf8");
129
+ const interior = extractGruntBody(text);
130
+ if (interior == null) return !normEq(text, gruntBody);
131
+ return !normEq(interior, gruntBody);
132
+ }
133
+
134
+ export function snapshotGuardedRoots(root) {
135
+ const snap = {};
136
+ for (const file of GUARDED_ROOT_FILES) {
137
+ const p = path.join(root, file);
138
+ if (!fs.existsSync(p)) continue;
139
+ const buf = fs.readFileSync(p);
140
+ const unsafe = inspectGuardedBuffer(buf);
141
+ if (unsafe) {
142
+ snap[file] = { unsafe, rawBuf: buf };
143
+ continue;
144
+ }
145
+ const raw = buf.toString("utf8");
146
+ snap[file] = { raw, user: extractUserMarkdown(raw) };
147
+ }
148
+ return snap;
149
+ }
150
+
151
+ export function remergeGuardedRoots(root, snap) {
152
+ for (const file of GUARDED_ROOT_FILES) {
153
+ const p = path.join(root, file);
154
+ const rec = snap[file];
155
+ if (rec?.unsafe) {
156
+ fs.writeFileSync(p, rec.rawBuf);
157
+ continue;
158
+ }
159
+ if (!fs.existsSync(p)) {
160
+ if (rec?.raw != null) fs.writeFileSync(p, rec.raw);
161
+ continue;
162
+ }
163
+ const buf = fs.readFileSync(p);
164
+ if (inspectGuardedBuffer(buf)) {
165
+ if (rec?.raw != null) fs.writeFileSync(p, rec.raw);
166
+ continue;
167
+ }
168
+ const current = buf.toString("utf8");
169
+ if (rec && current === rec.raw) continue;
170
+ const gruntBody = extractGruntBody(current) ?? current;
171
+ const nl = detectNewline((rec && rec.raw) || current);
172
+ let user = rec ? rec.user : extractUserMarkdown(current);
173
+ if (rec && !rec.raw.includes(SENTINEL_BEGIN) && normEq(rec.raw, gruntBody)) user = "";
174
+ if (!rec && extractGruntBody(current) == null && normEq(current, gruntBody)) user = "";
175
+ fs.writeFileSync(p, composeGuardedMarkdown(gruntBody, user, nl));
176
+ }
177
+ }
178
+
179
+ export function healGuardedRootFile(root, file, snap) {
180
+ if (!GUARDED_ROOT_FILES.includes(file)) return;
181
+ const p = path.join(root, file);
182
+ const rec = snap[file];
183
+ if (!fs.existsSync(p)) return;
184
+ if (rec?.unsafe) {
185
+ fs.writeFileSync(p, rec.rawBuf);
186
+ return;
187
+ }
188
+ const buf = fs.readFileSync(p);
189
+ if (inspectGuardedBuffer(buf)) {
190
+ if (rec?.raw != null) fs.writeFileSync(p, rec.raw);
191
+ return;
192
+ }
193
+ const current = buf.toString("utf8");
194
+ const interior = extractGruntBody(current);
195
+ if (interior != null) {
196
+ snap[file] = { raw: current, user: extractUserMarkdown(current) };
197
+ return;
198
+ }
199
+ if (rec && current === rec.raw) return;
200
+ const gruntBody = current;
201
+ const nl = detectNewline((rec && rec.raw) || current);
202
+ let user = rec ? rec.user : extractUserMarkdown(current);
203
+ if (rec && !rec.raw.includes(SENTINEL_BEGIN) && normEq(rec.raw, gruntBody)) user = "";
204
+ if (!rec && normEq(current, gruntBody)) user = "";
205
+ const out = composeGuardedMarkdown(gruntBody, user, nl);
206
+ fs.writeFileSync(p, out);
207
+ snap[file] = { raw: out, user };
208
+ }
209
+
210
+ export function withGuardedCheckInteriors(root, fn) {
211
+ const snap = snapshotGuardedRoots(root);
212
+ try {
213
+ for (const file of GUARDED_ROOT_FILES) {
214
+ const rec = snap[file];
215
+ if (!rec || rec.unsafe) continue;
216
+ const body = extractGruntBody(rec.raw);
217
+ if (body == null) continue;
218
+ const nl = detectNewline(rec.raw);
219
+ fs.writeFileSync(path.join(root, file), `${toNewline(trimTrailingNewlines(body), nl)}${nl}`);
220
+ }
221
+ return fn();
222
+ } finally {
223
+ for (const file of GUARDED_ROOT_FILES) {
224
+ const rec = snap[file];
225
+ if (!rec) continue;
226
+ if (rec.unsafe) fs.writeFileSync(path.join(root, file), rec.rawBuf);
227
+ else fs.writeFileSync(path.join(root, file), rec.raw);
228
+ }
229
+ }
230
+ }
@@ -10,7 +10,7 @@ import {
10
10
  remergeGuardedRoots,
11
11
  snapshotGuardedRoots,
12
12
  withGuardedCheckInteriors,
13
- } from "../cli/init.mjs";
13
+ } from "./guarded-md.mjs";
14
14
  import { runPipeline } from "./pipeline.mjs";
15
15
 
16
16
  export function attachGuardedRootWatchers(cwd, heal) {
@@ -0,0 +1,15 @@
1
+ /** TTY / CI / --yes probe. Copied into consumers; no clack. */
2
+ export function isInteractive({
3
+ argv = process.argv.slice(2),
4
+ env = process.env,
5
+ stdin = process.stdin,
6
+ stdout = process.stdout,
7
+ } = {}) {
8
+ if (!stdin?.isTTY || !stdout?.isTTY) return false;
9
+ const ci = env.CI;
10
+ if (ci != null && ci !== "" && ci !== "0" && ci !== "false") return false;
11
+ for (const a of argv) {
12
+ if (a === "--yes" || a === "-y" || a === "--non-interactive") return false;
13
+ }
14
+ return true;
15
+ }