@galda/cli 0.10.88 → 0.10.89
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/CLAUDE.md +2 -0
- package/app/index.html +26 -14
- package/engine/lib.mjs +11 -4
- package/package.json +1 -1
package/CLAUDE.md
CHANGED
|
@@ -105,6 +105,8 @@
|
|
|
105
105
|
- Worker/API へは**必ず所有ドメイン `https://galda.app`(custom domain)経由**で参照する。`*.workers.dev` サブドメインを製品コードに焼き込まない(`MANAGER_BILLING_API_URL` 等の既定値は `https://galda.app`)。
|
|
106
106
|
- **Cloudflare/wrangler にデプロイする前に `wrangler whoami` でデプロイ先アカウントを確認**し、Galda/Kodo 所有であること・workers.dev サブドメイン名に客先名や別プロジェクト名が出ていないことを確かめる。怪しければ止めて Masa に確認(本番デプロイは Masa 明示許可制)。
|
|
107
107
|
- **リリースは4面**(① npm ② Fly ③ Worker ④ Masaの常駐インスタンス `~/manager-for-ai`:4400)。①だけ出して④を忘れると「直したのに直ってない」+relay相互kickループ再発の実例あり(2026-07-16/17)。全文=`docs/RELEASE-WORKFLOW.md`の「本番は1つじゃない」表。
|
|
108
|
+
- **常駐Managerを直接 `kill`/`launchctl kickstart -k` しない**(2026-07-28、実行中3 workerを同時中断した実例)。再起動は対象checkoutで
|
|
109
|
+
`node tools/safe-restart-manager.mjs` を使う。このコマンドはDoing/Finalizingが1件でもあれば拒否する。拒否時は完了を待って再実行し、Agent切替で回避しない。
|
|
108
110
|
|
|
109
111
|
## relay接続(`app.galda.app`)を伴う作業の掟(Masa明言 2026-07-17・全レーン必読)
|
|
110
112
|
|
package/app/index.html
CHANGED
|
@@ -1558,6 +1558,14 @@
|
|
|
1558
1558
|
line-height:1.15;padding:2.5px 10px;border-radius:7px;box-shadow:inset 0 0 0 1px var(--hair2)}
|
|
1559
1559
|
#fsRoot .acts2 .errbtn:first-child{color:var(--ink2)}
|
|
1560
1560
|
#fsRoot .errbtn:hover{background:var(--hover);color:var(--ink)}
|
|
1561
|
+
/* The review/attention dialog is rendered in #seeall, outside #fsRoot.
|
|
1562
|
+
Keep its recovery actions on the same designed component instead of
|
|
1563
|
+
falling back to the browser's unstyled native button. */
|
|
1564
|
+
#seeall .acts2{display:flex;gap:6px;margin-top:3px;align-items:center}
|
|
1565
|
+
#seeall .errbtn{border:0;background:transparent;color:var(--ink3);font-family:var(--mono);font-size:10px;letter-spacing:.02em;cursor:pointer;
|
|
1566
|
+
line-height:1.15;padding:2.5px 10px;border-radius:7px;box-shadow:inset 0 0 0 1px var(--hair2)}
|
|
1567
|
+
#seeall .acts2 .errbtn:first-child{color:var(--ink2)}
|
|
1568
|
+
#seeall .errbtn:hover{background:var(--hover);color:var(--ink)}
|
|
1561
1569
|
/* AI question in the feed (q2 — §6.5: while current it lives in the chat feed).
|
|
1562
1570
|
H18 / CDO HANDOFF-question-ui-2026-07-13: QUESTION card = hairline frame +
|
|
1563
1571
|
2px --blue left rule + mono label + option chips + an always-on free-text
|
|
@@ -7189,6 +7197,7 @@ const FAILURE_COPY = {
|
|
|
7189
7197
|
infra: {
|
|
7190
7198
|
title: 'Galda基盤エラー',
|
|
7191
7199
|
timeout: 'Galda側の実行上限や待ち時間で止まりました。変更内容の失敗とは限りません。',
|
|
7200
|
+
interrupted: 'ローカルの実行が中断されました。変更内容やAgentの失敗とは限らないため、同じ作業を再開できます。',
|
|
7192
7201
|
auth: '接続や認証確認で止まりました。接続を直してから再開できます。',
|
|
7193
7202
|
relay: 'relay接続で止まりました。接続状態を確認してから再試行できます。',
|
|
7194
7203
|
chrome: 'Chrome/ブラウザ確認で止まりました。画面確認環境の問題で、実装失敗とは限りません。',
|
|
@@ -7198,8 +7207,8 @@ const FAILURE_COPY = {
|
|
|
7198
7207
|
unknown: 'Galdaの実行基盤で止まりました。ログを確認し、原因に応じて再試行できます。',
|
|
7199
7208
|
},
|
|
7200
7209
|
actions: {
|
|
7201
|
-
retry: '
|
|
7202
|
-
other: '
|
|
7210
|
+
retry: 'Retry', resume: 'Resume', connect: 'Connect', check: 'Check connection',
|
|
7211
|
+
other: 'Try another Agent', log: 'View log', tests: 'Re-run tests', pr: 'Retry PR',
|
|
7203
7212
|
},
|
|
7204
7213
|
},
|
|
7205
7214
|
en: {
|
|
@@ -7207,6 +7216,7 @@ const FAILURE_COPY = {
|
|
|
7207
7216
|
infra: {
|
|
7208
7217
|
title: 'Galda system issue',
|
|
7209
7218
|
timeout: 'Galda stopped this at the run limit or a wait timed out. This is not necessarily a problem with the change.',
|
|
7219
|
+
interrupted: 'The local run was interrupted. This does not necessarily reflect a problem with the change or agent; resume the same work.',
|
|
7210
7220
|
auth: 'Connection or authentication failed. Reconnect, then continue.',
|
|
7211
7221
|
relay: 'The relay connection failed. Check the connection, then retry.',
|
|
7212
7222
|
chrome: 'Chrome/browser verification failed. The UI check environment stopped, not necessarily the implementation.',
|
|
@@ -7227,17 +7237,23 @@ function failureLang(){
|
|
|
7227
7237
|
function inferErrorClass(text, agent){
|
|
7228
7238
|
const low = String(text || '').toLowerCase();
|
|
7229
7239
|
const infra = (reason, actionIds) => ({ owner: 'galda-infra', reason, actionIds });
|
|
7230
|
-
if (/run limit|実行上限|timed out|timeout|タイムアウト/.test(low)) return infra('timeout', ['retry', '
|
|
7231
|
-
if (/
|
|
7232
|
-
if (/
|
|
7240
|
+
if (/run limit|実行上限|timed out|timeout|タイムアウト/.test(low)) return infra('timeout', ['retry', 'view-log']);
|
|
7241
|
+
if (/worker was interrupted|作業が途中で中断|exit 143|sigterm|sigint/.test(low)) return infra('interrupted', ['retry', 'view-log']);
|
|
7242
|
+
if (/spawn|enoent|eacces|command not found|worker tool exited early|作業ツールが途中で終了/.test(low)) return infra('worker-start', ['retry', 'view-log']);
|
|
7243
|
+
if (/auth probe|preflight|not logged in|logged out|not authenticated|authentication|unauthorized|invalid api key|bad credentials|401\b|403\b|接続が必要|認証/.test(low)) return infra('auth', ['connect', 'check-connection', 'view-log']);
|
|
7233
7244
|
if (/relay|websocket|socket|econnreset|econnrefused|billing-api unreachable|cf access|cloudflare access/.test(low)) return infra('relay', ['retry', 'connect', 'view-log']);
|
|
7234
7245
|
if (/chrome|chromium|puppeteer|target closed|browser|navigation timeout|waiting failed|screenshot|headless/.test(low)) return infra('chrome', ['retry', 'view-log']);
|
|
7235
7246
|
if (/test runner|node --test|npm test|project tests|server exited \(code \d+\) before it was ready|did not report ready in time|test timed out after|tap|not ok \d+/.test(low)) return infra('test-runner', ['retry-tests', 'view-log']);
|
|
7236
7247
|
if (/pr step failed|openpr|pull request|github|gh:|gh auth|git push|git fetch|git .*failed|pr作成|pr failed/.test(low)) return infra('pr', ['retry-pr', 'view-log']);
|
|
7237
|
-
return { owner: 'agent', reason: agent === 'codex' ? 'codex' : 'claude-code', actionIds: ['retry', '
|
|
7248
|
+
return { owner: 'agent', reason: agent === 'codex' ? 'codex' : 'claude-code', actionIds: ['retry', 'view-log'] };
|
|
7238
7249
|
}
|
|
7239
7250
|
function taskErrorMeta(t, goal){
|
|
7240
|
-
|
|
7251
|
+
// Reclassify interrupted tasks from their concrete exit text instead of
|
|
7252
|
+
// trusting stale persisted metadata. Older records labelled an external
|
|
7253
|
+
// SIGTERM/restart as an Agent failure and permanently carried a Codex switch.
|
|
7254
|
+
const inferred = inferErrorClass(t.result, t.agent || goal?.agent);
|
|
7255
|
+
const raw = t.status === 'interrupted' ? inferred : (t.errorClass || inferred);
|
|
7256
|
+
const meta = { ...raw, actionIds: (raw.actionIds || []).filter((id) => !['run-with-codex', 'run-with-claude'].includes(id)) };
|
|
7241
7257
|
const lang = failureLang(), C = FAILURE_COPY[lang];
|
|
7242
7258
|
const isInfra = meta.owner === 'galda-infra';
|
|
7243
7259
|
return {
|
|
@@ -7251,20 +7267,16 @@ function goalBlockedErrorMeta(g){
|
|
|
7251
7267
|
const raw = g.blocked?.errorClass || (g.blocked?.kind === 'test'
|
|
7252
7268
|
? { owner: 'galda-infra', reason: 'test-runner', actionIds: ['retry-tests', 'view-log'] }
|
|
7253
7269
|
: inferErrorClass(g.blocked?.reason, g.agent));
|
|
7270
|
+
const meta = { ...raw, actionIds: (raw.actionIds || []).filter((id) => !['run-with-codex', 'run-with-claude'].includes(id)) };
|
|
7254
7271
|
const lang = failureLang(), C = FAILURE_COPY[lang];
|
|
7255
|
-
const isInfra =
|
|
7256
|
-
return { ...
|
|
7272
|
+
const isInfra = meta.owner === 'galda-infra';
|
|
7273
|
+
return { ...meta, title: isInfra ? C.infra.title : C.agent.title, body: isInfra ? (C.infra[meta.reason] || C.infra.unknown) : C.agent.body, copy: C };
|
|
7257
7274
|
}
|
|
7258
7275
|
function errorButtonsHtml(meta, { taskId = null, goalId = null, interrupted = false, agent = null, pr = false } = {}){
|
|
7259
7276
|
const C = meta.copy.actions;
|
|
7260
|
-
const canCodex = goalId != null && agent !== 'codex' && (state.agents || []).includes('codex');
|
|
7261
7277
|
const out = [];
|
|
7262
7278
|
for (const id of meta.actionIds || []) {
|
|
7263
7279
|
if (id === 'retry' && taskId != null) out.push(`<button class="errbtn" data-fsretry="${taskId}">${interrupted ? C.resume : C.retry}</button>`);
|
|
7264
|
-
// This keeps the existing agent-switch endpoint, but says what it really does
|
|
7265
|
-
// for an interrupted run: continue the saved goal with another agent rather
|
|
7266
|
-
// than imply a brand-new, contextless task will be created.
|
|
7267
|
-
else if (id === 'run-with-codex' && canCodex) out.push(`<button class="errbtn" data-fscodex="${goalId}">${interrupted ? (failureLang() === 'ja' ? 'Codexで再開' : 'Resume with Codex') : C.other}</button>`);
|
|
7268
7280
|
else if (id === 'connect') out.push(`<button class="errbtn" data-fsconnectworker="1">${C.connect}</button>`);
|
|
7269
7281
|
else if (id === 'check-connection') out.push(`<button class="errbtn" data-fscheckworker="1">${C.check}</button>`);
|
|
7270
7282
|
else if (id === 'retry-tests' && goalId != null) out.push(`<button class="errbtn" data-fsreverify="${goalId}">${C.tests}</button>`);
|
package/engine/lib.mjs
CHANGED
|
@@ -1258,13 +1258,20 @@ export function classifyWorkerFailure({ agent = 'claude-code', result = '', err
|
|
|
1258
1258
|
actionIds,
|
|
1259
1259
|
});
|
|
1260
1260
|
if (timedOut || /run limit|実行上限|timed out|timeout|タイムアウト/.test(low)) {
|
|
1261
|
-
return infra('timeout', ['retry', '
|
|
1261
|
+
return infra('timeout', ['retry', 'view-log']);
|
|
1262
|
+
}
|
|
1263
|
+
// SIGTERM/SIGINT means the local worker was stopped from outside the task
|
|
1264
|
+
// (for example while the local Manager was restarting). It says nothing
|
|
1265
|
+
// about either the requested change or the chosen agent, so never turn this
|
|
1266
|
+
// recovery path into a suggestion to switch agents.
|
|
1267
|
+
if (code === 143 || code === 130 || /worker was interrupted|作業が途中で中断|exit 143|sigterm|sigint/.test(low)) {
|
|
1268
|
+
return infra('interrupted', ['retry', 'view-log']);
|
|
1262
1269
|
}
|
|
1263
1270
|
if (/spawn|enoent|eacces|command not found|executable|worker tool exited early|作業ツールが途中で終了/.test(low)) {
|
|
1264
|
-
return infra('worker-start', ['retry', '
|
|
1271
|
+
return infra('worker-start', ['retry', 'view-log']);
|
|
1265
1272
|
}
|
|
1266
1273
|
if (/auth probe|preflight|not logged in|logged out|not authenticated|authentication|unauthorized|invalid api key|bad credentials|401\b|403\b|接続が必要|認証/.test(low)) {
|
|
1267
|
-
return infra('auth', ['connect', 'check-connection', '
|
|
1274
|
+
return infra('auth', ['connect', 'check-connection', 'view-log']);
|
|
1268
1275
|
}
|
|
1269
1276
|
if (/relay|websocket|socket|econnreset|econnrefused|billing-api unreachable|cf access|cloudflare access/.test(low)) {
|
|
1270
1277
|
return infra('relay', ['retry', 'connect', 'view-log']);
|
|
@@ -1281,7 +1288,7 @@ export function classifyWorkerFailure({ agent = 'claude-code', result = '', err
|
|
|
1281
1288
|
return {
|
|
1282
1289
|
owner: 'agent',
|
|
1283
1290
|
reason: agent === 'codex' ? 'codex' : 'claude-code',
|
|
1284
|
-
actionIds: ['retry',
|
|
1291
|
+
actionIds: ['retry', 'view-log'],
|
|
1285
1292
|
};
|
|
1286
1293
|
}
|
|
1287
1294
|
|
package/package.json
CHANGED