@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.
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+ import { N as Nu } from './stan.js';
3
+ import 'node:fs';
4
+ import 'node:fs/promises';
5
+ import 'node:path';
6
+ import 'fs-extra';
7
+ import 'node:process';
8
+ import 'node:url';
9
+ import 'process';
10
+ import 'buffer';
11
+ import 'node:crypto';
12
+ import 'node:child_process';
13
+ import 'os';
14
+ import 'path';
15
+ import 'util';
16
+ import 'stream';
17
+ import 'events';
18
+ import 'fs';
19
+ import 'node:module';
20
+ import 'node:os';
21
+ import 'node:tty';
22
+ import 'node:readline';
23
+ import 'clipboardy';
24
+ import 'child_process';
25
+
26
+ /** Present for compatibility with older/mocked test shapes. */
27
+ const buildApplyAttempts = () => {
28
+ return [];
29
+ };
30
+ /**
31
+ * Git-apply attempt wrapper (delegates to the engine pipeline).
32
+ * When mocked in tests, this function can force a failure path so the
33
+ * caller falls back to jsdiff.
34
+ */
35
+ const runGitApply = async (args) => {
36
+ const { cwd, patchAbs, cleaned, stripOrder } = args;
37
+ const out = await Nu({
38
+ cwd,
39
+ patchAbs,
40
+ cleaned,
41
+ check: false,
42
+ stripOrder: Array.isArray(stripOrder) && stripOrder.length > 0 ? stripOrder : [1, 0],
43
+ });
44
+ return out.result;
45
+ };
46
+
47
+ export { buildApplyAttempts, runGitApply };
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync } from 'node:fs';
3
+ import { readFile, writeFile, copyFile, rm } from 'node:fs/promises';
4
+ import { w as within, e as ensureDirs, A as ARCH_DIR, d as readJson, f as writeJson, S as STATE_FILE, h as SNAP_DIR } from './stan.js';
5
+ import 'node:path';
6
+ import 'fs-extra';
7
+ import 'node:process';
8
+ import 'node:url';
9
+ import 'process';
10
+ import 'buffer';
11
+ import 'node:crypto';
12
+ import 'node:child_process';
13
+ import 'os';
14
+ import 'path';
15
+ import 'util';
16
+ import 'stream';
17
+ import 'events';
18
+ import 'fs';
19
+ import 'node:module';
20
+ import 'node:os';
21
+ import 'node:tty';
22
+ import 'node:readline';
23
+ import 'clipboardy';
24
+ import 'child_process';
25
+
26
+ // src/stan/snap/capture.ts
27
+ /**
28
+ * Capture the current snapshot and (optionally) current archives into history,
29
+ * then update diff/.snap.state.json with bounded retention.
30
+ *
31
+ * - Copies <stanPath>/diff/.archive.snapshot.json to diff/snapshots/snap-<ts>.json
32
+ * - If present, copies <stanPath>/output/archive.tar and archive.diff.tar to diff/archives/
33
+ * - Pushes a new entry, clears any redos, and trims to maxUndos (oldest first),
34
+ * deleting dropped files best-effort.
35
+ */
36
+ const captureSnapshotAndArchives = async ({ cwd, stanPath, ts, maxUndos, }) => {
37
+ const diffDir = within(cwd, stanPath, 'diff');
38
+ const outDir = within(cwd, stanPath, 'output');
39
+ // ensureDirs will create as needed below
40
+ const statePath = within(diffDir, STATE_FILE);
41
+ const snapsDir = within(diffDir, SNAP_DIR);
42
+ const archDir = within(diffDir, ARCH_DIR);
43
+ await ensureDirs([diffDir, snapsDir, archDir]);
44
+ // Copy current snapshot body into history file
45
+ const currentSnapAbs = within(diffDir, '.archive.snapshot.json');
46
+ const snapRel = within(SNAP_DIR, `snap-${ts}.json`);
47
+ const snapAbs = within(diffDir, snapRel);
48
+ try {
49
+ const body = await readFile(currentSnapAbs, 'utf8');
50
+ await writeFile(snapAbs, body, 'utf8');
51
+ }
52
+ catch {
53
+ // best-effort
54
+ }
55
+ // Optionally capture current archives if present
56
+ let archRel;
57
+ let archDiffRel;
58
+ const outArchive = within(outDir, 'archive.tar');
59
+ const outDiff = within(outDir, 'archive.diff.tar');
60
+ try {
61
+ if (existsSync(outArchive)) {
62
+ archRel = within(ARCH_DIR, `archive-${ts}.tar`);
63
+ await copyFile(outArchive, within(diffDir, archRel));
64
+ }
65
+ if (existsSync(outDiff)) {
66
+ archDiffRel = within(ARCH_DIR, `archive-${ts}.diff.tar`);
67
+ await copyFile(outDiff, within(diffDir, archDiffRel));
68
+ }
69
+ }
70
+ catch {
71
+ // best-effort
72
+ }
73
+ // Load or initialize state
74
+ const st = (await readJson(statePath)) ?? {
75
+ entries: [],
76
+ index: -1,
77
+ maxUndos,
78
+ };
79
+ // Drop redos when we’re not at tip
80
+ if (st.index >= 0 && st.index < st.entries.length - 1) {
81
+ st.entries = st.entries.slice(0, st.index + 1);
82
+ }
83
+ // Push new entry and advance pointer
84
+ const entry = {
85
+ ts,
86
+ snapshot: snapRel,
87
+ archive: archRel,
88
+ archiveDiff: archDiffRel,
89
+ };
90
+ st.entries.push(entry);
91
+ st.index = st.entries.length - 1;
92
+ // Trim oldest beyond retention; remove dropped files best-effort
93
+ const maxKeep = st.maxUndos;
94
+ while (st.entries.length > maxKeep) {
95
+ const drop = st.entries.shift();
96
+ if (drop) {
97
+ try {
98
+ await rm(within(diffDir, drop.snapshot), { force: true });
99
+ }
100
+ catch {
101
+ // ignore
102
+ }
103
+ if (drop.archive) {
104
+ try {
105
+ await rm(within(diffDir, drop.archive), { force: true });
106
+ }
107
+ catch {
108
+ // ignore
109
+ }
110
+ }
111
+ if (drop.archiveDiff) {
112
+ try {
113
+ await rm(within(diffDir, drop.archiveDiff), { force: true });
114
+ }
115
+ catch {
116
+ // ignore
117
+ }
118
+ }
119
+ }
120
+ st.index = Math.max(0, st.entries.length - 1);
121
+ }
122
+ await writeJson(statePath, st);
123
+ };
124
+
125
+ export { captureSnapshotAndArchives };
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { stat, open, readFile } from 'node:fs/promises';
3
+ import { resolve } from 'node:path';
4
+
5
+ const s=1048576,o=async(o,i)=>{const a=[],c=[],h=[];await Promise.all(i.map(async i=>{const l=i.replace(/\\/g,"/");const u=resolve(o,i);let p=0;try{p=(await stat(u)).size;}catch{return}let f,g=false;try{g=await(async t=>{try{const e=await open(t,"r");try{const t=Buffer.allocUnsafe(8192),{bytesRead:n}=await e.read(t,0,t.length,0);for(let e=0;e<n;e+=1)if(0===t[e])return !0;return !1}finally{await e.close().catch(()=>{});}}catch{return !1}})(u);}catch{g=false;}if(g)return void c.push({path:l,size:p});a.push(l);try{if(p<=s||p<5*s){f=(t=>{const e=t.replace(/\r\n/g,"\n");return 0===e.length?0:e.split("\n").length})(await readFile(u,"utf8"));}}catch{}(p>s||"number"==typeof f&&f>3e3)&&h.push({path:l,size:p,loc:f});}));const l=[];if(c.length>0){l.push(`Binary files excluded from archive (${c.length.toString()}):`);for(const t of c)l.push(` - ${t.path} (${t.size.toString()} bytes)`);l.push("");}if(h.length>0){l.push(`Large text files (included; consider excludes if unwanted) (${h.length.toString()}):`);for(const t of h){const e=[` - ${t.path}`,`(${t.size.toString()} bytes)`];"number"==typeof t.loc&&e.push(`${t.loc.toString()} LOC`),l.push(e.join(" "));}l.push(""),l.push(`Thresholds: size > ${s.toString()} bytes or LOC > ${3e3.toString()}`);}0===l.length&&l.push("No archive warnings.");const u=l.join("\n")+(l.length?"\n":"");return {textFiles:a,excludedBinaries:c,largeText:h,warningsBody:u}};
6
+
7
+ export { o as classifyForArchive };
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env node
2
+ import { c as readRawConfigSync, p as pickCliNode, n as normalizeScriptsNode } from './stan.js';
3
+ import 'node:fs';
4
+ import 'node:fs/promises';
5
+ import 'node:path';
6
+ import 'fs-extra';
7
+ import 'node:process';
8
+ import 'node:url';
9
+ import 'process';
10
+ import 'buffer';
11
+ import 'node:crypto';
12
+ import 'node:child_process';
13
+ import 'os';
14
+ import 'path';
15
+ import 'util';
16
+ import 'stream';
17
+ import 'events';
18
+ import 'fs';
19
+ import 'node:module';
20
+ import 'node:os';
21
+ import 'node:tty';
22
+ import 'node:readline';
23
+ import 'clipboardy';
24
+ import 'child_process';
25
+
26
+ // src/cli/run/config-fallback.ts
27
+ /**
28
+ * SSR/mock‑robust fallbacks for reading CLI scripts and run.scripts defaults
29
+ * straight from stan.config.* when lazy import shapes are unavailable.
30
+ *
31
+ * Preference order (when a config is present):
32
+ * - namespaced: root['stan-cli'].\{ scripts, cliDefaults.run.scripts \}
33
+ * - legacy root: root.\{ scripts, cliDefaults.run.scripts \}
34
+ */
35
+ const normalizeScripts = (node) => {
36
+ return normalizeScriptsNode(node);
37
+ };
38
+ const readCliScriptsFallback = (cwd) => {
39
+ const root = readRawConfigSync(cwd);
40
+ // Prefer namespaced stan-cli.scripts
41
+ const cliNode = pickCliNode(root);
42
+ if (cliNode && cliNode.scripts && typeof cliNode.scripts === 'object') {
43
+ return normalizeScripts(cliNode.scripts);
44
+ }
45
+ // Legacy root-level scripts
46
+ if (root.scripts && typeof root.scripts === 'object') {
47
+ return normalizeScripts(root.scripts);
48
+ }
49
+ return {};
50
+ };
51
+ const readRunScriptsDefaultFallback = (cwd) => {
52
+ const root = readRawConfigSync(cwd);
53
+ // Prefer namespaced stan-cli.cliDefaults.run.scripts
54
+ const cliNode = pickCliNode(root);
55
+ if (cliNode &&
56
+ cliNode.cliDefaults &&
57
+ typeof cliNode.cliDefaults === 'object') {
58
+ const runNode = cliNode.cliDefaults
59
+ .run;
60
+ const v = runNode?.scripts;
61
+ if (typeof v === 'boolean')
62
+ return v;
63
+ if (Array.isArray(v))
64
+ return v.filter((x) => typeof x === 'string');
65
+ }
66
+ // Legacy root-level cliDefaults.run.scripts
67
+ if (root.cliDefaults && typeof root.cliDefaults === 'object') {
68
+ const runNode = root.cliDefaults.run;
69
+ const v = runNode?.scripts;
70
+ if (typeof v === 'boolean')
71
+ return v;
72
+ if (Array.isArray(v))
73
+ return v.filter((x) => typeof x === 'string');
74
+ }
75
+ return undefined;
76
+ };
77
+
78
+ export { readCliScriptsFallback, readRunScriptsDefaultFallback };
@@ -1,78 +1,64 @@
1
1
  #!/usr/bin/env node
