@happy-nut/monacori 0.1.25 → 0.1.26
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/app-main.js +16 -28
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +3 -0
- package/dist/diff.js +9 -1
- package/dist/i18n.js +12 -6
- package/dist/render.js +3 -1
- package/dist/self-update.d.ts +8 -0
- package/dist/self-update.js +18 -0
- package/dist/viewer.client.js +470 -14
- package/dist/viewer.client.min.js +1 -1
- package/dist/viewer.css +16 -9
- package/package.json +1 -1
- package/scripts/patch-electron-name.mjs +76 -26
package/dist/app-main.js
CHANGED
|
@@ -9,13 +9,15 @@ import { readGitLog, readCommitDiff } from "./git-log.js";
|
|
|
9
9
|
import { readUnifiedDiff } from "./diff.js";
|
|
10
10
|
import { isGitRepository } from "./git.js";
|
|
11
11
|
import { renderWelcomeHtml } from "./render.js";
|
|
12
|
+
import { relaunchUpdatedApp } from "./self-update.js";
|
|
12
13
|
import { createHash } from "node:crypto";
|
|
13
14
|
import { spawn as spawnPty } from "node-pty";
|
|
14
15
|
// `npm run dev` sets MONACORI_DEV=1 so a locally-built app announces itself — a window-title suffix
|
|
15
16
|
// plus a boot log with its on-disk path — making it obvious whether `mo` launched THIS checkout or
|
|
16
17
|
// the globally-installed package (their version numbers can be identical; the path is the tell).
|
|
17
18
|
const DEV_BUILD = process.env.MONACORI_DEV === "1";
|
|
18
|
-
const
|
|
19
|
+
const APP_NAME = "Monacori";
|
|
20
|
+
const APP_TITLE = DEV_BUILD ? `${APP_NAME} (dev)` : APP_NAME;
|
|
19
21
|
const FLOW_DIR = ".monacori";
|
|
20
22
|
const REVIEW_FILE = "app-review.html";
|
|
21
23
|
const WATCH_INTERVAL_MS = 1000;
|
|
@@ -46,12 +48,13 @@ function isLightTheme() {
|
|
|
46
48
|
return false;
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
|
-
app.setName(
|
|
51
|
+
app.setName(APP_NAME);
|
|
50
52
|
// Best-effort re-brand at startup. macOS shows the Dock / Cmd+Tab / menu-bar name from Electron.app's
|
|
51
|
-
// CFBundleName
|
|
52
|
-
// (run at postinstall)
|
|
53
|
-
// perms, leaving "Electron" everywhere. Re-run the patch here in a
|
|
54
|
-
// fresh install self-heals; it's idempotent and takes effect on the
|
|
53
|
+
// bundle directory, LaunchServices id, CFBundleName, and executable name, which app.setName() CANNOT change.
|
|
54
|
+
// scripts/patch-electron-name.mjs (run at postinstall) patches those on disk. That postinstall step can be
|
|
55
|
+
// skipped (npm --ignore-scripts) or fail on perms, leaving "Electron" everywhere. Re-run the patch here in a
|
|
56
|
+
// Node context (ELECTRON_RUN_AS_NODE) so a fresh install self-heals; it's idempotent and takes effect on the
|
|
57
|
+
// NEXT launch.
|
|
55
58
|
if (process.platform === "darwin") {
|
|
56
59
|
try {
|
|
57
60
|
const patchScript = join(dirname(fileURLToPath(import.meta.url)), "..", "scripts", "patch-electron-name.mjs");
|
|
@@ -208,32 +211,17 @@ ipcMain.handle("monacori:self-update", (event) => new Promise((resolve) => {
|
|
|
208
211
|
return;
|
|
209
212
|
}
|
|
210
213
|
resolve({ ok: true });
|
|
211
|
-
// The global install replaced our on-disk dist, so THIS process is stale.
|
|
212
|
-
//
|
|
213
|
-
//
|
|
214
|
-
// `mo` spawn under detached/unref went unnoticed and the app just exited without relaunching).
|
|
214
|
+
// The global install replaced our on-disk dist, so THIS process is stale. Use Electron's native relaunch
|
|
215
|
+
// path instead of shelling out to `mo`: GUI apps often have a thin PATH, and a detached shell can fail
|
|
216
|
+
// without a reliable event before our exit timer fires.
|
|
215
217
|
setTimeout(() => {
|
|
216
|
-
let done = false;
|
|
217
|
-
const relaunch = () => { if (done)
|
|
218
|
-
return; done = true; try {
|
|
219
|
-
app.relaunch();
|
|
220
|
-
}
|
|
221
|
-
catch { /* nothing else to try */ } app.exit(0); };
|
|
222
218
|
try {
|
|
223
|
-
|
|
224
|
-
c.on("error", relaunch);
|
|
225
|
-
c.on("exit", (exitCode) => { if (exitCode && exitCode !== 0)
|
|
226
|
-
relaunch(); });
|
|
227
|
-
c.unref();
|
|
228
|
-
setTimeout(() => { if (!done) {
|
|
229
|
-
done = true;
|
|
230
|
-
app.exit(0);
|
|
231
|
-
} }, 800); // `mo` launched fine -> hand off and exit
|
|
219
|
+
relaunchUpdatedApp(app, process.argv, cwd);
|
|
232
220
|
}
|
|
233
|
-
catch {
|
|
234
|
-
relaunch();
|
|
221
|
+
catch (error) {
|
|
222
|
+
console.error("monacori: update installed, but relaunch failed: " + (error instanceof Error ? error.message : String(error)));
|
|
235
223
|
}
|
|
236
|
-
},
|
|
224
|
+
}, 250);
|
|
237
225
|
});
|
|
238
226
|
}));
|
|
239
227
|
// Integrated terminal: own node-pty sessions in the main process (the sandboxed renderer can't spawn
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export declare const FLOW_DIR = ".monacori";
|
|
2
2
|
export declare const GITIGNORE_FILE = ".gitignore";
|
|
3
|
+
export declare const PLAN_FILE = "plan.md";
|
|
3
4
|
export declare const CONFIG_FILE = "config.json";
|
|
4
5
|
export declare const STATE_FILE = "state.md";
|
|
5
6
|
export declare const DECISIONS_FILE = "decisions.md";
|
package/dist/constants.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export const FLOW_DIR = ".monacori";
|
|
2
2
|
export const GITIGNORE_FILE = ".gitignore";
|
|
3
|
+
// The agent's implementation plan, written under FLOW_DIR. Force-surfaced as a source file so it renders
|
|
4
|
+
// as Markdown, shows in Quick Open, and takes line comments — even though FLOW_DIR is gitignored.
|
|
5
|
+
export const PLAN_FILE = "plan.md";
|
|
3
6
|
export const CONFIG_FILE = "config.json";
|
|
4
7
|
export const STATE_FILE = "state.md";
|
|
5
8
|
export const DECISIONS_FILE = "decisions.md";
|
package/dist/diff.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
2
|
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
3
3
|
import { basename, join } from "node:path";
|
|
4
|
-
import { FLOW_DIR, IMAGE_MAX_BYTES, SOURCE_MAX_FILE_BYTES, SOURCE_MAX_FILES, SOURCE_MAX_TOTAL_BYTES } from "./constants.js";
|
|
4
|
+
import { FLOW_DIR, IMAGE_MAX_BYTES, PLAN_FILE, SOURCE_MAX_FILE_BYTES, SOURCE_MAX_FILES, SOURCE_MAX_TOTAL_BYTES } from "./constants.js";
|
|
5
5
|
import { formatBytes, hashText, isLikelyBinary, languageForPath, stripDiffPath } from "./util.js";
|
|
6
6
|
import { git, repoRoot } from "./git.js";
|
|
7
7
|
// File content + signature cache, keyed by path and validated on (mtime, size). Under `watch` the app
|
|
@@ -251,6 +251,14 @@ export function collectSourceFiles(diffFiles, rootArg) {
|
|
|
251
251
|
paths.add(path);
|
|
252
252
|
}
|
|
253
253
|
}
|
|
254
|
+
// The agent's plan lives under the gitignored FLOW_DIR, so neither `git ls-files --exclude-standard` nor
|
|
255
|
+
// isSourceCandidate (which excludes FLOW_DIR) ever surfaces it. Force-include it when present so the plan
|
|
256
|
+
// shows up as a normal source file — rendered as Markdown, searchable in Quick Open, and commentable. The
|
|
257
|
+
// watch re-runs this every tick, so a plan written after launch appears on the next refresh.
|
|
258
|
+
const planRel = `${FLOW_DIR}/${PLAN_FILE}`;
|
|
259
|
+
if (existsSync(join(root, planRel))) {
|
|
260
|
+
paths.add(planRel);
|
|
261
|
+
}
|
|
254
262
|
const sourceFiles = [];
|
|
255
263
|
let embeddedFiles = 0;
|
|
256
264
|
let embeddedBytes = 0;
|
package/dist/i18n.js
CHANGED
|
@@ -147,7 +147,8 @@ export const MESSAGES = {
|
|
|
147
147
|
"kbd.closeTerminal": "Close terminal (when focused)",
|
|
148
148
|
// Settings — Merge prompts
|
|
149
149
|
"mergePrompts.title": "Merge prompts",
|
|
150
|
-
"mergePrompts.desc": "
|
|
150
|
+
"mergePrompts.desc": "Headings prepended to the prompts you send to the agent. The plan contract is prepended to change requests (⌘⇧.) and to the prompt memo. Leave any field blank to use the default.",
|
|
151
|
+
"mergePrompts.planHeading": "Plan contract (change requests + memo)",
|
|
151
152
|
"mergePrompts.qHeading": "Questions heading",
|
|
152
153
|
"mergePrompts.cHeading": "Change-requests heading",
|
|
153
154
|
"mergePrompts.reset": "Reset to defaults",
|
|
@@ -159,8 +160,8 @@ export const MESSAGES = {
|
|
|
159
160
|
"composer.cancel": "Cancel",
|
|
160
161
|
"composer.hint": "⌘Enter to save, Esc to cancel",
|
|
161
162
|
"composer.delete": "Delete",
|
|
162
|
-
"comment.kind.q": "
|
|
163
|
-
"comment.kind.c": "
|
|
163
|
+
"comment.kind.q": "Question",
|
|
164
|
+
"comment.kind.c": "Change request",
|
|
164
165
|
"badge.questions": "question(s)",
|
|
165
166
|
"badge.changeRequests": "change request(s)",
|
|
166
167
|
// Merged comments modal
|
|
@@ -182,6 +183,8 @@ export const MESSAGES = {
|
|
|
182
183
|
// Merge-prompt default agent contracts (these follow the locale — a Korean user gets Korean defaults)
|
|
183
184
|
"mergePrompt.default.q": "The following are questions about code you just wrote. Answer each one — explain the intent, rationale, or context. Do not change any code; this clarifies understanding before any revisions.",
|
|
184
185
|
"mergePrompt.default.c": "The following are change requests for code you just wrote. For each, edit the code at the quoted location to satisfy the request. Keep changes minimal and focused; do not make unrelated edits.",
|
|
186
|
+
// Plan contract — prepended to change requests and the prompt memo so every task starts with a small, verifiable plan written to a file.
|
|
187
|
+
"plan.contract": "Before changing any code, write a short implementation PLAN to `.monacori/plan.md` as Markdown. Break the work into small, independently verifiable steps — each with a one-line check for how you'll confirm it works. Get the plan right first, then implement one step at a time, keeping each step small enough to review on its own.",
|
|
185
188
|
},
|
|
186
189
|
ko: {
|
|
187
190
|
// Tabs (sidebar)
|
|
@@ -320,7 +323,8 @@ export const MESSAGES = {
|
|
|
320
323
|
"kbd.closeTerminal": "터미널 닫기 (포커스 시)",
|
|
321
324
|
// Settings — Merge prompts
|
|
322
325
|
"mergePrompts.title": "병합 프롬프트",
|
|
323
|
-
"mergePrompts.desc": "
|
|
326
|
+
"mergePrompts.desc": "에이전트에게 보내는 프롬프트 맨 앞에 붙는 머리말입니다. 플랜 계약문은 변경요청(⌘⇧.)과 프롬프트 메모 앞에 붙습니다. 각 칸을 비워 두면 기본값을 사용합니다.",
|
|
327
|
+
"mergePrompts.planHeading": "플랜 계약문 (변경요청 + 메모)",
|
|
324
328
|
"mergePrompts.qHeading": "질문 머리말",
|
|
325
329
|
"mergePrompts.cHeading": "변경요청 머리말",
|
|
326
330
|
"mergePrompts.reset": "기본값으로 초기화",
|
|
@@ -332,8 +336,8 @@ export const MESSAGES = {
|
|
|
332
336
|
"composer.cancel": "취소",
|
|
333
337
|
"composer.hint": "⌘Enter로 저장, Esc로 취소",
|
|
334
338
|
"composer.delete": "삭제",
|
|
335
|
-
"comment.kind.q": "
|
|
336
|
-
"comment.kind.c": "
|
|
339
|
+
"comment.kind.q": "질문",
|
|
340
|
+
"comment.kind.c": "변경 요청",
|
|
337
341
|
"badge.questions": "개 질문",
|
|
338
342
|
"badge.changeRequests": "개 변경 요청",
|
|
339
343
|
// Merged comments modal
|
|
@@ -356,5 +360,7 @@ export const MESSAGES = {
|
|
|
356
360
|
// Merge-prompt default agent contracts (Korean default for Korean users)
|
|
357
361
|
"mergePrompt.default.q": "다음은 방금 작성한 코드에 대한 질문입니다. 각 질문에 답하면서 의도, 근거, 맥락을 설명하세요. 코드는 변경하지 마세요. 이 단계는 수정에 앞서 이해를 명확히 하기 위한 것입니다.",
|
|
358
362
|
"mergePrompt.default.c": "다음은 방금 작성한 코드에 대한 변경 요청입니다. 각 요청에 대해 인용된 위치의 코드를 수정하여 요구사항을 충족하세요. 변경은 최소한으로 집중해서 하고, 관련 없는 수정은 하지 마세요.",
|
|
363
|
+
// 플랜 계약문 — 모든 작업이 파일로 작성된 작고 검증 가능한 플랜에서 시작하도록 변경요청과 프롬프트 메모 앞에 붙는다.
|
|
364
|
+
"plan.contract": "코드를 변경하기 전에, 먼저 `.monacori/plan.md`에 마크다운으로 짧은 구현 플랜을 작성하세요. 작업을 독립적으로 검증 가능한 작은 단계로 쪼개고, 각 단계마다 어떻게 확인할지 한 줄짜리 검증 기준을 적으세요. 플랜이 맞는지 먼저 확정한 뒤 한 번에 한 단계씩 구현하고, 각 단계는 따로 리뷰할 수 있을 만큼 작게 유지하세요.",
|
|
359
365
|
},
|
|
360
366
|
};
|
package/dist/render.js
CHANGED
|
@@ -356,7 +356,9 @@ export function renderDiffHtml(input) {
|
|
|
356
356
|
"</section>",
|
|
357
357
|
'<section class="settings-section hidden" data-cat="prompts">',
|
|
358
358
|
'<div class="settings-h" data-i18n="mergePrompts.title">Merge prompts</div>',
|
|
359
|
-
'<div class="settings-desc" data-i18n="mergePrompts.desc">
|
|
359
|
+
'<div class="settings-desc" data-i18n="mergePrompts.desc">Headings prepended to the prompts you send to the agent. The plan contract is prepended to change requests (⌘⇧.) and to the prompt memo. Leave any field blank to use the default.</div>',
|
|
360
|
+
'<label class="settings-label" for="settings-prompt-plan" data-i18n="mergePrompts.planHeading">Plan contract (change requests + memo)</label>',
|
|
361
|
+
'<textarea id="settings-prompt-plan" class="settings-textarea" rows="5" spellcheck="false"></textarea>',
|
|
360
362
|
'<label class="settings-label" for="settings-prompt-q" data-i18n="mergePrompts.qHeading">Questions heading</label>',
|
|
361
363
|
'<textarea id="settings-prompt-q" class="settings-textarea" rows="4" spellcheck="false"></textarea>',
|
|
362
364
|
'<label class="settings-label" for="settings-prompt-c" data-i18n="mergePrompts.cHeading">Change-requests heading</label>',
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type RelaunchTarget = {
|
|
2
|
+
relaunch(options?: {
|
|
3
|
+
args?: string[];
|
|
4
|
+
}): void;
|
|
5
|
+
exit(exitCode?: number): void;
|
|
6
|
+
};
|
|
7
|
+
export declare function relaunchArgsForCwd(argv: string[], cwd: string): string[];
|
|
8
|
+
export declare function relaunchUpdatedApp(app: RelaunchTarget, argv: string[], cwd: string): void;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function relaunchArgsForCwd(argv, cwd) {
|
|
2
|
+
const args = argv.slice(1);
|
|
3
|
+
const cwdIndex = args.indexOf("--cwd");
|
|
4
|
+
if (cwdIndex >= 0) {
|
|
5
|
+
if (cwdIndex === args.length - 1)
|
|
6
|
+
args.push(cwd);
|
|
7
|
+
else
|
|
8
|
+
args[cwdIndex + 1] = cwd;
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
args.push("--cwd", cwd);
|
|
12
|
+
}
|
|
13
|
+
return args;
|
|
14
|
+
}
|
|
15
|
+
export function relaunchUpdatedApp(app, argv, cwd) {
|
|
16
|
+
app.relaunch({ args: relaunchArgsForCwd(argv, cwd) });
|
|
17
|
+
app.exit(0);
|
|
18
|
+
}
|