Compare commits
11 Commits
feat/stora
...
fix/storag
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b4767bd8b | ||
| 0b0fe10b37 | |||
| acfb31f8f6 | |||
| d4c5797a65 | |||
| 70a51ba711 | |||
| db8023bdbb | |||
| 9e597ecf87 | |||
| a23c117ea4 | |||
| 0cf80dab8c | |||
| 381b0eed7b | |||
|
|
e7db9ddf98 |
@@ -15,6 +15,7 @@ steps:
|
|||||||
image: *node_image
|
image: *node_image
|
||||||
commands:
|
commands:
|
||||||
- corepack enable
|
- corepack enable
|
||||||
|
- apk add --no-cache python3 make g++
|
||||||
- pnpm install --frozen-lockfile
|
- pnpm install --frozen-lockfile
|
||||||
|
|
||||||
typecheck:
|
typecheck:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@mosaic/cli",
|
"name": "@mosaic/cli",
|
||||||
"version": "0.0.3",
|
"version": "0.0.10",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { createRequire } from 'module';
|
import { createRequire } from 'module';
|
||||||
import { Command } from 'commander';
|
import { Command } from 'commander';
|
||||||
import { createQualityRailsCli } from '@mosaic/quality-rails';
|
import { registerQualityRails } from '@mosaic/quality-rails';
|
||||||
import { registerAgentCommand } from './commands/agent.js';
|
import { registerAgentCommand } from './commands/agent.js';
|
||||||
import { registerMissionCommand } from './commands/mission.js';
|
import { registerMissionCommand } from './commands/mission.js';
|
||||||
// prdy is registered via launch.ts
|
// prdy is registered via launch.ts
|
||||||
@@ -305,11 +305,7 @@ registerMissionCommand(program);
|
|||||||
|
|
||||||
// ─── quality-rails ──────────────────────────────────────────────────────
|
// ─── quality-rails ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
const qrWrapper = createQualityRailsCli();
|
registerQualityRails(program);
|
||||||
const qrCmd = qrWrapper.commands.find((c) => c.name() === 'quality-rails');
|
|
||||||
if (qrCmd !== undefined) {
|
|
||||||
program.addCommand(qrCmd as unknown as Command);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ─── update ─────────────────────────────────────────────────────────────
|
// ─── update ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
import { execFileSync, execSync, spawnSync } from 'node:child_process';
|
import { execFileSync, execSync, spawnSync } from 'node:child_process';
|
||||||
import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync, rmSync } from 'node:fs';
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync, rmSync } from 'node:fs';
|
||||||
|
import { createRequire } from 'node:module';
|
||||||
import { homedir } from 'node:os';
|
import { homedir } from 'node:os';
|
||||||
import { join, dirname } from 'node:path';
|
import { join, dirname } from 'node:path';
|
||||||
import type { Command } from 'commander';
|
import type { Command } from 'commander';
|
||||||
@@ -67,7 +68,7 @@ function checkSoul(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fallback: legacy bash mosaic-init
|
// Fallback: legacy bash mosaic-init
|
||||||
const initBin = join(MOSAIC_HOME, 'tools', '_scripts', 'mosaic-init');
|
const initBin = fwScript('mosaic-init');
|
||||||
if (existsSync(initBin)) {
|
if (existsSync(initBin)) {
|
||||||
spawnSync(initBin, [], { stdio: 'inherit' });
|
spawnSync(initBin, [], { stdio: 'inherit' });
|
||||||
} else {
|
} else {
|
||||||
@@ -78,7 +79,7 @@ function checkSoul(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function checkSequentialThinking(runtime: string): void {
|
function checkSequentialThinking(runtime: string): void {
|
||||||
const checker = join(MOSAIC_HOME, 'tools', '_scripts', 'mosaic-ensure-sequential-thinking');
|
const checker = fwScript('mosaic-ensure-sequential-thinking');
|
||||||
if (!existsSync(checker)) return; // Skip if checker doesn't exist
|
if (!existsSync(checker)) return; // Skip if checker doesn't exist
|
||||||
const result = spawnSync(checker, ['--check', '--runtime', runtime], { stdio: 'ignore' });
|
const result = spawnSync(checker, ['--check', '--runtime', runtime], { stdio: 'ignore' });
|
||||||
if (result.status !== 0) {
|
if (result.status !== 0) {
|
||||||
@@ -491,12 +492,29 @@ function delegateToScript(scriptPath: string, args: string[], env?: Record<strin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve a path under the framework tools directory. Prefers the version
|
||||||
|
* bundled in the @mosaic/mosaic npm package (always matches the installed
|
||||||
|
* CLI version) over the deployed copy in ~/.config/mosaic/ (may be stale).
|
||||||
|
*/
|
||||||
|
function resolveTool(...segments: string[]): string {
|
||||||
|
try {
|
||||||
|
const req = createRequire(import.meta.url);
|
||||||
|
const mosaicPkg = dirname(req.resolve('@mosaic/mosaic/package.json'));
|
||||||
|
const bundled = join(mosaicPkg, 'framework', 'tools', ...segments);
|
||||||
|
if (existsSync(bundled)) return bundled;
|
||||||
|
} catch {
|
||||||
|
// Fall through to deployed copy
|
||||||
|
}
|
||||||
|
return join(MOSAIC_HOME, 'tools', ...segments);
|
||||||
|
}
|
||||||
|
|
||||||
function fwScript(name: string): string {
|
function fwScript(name: string): string {
|
||||||
return join(MOSAIC_HOME, 'tools', '_scripts', name);
|
return resolveTool('_scripts', name);
|
||||||
}
|
}
|
||||||
|
|
||||||
function toolScript(toolDir: string, name: string): string {
|
function toolScript(toolDir: string, name: string): string {
|
||||||
return join(MOSAIC_HOME, 'tools', toolDir, name);
|
return resolveTool(toolDir, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Coord (mission orchestrator) ───────────────────────────────────────────
|
// ─── Coord (mission orchestrator) ───────────────────────────────────────────
|
||||||
|
|||||||
@@ -56,24 +56,66 @@ if [[ $fetch -eq 1 ]]; then
|
|||||||
if [[ -d "$SKILLS_REPO_DIR/.git" ]]; then
|
if [[ -d "$SKILLS_REPO_DIR/.git" ]]; then
|
||||||
echo "[mosaic-skills] Updating skills source: $SKILLS_REPO_DIR"
|
echo "[mosaic-skills] Updating skills source: $SKILLS_REPO_DIR"
|
||||||
|
|
||||||
# Stash any local changes (dirty index or worktree) before pulling
|
# ── Detect dirty state ──────────────────────────────────────────────
|
||||||
local_changes=0
|
dirty=""
|
||||||
if ! git -C "$SKILLS_REPO_DIR" diff --quiet 2>/dev/null || \
|
dirty="$(git -C "$SKILLS_REPO_DIR" status --porcelain 2>/dev/null || true)"
|
||||||
! git -C "$SKILLS_REPO_DIR" diff --cached --quiet 2>/dev/null; then
|
|
||||||
local_changes=1
|
if [[ -n "$dirty" ]]; then
|
||||||
echo "[mosaic-skills] Stashing local changes..."
|
# ── Auto-migrate customized skills to skills-local/ ─────────────
|
||||||
git -C "$SKILLS_REPO_DIR" stash push -q -m "mosaic-sync-skills auto-stash"
|
# Instead of stash/pop (fragile, merge conflicts), we:
|
||||||
|
# 1. Identify which skill dirs contain user edits
|
||||||
|
# 2. Copy those full skill dirs into skills-local/ (preserving edits)
|
||||||
|
# 3. Reset the repo clean so pull always succeeds
|
||||||
|
# 4. skills-local/ takes precedence during linking, so edits win
|
||||||
|
|
||||||
|
SOURCE_SKILLS_SUBDIR="$SKILLS_REPO_DIR/skills"
|
||||||
|
migrated=()
|
||||||
|
|
||||||
|
while IFS= read -r line; do
|
||||||
|
# porcelain format: XY <path> — extract the file path
|
||||||
|
file="${line:3}"
|
||||||
|
# Only migrate files under skills/ subdir in the repo
|
||||||
|
if [[ "$file" == skills/* ]]; then
|
||||||
|
# Extract the skill directory name (first path component after skills/)
|
||||||
|
skill_name="${file#skills/}"
|
||||||
|
skill_name="${skill_name%%/*}"
|
||||||
|
|
||||||
|
# Skip if already migrated this skill in this run
|
||||||
|
local_skill_dir="$MOSAIC_LOCAL_SKILLS_DIR/$skill_name"
|
||||||
|
if [[ -d "$local_skill_dir" ]]; then
|
||||||
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! git -C "$SKILLS_REPO_DIR" pull --rebase; then
|
# Skip if skill_name is empty or hidden
|
||||||
|
if [[ -z "$skill_name" || "$skill_name" == .* ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Copy the skill (with user's edits) from repo working tree to skills-local/
|
||||||
|
if [[ -d "$SOURCE_SKILLS_SUBDIR/$skill_name" ]]; then
|
||||||
|
cp -R "$SOURCE_SKILLS_SUBDIR/$skill_name" "$local_skill_dir"
|
||||||
|
migrated+=("$skill_name")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done <<< "$dirty"
|
||||||
|
|
||||||
|
if [[ ${#migrated[@]} -gt 0 ]]; then
|
||||||
|
echo "[mosaic-skills] Migrated ${#migrated[@]} customized skill(s) to skills-local/:"
|
||||||
|
for s in "${migrated[@]}"; do
|
||||||
|
echo " → $MOSAIC_LOCAL_SKILLS_DIR/$s"
|
||||||
|
done
|
||||||
|
echo "[mosaic-skills] Your edits are preserved there and take precedence over canonical."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Reset repo to clean state so pull always works
|
||||||
|
echo "[mosaic-skills] Resetting source repo to clean state..."
|
||||||
|
git -C "$SKILLS_REPO_DIR" checkout . 2>/dev/null || true
|
||||||
|
git -C "$SKILLS_REPO_DIR" clean -fd 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! git -C "$SKILLS_REPO_DIR" pull --rebase 2>/dev/null; then
|
||||||
echo "[mosaic-skills] WARN: pull failed — continuing with existing checkout" >&2
|
echo "[mosaic-skills] WARN: pull failed — continuing with existing checkout" >&2
|
||||||
fi
|
git -C "$SKILLS_REPO_DIR" rebase --abort 2>/dev/null || true
|
||||||
|
|
||||||
# Restore stashed changes
|
|
||||||
if [[ $local_changes -eq 1 ]]; then
|
|
||||||
echo "[mosaic-skills] Restoring local changes..."
|
|
||||||
git -C "$SKILLS_REPO_DIR" stash pop -q 2>/dev/null || \
|
|
||||||
echo "[mosaic-skills] WARN: stash pop had conflicts — check $SKILLS_REPO_DIR" >&2
|
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "[mosaic-skills] Cloning skills source to: $SKILLS_REPO_DIR"
|
echo "[mosaic-skills] Cloning skills source to: $SKILLS_REPO_DIR"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@mosaic/mosaic",
|
"name": "@mosaic/mosaic",
|
||||||
"version": "0.0.3-1",
|
"version": "0.0.10",
|
||||||
"description": "Mosaic agent framework — installation wizard and meta package",
|
"description": "Mosaic agent framework — installation wizard and meta package",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { readFileSync, existsSync } from 'node:fs';
|
import { readFileSync, existsSync, readdirSync, statSync, copyFileSync } from 'node:fs';
|
||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
import type { ConfigService } from './config-service.js';
|
import type { ConfigService } from './config-service.js';
|
||||||
import type { SoulConfig, UserConfig, ToolsConfig, InstallAction } from '../types.js';
|
import type { SoulConfig, UserConfig, ToolsConfig, InstallAction } from '../types.js';
|
||||||
@@ -140,6 +140,23 @@ export class FileConfigAdapter implements ConfigService {
|
|||||||
preserve: preservePaths,
|
preserve: preservePaths,
|
||||||
excludeGit: true,
|
excludeGit: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Copy default root-level .md files (AGENTS.md, STANDARDS.md, etc.)
|
||||||
|
// from framework/defaults/ into mosaicHome root if they don't exist yet.
|
||||||
|
// These are framework contracts — only written on first install, never
|
||||||
|
// overwritten (user may have customized them).
|
||||||
|
const defaultsDir = join(this.sourceDir, 'defaults');
|
||||||
|
if (existsSync(defaultsDir)) {
|
||||||
|
for (const entry of readdirSync(defaultsDir)) {
|
||||||
|
const dest = join(this.mosaicHome, entry);
|
||||||
|
if (!existsSync(dest)) {
|
||||||
|
const src = join(defaultsDir, entry);
|
||||||
|
if (statSync(src).isFile()) {
|
||||||
|
copyFileSync(src, dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
import { resolve } from 'node:path';
|
import { existsSync } from 'node:fs';
|
||||||
|
import { dirname, resolve } from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
import { Command } from 'commander';
|
import { Command } from 'commander';
|
||||||
@@ -49,7 +50,14 @@ program
|
|||||||
.action(async (opts: Record<string, string | boolean | undefined>) => {
|
.action(async (opts: Record<string, string | boolean | undefined>) => {
|
||||||
try {
|
try {
|
||||||
const mosaicHome = (opts['mosaicHome'] as string) ?? DEFAULT_MOSAIC_HOME;
|
const mosaicHome = (opts['mosaicHome'] as string) ?? DEFAULT_MOSAIC_HOME;
|
||||||
const sourceDir = (opts['sourceDir'] as string | undefined) ?? mosaicHome;
|
// Default source to the framework/ dir bundled in this npm package.
|
||||||
|
// This ensures syncFramework copies AGENTS.md, STANDARDS.md, guides/, etc.
|
||||||
|
// Falls back to mosaicHome if the bundled dir doesn't exist (shouldn't happen).
|
||||||
|
const pkgRoot = dirname(fileURLToPath(import.meta.url));
|
||||||
|
const bundledFramework = resolve(pkgRoot, '..', 'framework');
|
||||||
|
const sourceDir =
|
||||||
|
(opts['sourceDir'] as string | undefined) ??
|
||||||
|
(existsSync(bundledFramework) ? bundledFramework : mosaicHome);
|
||||||
|
|
||||||
const prompter = opts['nonInteractive'] ? new HeadlessPrompter() : new ClackPrompter();
|
const prompter = opts['nonInteractive'] ? new HeadlessPrompter() : new ClackPrompter();
|
||||||
|
|
||||||
|
|||||||
@@ -122,10 +122,18 @@ export function semverLt(a: string, b: string): boolean {
|
|||||||
|
|
||||||
// ─── Cache ──────────────────────────────────────────────────────────────────
|
// ─── Cache ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
function readCache(): UpdateCheckResult | null {
|
/** Cache stores only the latest registry version (the expensive network call).
|
||||||
|
* The installed version is always checked fresh — it's a local `npm ls`. */
|
||||||
|
interface RegistryCache {
|
||||||
|
latest: string;
|
||||||
|
checkedAt: string;
|
||||||
|
registry: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readCache(): RegistryCache | null {
|
||||||
try {
|
try {
|
||||||
if (!existsSync(CACHE_FILE)) return null;
|
if (!existsSync(CACHE_FILE)) return null;
|
||||||
const raw = JSON.parse(readFileSync(CACHE_FILE, 'utf-8')) as UpdateCheckResult;
|
const raw = JSON.parse(readFileSync(CACHE_FILE, 'utf-8')) as RegistryCache;
|
||||||
const age = Date.now() - new Date(raw.checkedAt).getTime();
|
const age = Date.now() - new Date(raw.checkedAt).getTime();
|
||||||
if (age > CACHE_TTL_MS) return null;
|
if (age > CACHE_TTL_MS) return null;
|
||||||
return raw;
|
return raw;
|
||||||
@@ -134,10 +142,10 @@ function readCache(): UpdateCheckResult | null {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeCache(result: UpdateCheckResult): void {
|
function writeCache(entry: RegistryCache): void {
|
||||||
try {
|
try {
|
||||||
mkdirSync(CACHE_DIR, { recursive: true });
|
mkdirSync(CACHE_DIR, { recursive: true });
|
||||||
writeFileSync(CACHE_FILE, JSON.stringify(result, null, 2) + '\n', 'utf-8');
|
writeFileSync(CACHE_FILE, JSON.stringify(entry, null, 2) + '\n', 'utf-8');
|
||||||
} catch {
|
} catch {
|
||||||
// Best-effort — cache is not critical
|
// Best-effort — cache is not critical
|
||||||
}
|
}
|
||||||
@@ -174,29 +182,40 @@ export function getLatestVersion(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform an update check — uses cache when fresh, otherwise hits registry.
|
* Perform an update check — uses registry cache when fresh, always checks
|
||||||
|
* installed version fresh (local npm ls is cheap, caching it causes stale
|
||||||
|
* "update available" banners after an upgrade).
|
||||||
* Never throws.
|
* Never throws.
|
||||||
*/
|
*/
|
||||||
export function checkForUpdate(options?: { skipCache?: boolean }): UpdateCheckResult {
|
export function checkForUpdate(options?: { skipCache?: boolean }): UpdateCheckResult {
|
||||||
|
const current = getInstalledVersion();
|
||||||
|
|
||||||
|
let latest: string;
|
||||||
|
let checkedAt: string;
|
||||||
|
|
||||||
if (!options?.skipCache) {
|
if (!options?.skipCache) {
|
||||||
const cached = readCache();
|
const cached = readCache();
|
||||||
if (cached) return cached;
|
if (cached) {
|
||||||
|
latest = cached.latest;
|
||||||
|
checkedAt = cached.checkedAt;
|
||||||
|
} else {
|
||||||
|
latest = getLatestVersion();
|
||||||
|
checkedAt = new Date().toISOString();
|
||||||
|
writeCache({ latest, checkedAt, registry: REGISTRY });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
latest = getLatestVersion();
|
||||||
|
checkedAt = new Date().toISOString();
|
||||||
|
writeCache({ latest, checkedAt, registry: REGISTRY });
|
||||||
}
|
}
|
||||||
|
|
||||||
const current = getInstalledVersion();
|
return {
|
||||||
const latest = getLatestVersion();
|
|
||||||
const updateAvailable = !!(current && latest && semverLt(current, latest));
|
|
||||||
|
|
||||||
const result: UpdateCheckResult = {
|
|
||||||
current,
|
current,
|
||||||
latest,
|
latest,
|
||||||
updateAvailable,
|
updateAvailable: !!(current && latest && semverLt(current, latest)),
|
||||||
checkedAt: new Date().toISOString(),
|
checkedAt,
|
||||||
registry: REGISTRY,
|
registry: REGISTRY,
|
||||||
};
|
};
|
||||||
|
|
||||||
writeCache(result);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@mosaic/quality-rails",
|
"name": "@mosaic/quality-rails",
|
||||||
"version": "0.0.2",
|
"version": "0.0.3",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
"test": "vitest run --passWithNoTests"
|
"test": "vitest run --passWithNoTests"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": "^12.0.0"
|
"commander": "^13.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^22.0.0",
|
"@types/node": "^22.0.0",
|
||||||
|
|||||||
@@ -106,12 +106,26 @@ function printScaffoldResult(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register quality-rails subcommands on an existing Commander program.
|
||||||
|
* This avoids cross-package Commander version mismatches by using the
|
||||||
|
* caller's Command instance directly.
|
||||||
|
*/
|
||||||
|
export function registerQualityRails(parent: Command): void {
|
||||||
|
buildQualityRailsCommand(
|
||||||
|
parent.command('quality-rails').description('Manage quality rails scaffolding'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function createQualityRailsCli(): Command {
|
export function createQualityRailsCli(): Command {
|
||||||
const program = new Command('mosaic');
|
const program = new Command('mosaic');
|
||||||
const qualityRails = program
|
buildQualityRailsCommand(
|
||||||
.command('quality-rails')
|
program.command('quality-rails').description('Manage quality rails scaffolding'),
|
||||||
.description('Manage quality rails scaffolding');
|
);
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildQualityRailsCommand(qualityRails: Command): void {
|
||||||
qualityRails
|
qualityRails
|
||||||
.command('init')
|
.command('init')
|
||||||
.requiredOption('--project <path>', 'Project path')
|
.requiredOption('--project <path>', 'Project path')
|
||||||
@@ -184,8 +198,6 @@ export function createQualityRailsCli(): Command {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return program;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function runQualityRailsCli(argv: string[] = process.argv): Promise<void> {
|
export async function runQualityRailsCli(argv: string[] = process.argv): Promise<void> {
|
||||||
|
|||||||
4
pnpm-lock.yaml
generated
4
pnpm-lock.yaml
generated
@@ -572,8 +572,8 @@ importers:
|
|||||||
packages/quality-rails:
|
packages/quality-rails:
|
||||||
dependencies:
|
dependencies:
|
||||||
commander:
|
commander:
|
||||||
specifier: ^12.0.0
|
specifier: ^13.0.0
|
||||||
version: 12.1.0
|
version: 13.1.0
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^22.0.0
|
specifier: ^22.0.0
|
||||||
|
|||||||
Reference in New Issue
Block a user