@ikunin/sprintpilot 1.0.4 → 2.0.4

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 (37) hide show
  1. package/_Sprintpilot/Sprintpilot.md +14 -1
  2. package/_Sprintpilot/manifest.yaml +1 -1
  3. package/_Sprintpilot/modules/autopilot/config.yaml +22 -0
  4. package/_Sprintpilot/modules/autopilot/profiles/_base.yaml +45 -0
  5. package/_Sprintpilot/modules/autopilot/profiles/large.yaml +22 -0
  6. package/_Sprintpilot/modules/autopilot/profiles/legacy.yaml +35 -0
  7. package/_Sprintpilot/modules/autopilot/profiles/medium.yaml +5 -0
  8. package/_Sprintpilot/modules/autopilot/profiles/nano.yaml +35 -0
  9. package/_Sprintpilot/modules/autopilot/profiles/small.yaml +5 -0
  10. package/_Sprintpilot/modules/git/config.yaml +8 -0
  11. package/_Sprintpilot/modules/ma/config.yaml +42 -0
  12. package/_Sprintpilot/scripts/agent-adapter.js +247 -0
  13. package/_Sprintpilot/scripts/cached-read.js +238 -0
  14. package/_Sprintpilot/scripts/check-prereqs.js +139 -0
  15. package/_Sprintpilot/scripts/dispatch-layer.js +192 -0
  16. package/_Sprintpilot/scripts/git-portable.js +219 -0
  17. package/_Sprintpilot/scripts/infer-dependencies.js +594 -0
  18. package/_Sprintpilot/scripts/inject-tasks-section.js +279 -0
  19. package/_Sprintpilot/scripts/list-remaining-stories.js +295 -0
  20. package/_Sprintpilot/scripts/log-timing.js +360 -0
  21. package/_Sprintpilot/scripts/mark-done-stories-tasks.js +254 -0
  22. package/_Sprintpilot/scripts/merge-shards.js +339 -0
  23. package/_Sprintpilot/scripts/preflight-merge.js +235 -0
  24. package/_Sprintpilot/scripts/resolve-dag.js +559 -0
  25. package/_Sprintpilot/scripts/resolve-profile.js +355 -0
  26. package/_Sprintpilot/scripts/state-shard.js +602 -0
  27. package/_Sprintpilot/scripts/submodule-lock.js +130 -0
  28. package/_Sprintpilot/scripts/summarize-timings.js +362 -0
  29. package/_Sprintpilot/scripts/sync-status.js +13 -0
  30. package/_Sprintpilot/scripts/with-retry.js +145 -0
  31. package/_Sprintpilot/skills/sprint-autopilot-on/workflow.md +673 -540
  32. package/_Sprintpilot/skills/sprintpilot-update/workflow.md +2 -1
  33. package/_Sprintpilot/templates/epic-retrospective.md +24 -0
  34. package/_Sprintpilot/templates/sprint-report.txt +60 -0
  35. package/bin/sprintpilot.js +4 -0
  36. package/lib/commands/install.js +157 -1
  37. package/package.json +1 -1
