agentlas 1.0.66 → 1.0.67
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/CHANGELOG.md +16 -0
- package/README.md +6 -0
- package/bin/agentlas.cjs +17 -4
- package/engine/acp/server.cjs +7 -2
- package/engine/agentlas-workforce.cjs +1 -0
- package/engine/agentlas.cjs +11 -1
- package/engine/cli-output.cjs +16 -2
- package/engine/cloud-assets/state.cjs +375 -77
- package/engine/commands/build.cjs +32 -4
- package/engine/commands/mcp.cjs +144 -37
- package/engine/experience/intents.cjs +6 -0
- package/engine/hub/install.cjs +280 -28
- package/engine/mcp/inventory.cjs +31 -5
- package/engine/mcp/plan.cjs +5 -0
- package/engine/project/credentials.cjs +197 -27
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.67 — 2026-08-30
|
|
4
|
+
|
|
5
|
+
- Cloud local state, source markers, and project credential imports now use
|
|
6
|
+
anchored no-follow atomic publication and fail closed on directory/file swaps
|
|
7
|
+
or unexpected successors.
|
|
8
|
+
- ACP JSON-RPC notifications no longer receive responses, while explicit
|
|
9
|
+
`id: null` requests retain normal request semantics.
|
|
10
|
+
- CLI build/MCP output now keeps JSON, YAML, quiet, header, and color modes
|
|
11
|
+
consistent and returns typed errors for contradictory machine-format input.
|
|
12
|
+
- Workforce candidate sets now require the exact WorkOrder ontology version,
|
|
13
|
+
and Experience packs reject duplicate MCP requirement identifiers before
|
|
14
|
+
they can persist invalid state.
|
|
15
|
+
- MCP consent is bound to the command, arguments, and relevant environment
|
|
16
|
+
material at approval time, while Hub installs recheck managed parents and
|
|
17
|
+
publish atomically without following path swaps.
|
|
18
|
+
|
|
3
19
|
## 1.0.66 — 2026-08-30
|
|
4
20
|
|
|
5
21
|
- API 스트리밍 요청이 연결·본문 읽기 중 실패하거나 취소돼도 부모 취소 리스너와 idle 타이머를 즉시 정리해, 오래 실행한 Terminal 세션에 실패한 요청의 리스너가 누적되지 않게 했습니다.
|
package/README.md
CHANGED
|
@@ -17,6 +17,12 @@ Use this existing independent Terminal as the command-line runtime: inspect owne
|
|
|
17
17
|
|
|
18
18
|
Agent Trust is our product principle: agent packages are treated as portable, owner-scoped, inspectable, and restorable assets. (It does not imply regulated financial or fiduciary services.) Agent Cloud stores package assets in your private cloud account, while Agentlas Terminal verifies and executes local runtime copies on your host machine.
|
|
19
19
|
|
|
20
|
+
Current release: 1.0.67. It hardens local Cloud and credential storage against
|
|
21
|
+
path races, keeps ACP notifications protocol-correct, aligns CLI machine output
|
|
22
|
+
and typed errors, binds Workforce selections to exact ontology versions,
|
|
23
|
+
rejects duplicate Experience requirements, and makes MCP consent and Hub
|
|
24
|
+
installs race-safe.
|
|
25
|
+
|
|
20
26
|
---
|
|
21
27
|
|
|
22
28
|
## Requirements
|
package/bin/agentlas.cjs
CHANGED
|
@@ -72,7 +72,7 @@ function dbPath() {
|
|
|
72
72
|
// Keep the launcher's no-database path identical to the engine's CLI grammar.
|
|
73
73
|
// A plain word "help" is valid task content (`agentlas run -p help`); only the
|
|
74
74
|
// actual help/version command forms may skip first-run database bootstrap.
|
|
75
|
-
function isMetadataOnlyInvocation(argv) {
|
|
75
|
+
function isMetadataOnlyInvocation(argv, parsedOutput) {
|
|
76
76
|
const args = Array.isArray(argv) ? argv : [];
|
|
77
77
|
const helpRequested = args.some((arg) => arg === "--help" || arg === "-h");
|
|
78
78
|
const helpCommand = args.find((arg) => arg !== "--help" && arg !== "-h" && !String(arg).startsWith("-"));
|
|
@@ -83,7 +83,7 @@ function isMetadataOnlyInvocation(argv) {
|
|
|
83
83
|
if (arg === "--version" || arg === "-V") return "version";
|
|
84
84
|
return arg;
|
|
85
85
|
});
|
|
86
|
-
const { rest } = parseOutputFlags(normalized);
|
|
86
|
+
const { rest } = parsedOutput || parseOutputFlags(normalized);
|
|
87
87
|
const [rawCommand, ...commandArgs] = rest;
|
|
88
88
|
if (rawCommand === "help" || rawCommand === "version") return true;
|
|
89
89
|
return SELF_HELP_COMMANDS.has(resolveCommandName(rawCommand)) && commandArgs[0] === "help";
|
|
@@ -556,8 +556,21 @@ function bootstrapDbIfMissing() {
|
|
|
556
556
|
|
|
557
557
|
function main() {
|
|
558
558
|
const args = process.argv.slice(2);
|
|
559
|
-
const
|
|
560
|
-
|
|
559
|
+
const normalized = args.map((arg) => {
|
|
560
|
+
if (arg === "--help" || arg === "-h") return "help";
|
|
561
|
+
if (arg === "--version" || arg === "-V") return "version";
|
|
562
|
+
return arg;
|
|
563
|
+
});
|
|
564
|
+
let parsedOutput;
|
|
565
|
+
try {
|
|
566
|
+
parsedOutput = parseOutputFlags(normalized);
|
|
567
|
+
} catch (error) {
|
|
568
|
+
process.stderr.write(renderError(error, { format: "table", noColor: true }) + "\n");
|
|
569
|
+
process.exitCode = 1;
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
const { options: outputOptions } = parsedOutput;
|
|
573
|
+
const metadataOnly = isMetadataOnlyInvocation(args, parsedOutput);
|
|
561
574
|
const sqliteDriver = probeSqliteDriver();
|
|
562
575
|
const engineFound = exists(ENGINE);
|
|
563
576
|
|
package/engine/acp/server.cjs
CHANGED
|
@@ -170,8 +170,13 @@ class AcpAgentServer {
|
|
|
170
170
|
this.output.write(JSON.stringify(obj) + "\n");
|
|
171
171
|
}
|
|
172
172
|
notify(method, params) { this.send({ jsonrpc: "2.0", method, params }); }
|
|
173
|
-
|
|
174
|
-
|
|
173
|
+
// JSON-RPC notifications have no response channel. Keep `id: null` as a
|
|
174
|
+
// request (the protocol distinguishes an absent id from an explicit null).
|
|
175
|
+
reply(id, result) { if (id === undefined) return; this.send({ jsonrpc: "2.0", id, result }); }
|
|
176
|
+
error(id, code, message, data) {
|
|
177
|
+
if (id === undefined) return;
|
|
178
|
+
this.send({ jsonrpc: "2.0", id, error: { code, message, ...(data !== undefined ? { data } : {}) } });
|
|
179
|
+
}
|
|
175
180
|
|
|
176
181
|
start() {
|
|
177
182
|
const rl = readline.createInterface({ input: this.input, crlfDelay: Infinity });
|
|
@@ -1111,6 +1111,7 @@ function validateCandidateSet(value, workOrder, now = new Date(), options = {})
|
|
|
1111
1111
|
assertId(set.selectionSessionId, "candidateSet.selectionSessionId");
|
|
1112
1112
|
if (set.workOrderId !== workOrder.workOrderId) fail("candidate_set_invalid", "candidate set workOrderId mismatch");
|
|
1113
1113
|
assertId(set.ontologyVersion, "candidateSet.ontologyVersion");
|
|
1114
|
+
if (set.ontologyVersion !== workOrder.ontologyVersion) fail("candidate_set_invalid", "candidate set ontologyVersion mismatch");
|
|
1114
1115
|
assertHash(set.candidateSetDigest, "candidateSet.candidateSetDigest");
|
|
1115
1116
|
if (set.decisionOwner !== "host_llm") fail("candidate_set_invalid", "Hub candidate set tried to take selection authority");
|
|
1116
1117
|
if (set.historyInfluence !== "none") fail("candidate_set_invalid", "history/popularity influenced candidate retrieval");
|
package/engine/agentlas.cjs
CHANGED
|
@@ -189,7 +189,17 @@ function main() {
|
|
|
189
189
|
|
|
190
190
|
// 전역 출력 플래그는 명령에 닿기 전에 한 곳에서 뜯어낸다 —
|
|
191
191
|
// 명령마다 --json 유무가 갈리던 것을 구조로 막는다.
|
|
192
|
-
|
|
192
|
+
// --json + --yaml 은 모순된 요청이라 JSON/YAML 중 하나를 임의로 고르지 않고,
|
|
193
|
+
// 진입점에서 결정적인 평문 INVALID_ARGUMENT 로 멈춘다.
|
|
194
|
+
let parsedOutput;
|
|
195
|
+
try {
|
|
196
|
+
parsedOutput = parseOutputFlags(normalized);
|
|
197
|
+
} catch (error) {
|
|
198
|
+
process.stderr.write(renderError(error, { format: "table", noColor: true }) + "\n");
|
|
199
|
+
process.exitCode = 1;
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const { options: outputOptions, rest: commandArgv } = parsedOutput;
|
|
193
203
|
const ctx = buildCtx();
|
|
194
204
|
ctx.output = outputOptions;
|
|
195
205
|
let code;
|
package/engine/cli-output.cjs
CHANGED
|
@@ -276,19 +276,33 @@ function renderError(error, options = {}) {
|
|
|
276
276
|
function parseOutputFlags(argv, env = process.env, isTty = Boolean(process.stdout.isTTY)) {
|
|
277
277
|
const rest = [];
|
|
278
278
|
const options = { ...DEFAULT_OPTIONS };
|
|
279
|
+
let sawJson = false;
|
|
280
|
+
let sawYaml = false;
|
|
279
281
|
for (let index = 0; index < argv.length; index += 1) {
|
|
280
282
|
const token = argv[index];
|
|
281
283
|
if (token === "--") {
|
|
282
284
|
rest.push(...argv.slice(index + 1));
|
|
283
285
|
break;
|
|
284
286
|
}
|
|
285
|
-
if (token === "--json")
|
|
286
|
-
|
|
287
|
+
if (token === "--json") {
|
|
288
|
+
sawJson = true;
|
|
289
|
+
options.format = "json";
|
|
290
|
+
}
|
|
291
|
+
else if (token === "--yaml") {
|
|
292
|
+
sawYaml = true;
|
|
293
|
+
options.format = "yaml";
|
|
294
|
+
}
|
|
287
295
|
else if (token === "--quiet" || token === "-q") options.quiet = true;
|
|
288
296
|
else if (token === "--no-headers") options.noHeaders = true;
|
|
289
297
|
else if (token === "--no-color") options.noColor = true;
|
|
290
298
|
else rest.push(token);
|
|
291
299
|
}
|
|
300
|
+
if (sawJson && sawYaml) {
|
|
301
|
+
const error = new Error("--json and --yaml cannot be used together");
|
|
302
|
+
error.code = "INVALID_ARGUMENT";
|
|
303
|
+
error.details = { flags: ["--json", "--yaml"] };
|
|
304
|
+
throw error;
|
|
305
|
+
}
|
|
292
306
|
if (env && (env.NO_COLOR || env.AGENTLAS_NO_COLOR)) options.noColor = true;
|
|
293
307
|
if (!isTty) options.noColor = true;
|
|
294
308
|
return { options, rest };
|