@galda/cli 0.10.71 → 0.10.72

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/app/index.html CHANGED
@@ -2120,6 +2120,12 @@
2120
2120
  /* the note is body prose like every other section's — same 14px / −.012em / --ink as
2121
2121
  .rbody (Masa 2026-07-22: it was a shade lighter and read as a different kind of text) */
2122
2122
  .redesign .ropen .v{margin:4px 0 0 !important}
2123
+ /* A malformed .manager-run.json advisory (goal #733, Masa 2026-07-26): plain
2124
+ danger-red text, no box — this must not read as calm/resolved like a normal
2125
+ note (Masa: "めっちゃdoneっぽい"). Same --danger token .prfail already uses
2126
+ for a blocked PR, so it speaks the SAME "needs your attention" language the
2127
+ app already has, rather than inventing a new one. */
2128
+ .redesign .ropen.rdeclerr .v{color:var(--danger) !important}
2123
2129
  /* sections — Linear-docs bold sentence-case headings + high-contrast body.
2124
2130
  margins are !important: the app's pre-existing .lg / .sa-item rules load first and
2125
2131
  otherwise tie/beat these on specificity, flattening the Linear-docs rhythm. */
@@ -6308,7 +6314,16 @@ const FS_ICONS = {
6308
6314
  // per-project count icons (HANDOFF-v45 §10): To Do = rounded square, Review = Scan
6309
6315
  // (magnifier) — both stroked, NEUTRAL ink (never green); shape is the only distinction.
6310
6316
  const FS_ICO_TD = '<svg class="pcg" viewBox="0 0 24 24"><rect x="5" y="5" width="14" height="14" rx="3.5"/></svg>';
6311
- const FS_ICO_SCAN = '<svg class="pcg" viewBox="0 0 24 24"><circle cx="10.5" cy="10.5" r="5.5"/><path d="M19 19l-4.5-4.5"/></svg>';
6317
+ // Eye, not magnifying glass or checkmark (Masa 2026-07-26): the magnifying-glass
6318
+ // read as "search". The first replacement — a square with a checkmark inside,
6319
+ // matching FS_ICO_TD's (To Do) frame — read as "done" instead ("あれ、これだと
6320
+ // めっちゃdoneっぽいわ"): a checkmark is universally a completion signal, and
6321
+ // pairing it with To Do's exact square made it worse, not better. An eye carries
6322
+ // neither "search" nor "done" — it says "look at this", which is what Review
6323
+ // actually is. Standard minimal eye glyph (outline + pupil), legible at the real
6324
+ // 11px render size (verified: a smaller pupil or added detail merges into a
6325
+ // blob at that size — this is the simplest shape that still reads as an eye).
6326
+ const FS_ICO_SCAN = '<svg class="pcg" viewBox="0 0 24 24"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>';
6312
6327
  // hover-only Reply / Edit / Delete on a To Do row (§1.5-10; flagship ACTS port)
6313
6328
  function fsActs(goalId){
6314
6329
  if (goalId == null || !state.goals.some((g) => g.id === goalId)) return '';
@@ -9177,6 +9192,15 @@ function saRowFromDigest(r, gs, ts){
9177
9192
  run: (() => {
9178
9193
  return latestGoalRunForOutcome(g?.id, ts, outcome);
9179
9194
  })(),
9195
+ // The worker DID try to declare something but it came out unusable (goal #733,
9196
+ // 2026-07-26: a Write followed by an Edit broke the JSON mid-edit; Review showed
9197
+ // no "Open it" section and no explanation, indistinguishable from "nothing to
9198
+ // run"). engine/server.mjs's readRunDeclaration sets task.runDeclError in that
9199
+ // case; only shown when there's no successful `run` to display instead.
9200
+ runDeclError: (() => {
9201
+ const t = ts.find((x) => r.goalIds.includes(x.goalId) && x.runDeclError);
9202
+ return t?.runDeclError ?? null;
9203
+ })(),
9180
9204
  // Explicit review-summary display fields (spec §11: the card's shape follows the
9181
9205
  // task). A goal's reviewSummary may carry them directly (e.g. a conversational task
9182
9206
  // that reports an Answer + its Activity, or a ticket whose test count / diff totals
@@ -9603,11 +9627,20 @@ function saItemHtml(it, i){
9603
9627
  // failure reason land after the press. Nothing declared → no section (§1.5-3). ──
9604
9628
  // it.run?.compare/title alone (no cmd/url) has nothing a press can start — a
9605
9629
  // compare-only or title-only declaration must not draw the "Start it" button.
9630
+ // it.runDeclError (2026-07-26, goal #733): the worker DID try to declare an
9631
+ // artifact/command, but .manager-run.json came out unusable (e.g. a Write then
9632
+ // an Edit broke the JSON mid-edit) — this must not look identical to "nothing
9633
+ // to run" (§1.5-3 no empty box still applies: don't invent a fake Open it, but
9634
+ // don't stay silent about a real attempt either). Same honest-advisory shape as
9635
+ // prRepairBody below. A reply is the repair path: the worker rewrites the file.
9636
+ const runDeclErrorBody = (!((it.run?.cmd || it.run?.url)) && it.runDeclError)
9637
+ ? `<div class="ropen rdeclerr"><p class="rbody v">${failureLang() === 'ja' ? 'AIが開けるものを用意しようとしましたが、記録が読み取れませんでした。返信して直させてください。' : 'The AI tried to declare something to open here, but the record was unreadable. Reply to have it rewritten.'}</p></div>`
9638
+ : '';
9606
9639
  const openBody = (it.run?.cmd || it.run?.url)
9607
9640
  ? `<div class="ropen" id="runlocal${i}"><button type="button" class="olink" data-saact="preview:${i}" id="prevlink${i}">${esc(it.run.url || 'Start it')}<span class="ar">↗</span></button><p class="rbody v">${esc(it.run.note || it.run.cmd || 'Starts when you press it.')}</p></div>`
9608
9641
  : it.pr
9609
9642
  ? `<div class="ropen"><a class="olink" href="${esc(it.pr)}" target="_blank" rel="noopener">${esc(it.pr)}<span class="ar">↗</span></a><p class="rbody v">Review and merge this pull request to finish the item.</p></div>`
9610
- : '';
9643
+ : runDeclErrorBody;
9611
9644
  const prRepairBody = it.goal?.prError
9612
9645
  ? `<div class="prfail"><b>${esc(it.goal.prRepair?.title || 'PR blocked')}</b> <span class="dim">${esc(it.goal.prError)}</span>${it.goal.prRepair?.steps?.length ? `<ul>${it.goal.prRepair.steps.map((s) => `<li>${esc(s)}</li>`).join('')}</ul>` : ''}${it.goal.prRepair?.dirtyFiles?.length ? `<div class="dim">dirty: ${it.goal.prRepair.dirtyFiles.map(esc).join(' · ')}</div>` : ''}<div class="acts2"><button class="errbtn" data-saact="retrypr:${i}">${failureLang() === 'ja' ? 'PR再試行' : 'Retry PR'}</button><button class="errbtn" data-saact="glog:${i}">${failureLang() === 'ja' ? 'ログ確認' : 'View log'}</button></div></div>`
9613
9646
  : '';
package/engine/lib.mjs CHANGED
@@ -3151,8 +3151,21 @@ export function workerPrompt(task, goal, lastFailure, agentName = 'claude-code',
3151
3151
  // (research, summaries, answers) simply skip this — the worker decides,
3152
3152
  // never us.
3153
3153
  `- 人が実際に動かして結果を見られる依頼なら、最後にプロジェクト直下へ ${RUN_DECL_FILE} を書く: {"cmd": "<起動コマンド>", "url": "<開くURL>", "note": "<何が見えるか1行>", "check": "<人に何を見て判断してほしいか1行>", "title": "<この作業のチケット名。対象が分かる程度に説明的で動作を含む短い名前。例「看板モードの追加」「ヘッダのズレの修正」。依頼文をそのまま写さない>"}。Manager はこれを使って人に「動かして見る」と「何を見ればいいか」を出す。動かして見せるものが無い依頼(調査・要約・質問への回答など)では書かなくてよい。`,
3154
+ // Root-cause prevention (goal #733, 2026-07-26): the worker Wrote this file,
3155
+ // then Edit'd it, and the edit broke the JSON mid-edit — Manager silently
3156
+ // dropped the whole declaration (fixed separately: it now surfaces an honest
3157
+ // note instead of vanishing). But the honest note is a recovery, not a fix —
3158
+ // the real fix is stopping the corruption before it happens. Edit requires an
3159
+ // exact byte-for-byte match against the file's current content; a small slip
3160
+ // (a stray character, a stale in-memory copy) breaks the JSON with no error
3161
+ // the worker would notice, because it happens in the tool call, not in
3162
+ // anything it reads back. Write overwrites the whole file atomically — there
3163
+ // is no "current content" to mismatch against — so telling the worker to
3164
+ // always fully overwrite rather than partially edit removes the failure mode
3165
+ // structurally, not just its symptom.
3166
+ `- ${RUN_DECL_FILE} は毎回 Write で全文を書き直すこと。Edit で一部だけ直さない(既存内容と一致しないと壊れたJSONになり、Managerに握りつぶされて人に何も表示されない)。`,
3154
3167
  `- Markdown・設計文書・調査メモなど文章そのものが成果物なら、${RUN_DECL_FILE} に別のHTMLや過去のURLを書かない。最終回答に成果物の本文も貼り、保存先のMarkdownリンクを添えること。「ファイルに書きました」だけで終わらない。`,
3155
- `- 「ローカルで見れない」というフィードバックには、ターミナル操作や npx の再実行を案内して終わらないこと。${RUN_DECL_FILE} を実際に開ける内容へ更新し、可能なら自分でURLへ接続確認してから完了すること。`,
3168
+ `- 「ローカルで見れない」というフィードバックには、ターミナル操作や npx の再実行を案内して終わらないこと。${RUN_DECL_FILE} を Write で全文書き直して実際に開ける内容へ更新し、可能なら自分でURLへ接続確認してから完了すること。`,
3156
3169
  // Links are rendered as links. The product cannot tell a real one from a
3157
3170
  // decorative one, so the only place this can be held is here.
3158
3171
  `- 自分が作っていない場所へのリンクを報告に書かない(存在しないURLや「詳しくはここ」のような飾りのリンクは、そのままリンクとして人に表示される)。`,
package/engine/server.mjs CHANGED
@@ -2407,7 +2407,18 @@ function readRunDeclaration(task, workDir) {
2407
2407
  try { unlinkSync(file); } catch { /* best effort — never fail a task over cleanup */ }
2408
2408
  const run = parseRunDeclaration(raw);
2409
2409
  if (!run) {
2410
- sendAct(task, `run declaration ignored ${RUN_DECL_FILE} was not usable JSON`);
2410
+ // The worker DID try to declare something (the file exists) but it came out
2411
+ // unusable — e.g. a Write followed by an Edit that broke the JSON mid-edit
2412
+ // (goal #733, 2026-07-26: Masa saw a working artifact with no "Open it" and
2413
+ // no explanation at all — the Review card just silently had no section,
2414
+ // indistinguishable from "nothing to run"). Silence was already the honest
2415
+ // answer for a request with nothing to run; it stops being honest the moment
2416
+ // a declaration was attempted and swallowed. Keep a short snippet of what was
2417
+ // actually written (raw content is deleted above and never otherwise
2418
+ // recoverable) so both the activity log and the Review card can say WHY,
2419
+ // instead of the human having to guess or dig through file loss.
2420
+ task.runDeclError = { snippet: String(raw ?? '').slice(0, 200) };
2421
+ sendAct(task, `run declaration ignored — ${RUN_DECL_FILE} was not usable JSON: ${task.runDeclError.snippet.slice(0, 80)}`);
2411
2422
  return;
2412
2423
  }
2413
2424
  task.run = { ...run, dir: workDir };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@galda/cli",
3
- "version": "0.10.71",
3
+ "version": "0.10.72",
4
4
  "type": "module",
5
5
  "description": "Galda - hand off work to Claude Code or Codex, get proof back. Runs on your existing subscription, no extra API cost.",
6
6
  "scripts": {