@@ -0,0 +1,219 @@
1
+ #!/usr/bin/env node
2
+
3
+ // git-portable.js — cross-platform replacements for POSIX-shell git idioms
4
+ // that workflow.md previously inlined. Every subcommand emits a clean stdout
5
+ // value with no dependency on shell features (no `2>/dev/null`, no `||`, no
6
+ // `$(...)` substitution, no `grep`/`echo`/`true`).
7
+ //
8
+ // Usage:
9
+ // git-portable.js count-worktrees [--project-root <path>]
10
+ // git-portable.js config-get <key> [--default <value>] [--scope local|global|system]
11
+ // [--project-root <path>]
12
+ // git-portable.js common-dir [--project-root <path>]
13
+ // git-portable.js safe-add <path>... [--project-root <path>]
14
+ //
15
+ // Subcommands
16
+ //
17
+ // count-worktrees
18
+ // Replaces: `git worktree list --porcelain 2>/dev/null | grep -c '^worktree '`
19
+ // Stdout: an integer. Exits 0. Falls back to the integer 2 (matching
20
+ // workflow.md's "fail-open to 2 to force the full boot path" semantic)
21
+ // when git fails for any reason.
22
+ //
23
+ // config-get <key> [--default <value>]
24
+ // Replaces: `git config --get <key> 2>/dev/null || echo <value>`
25
+ // Stdout: the config value, or <value> on absence ("unset" if not given).
26
+ // --scope chooses the git config scope (default: local + global cascade,
27
+ // i.e. plain `git config --get`).
28
+ //
29
+ // common-dir
30
+ // Replaces: `GIT_COMMON=$(git -C <root> rev-parse --git-common-dir)`
31
+ // Stdout: the absolute path of the common git directory. Exit 1 on
32
+ // failure (the caller should error out — this is load-bearing for
33
+ // submodule init).
34
+ //
35
+ // safe-add <path>...
36
+ // Replaces: `git add <path1> <path2> ... 2>/dev/null || true`
37
+ // Filters paths to those that exist on disk, then runs `git add` on
38
+ // the survivors only. Emits a JSON summary on stdout:
39
+ // { "added": ["a", "b"], "skipped": ["c"] }
40
+ // Exit 0 always (best-effort by design). When zero paths exist,
41
+ // `added: []` and `git add` is not invoked.
42
+
43
+ const fs = require('node:fs');
44
+ const path = require('node:path');
45
+ const { spawnSync } = require('node:child_process');
46
+
47
+ const { parseArgs } = require('../lib/runtime/args');
48
+ const log = require('../lib/runtime/log');
49
+
50
+ const VALID_COMMANDS = ['count-worktrees', 'config-get', 'common-dir', 'safe-add'];
51
+ const VALID_SCOPES = ['local', 'global', 'system'];
52
+
53
+ function help() {
54
+ log.out(
55
+ [
56
+ 'Usage:',
57
+ ' git-portable.js count-worktrees [--project-root <path>]',
58
+ ' git-portable.js config-get <key> [--default <value>] [--scope local|global|system] [--project-root <path>]',
59
+ ' git-portable.js common-dir [--project-root <path>]',
60
+ ' git-portable.js safe-add <path>... [--project-root <path>]',
61
+ '',
62
+ 'Cross-platform replacements for POSIX-shell git idioms used in workflow.md.',
63
+ 'No shell features (pipes, redirects, $(), || ) — safe under cmd.exe and PowerShell.',
64
+ ].join('\n'),
65
+ );
66
+ }
67
+
68
+ function git(projectRoot, args) {
69
+ return spawnSync('git', ['-C', projectRoot, ...args], {
70
+ encoding: 'utf8',
71
+ stdio: ['ignore', 'pipe', 'pipe'],
72
+ windowsHide: true,
73
+ });
74
+ }
75
+
76
+ // ---------------------------------------------------------------
77
+ // count-worktrees
78
+ // ---------------------------------------------------------------
79
+
80
+ function countWorktrees(projectRoot) {
81
+ const res = git(projectRoot, ['worktree', 'list', '--porcelain']);
82
+ if (res.status !== 0) return 2; // fail-open per workflow contract
83
+ const out = String(res.stdout || '');
84
+ let count = 0;
85
+ for (const line of out.split(/\r?\n/)) {
86
+ if (line.startsWith('worktree ')) count++;
87
+ }
88
+ return count;
89
+ }
90
+
91
+ // ---------------------------------------------------------------
92
+ // config-get
93
+ // ---------------------------------------------------------------
94
+
95
+ function configGet(projectRoot, key, { defaultValue, scope }) {
96
+ const args = ['config'];
97
+ if (scope) args.push(`--${scope}`);
98
+ args.push('--get', key);
99
+ const res = git(projectRoot, args);
100
+ if (res.status === 0) {
101
+ return String(res.stdout || '').trim();
102
+ }
103
+ // git config --get exits 1 when the key is absent. Return default.
104
+ return defaultValue;
105
+ }
106
+
107
+ // ---------------------------------------------------------------
108
+ // common-dir
109
+ // ---------------------------------------------------------------
110
+
111
+ function commonDir(projectRoot) {
112
+ const res = git(projectRoot, ['rev-parse', '--git-common-dir']);
113
+ if (res.status !== 0) {
114
+ return { ok: false, error: String(res.stderr || '').trim() };
115
+ }
116
+ const raw = String(res.stdout || '').trim();
117
+ if (!raw) return { ok: false, error: 'empty output' };
118
+ // git emits a relative path when run from inside the repo root; resolve
119
+ // against projectRoot for an absolute, parser-safe value.
120
+ const abs = path.isAbsolute(raw) ? raw : path.resolve(projectRoot, raw);
121
+ return { ok: true, value: abs };
122
+ }
123
+
124
+ // ---------------------------------------------------------------
125
+ // safe-add
126
+ // ---------------------------------------------------------------
127
+
128
+ function safeAdd(projectRoot, paths) {
129
+ const added = [];
130
+ const skipped = [];
131
+ for (const p of paths) {
132
+ const abs = path.isAbsolute(p) ? p : path.join(projectRoot, p);
133
+ if (fs.existsSync(abs)) {
134
+ added.push(p);
135
+ } else {
136
+ skipped.push(p);
137
+ }
138
+ }
139
+ if (added.length === 0) return { added, skipped };
140
+ const res = git(projectRoot, ['add', '--', ...added]);
141
+ if (res.status !== 0) {
142
+ // Surface partial-failure detail on stderr, but never throw.
143
+ log.warn(`git add failed (${res.status}): ${String(res.stderr || '').trim()}`);
144
+ }
145
+ return { added, skipped };
146
+ }
147
+
148
+ // ---------------------------------------------------------------
149
+ // CLI
150
+ // ---------------------------------------------------------------
151
+
152
+ function main() {
153
+ const { opts, positional } = parseArgs(process.argv.slice(2));
154
+ if (opts.help || positional.length === 0) {
155
+ help();
156
+ process.exit(opts.help ? 0 : 1);
157
+ }
158
+ const command = positional[0];
159
+ if (!VALID_COMMANDS.includes(command)) {
160
+ log.error(`unknown command '${command}'. Valid: ${VALID_COMMANDS.join(', ')}`);
161
+ process.exit(1);
162
+ }
163
+ const projectRoot = opts['project-root'] || process.cwd();
164
+
165
+ if (command === 'count-worktrees') {
166
+ process.stdout.write(`${countWorktrees(projectRoot)}\n`);
167
+ return;
168
+ }
169
+
170
+ if (command === 'config-get') {
171
+ const key = positional[1];
172
+ if (!key) {
173
+ log.error('config-get requires <key>');
174
+ process.exit(1);
175
+ }
176
+ const defaultValue = opts.default !== undefined ? String(opts.default) : 'unset';
177
+ const scope = opts.scope ? String(opts.scope) : null;
178
+ if (scope && !VALID_SCOPES.includes(scope)) {
179
+ log.error(`invalid --scope '${scope}'. Valid: ${VALID_SCOPES.join(', ')}`);
180
+ process.exit(1);
181
+ }
182
+ process.stdout.write(`${configGet(projectRoot, key, { defaultValue, scope })}\n`);
183
+ return;
184
+ }
185
+
186
+ if (command === 'common-dir') {
187
+ const r = commonDir(projectRoot);
188
+ if (!r.ok) {
189
+ log.error(`failed to resolve git common dir: ${r.error}`);
190
+ process.exit(1);
191
+ }
192
+ process.stdout.write(`${r.value}\n`);
193
+ return;
194
+ }
195
+
196
+ if (command === 'safe-add') {
197
+ const paths = positional.slice(1);
198
+ if (paths.length === 0) {
199
+ log.error('safe-add requires at least one <path>');
200
+ process.exit(1);
201
+ }
202
+ const summary = safeAdd(projectRoot, paths);
203
+ process.stdout.write(`${JSON.stringify(summary)}\n`);
204
+ return;
205
+ }
206
+ }
207
+
208
+ module.exports = {
209
+ VALID_COMMANDS,
210
+ VALID_SCOPES,
211
+ countWorktrees,
212
+ configGet,
213
+ commonDir,
214
+ safeAdd,
215
+ };
216
+
217
+ if (require.main === module) {
218
+ main();
219
+ }