agentlas 1.0.55 → 1.0.57

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.
@@ -157,6 +157,116 @@ function listGraphs(ctx) {
157
157
  return 0;
158
158
  }
159
159
 
160
+ /**
161
+ * 옛 실행이 부수효과를 남겨 막힌 자동화를, 사람이 **한 번** 판단해 풀어 준다.
162
+ *
163
+ * 실측 2026-08-20: 터미널 코어에는 재조정 모듈이 아예 실리지 않아,
164
+ * `automation_partial_reconciliation_required` 를 **낼 수는 있는데 풀 수단이 없었다**.
165
+ * CLI 만 쓰는 사람은 그 자동화를 영원히 못 돌린다. 내는 오류가 있으면 푸는 길도 있어야 한다.
166
+ *
167
+ * 판단은 노드마다 둘 중 하나다 — "이미 일어났다(--done)" / "확실히 안 일어났다(--not-done)".
168
+ * 아무 것도 주지 않으면 무엇을 정해야 하는지 보여 주기만 한다. 실행 중에 묻지 않는다.
169
+ */
170
+ function reconcileGraph(ctx, needle, flags, en) {
171
+ const rows = graphRows(ctx, ctx.db());
172
+ const row = findGraph(rows, needle);
173
+ if (row?.ambiguous) { reportAmbiguous(ctx, needle, row.ambiguous, en); return 1; }
174
+ if (!row) {
175
+ ctx.err(en ? `No graph matches "${needle}".` : `"${needle}"와 맞는 그래프가 없습니다.`);
176
+ return 1;
177
+ }
178
+ const core = ctx.desktopCore || require("../core/desktop-core.cjs").loadDesktopCore();
179
+ const reconciliation = core && core.graphReconciliation;
180
+ if (!reconciliation || typeof reconciliation.get !== "function") {
181
+ ctx.err(en
182
+ ? "This engine build cannot reconcile. Update the CLI (`npm i -g agentlas@latest`) and try again."
183
+ : "이 엔진에는 재조정 기능이 없습니다. CLI를 업데이트한 뒤(`npm i -g agentlas@latest`) 다시 시도하세요.");
184
+ return 1;
185
+ }
186
+ const view = reconciliation.get(row.id);
187
+ if (!view) {
188
+ ctx.out(en
189
+ ? `"${row.name}" has nothing waiting to be reconciled.`
190
+ : `"${row.name}"에는 재조정을 기다리는 것이 없습니다.`);
191
+ return 0;
192
+ }
193
+
194
+ const done = new Set(asList(flags && (flags.done ?? flags["done"])));
195
+ const notDone = new Set(asList(flags && (flags["not-done"] ?? flags.notDone)));
196
+ const outputs = new Map();
197
+ for (const pair of asList(flags && flags.output)) {
198
+ const at = String(pair).indexOf("=");
199
+ if (at > 0) outputs.set(String(pair).slice(0, at).trim(), String(pair).slice(at + 1));
200
+ }
201
+
202
+ if (done.size === 0 && notDone.size === 0) {
203
+ ctx.out(en
204
+ ? `"${row.name}" stopped with steps whose effect cannot be told from the record.`
205
+ : `"${row.name}"은(는) 기록만으로는 일어났는지 알 수 없는 단계가 있어 멈춰 있습니다.`);
206
+ ctx.out("");
207
+ for (const node of view.nodes) {
208
+ const needs = node.outputRequired
209
+ ? (en ? ` (needs --output ${node.nodeId}=<value> when done)` : ` (일어났다면 --output ${node.nodeId}=<값> 필요)`)
210
+ : "";
211
+ ctx.out(` ${node.nodeId} ${node.label}${needs}`);
212
+ }
213
+ ctx.out("");
214
+ ctx.out(ctx.ui.dim(en
215
+ ? `Decide each one: agentlas graph reconcile "${row.name}" --done <node> --not-done <node>`
216
+ : `각각 정하세요: agentlas graph reconcile "${row.name}" --done <노드> --not-done <노드>`));
217
+ return 0;
218
+ }
219
+
220
+ const undecided = view.nodes.filter((n) => !done.has(n.nodeId) && !notDone.has(n.nodeId));
221
+ if (undecided.length > 0) {
222
+ ctx.err(en
223
+ ? `Still undecided: ${undecided.map((n) => n.nodeId).join(", ")}. Every step needs one answer.`
224
+ : `아직 안 정한 단계가 있습니다: ${undecided.map((n) => n.nodeId).join(", ")}. 모든 단계에 답이 필요합니다.`);
225
+ return 1;
226
+ }
227
+ const missingOutput = view.nodes.filter((n) => done.has(n.nodeId) && n.outputRequired && !outputs.has(n.nodeId));
228
+ if (missingOutput.length > 0) {
229
+ ctx.err(en
230
+ ? `These steps populate a value, so completing them needs it: ${missingOutput.map((n) => `--output ${n.nodeId}=<value>`).join(" ")}`
231
+ : `값을 만드는 단계라 "일어났다"로 두려면 값이 필요합니다: ${missingOutput.map((n) => `--output ${n.nodeId}=<값>`).join(" ")}`);
232
+ return 1;
233
+ }
234
+
235
+ try {
236
+ const result = reconciliation.apply({
237
+ automationId: view.automationId,
238
+ runId: view.runId,
239
+ occurrenceId: view.occurrenceId,
240
+ graphDigest: view.graphDigest,
241
+ checkpointDigest: view.checkpointDigest,
242
+ expectedUpdatedAt: view.updatedAt,
243
+ eventId: view.triggerEvent ? view.triggerEvent.id : null,
244
+ expectedEventUpdatedAt: view.triggerEvent ? view.triggerEvent.updatedAt : null,
245
+ decisions: view.nodes.map((n) => (done.has(n.nodeId)
246
+ ? { nodeId: n.nodeId, resolution: "completed", ...(outputs.has(n.nodeId) ? { output: outputs.get(n.nodeId) } : {}) }
247
+ : { nodeId: n.nodeId, resolution: "retry" })),
248
+ });
249
+ ctx.out(en
250
+ ? `Reconciled. ${result.completedNodeIds.length} step(s) marked as done, ${result.retryNodeIds.length} to redo.`
251
+ : `재조정했습니다. ${result.completedNodeIds.length}개는 일어난 것으로, ${result.retryNodeIds.length}개는 다시 하는 것으로 두었습니다.`);
252
+ ctx.out(ctx.ui.dim(en
253
+ ? `Now run it: agentlas graph run "${row.name}"`
254
+ : `이제 실행하세요: agentlas graph run "${row.name}"`));
255
+ return 0;
256
+ } catch (error) {
257
+ ctx.err(en
258
+ ? `Reconciliation was refused: ${String(error && error.message || error)}`
259
+ : `재조정이 거절됐습니다: ${String(error && error.message || error)}`);
260
+ return 1;
261
+ }
262
+ }
263
+
264
+ /** 같은 깃발이 여러 번 올 수 있다 — 하나든 여럿이든 배열로 본다. */
265
+ function asList(value) {
266
+ if (value == null) return [];
267
+ return Array.isArray(value) ? value.map(String) : [String(value)];
268
+ }
269
+
160
270
  function showGraph(ctx, needle) {
161
271
  const db = ctx.db();
162
272
  const rows = graphRows(ctx, db);
@@ -1154,6 +1264,23 @@ async function run(ctx, args = []) {
1154
1264
  // 실제로는 한 번도 동작한 적이 없었다(실사용 실측 2026-08-06).
1155
1265
  if (arg === "--name" || arg === "-n") { flags.name = String(args[i + 1] ?? "").trim(); i += 1; continue; }
1156
1266
  if (arg.startsWith("--name=")) { flags.name = arg.slice("--name=".length).trim(); continue; }
1267
+ // 재조정 판단 — 같은 깃발이 여러 번 올 수 있으므로 모아 둔다. 값을 함께 걷어내지
1268
+ // 않으면 위 --name 사고와 똑같이 그래프 이름에 붙어 "맞는 그래프가 없다"가 된다.
1269
+ {
1270
+ const multi = { "--done": "done", "--not-done": "not-done", "--output": "output" };
1271
+ let matched = false;
1272
+ for (const [token, key] of Object.entries(multi)) {
1273
+ if (arg === token) {
1274
+ (flags[key] || (flags[key] = [])).push(String(args[i + 1] ?? "").trim());
1275
+ i += 1; matched = true; break;
1276
+ }
1277
+ if (arg.startsWith(`${token}=`)) {
1278
+ (flags[key] || (flags[key] = [])).push(arg.slice(token.length + 1).trim());
1279
+ matched = true; break;
1280
+ }
1281
+ }
1282
+ if (matched) continue;
1283
+ }
1157
1284
  rest.push(arg);
1158
1285
  }
1159
1286
  const sub = (rest[0] || "list").toLowerCase();
@@ -1165,6 +1292,7 @@ async function run(ctx, args = []) {
1165
1292
  ctx.out(en ? " list what is saved" : " list 저장된 것 목록");
1166
1293
  ctx.out(en ? " show \"<name>\" steps, wiring, and problems" : " show \"<이름>\" 단계·배선·문제점");
1167
1294
  ctx.out(en ? " run \"<name>\" [--input \"<value>\"] run locally with the included Desktop Core" : " run \"<이름>\" [--input \"<값>\"] 포함된 Desktop Core로 로컬 실행");
1295
+ ctx.out(en ? " reconcile \"<name>\" decide what already happened, when a run stopped unsure" : " reconcile \"<이름>\" 멈춘 실행에서 무엇이 이미 일어났는지 정하기");
1168
1296
  ctx.out(en ? " export \"<name>\" [file] write a shareable package file" : " export \"<이름>\" [파일] 남에게 줄 수 있는 파일로 저장");
1169
1297
  ctx.out(en ? " inspect <file> read a package file before installing" : " inspect <파일> 설치 전에 패키지 파일 확인");
1170
1298
  ctx.out(en ? " install <file> [--name \"<new name>\"] install a package file" : " install <파일> [--name \"<새 이름>\"] 패키지 파일 설치");
@@ -1185,6 +1313,15 @@ async function run(ctx, args = []) {
1185
1313
  }
1186
1314
  return showGraph(ctx, target);
1187
1315
  }
1316
+ if (sub === "reconcile") {
1317
+ if (!target) {
1318
+ ctx.err(en
1319
+ ? "Usage: agentlas graph reconcile \"<name>\" [--done <node>] [--not-done <node>] [--output <node>=<value>]"
1320
+ : "사용법: agentlas graph reconcile \"<이름>\" [--done <노드>] [--not-done <노드>] [--output <노드>=<값>]");
1321
+ return 1;
1322
+ }
1323
+ return reconcileGraph(ctx, target, flags, en);
1324
+ }
1188
1325
  if (sub === "export") {
1189
1326
  if (!target) {
1190
1327
  ctx.err(en ? "Usage: agentlas graph export \"<name>\" [file]" : "사용법: agentlas graph export \"<이름>\" [파일]");
@@ -233,6 +233,24 @@ function loadDesktopCore(options = {}) {
233
233
  runGraph: kernel.runGraph,
234
234
  graphFailureOf: kernel.graphFailureOf,
235
235
  planGraphLoops: kernel.planGraphLoops,
236
+ /*
237
+ * ★내는 오류가 있으면 푸는 길도 함께 준다. 실측 2026-08-20: 커널은
238
+ * `automation_partial_reconciliation_required` 를 내는데, 그것을 푸는 모듈은
239
+ * 벤더에 실리지도 않았고 여기 표면에도 없었다 — CLI 만 쓰는 사람은 그 자동화를
240
+ * 영원히 못 돌린다. 옛 코어를 쓰는 동안에는 없을 수 있으므로 정직하게 null 로 둔다.
241
+ */
242
+ graphReconciliation: (() => {
243
+ try {
244
+ const mod = req("store/graph-reconciliation");
245
+ if (typeof mod.getAutomationGraphReconciliation !== "function") return null;
246
+ return {
247
+ get: mod.getAutomationGraphReconciliation,
248
+ apply: mod.reconcileAutomationGraph,
249
+ };
250
+ } catch {
251
+ return null;
252
+ }
253
+ })(),
236
254
  };
237
255
  return _cache;
238
256
  }
@@ -1,7 +1,7 @@
1
1
  {
2
- "version": "8",
3
- "url": "https://github.com/agentlas-ai/agentlas-terminal/releases/download/desktop-core-v8/desktop-core.tar.gz",
4
- "sha256": "035dab73fb904fe395074b2f75c238b7c65360f454e31e4ac840fbf6baa89afd",
5
- "sizeBytes": 12544238,
6
- "writtenAt": "2026-08-19T20:34:43.158Z"
2
+ "version": "9",
3
+ "url": "https://github.com/agentlas-ai/agentlas-terminal/releases/download/desktop-core-v9/desktop-core.tar.gz",
4
+ "sha256": "1660ff39c1d06840f5b5f047e2520df32b20b2efb70cf1e5cd4f5e43814837a2",
5
+ "sizeBytes": 12553853,
6
+ "writtenAt": "2026-08-19T20:57:26.499Z"
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentlas",
3
- "version": "1.0.55",
3
+ "version": "1.0.57",
4
4
  "description": "Agentlas project terminal — run project controllers and task-scoped agent teams from the terminal. Standalone: no desktop app process required.",
5
5
  "bin": {
6
6
  "agentlas": "bin/agentlas.cjs"
@@ -13,7 +13,8 @@
13
13
  "vendor:core": "node scripts/vendor-desktop-core.cjs",
14
14
  "test:tool-access-notice-parity": "node test/tool-access-notice-parity.cjs",
15
15
  "verify:engine-reachable": "node scripts/verify-engine-reachable.cjs",
16
- "prepublishOnly": "npm run verify:engine-reachable"
16
+ "prepublishOnly": "npm run verify:engine-reachable && npm run verify:way-out",
17
+ "verify:way-out": "node scripts/verify-raised-errors-have-a-way-out.cjs"
17
18
  },
18
19
  "engines": {
19
20
  "node": ">=20.19"