2
- import { writeFile, readFile } from 'node:fs/promises';
3
2
  import path from 'node:path';
4
- import { ensureDir } from 'fs-extra';
5
- import { b as resolveNamedOrDefaultFunction, D as DBG_SCOPE_SNAP_CONTEXT_LEGACY, l as loadCliConfig } from './stan.js';
3
+ import { D as DBG_SCOPE_SNAP_CONTEXT_LEGACY, l as loadCliConfig } from './stan.js';
4
+ import 'node:fs';
5
+ import 'node:fs/promises';
6
+ import 'fs-extra';
7
+ import 'node:process';
8
+ import 'node:url';
9
+ import 'process';
10
+ import 'buffer';
11
+ import 'node:crypto';
12
+ import 'node:child_process';
13
+ import 'os';
14
+ import 'path';
15
+ import 'util';
16
+ import 'stream';
17
+ import 'events';
18
+ import 'fs';
19
+ import 'node:module';
20
+ import 'node:os';
21
+ import 'node:tty';
22
+ import 'node:readline';
23
+ import 'clipboardy';
24
+ import 'child_process';
6
25
 
26
+ // src/common/interop/resolve.ts
7
27
  /**
8
- * UTC timestamp in YYYYMMDD-HHMMSS for filenames and logs.
9
- */
10
- function utcStamp() {
11
- const d = new Date();
12
- const pad = (n) => n.toString().padStart(2, '0');
13
- return `${d.getUTCFullYear()}${pad(d.getUTCMonth() + 1)}${pad(d.getUTCDate())}-${pad(d.getUTCHours())}${pad(d.getUTCMinutes())}${pad(d.getUTCSeconds())}`;
14
- }
15
- /**
16
- * Convert a UTC stamp (YYYYMMDD-HHMMSS) to a local time string.
17
- * Falls back to the original stamp if parsing fails.
28
+ * Resolve a function export from a module, preferring a named export and
29
+ * falling back to an identically named property on the module's default export.
18
30
  *
19
- * @param ts - UTC stamp in the form YYYYMMDD-HHMMSS.
20
- * @returns Local time string "YYYY-MM-DD HH:MM:SS", or the original input if parsing fails.
21
- */
22
- function formatUtcStampLocal(ts) {
23
- const m = ts.match(/^(\d{4})(\d{2})(\d{2})-(\d{2})(\d{2})(\d{2})$/);
24
- if (!m)
25
- return ts;
26
- const [, y, mo, d, h, mi, s] = m.map((x) => Number.parseInt(x ?? '', 10));
27
- const dt = new Date(Date.UTC(y, mo - 1, d, h, mi, s));
28
- // Fixed-width local: YYYY-MM-DD HH:MM:SS
29
- const pad = (n) => n.toString().padStart(2, '0');
30
- const yyyy = dt.getFullYear();
31
- const MM = pad(dt.getMonth() + 1);
32
- const DD = pad(dt.getDate());
33
- const HH = pad(dt.getHours());
34
- const MMi = pad(dt.getMinutes());
35
- const SS = pad(dt.getSeconds());
36
- return `${yyyy}-${MM}-${DD} ${HH}:${MMi}:${SS}`;
37
- }
38
-
39
- const STATE_FILE = '.snap.state.json';
40
- const SNAP_DIR = 'snapshots';
41
- const ARCH_DIR = 'archives';
42
- const within = (...parts) => path.join(...parts);
43
- /**
44
- * Ensure all provided directories exist (best‑effort).
45
- *
46
- * @param paths - Absolute directory paths to create (recursively).
47
- * @returns A promise that resolves when creation attempts finish.
48
- */
49
- const ensureDirs = async (paths) => {
50
- await Promise.all(paths.map((p) => ensureDir(p)));
51
- };
52
- /**
53
- * Read and parse a JSON file, returning `null` on failure.
31
+ * This helper avoids the use of `any`; callers provide the function type `F`
32
+ * and the pickers that extract the candidate from the module shape (typed or unknown).
54
33
  *
55
- * @param p - Absolute file path.
56
- * @returns Parsed value or `null` if the file is missing or invalid.
34
+ * @typeParam F - Function type to resolve (e.g., typeof import('./mod')['foo']).
35
+ * @param mod - The imported module object (typed or unknown).
36
+ * @param pickNamed - Extractor for the named export (returns undefined when absent).
37
+ * @param pickDefault - Extractor for the default export's property (returns undefined when absent).
38
+ * @param label - Optional label for error messaging.
39
+ * @returns The resolved function of type F.
40
+ * @throws When neither the named nor the default export provides the function.
57
41
  */
