@soleri/cli 9.7.1 → 9.8.0
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/commands/add-domain.js +1 -0
- package/dist/commands/add-domain.js.map +1 -1
- package/dist/commands/add-pack.js +7 -147
- package/dist/commands/add-pack.js.map +1 -1
- package/dist/commands/agent.js +130 -0
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/create.js +78 -2
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/doctor.js +2 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/extend.js +17 -0
- package/dist/commands/extend.js.map +1 -1
- package/dist/commands/install-knowledge.js +1 -0
- package/dist/commands/install-knowledge.js.map +1 -1
- package/dist/commands/test.js +140 -1
- package/dist/commands/test.js.map +1 -1
- package/dist/hook-packs/flock-guard/manifest.json +2 -1
- package/dist/hook-packs/installer.js +12 -5
- package/dist/hook-packs/installer.js.map +1 -1
- package/dist/hook-packs/installer.ts +26 -7
- package/dist/hook-packs/marketing-research/manifest.json +2 -1
- package/dist/hook-packs/registry.d.ts +2 -0
- package/dist/hook-packs/registry.js.map +1 -1
- package/dist/hook-packs/registry.ts +2 -0
- package/dist/prompts/create-wizard.d.ts +16 -2
- package/dist/prompts/create-wizard.js +84 -11
- package/dist/prompts/create-wizard.js.map +1 -1
- package/dist/utils/checks.d.ts +8 -5
- package/dist/utils/checks.js +105 -10
- package/dist/utils/checks.js.map +1 -1
- package/dist/utils/format-paths.d.ts +14 -0
- package/dist/utils/format-paths.js +27 -0
- package/dist/utils/format-paths.js.map +1 -0
- package/dist/utils/git.d.ts +29 -0
- package/dist/utils/git.js +88 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/logger.d.ts +1 -0
- package/dist/utils/logger.js +4 -0
- package/dist/utils/logger.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/create-wizard-git.test.ts +208 -0
- package/src/__tests__/git-utils.test.ts +268 -0
- package/src/__tests__/hook-packs.test.ts +5 -1
- package/src/__tests__/scaffold-git-e2e.test.ts +105 -0
- package/src/commands/add-domain.ts +1 -0
- package/src/commands/add-pack.ts +10 -163
- package/src/commands/agent.ts +161 -0
- package/src/commands/create.ts +89 -3
- package/src/commands/doctor.ts +1 -0
- package/src/commands/extend.ts +20 -1
- package/src/commands/install-knowledge.ts +1 -0
- package/src/commands/test.ts +141 -2
- package/src/hook-packs/flock-guard/manifest.json +2 -1
- package/src/hook-packs/installer.ts +26 -7
- package/src/hook-packs/marketing-research/manifest.json +2 -1
- package/src/hook-packs/registry.ts +2 -0
- package/src/prompts/create-wizard.ts +109 -14
- package/src/utils/checks.ts +122 -13
- package/src/utils/format-paths.ts +41 -0
- package/src/utils/git.ts +118 -0
- package/src/utils/logger.ts +5 -0
package/src/utils/git.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git utility functions for the Soleri CLI scaffold flow.
|
|
3
|
+
*
|
|
4
|
+
* Uses child_process.execFile (not exec) for security — no shell interpolation.
|
|
5
|
+
* Never throws — all functions return { ok, error? } for graceful handling.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { execFile } from 'node:child_process';
|
|
9
|
+
|
|
10
|
+
export interface GitResult {
|
|
11
|
+
ok: boolean;
|
|
12
|
+
error?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Default timeout for local git operations (30s). */
|
|
16
|
+
const LOCAL_TIMEOUT = 30_000;
|
|
17
|
+
|
|
18
|
+
/** Timeout for network operations — push, gh create (60s). */
|
|
19
|
+
const NETWORK_TIMEOUT = 60_000;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Run a command via execFile and return stdout on success, or an error string on failure.
|
|
23
|
+
*/
|
|
24
|
+
function run(
|
|
25
|
+
cmd: string,
|
|
26
|
+
args: string[],
|
|
27
|
+
options: { cwd?: string; timeout: number },
|
|
28
|
+
): Promise<{ stdout: string; error?: string }> {
|
|
29
|
+
return new Promise((resolve) => {
|
|
30
|
+
try {
|
|
31
|
+
execFile(
|
|
32
|
+
cmd,
|
|
33
|
+
args,
|
|
34
|
+
{
|
|
35
|
+
cwd: options.cwd,
|
|
36
|
+
signal: AbortSignal.timeout(options.timeout),
|
|
37
|
+
},
|
|
38
|
+
(error, stdout, stderr) => {
|
|
39
|
+
if (error) {
|
|
40
|
+
resolve({ stdout: '', error: stderr?.trim() || error.message });
|
|
41
|
+
} else {
|
|
42
|
+
resolve({ stdout: stdout ?? '' });
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
);
|
|
46
|
+
} catch (err: unknown) {
|
|
47
|
+
// execFile itself can throw (e.g. ENOENT)
|
|
48
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
49
|
+
resolve({ stdout: '', error: msg });
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Check if the `git` binary is available on PATH. */
|
|
55
|
+
export async function isGitInstalled(): Promise<boolean> {
|
|
56
|
+
const { error } = await run('which', ['git'], { timeout: LOCAL_TIMEOUT });
|
|
57
|
+
return !error;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Check if the `gh` (GitHub CLI) binary is available on PATH. */
|
|
61
|
+
export async function isGhInstalled(): Promise<boolean> {
|
|
62
|
+
const { error } = await run('which', ['gh'], { timeout: LOCAL_TIMEOUT });
|
|
63
|
+
return !error;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Run `git init` in the given directory. */
|
|
67
|
+
export async function gitInit(dir: string): Promise<GitResult> {
|
|
68
|
+
const { error } = await run('git', ['init'], { cwd: dir, timeout: LOCAL_TIMEOUT });
|
|
69
|
+
return error ? { ok: false, error } : { ok: true };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Stage all files and create an initial commit. */
|
|
73
|
+
export async function gitInitialCommit(dir: string, message: string): Promise<GitResult> {
|
|
74
|
+
const add = await run('git', ['add', '.'], { cwd: dir, timeout: LOCAL_TIMEOUT });
|
|
75
|
+
if (add.error) return { ok: false, error: add.error };
|
|
76
|
+
|
|
77
|
+
const commit = await run('git', ['commit', '-m', message], { cwd: dir, timeout: LOCAL_TIMEOUT });
|
|
78
|
+
if (commit.error) return { ok: false, error: commit.error };
|
|
79
|
+
|
|
80
|
+
return { ok: true };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Add a remote origin URL. */
|
|
84
|
+
export async function gitAddRemote(dir: string, url: string): Promise<GitResult> {
|
|
85
|
+
const { error } = await run('git', ['remote', 'add', 'origin', url], {
|
|
86
|
+
cwd: dir,
|
|
87
|
+
timeout: LOCAL_TIMEOUT,
|
|
88
|
+
});
|
|
89
|
+
return error ? { ok: false, error } : { ok: true };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Push to origin main with the -u flag. */
|
|
93
|
+
export async function gitPush(dir: string): Promise<GitResult> {
|
|
94
|
+
const { error } = await run('git', ['push', '-u', 'origin', 'main'], {
|
|
95
|
+
cwd: dir,
|
|
96
|
+
timeout: NETWORK_TIMEOUT,
|
|
97
|
+
});
|
|
98
|
+
return error ? { ok: false, error } : { ok: true };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Create a GitHub repo using the `gh` CLI. */
|
|
102
|
+
export async function ghCreateRepo(
|
|
103
|
+
name: string,
|
|
104
|
+
options: { visibility: 'public' | 'private'; dir: string },
|
|
105
|
+
): Promise<GitResult & { url?: string }> {
|
|
106
|
+
const visFlag = options.visibility === 'public' ? '--public' : '--private';
|
|
107
|
+
const { stdout, error } = await run(
|
|
108
|
+
'gh',
|
|
109
|
+
['repo', 'create', name, visFlag, `--source=${options.dir}`, '--remote=origin', '--push'],
|
|
110
|
+
{ cwd: options.dir, timeout: NETWORK_TIMEOUT },
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
if (error) return { ok: false, error };
|
|
114
|
+
|
|
115
|
+
// gh repo create prints the repo URL on stdout
|
|
116
|
+
const url = stdout.trim() || undefined;
|
|
117
|
+
return { ok: true, url };
|
|
118
|
+
}
|
package/src/utils/logger.ts
CHANGED
|
@@ -26,6 +26,11 @@ export function warn(label: string, detail?: string): void {
|
|
|
26
26
|
console.log(` ${YELLOW}!${RESET} ${label}${suffix}`);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
export function skip(label: string, detail?: string): void {
|
|
30
|
+
const suffix = detail ? ` ${DIM}${detail}${RESET}` : '';
|
|
31
|
+
console.log(` ${DIM}–${RESET} ${label}${suffix}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
29
34
|
export function info(message: string): void {
|
|
30
35
|
console.log(` ${CYAN}ℹ${RESET} ${message}`);
|
|
31
36
|
}
|