Astra v2.2.52

- 채팅 기록 목록 누락 수정: 후처리 예외로 _saveCurrentSession 이 건너뛰던 회귀를
  try/finally 로 보장, _saveCurrentSession 자체도 throw 방지. 1인 기업 모드 업무
  턴(_runCompanyTurn)도 요청/보고서 쌍으로 기록 (_saveCompanyTurnSession).
- Self-Reflector 실행 검증 크로스플랫폼화: .py 는 python3 자동 탐지, .ts 는 로컬
  node_modules/typescript/bin/tsc 직접 호출.
- 버전 2.2.52 상향 + package-lock 동기화 + 재패키징.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
g1nation
2026-05-20 23:48:39 +09:00
parent eeb527c242
commit dea5953f59
11 changed files with 173 additions and 33 deletions
@@ -8,7 +8,7 @@
* 1. action-tag executor가 반환한 report를 받아 `✅ Created: <path>` /
* `✅ Edited: <path>` 항목에서 경로를 추출
* 2. 파일 확장자별 toolchain 선택:
* .py → `python -m py_compile <path>`
* .py → `python3 -m py_compile <path>` (`python` on Windows)
* .js / .mjs / .cjs → `node --check <path>`
* .ts / .tsx → 프로젝트 단위 `tsc --noEmit` (단일 파일 체크는 의존성 때문에 실패율 높음)
* .json → `JSON.parse` (node)
@@ -21,7 +21,7 @@
* - 워크스페이스 외부 경로 무시
* - 사용자가 `executionVerification=false`면 통째로 skip — 호출자가 가드
*/
import { spawn } from 'child_process';
import { spawn, spawnSync } from 'child_process';
import * as path from 'path';
import * as fs from 'fs';
import { logError, logInfo } from '../../utils';
@@ -76,11 +76,40 @@ function _firstNonEmptyLine(s: string): string {
return (s || '').split(/\r?\n/).map((x) => x.trim()).find((x) => x.length > 0) ?? '';
}
/**
* Resolve the Python executable name once and cache it.
*
* macOS 12.3+ removed the bare `/usr/bin/python`; it ships `python3` only.
* Windows installers, conversely, expose `python` (and often no `python3`).
* So probe the platform-preferred name first, fall back to the other.
*
* Returns the platform-preferred default when neither is found so the caller
* still produces the usual "미설치" warning via the spawn-failure path.
*/
let _pythonCmdCache: string | undefined;
function _resolvePythonCmd(): string {
if (_pythonCmdCache !== undefined) return _pythonCmdCache;
const candidates = process.platform === 'win32'
? ['python', 'python3']
: ['python3', 'python'];
for (const cmd of candidates) {
try {
const r = spawnSync(cmd, ['--version'], { stdio: 'ignore', windowsHide: true });
if (!r.error && (r.status === 0 || r.status === null)) {
_pythonCmdCache = cmd;
return cmd;
}
} catch { /* try next candidate */ }
}
_pythonCmdCache = candidates[0];
return _pythonCmdCache;
}
/** 확장자별 검사 명령 결정. 지원 안 하는 확장자면 null 반환 (skip). */
function _pickTool(absPath: string, projectRoot: string): { cmd: string; args: string[]; cwd: string; label: string } | null {
const ext = path.extname(absPath).toLowerCase();
if (ext === '.py') {
return { cmd: 'python', args: ['-m', 'py_compile', absPath], cwd: projectRoot, label: 'py_compile' };
return { cmd: _resolvePythonCmd(), args: ['-m', 'py_compile', absPath], cwd: projectRoot, label: 'py_compile' };
}
if (ext === '.js' || ext === '.mjs' || ext === '.cjs') {
return { cmd: 'node', args: ['--check', absPath], cwd: projectRoot, label: 'node --check' };
@@ -99,8 +128,14 @@ function _pickTool(absPath: string, projectRoot: string): { cmd: string; args: s
// 비용은 더 크지만 실제 사용자 환경에서 의미 있는 결과를 낸다.
const tsconfig = path.join(projectRoot, 'tsconfig.json');
if (!fs.existsSync(tsconfig)) return null;
// `npx` is a `.cmd` shim on Windows and won't spawn under shell:false,
// so invoke the TypeScript compiler's plain-JS bin script via `node`
// directly — identical behavior on macOS, Linux and Windows. If the
// project has no local typescript install there is nothing to run.
const tscBin = path.join(projectRoot, 'node_modules', 'typescript', 'bin', 'tsc');
if (!fs.existsSync(tscBin)) return null;
return {
cmd: 'npx', args: ['--no-install', 'tsc', '--noEmit', '-p', tsconfig],
cmd: 'node', args: [tscBin, '--noEmit', '-p', tsconfig],
cwd: projectRoot, label: 'tsc --noEmit',
};
}