58
- const readJson = async (p) => {
42
+ function resolveNamedOrDefaultFunction(mod, pickNamed, pickDefault, label) {
59
43
  try {
60
- const raw = await readFile(p, 'utf8');
61
- return JSON.parse(raw);
44
+ const named = pickNamed(mod);
45
+ if (typeof named === 'function')
46
+ return named;
62
47
  }
63
48
  catch {
64
- return null;
49
+ /* ignore pickNamed errors */
65
50
  }
66
- };
67
- /**
68
- * Write a JSON value to a file with 2‑space indentation.
69
- *
70
- * @param p - Absolute destination path.
71
- * @param v - Value to serialize.
72
- */
73
- const writeJson = async (p, v) => {
74
- await writeFile(p, JSON.stringify(v, null, 2), 'utf8');
75
- };
51
+ try {
52
+ const viaDefault = pickDefault(mod);
53
+ if (typeof viaDefault === 'function')
54
+ return viaDefault;
55
+ }
56
+ catch {
57
+ /* ignore pickDefault errors */
58
+ }
59
+ const what = label && label.trim().length ? label.trim() : 'export';
60
+ throw new Error(`resolveNamedOrDefaultFunction: ${what} not found`);
61
+ }
76
62
 
77
63
  /* src/stan/snap/context.ts
78
64
  * Resolve execution context for snap commands (cwd, stanPath, maxUndos).
@@ -91,7 +77,7 @@ async function resolveContext(cwd0) {
91
77
  let cwd = cwd0;
92
78
  let resolveStanPathSyncResolved = null;
93
79
  try {
94
- const coreMod = (await import('./stan.js').then(function (n) { return n.j; }));
80
+ const coreMod = (await import('./stan.js').then(function (n) { return n.i; }));
95
81
  const findConfigPathSyncResolved = resolveNamedOrDefaultFunction(coreMod, (m) => m.findConfigPathSync, (m) => m.default?.findConfigPathSync, 'findConfigPathSync');
96
82
  const cfgPath = findConfigPathSyncResolved(cwd0);
97
83
  cwd = cfgPath ? path.dirname(cfgPath) : cwd0;
@@ -107,7 +93,7 @@ async function resolveContext(cwd0) {
107
93
  // evaluation-order hazards during module import.
108
94
  let engine;
109
95
  try {
110
- const effModUnknown = (await import('./effective-CXoq4vkL.js'));
96
+ const effModUnknown = (await import('./stan.js').then(function (n) { return n.j; }));
111
97
  // Decide if we should print a single success trace when STAN_DEBUG=1.
112
98
  const debugOn = () => process.env.STAN_DEBUG === '1';
113
99
  const debugTrace = (kind) => {
@@ -305,4 +291,4 @@ async function resolveContext(cwd0) {
305
291
  };
306
292
  }
307
293
 
308
- export { ARCH_DIR as A, SNAP_DIR as S, writeJson as a, STATE_FILE as b, resolveContext as c, ensureDirs as e, formatUtcStampLocal as f, readJson as r, utcStamp as u, within as w };
294
+ export { resolveContext };
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env node
2
+ import { spawn } from 'node:child_process';
3
+
4
+ /**
5
+ * Run a `git` command and capture its exit code, stdout, and stderr.
6
+ *
7
+ * Streams are buffered in memory; when `STAN_DEBUG=1`, output is mirrored
8
+ * to the current process.
9
+ *
10
+ * @param cwd - Working directory for the git process.
11
+ * @param args - Arguments to pass to `git`.
12
+ * @returns `{ code, stdout, stderr }` from the completed process.
13
+ */
14
+ const runGit = async (cwd, args) => new Promise((resolve) => {
15
+ const child = spawn('git', args, {
16
+ cwd,
17
+ shell: false,
18
+ windowsHide: true,
19
+ stdio: ['ignore', 'pipe', 'pipe'],
20
+ });
21
+ let stdout = '';
22
+ let stderr = '';
23
+ const cp = child;
24
+ cp.stdout?.on('data', (d) => {
25
+ const s = d.toString('utf8');
26
+ stdout += s;
27
+ if (process.env.STAN_DEBUG === '1')
28
+ process.stdout.write(s);
29
+ });
30
+ cp.stderr?.on('data', (d) => {
31
+ const s = d.toString('utf8');
32
+ stderr += s;
33
+ if (process.env.STAN_DEBUG === '1')
34
+ process.stderr.write(s);
35
+ });
36
+ child.on('close', (code) => {
37
+ resolve({ code: code ?? 0, stdout, stderr });
38
+ });
39
+ });
40
+
41
+ export { runGit };
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import * as readline$1 from 'node:readline';
3
3
  import readline__default from 'node:readline';
4
- import { g as getDefaultExportFromCjs, f as requireIsFullwidthCodePoint, h as requireEmojiRegex, i as requireColorConvert, o as onExit } from './stan.js';
5
- import R from 'stream';
4
+ import { g as getDefaultExportFromCjs, r as requireIsFullwidthCodePoint, a as requireEmojiRegex, b as requireColorConvert, o as onExit } from './stan.js';
5
+ import $ from 'stream';
6
6
  import { createRequire } from 'node:module';
7
7
  import process$1 from 'node:process';
8
8
  import { AsyncLocalStorage, AsyncResource } from 'node:async_hooks';
@@ -1404,7 +1404,7 @@ var hasRequiredLib$2;
1404
1404
  function requireLib$2 () {
1405
1405
  if (hasRequiredLib$2) return lib$2;
1406
1406
  hasRequiredLib$2 = 1;
1407
- const Stream = R;
1407
+ const Stream = $;
1408
1408
 
1409
1409
  class MuteStream extends Stream {
1410
1410
  #isTTY = null