@karmaniverous/stan-cli 0.11.0 → 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-D1XMoxMA.js +294 -0
- package/dist/cli/git-W31Nw3SI.js +41 -0
- package/dist/cli/{index-CoyGQCX9.js → index-Dy6XnoRx.js} +2 -2
- package/dist/cli/index-ucZa1KMb-CNGeWGvV.js +20 -0
- package/dist/cli/stan.js +4453 -3038
- package/dist/mjs/classifier-DeYwffC_-C7wwqop3.js +1 -0
- package/dist/mjs/index.js +1 -1
- package/dist/types/index.d.ts +4 -1
- package/package.json +17 -17
- package/dist/cli/index-ucZa1KMb-CSQ-GldX.js +0 -20
|
@@ -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 };
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import path from 'node:path';
|
|
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';
|
|
25
|
+
|
|
26
|
+
// src/common/interop/resolve.ts
|
|
27
|
+
/**
|
|
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.
|
|
30
|
+
*
|
|
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).
|
|
33
|
+
*
|
|
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.
|
|
41
|
+
*/
|
|
42
|
+
function resolveNamedOrDefaultFunction(mod, pickNamed, pickDefault, label) {
|
|
43
|
+
try {
|
|
44
|
+
const named = pickNamed(mod);
|
|
45
|
+
if (typeof named === 'function')
|
|
46
|
+
return named;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
/* ignore pickNamed errors */
|
|
50
|
+
}
|
|
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
|
+
}
|
|
62
|
+
|
|
63
|
+
/* src/stan/snap/context.ts
|
|
64
|
+
* Resolve execution context for snap commands (cwd, stanPath, maxUndos).
|
|
65
|
+
*/
|
|
66
|
+
/**
|
|
67
|
+
* Resolve the effective execution context for snapshot operations.
|
|
68
|
+
* Starting from `cwd0`, locates the nearest `stan.config.*` and returns:
|
|
69
|
+
* - `cwd`: the directory containing that config (or `cwd0` if none found),
|
|
70
|
+
* - `stanPath`: configured workspace folder (defaults to ".stan"),
|
|
71
|
+
* - `maxUndos`: normalized retention for snapshot history (default 10).
|
|
72
|
+
*
|
|
73
|
+
* @param cwd0 - Directory to start searching from.
|
|
74
|
+
* @returns Resolved `{ cwd, stanPath, maxUndos }`.
|
|
75
|
+
*/
|
|
76
|
+
async function resolveContext(cwd0) {
|
|
77
|
+
let cwd = cwd0;
|
|
78
|
+
let resolveStanPathSyncResolved = null;
|
|
79
|
+
try {
|
|
80
|
+
const coreMod = (await import('./stan.js').then(function (n) { return n.i; }));
|
|
81
|
+
const findConfigPathSyncResolved = resolveNamedOrDefaultFunction(coreMod, (m) => m.findConfigPathSync, (m) => m.default?.findConfigPathSync, 'findConfigPathSync');
|
|
82
|
+
const cfgPath = findConfigPathSyncResolved(cwd0);
|
|
83
|
+
cwd = cfgPath ? path.dirname(cfgPath) : cwd0;
|
|
84
|
+
// Keep a resolved handle for fallback stanPath derivation
|
|
85
|
+
resolveStanPathSyncResolved =
|
|
86
|
+
resolveNamedOrDefaultFunction(coreMod, (m) => m.resolveStanPathSync, (m) => m.default?.resolveStanPathSync, 'resolveStanPathSync');
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// best‑effort; keep cwd=cwd0 and derive stanPath in the general fallback below
|
|
90
|
+
resolveStanPathSyncResolved = null;
|
|
91
|
+
}
|
|
92
|
+
// Engine context (namespaced or legacy), resolved lazily to avoid SSR/ESM
|
|
93
|
+
// evaluation-order hazards during module import.
|
|
94
|
+
let engine;
|
|
95
|
+
try {
|
|
96
|
+
const effModUnknown = (await import('./stan.js').then(function (n) { return n.j; }));
|
|
97
|
+
// Decide if we should print a single success trace when STAN_DEBUG=1.
|
|
98
|
+
const debugOn = () => process.env.STAN_DEBUG === '1';
|
|
99
|
+
const debugTrace = (kind) => {
|
|
100
|
+
if (!debugOn())
|
|
101
|
+
return;
|
|
102
|
+
try {
|
|
103
|
+
// concise, single-line marker for CI logs
|
|
104
|
+
console.error(`stan: debug: snap.context: candidate=${kind}`);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
/* ignore */
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
// Candidate caller: try multiple signatures and short-circuit on first valid config.
|
|
111
|
+
const tryCall = async (fnMaybe, kind) => {
|
|
112
|
+
if (typeof fnMaybe !== 'function')
|
|
113
|
+
return null;
|
|
114
|
+
const invoke = async (...args) => {
|
|
115
|
+
try {
|
|
116
|
+
const out = await fnMaybe(...args);
|
|
117
|
+
if (out &&
|
|
118
|
+
typeof out === 'object' &&
|
|
119
|
+
typeof out.stanPath === 'string') {
|
|
120
|
+
return out;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
/* try next signature */
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
};
|
|
128
|
+
// Prefer 2+ arity with scope when declared suggests it.
|
|
129
|
+
const declared = fnMaybe.length;
|
|
130
|
+
if (typeof declared === 'number' && declared >= 2) {
|
|
131
|
+
const a2 = await invoke(cwd, DBG_SCOPE_SNAP_CONTEXT_LEGACY);
|
|
132
|
+
if (a2) {
|
|
133
|
+
debugTrace(kind);
|
|
134
|
+
return a2;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Always try (cwd)
|
|
138
|
+
const a1 = await invoke(cwd);
|
|
139
|
+
if (a1) {
|
|
140
|
+
debugTrace(kind);
|
|
141
|
+
return a1;
|
|
142
|
+
}
|
|
143
|
+
// Finally, no-arg call
|
|
144
|
+
const a0 = await invoke();
|
|
145
|
+
if (a0) {
|
|
146
|
+
debugTrace(kind);
|
|
147
|
+
return a0;
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
};
|
|
151
|
+
// Build ordered candidates (short‑circuit on first success).
|
|
152
|
+
const mod = effModUnknown;
|
|
153
|
+
// Immediate fast path: function-as-default — call directly before building the list
|
|
154
|
+
try {
|
|
155
|
+
const dAny = mod.default;
|
|
156
|
+
if (typeof dAny === 'function') {
|
|
157
|
+
const fast = await tryCall(dAny, 'default-fn');
|
|
158
|
+
if (fast) {
|
|
159
|
+
engine = fast;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
/* best-effort */
|
|
165
|
+
}
|
|
166
|
+
const candidates = [];
|
|
167
|
+
if (!engine) {
|
|
168
|
+
// Prefer default‑only shapes first (matches common test/mock shapes):
|
|
169
|
+
// 1) function‑as‑default (still include in list for completeness)
|
|
170
|
+
const dAny = mod.default;
|
|
171
|
+
if (typeof dAny === 'function')
|
|
172
|
+
candidates.push({ fn: dAny, kind: 'default-fn' });
|
|
173
|
+
// 2) default.resolveEffectiveEngineConfig
|
|
174
|
+
const dObj = dAny && typeof dAny === 'object'
|
|
175
|
+
? dAny
|
|
176
|
+
: undefined;
|
|
177
|
+
if (dObj && typeof dObj.resolveEffectiveEngineConfig === 'function') {
|
|
178
|
+
candidates.push({
|
|
179
|
+
fn: dObj.resolveEffectiveEngineConfig,
|
|
180
|
+
kind: 'default.resolve',
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
// 3) named export
|
|
184
|
+
if (typeof mod.resolveEffectiveEngineConfig === 'function') {
|
|
185
|
+
candidates.push({
|
|
186
|
+
fn: mod.resolveEffectiveEngineConfig,
|
|
187
|
+
kind: 'named',
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
// 4) nested default.default function (rare)
|
|
191
|
+
if (dObj && typeof dObj.default === 'function') {
|
|
192
|
+
candidates.push({ fn: dObj.default, kind: 'default.default-fn' });
|
|
193
|
+
}
|
|
194
|
+
// 5) module‑as‑function (edge mocks)
|
|
195
|
+
if (typeof mod === 'function') {
|
|
196
|
+
candidates.push({
|
|
197
|
+
fn: mod,
|
|
198
|
+
kind: 'module-fn',
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
// Also scan the immediate default object for any function-valued properties.
|
|
202
|
+
// This catches odd default-only mock shapes without waiting for the deeper walk.
|
|
203
|
+
if (dObj && typeof dObj === 'object') {
|
|
204
|
+
try {
|
|
205
|
+
for (const [, v] of Object.entries(dObj)) {
|
|
206
|
+
if (typeof v === 'function') {
|
|
207
|
+
// Avoid duplicate candidates (simple identity/label guard)
|
|
208
|
+
if (!candidates.some((c) => c.fn === v)) {
|
|
209
|
+
candidates.push({ fn: v, kind: 'default.obj-fn' });
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
/* best-effort */
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// Try in order
|
|
219
|
+
for (const c of candidates) {
|
|
220
|
+
const out = await tryCall(c.fn, c.kind);
|
|
221
|
+
if (out) {
|
|
222
|
+
engine = out;
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// As a last‑resort, walk nested defaults a couple of levels to catch exotic shapes.
|
|
227
|
+
if (!engine) {
|
|
228
|
+
const seen = new Set();
|
|
229
|
+
const walk = (obj, depth = 0) => {
|
|
230
|
+
if (!obj || seen.has(obj) || depth > 3)
|
|
231
|
+
return;
|
|
232
|
+
seen.add(obj);
|
|
233
|
+
if (typeof obj === 'function')
|
|
234
|
+
candidates.push({
|
|
235
|
+
fn: obj,
|
|
236
|
+
kind: 'nested.fn',
|
|
237
|
+
});
|
|
238
|
+
if (typeof obj !== 'object' && typeof obj !== 'function')
|
|
239
|
+
return;
|
|
240
|
+
const o = obj;
|
|
241
|
+
if (typeof o.resolveEffectiveEngineConfig === 'function')
|
|
242
|
+
candidates.push({
|
|
243
|
+
fn: o.resolveEffectiveEngineConfig,
|
|
244
|
+
kind: 'nested.resolve',
|
|
245
|
+
});
|
|
246
|
+
if ('default' in o)
|
|
247
|
+
walk(o.default, depth + 1);
|
|
248
|
+
};
|
|
249
|
+
walk(mod);
|
|
250
|
+
for (const c of candidates) {
|
|
251
|
+
const out = await tryCall(c.fn ?? c, c.kind ?? 'nested-fn');
|
|
252
|
+
if (out) {
|
|
253
|
+
engine = out;
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (!engine)
|
|
258
|
+
throw new Error('resolveEffectiveEngineConfig not found');
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
// Minimal, safe fallback: derive stanPath only. This preserves snap
|
|
264
|
+
// behavior even when the effective-config module cannot be resolved
|
|
265
|
+
// (e.g., SSR/mock edge cases). Downstream consumers treat includes/
|
|
266
|
+
// excludes as optional and default to [].
|
|
267
|
+
let stanPath = '.stan';
|
|
268
|
+
try {
|
|
269
|
+
stanPath = resolveStanPathSyncResolved
|
|
270
|
+
? resolveStanPathSyncResolved(cwd)
|
|
271
|
+
: stanPath;
|
|
272
|
+
}
|
|
273
|
+
catch {
|
|
274
|
+
/* keep default */
|
|
275
|
+
}
|
|
276
|
+
engine = { stanPath };
|
|
277
|
+
}
|
|
278
|
+
// CLI config for snap retention
|
|
279
|
+
let maxUndos;
|
|
280
|
+
try {
|
|
281
|
+
const cli = await loadCliConfig(cwd);
|
|
282
|
+
maxUndos = cli.maxUndos;
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
/* ignore */
|
|
286
|
+
}
|
|
287
|
+
return {
|
|
288
|
+
cwd,
|
|
289
|
+
stanPath: engine.stanPath,
|
|
290
|
+
maxUndos: maxUndos ?? 10,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
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 };
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import * as readline$1 from 'node:readline';
|
|
3
3
|
import readline__default from 'node:readline';
|
|
4
4
|
import { g as getDefaultExportFromCjs, r as requireIsFullwidthCodePoint, a as requireEmojiRegex, b as requireColorConvert, o as onExit } from './stan.js';
|
|
5
|
-
import
|
|
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 =
|
|
1407
|
+
const Stream = $;
|
|
1408
1408
|
|
|
1409
1409
|
class MuteStream extends Stream {
|
|
1410
1410
|
#isTTY = null
|