idea-manager 0.9.2 → 0.9.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "idea-manager",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
4
4
  "description": "AI 기반 브레인스토밍 → 구조화 → 프롬프트 생성 도구. MCP Server 내장.",
5
5
  "keywords": [
6
6
  "brainstorm",
package/src/cli.ts CHANGED
@@ -11,9 +11,15 @@ import { spawn } from 'child_process';
11
11
  import path from 'path';
12
12
  import { fileURLToPath } from 'url';
13
13
 
14
- const __filename = fileURLToPath(import.meta.url);
15
- const __dirname = path.dirname(__filename);
16
- const PKG_ROOT = path.resolve(__dirname, '..');
14
+ // Resolve PKG_ROOT robustly across macOS/Windows and tsx/cjs context
15
+ let PKG_ROOT: string;
16
+ try {
17
+ const thisFile = fileURLToPath(import.meta.url);
18
+ PKG_ROOT = path.resolve(path.dirname(thisFile), '..');
19
+ } catch {
20
+ // Fallback for CJS context (tsx/cjs on some Windows setups)
21
+ PKG_ROOT = path.resolve(__dirname, '..');
22
+ }
17
23
 
18
24
  async function openAsApp(url: string) {
19
25
  const { exec: execCb } = await import('child_process');
@@ -29,8 +35,8 @@ async function openAsApp(url: string) {
29
35
  ]
30
36
  : platform === 'win32'
31
37
  ? [
32
- `start "" chrome --app=${url}`,
33
- `start "" msedge --app=${url}`,
38
+ `start "" "chrome" "--app=${url}"`,
39
+ `start "" "msedge" "--app=${url}"`,
34
40
  ]
35
41
  : [
36
42
  `google-chrome --app=${url}`,
@@ -124,11 +130,29 @@ program
124
130
  process.exit(1);
125
131
  });
126
132
 
127
- setTimeout(async () => {
128
- try {
129
- await openAsApp(`http://localhost:${port}`);
130
- } catch { /* ignore */ }
131
- }, 3000);
133
+ // Wait for server to be ready, then open browser
134
+ const waitAndOpen = async () => {
135
+ const url = `http://localhost:${port}`;
136
+ for (let i = 0; i < 30; i++) {
137
+ try {
138
+ await new Promise<void>((resolve, reject) => {
139
+ const http = require('http');
140
+ const req = http.get(url, (res: { statusCode: number }) => {
141
+ if (res.statusCode === 200) resolve();
142
+ else reject();
143
+ });
144
+ req.on('error', reject);
145
+ req.setTimeout(1000, () => { req.destroy(); reject(); });
146
+ });
147
+ // Server is ready
148
+ await openAsApp(url);
149
+ return;
150
+ } catch {
151
+ await new Promise(r => setTimeout(r, 1000));
152
+ }
153
+ }
154
+ };
155
+ waitAndOpen().catch(() => {});
132
156
 
133
157
  process.on('SIGINT', () => { child.kill(); process.exit(0); });
134
158
  process.on('SIGTERM', () => { child.kill(); process.exit(0); });
@@ -4,10 +4,12 @@ import path from 'path';
4
4
 
5
5
  function quoteArg(arg: string): string {
6
6
  // Quote args with spaces for shell mode
7
- if (arg.includes(' ') || arg.includes('"')) {
8
- return `"${arg.replace(/"/g, '\\"')}"`;
7
+ if (!arg.includes(' ') && !arg.includes('"')) return arg;
8
+ if (process.platform === 'win32') {
9
+ // cmd.exe uses "" to escape quotes
10
+ return `"${arg.replace(/"/g, '""')}"`;
9
11
  }
10
- return arg;
12
+ return `"${arg.replace(/"/g, '\\"')}"`;
11
13
  }
12
14
 
13
15
  function exec(cmd: string, args: string[], cwd?: string): Promise<string> {
@@ -78,21 +78,31 @@ export async function syncInit() {
78
78
  }
79
79
  }
80
80
 
81
- // Clean sync dir and clone
81
+ // Clone into a temp dir, then move contents to sync dir
82
82
  console.log(`\n Cloning to ${syncDir}...`);
83
+ const tmpCloneDir = syncDir + '-tmp-' + Date.now();
84
+ let cloned = false;
85
+
83
86
  try {
84
- // Remove sync dir contents (keep the dir itself)
85
- const entries = fs.readdirSync(syncDir);
86
- for (const e of entries) {
87
+ await git.gitClone(repoUrl, tmpCloneDir);
88
+ // Move contents from tmp to sync dir
89
+ const entries = fs.readdirSync(tmpCloneDir, { withFileTypes: true });
90
+ // Clean sync dir first
91
+ for (const e of fs.readdirSync(syncDir)) {
87
92
  fs.rmSync(path.join(syncDir, e), { recursive: true, force: true });
88
93
  }
89
-
90
- await git.gitClone(repoUrl, syncDir);
94
+ for (const e of entries) {
95
+ fs.renameSync(path.join(tmpCloneDir, e.name), path.join(syncDir, e.name));
96
+ }
97
+ fs.rmSync(tmpCloneDir, { recursive: true, force: true });
98
+ cloned = true;
91
99
  } catch {
92
- // Clone into existing empty dir — init + add remote instead
100
+ // Clone failed — init locally + add remote
101
+ fs.rmSync(tmpCloneDir, { recursive: true, force: true });
93
102
  try {
94
103
  await git.gitInit(syncDir);
95
104
  await git.gitAddRemote(syncDir, repoUrl);
105
+ cloned = true;
96
106
  } catch (err2) {
97
107
  console.error(` Failed: ${(err2 as Error).message}\n`);
98
108
  process.exit(1);