@karmaniverous/stan-cli 0.11.1 → 0.11.2
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/dist/cjs/classifier-DeYwffC_-CjzCgatc.js +1 -0
- package/dist/cjs/index.js +1 -1
- package/dist/cli/apply-BpKTYoHV.js +47 -0
- package/dist/cli/capture-qFIjLi_h.js +125 -0
- package/dist/cli/classifier-DeYwffC_-DftahF7h.js +7 -0
- package/dist/cli/config-fallback-S2V_I40B.js +78 -0
- package/dist/cli/{context-CToKAifL.js → context-D1XMoxMA.js} +53 -67
- package/dist/cli/git-W31Nw3SI.js +41 -0
- package/dist/cli/{index-TG0UHkTg.js → index-Dy6XnoRx.js} +3 -3
- package/dist/cli/index-ucZa1KMb-CNGeWGvV.js +20 -0
- package/dist/cli/stan.js +3713 -2688
- package/dist/mjs/classifier-DeYwffC_-C7wwqop3.js +1 -0
- package/dist/mjs/index.js +1 -1
- package/dist/types/index.d.ts +2 -1
- package/package.json +9 -9
- package/dist/cli/effective-CXoq4vkL.js +0 -149
- package/dist/cli/history-9hg6BFgc.js +0 -169
- package/dist/cli/index-ucZa1KMb-CSQ-GldX.js +0 -20
- package/dist/cli/snap-run-DIWU31M8.js +0 -279
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { V as Vc, s as su, l as loadCliConfig, r as resolvePromptSource, a as sha256File, u as updateDocsMetaPrompt } from './stan.js';
|
|
3
|
-
import { w as within, e as ensureDirs, A as ARCH_DIR, r as readJson, a as writeJson, S as SNAP_DIR, b as STATE_FILE, c as resolveContext, u as utcStamp } from './context-CToKAifL.js';
|
|
4
|
-
import { existsSync } from 'node:fs';
|
|
5
|
-
import { readFile, writeFile, copyFile, rm } from 'node:fs/promises';
|
|
6
|
-
import { spawn } from 'node:child_process';
|
|
7
|
-
import 'node:module';
|
|
8
|
-
import 'node:path';
|
|
9
|
-
import 'fs-extra';
|
|
10
|
-
import 'node:process';
|
|
11
|
-
import 'node:url';
|
|
12
|
-
import 'process';
|
|
13
|
-
import 'buffer';
|
|
14
|
-
import 'node:crypto';
|
|
15
|
-
import 'os';
|
|
16
|
-
import 'path';
|
|
17
|
-
import 'util';
|
|
18
|
-
import 'stream';
|
|
19
|
-
import 'events';
|
|
20
|
-
import 'fs';
|
|
21
|
-
import 'node:os';
|
|
22
|
-
import 'node:tty';
|
|
23
|
-
import 'node:readline';
|
|
24
|
-
import 'clipboardy';
|
|
25
|
-
import 'child_process';
|
|
26
|
-
|
|
27
|
-
// src/stan/snap/capture.ts
|
|
28
|
-
/**
|
|
29
|
-
* Capture the current snapshot and (optionally) current archives into history,
|
|
30
|
-
* then update diff/.snap.state.json with bounded retention.
|
|
31
|
-
*
|
|
32
|
-
* - Copies <stanPath>/diff/.archive.snapshot.json to diff/snapshots/snap-<ts>.json
|
|
33
|
-
* - If present, copies <stanPath>/output/archive.tar and archive.diff.tar to diff/archives/
|
|
34
|
-
* - Pushes a new entry, clears any redos, and trims to maxUndos (oldest first),
|
|
35
|
-
* deleting dropped files best-effort.
|
|
36
|
-
*/
|
|
37
|
-
const captureSnapshotAndArchives = async ({ cwd, stanPath, ts, maxUndos, }) => {
|
|
38
|
-
const diffDir = within(cwd, stanPath, 'diff');
|
|
39
|
-
const outDir = within(cwd, stanPath, 'output');
|
|
40
|
-
// ensureDirs will create as needed below
|
|
41
|
-
const statePath = within(diffDir, STATE_FILE);
|
|
42
|
-
const snapsDir = within(diffDir, SNAP_DIR);
|
|
43
|
-
const archDir = within(diffDir, ARCH_DIR);
|
|
44
|
-
await ensureDirs([diffDir, snapsDir, archDir]);
|
|
45
|
-
// Copy current snapshot body into history file
|
|
46
|
-
const currentSnapAbs = within(diffDir, '.archive.snapshot.json');
|
|
47
|
-
const snapRel = within(SNAP_DIR, `snap-${ts}.json`);
|
|
48
|
-
const snapAbs = within(diffDir, snapRel);
|
|
49
|
-
try {
|
|
50
|
-
const body = await readFile(currentSnapAbs, 'utf8');
|
|
51
|
-
await writeFile(snapAbs, body, 'utf8');
|
|
52
|
-
}
|
|
53
|
-
catch {
|
|
54
|
-
// best-effort
|
|
55
|
-
}
|
|
56
|
-
// Optionally capture current archives if present
|
|
57
|
-
let archRel;
|
|
58
|
-
let archDiffRel;
|
|
59
|
-
const outArchive = within(outDir, 'archive.tar');
|
|
60
|
-
const outDiff = within(outDir, 'archive.diff.tar');
|
|
61
|
-
try {
|
|
62
|
-
if (existsSync(outArchive)) {
|
|
63
|
-
archRel = within(ARCH_DIR, `archive-${ts}.tar`);
|
|
64
|
-
await copyFile(outArchive, within(diffDir, archRel));
|
|
65
|
-
}
|
|
66
|
-
if (existsSync(outDiff)) {
|
|
67
|
-
archDiffRel = within(ARCH_DIR, `archive-${ts}.diff.tar`);
|
|
68
|
-
await copyFile(outDiff, within(diffDir, archDiffRel));
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
catch {
|
|
72
|
-
// best-effort
|
|
73
|
-
}
|
|
74
|
-
// Load or initialize state
|
|
75
|
-
const st = (await readJson(statePath)) ?? {
|
|
76
|
-
entries: [],
|
|
77
|
-
index: -1,
|
|
78
|
-
maxUndos,
|
|
79
|
-
};
|
|
80
|
-
// Drop redos when we’re not at tip
|
|
81
|
-
if (st.index >= 0 && st.index < st.entries.length - 1) {
|
|
82
|
-
st.entries = st.entries.slice(0, st.index + 1);
|
|
83
|
-
}
|
|
84
|
-
// Push new entry and advance pointer
|
|
85
|
-
const entry = {
|
|
86
|
-
ts,
|
|
87
|
-
snapshot: snapRel,
|
|
88
|
-
archive: archRel,
|
|
89
|
-
archiveDiff: archDiffRel,
|
|
90
|
-
};
|
|
91
|
-
st.entries.push(entry);
|
|
92
|
-
st.index = st.entries.length - 1;
|
|
93
|
-
// Trim oldest beyond retention; remove dropped files best-effort
|
|
94
|
-
const maxKeep = st.maxUndos ?? maxUndos;
|
|
95
|
-
while (st.entries.length > maxKeep) {
|
|
96
|
-
const drop = st.entries.shift();
|
|
97
|
-
if (drop) {
|
|
98
|
-
try {
|
|
99
|
-
await rm(within(diffDir, drop.snapshot), { force: true });
|
|
100
|
-
}
|
|
101
|
-
catch {
|
|
102
|
-
// ignore
|
|
103
|
-
}
|
|
104
|
-
if (drop.archive) {
|
|
105
|
-
try {
|
|
106
|
-
await rm(within(diffDir, drop.archive), { force: true });
|
|
107
|
-
}
|
|
108
|
-
catch {
|
|
109
|
-
// ignore
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
if (drop.archiveDiff) {
|
|
113
|
-
try {
|
|
114
|
-
await rm(within(diffDir, drop.archiveDiff), { force: true });
|
|
115
|
-
}
|
|
116
|
-
catch {
|
|
117
|
-
// ignore
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
st.index = Math.max(0, st.entries.length - 1);
|
|
122
|
-
}
|
|
123
|
-
await writeJson(statePath, st);
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Run a `git` command and capture its exit code, stdout, and stderr.
|
|
128
|
-
*
|
|
129
|
-
* Streams are buffered in memory; when `STAN_DEBUG=1`, output is mirrored
|
|
130
|
-
* to the current process.
|
|
131
|
-
*
|
|
132
|
-
* @param cwd - Working directory for the git process.
|
|
133
|
-
* @param args - Arguments to pass to `git`.
|
|
134
|
-
* @returns `{ code, stdout, stderr }` from the completed process.
|
|
135
|
-
*/
|
|
136
|
-
const runGit = async (cwd, args) => new Promise((resolve) => {
|
|
137
|
-
const child = spawn('git', args, {
|
|
138
|
-
cwd,
|
|
139
|
-
shell: false,
|
|
140
|
-
windowsHide: true,
|
|
141
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
142
|
-
});
|
|
143
|
-
let stdout = '';
|
|
144
|
-
let stderr = '';
|
|
145
|
-
const cp = child;
|
|
146
|
-
cp.stdout?.on('data', (d) => {
|
|
147
|
-
const s = d.toString('utf8');
|
|
148
|
-
stdout += s;
|
|
149
|
-
if (process.env.STAN_DEBUG === '1')
|
|
150
|
-
process.stdout.write(s);
|
|
151
|
-
});
|
|
152
|
-
cp.stderr?.on('data', (d) => {
|
|
153
|
-
const s = d.toString('utf8');
|
|
154
|
-
stderr += s;
|
|
155
|
-
if (process.env.STAN_DEBUG === '1')
|
|
156
|
-
process.stderr.write(s);
|
|
157
|
-
});
|
|
158
|
-
child.on('close', (code) => resolve({ code: code ?? 0, stdout, stderr }));
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
// src/stan/snap/selection.ts
|
|
162
|
-
// Helper to read selection context (stanPath, includes, excludes) from repo config.
|
|
163
|
-
const readSelection = async (cwd) => {
|
|
164
|
-
try {
|
|
165
|
-
const cfg = await Vc(cwd);
|
|
166
|
-
return {
|
|
167
|
-
stanPath: cfg.stanPath,
|
|
168
|
-
includes: Array.isArray(cfg.includes) ? cfg.includes : [],
|
|
169
|
-
excludes: Array.isArray(cfg.excludes) ? cfg.excludes : [],
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
catch {
|
|
173
|
-
// Best-effort fallback (aligns with transitional defaults elsewhere)
|
|
174
|
-
return {
|
|
175
|
-
stanPath: '.stan',
|
|
176
|
-
includes: [],
|
|
177
|
-
excludes: [],
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
/* src/stan/snap/snap-run.ts
|
|
183
|
-
* Snapshot capture operation with optional stash.
|
|
184
|
-
*/
|
|
185
|
-
const handleSnap = async (opts) => {
|
|
186
|
-
const { cwd, stanPath, maxUndos } = await resolveContext(process.cwd());
|
|
187
|
-
const wantStash = Boolean(opts?.stash);
|
|
188
|
-
let attemptPop = false;
|
|
189
|
-
if (wantStash) {
|
|
190
|
-
const res = await runGit(cwd, ['stash', '-u']);
|
|
191
|
-
if (res.code === 0 && !/No local changes to save/i.test(res.stdout)) {
|
|
192
|
-
attemptPop = true;
|
|
193
|
-
console.log('stan: stash saved changes');
|
|
194
|
-
}
|
|
195
|
-
else if (res.code === 0) {
|
|
196
|
-
// Nothing to stash is a successful no-op; print a concise confirmation.
|
|
197
|
-
console.log('stan: no local changes to stash');
|
|
198
|
-
}
|
|
199
|
-
else if (res.code !== 0) {
|
|
200
|
-
console.error('stan: git stash -u failed; snapshot aborted (no changes made)');
|
|
201
|
-
// Visual separation from next prompt
|
|
202
|
-
console.log('');
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
// Resolve selection from repo config so the snapshot and diff use the same rules
|
|
207
|
-
const { includes: cfgIncludes, excludes: cfgExcludes } = await readSelection(cwd).catch(() => ({
|
|
208
|
-
stanPath,
|
|
209
|
-
includes: [],
|
|
210
|
-
excludes: [],
|
|
211
|
-
}));
|
|
212
|
-
try {
|
|
213
|
-
await su({
|
|
214
|
-
cwd,
|
|
215
|
-
stanPath,
|
|
216
|
-
includes: cfgIncludes,
|
|
217
|
-
excludes: cfgExcludes,
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
catch (e) {
|
|
221
|
-
console.error('stan: snapshot write failed', e);
|
|
222
|
-
if (wantStash && attemptPop) {
|
|
223
|
-
const pop = await runGit(cwd, ['stash', 'pop']);
|
|
224
|
-
if (pop.code !== 0) {
|
|
225
|
-
console.error('stan: git stash pop failed');
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
// Visual separation from next prompt
|
|
229
|
-
console.log('');
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
// Record effective prompt identity (baseline-at-snap): source/hash/path?
|
|
233
|
-
try {
|
|
234
|
-
const cli = await loadCliConfig(cwd);
|
|
235
|
-
const choice = typeof cli.cliDefaults?.run?.prompt === 'string' &&
|
|
236
|
-
cli.cliDefaults.run.prompt.trim().length
|
|
237
|
-
? cli.cliDefaults.run.prompt.trim()
|
|
238
|
-
: 'auto';
|
|
239
|
-
const rp = resolvePromptSource(cwd, stanPath, choice);
|
|
240
|
-
// Hash the effective source bytes
|
|
241
|
-
let hash;
|
|
242
|
-
try {
|
|
243
|
-
hash = await sha256File(rp.abs);
|
|
244
|
-
}
|
|
245
|
-
catch {
|
|
246
|
-
hash = undefined;
|
|
247
|
-
}
|
|
248
|
-
const pathForMeta = rp.kind === 'path' ? rp.abs : undefined;
|
|
249
|
-
await updateDocsMetaPrompt(cwd, stanPath, {
|
|
250
|
-
source: rp.kind,
|
|
251
|
-
hash,
|
|
252
|
-
path: pathForMeta,
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
catch {
|
|
256
|
-
// best-effort; missing hash/path is acceptable
|
|
257
|
-
}
|
|
258
|
-
const ts = utcStamp();
|
|
259
|
-
await captureSnapshotAndArchives({
|
|
260
|
-
cwd,
|
|
261
|
-
stanPath,
|
|
262
|
-
ts,
|
|
263
|
-
maxUndos,
|
|
264
|
-
});
|
|
265
|
-
if (wantStash && attemptPop) {
|
|
266
|
-
const pop = await runGit(cwd, ['stash', 'pop']);
|
|
267
|
-
if (pop.code !== 0) {
|
|
268
|
-
console.error('stan: git stash pop failed');
|
|
269
|
-
}
|
|
270
|
-
else {
|
|
271
|
-
console.log('stan: stash pop restored changes');
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
console.log('stan: snapshot updated');
|
|
275
|
-
// Visual separation from next prompt
|
|
276
|
-
console.log('');
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
export { handleSnap };
|