@desplega.ai/agent-swarm 2.4.1 → 2.4.2
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/{acp-adapter-zvzr538d.js → acp-adapter-dv7hmx4r.js} +1 -1
- package/dist/{actions-jhtqdw69.js → actions-51nc1gny.js} +16 -16
- package/dist/{amp-adapter-bd84rhs2.js → amp-adapter-abp5tdx8.js} +1 -1
- package/dist/{app-kreq1gwg.js → app-9h14qvr6.js} +3 -3
- package/dist/{assistant-3k22sbsq.js → assistant-wv1gz3mt.js} +17 -17
- package/dist/{boot-reembed-e53x6b9v.js → boot-reembed-6yn53ms9.js} +1 -1
- package/dist/{boot-reembed-f6z923ny.js → boot-reembed-7fcka4z5.js} +1 -1
- package/dist/{boot-scrub-sweep-0538vsb7.js → boot-scrub-sweep-pm1580ax.js} +2 -2
- package/dist/{boot-seeds-6wxqkfk2.js → boot-seeds-g5hfc1x8.js} +4 -4
- package/dist/{claude-adapter-gfts5044.js → claude-adapter-gf3kxhf0.js} +2 -2
- package/dist/{claude-sdk-session-56besmfz.js → claude-sdk-session-s2k1qd8y.js} +2 -2
- package/dist/{cli-tbhwrxpt.js → cli-02qm7src.js} +3 -3
- package/dist/{cli-3kh4kpqy.js → cli-0qvtffe9.js} +5 -5
- package/dist/{cli-p6argxh9.js → cli-10hhg0km.js} +6 -6
- package/dist/{cli-gf0kfg81.js → cli-239yjk27.js} +2 -2
- package/dist/{cli-kr2pmfqx.js → cli-5rk36sjf.js} +72 -59
- package/dist/{cli-nx462e4v.js → cli-7awf1fp8.js} +1 -1
- package/dist/{cli-jh0qcrga.js → cli-8sxqsbbq.js} +1 -1
- package/dist/{cli-axh29tyr.js → cli-8zwe9mpk.js} +5 -5
- package/dist/{cli-z1ew8vbq.js → cli-ahtpy9kf.js} +1 -1
- package/dist/{cli-3r448dqn.js → cli-bcj753sq.js} +3 -3
- package/dist/{cli-rqqsfz30.js → cli-d3qqdy4c.js} +82 -12
- package/dist/{cli-z071fb95.js → cli-efaqv1c7.js} +4 -4
- package/dist/{cli-s48yvzb8.js → cli-faypxz7q.js} +3 -3
- package/dist/{cli-m2qgh5sv.js → cli-ftyypbg5.js} +1 -1
- package/dist/{cli-6ncjvx55.js → cli-fyzjmseb.js} +1 -1
- package/dist/{cli-0bh477zn.js → cli-h38rjv87.js} +117 -9
- package/dist/{cli-3p8fqcnh.js → cli-h93c9vb3.js} +1 -1
- package/dist/{cli-rdq7tzwm.js → cli-hyfw2j1e.js} +8 -8
- package/dist/{cli-bn5kevnf.js → cli-n85dqg6d.js} +2 -2
- package/dist/{cli-fz9kewbh.js → cli-nmqdc2t3.js} +1 -1
- package/dist/{cli-vy0fay6k.js → cli-nn47d7e8.js} +10 -10
- package/dist/{cli-mfe7f7b5.js → cli-pkht5hap.js} +1 -1
- package/dist/{cli-xftrvxag.js → cli-r99kc9yq.js} +1 -1
- package/dist/{cli-p0rakbrk.js → cli-rdyw3mct.js} +1 -1
- package/dist/{cli-sjyetj21.js → cli-s6vr7r2d.js} +1 -1
- package/dist/{cli-k9z4zd4p.js → cli-saw9a6f6.js} +2 -2
- package/dist/{cli-ash6xxk7.js → cli-shvfedvm.js} +2 -2
- package/dist/{cli-syhq378v.js → cli-t30yj95q.js} +1 -1
- package/dist/{cli-kmqgmcnb.js → cli-y2x52gs2.js} +4 -4
- package/dist/{cli-471qk6s2.js → cli-y8n5k515.js} +14 -14
- package/dist/{cli-3tnpj2bh.js → cli-z4wd2ftv.js} +1 -1
- package/dist/cli.js +12 -12
- package/dist/{codex-adapter-p6rmm7vv.js → codex-adapter-ttygw382.js} +1 -1
- package/dist/{codex-session-runner-8vd5t9t0.js → codex-session-runner-60b58vv3.js} +1 -1
- package/dist/{commands-7ems2p13.js → commands-edmdwa4x.js} +2 -2
- package/dist/{controllers-connect-bg33ae53.js → controllers-connect-5fym8sw1.js} +16 -16
- package/dist/{db-ys2rbdft.js → db-2y0mgstc.js} +3 -3
- package/dist/{db-w505dwa8.js → db-nn0hcmx5.js} +5 -1
- package/dist/{dispatcher-0s0mckqr.js → dispatcher-0a9wwjcx.js} +15 -15
- package/dist/{external-channel-5b23fv8z.js → external-channel-zhvt95n3.js} +2 -2
- package/dist/{grok-adapter-q9fghe5q.js → grok-adapter-qnr1hp2y.js} +2 -2
- package/dist/{handlers-mqrym347.js → handlers-dkcarkd0.js} +18 -18
- package/dist/{heartbeat-tww6yx1w.js → heartbeat-gz97r7ac.js} +17 -17
- package/dist/{hook-dx0pkvar.js → hook-1mmdgjqs.js} +1 -1
- package/dist/{hook-pvmh9b6m.js → hook-x8rthca4.js} +1 -1
- package/dist/{http-k2ejbt05.js → http-r8f85xr9.js} +111 -65
- package/dist/{index-pqfwh9nn.js → index-5jecgp3n.js} +17 -17
- package/dist/{index-h2ek08d6.js → index-aex0eba9.js} +15 -15
- package/dist/{index-x5aktmp8.js → index-smxyk04s.js} +1 -1
- package/dist/{index-dgz61nff.js → index-vzvfqzfj.js} +15 -15
- package/dist/{index-2z710v4x.js → index-y7rbcrc1.js} +8 -8
- package/dist/{keepalive-nhvpw10z.js → keepalive-64c0f34c.js} +3 -3
- package/dist/{lead-jb6sf69z.js → lead-b1da0f97.js} +23 -23
- package/dist/{maintenance-agakc519.js → maintenance-mnxpar12.js} +1 -1
- package/dist/{oauth-refresh-sweep-4dcbhtn0.js → oauth-refresh-sweep-36hs2v4h.js} +2 -2
- package/dist/{onboard-4n2kwa4v.js → onboard-xes8de61.js} +2 -2
- package/dist/{otel-impl-tfa12080.js → otel-impl-fzc57kcq.js} +1 -1
- package/dist/{pricing-refresh-3cqx3f3x.js → pricing-refresh-1nek2w7b.js} +3 -3
- package/dist/{rbac-roles-y6zbfzve.js → rbac-roles-sqefb5hw.js} +2 -2
- package/dist/{rbac-roles-9fae5rnv.js → rbac-roles-ttyfaep2.js} +1 -1
- package/dist/{render-v2-emawjvc4.js → render-v2-vb527jwn.js} +3 -3
- package/dist/{resume-zhgts7h7.js → resume-jcdzg1bn.js} +5 -5
- package/dist/{session-access-cm823e06.js → session-access-zsp4wsp0.js} +4 -4
- package/dist/{setup-tkp99w1e.js → setup-1nb2zqd3.js} +1 -1
- package/dist/{work-objects-f722h263.js → work-objects-61w08fwr.js} +18 -18
- package/dist/{worker-p7f336rq.js → worker-c1e68hpa.js} +23 -23
- package/openapi.json +393 -1
- package/package.json +2 -2
- package/src/apps/catalog.generated.json +3 -2
- package/src/apps/definition.ts +152 -4
- package/src/apps/row-store.ts +19 -7
- package/src/apps/schema-migrate.ts +14 -6
- package/src/apps/script-types.ts +1 -0
- package/src/apps/sync.ts +20 -19
- package/src/be/db/tasks/read.ts +112 -0
- package/src/be/db.ts +2 -0
- package/src/be/swarm-config-guard.ts +15 -0
- package/src/http/apps.ts +15 -2
- package/src/http/status.ts +49 -43
- package/src/http/tasks.ts +47 -0
- package/src/providers/acp-targets.ts +1 -1
- package/src/providers/amp-adapter.ts +1 -1
- package/src/telemetry.ts +15 -3
- package/src/tests/app-row-tools.test.ts +25 -0
- package/src/tests/apps-json-column.test.ts +611 -0
- package/src/tests/apps-script-types.test.ts +2 -0
- package/src/tests/apps-sync-engine.test.ts +42 -0
- package/src/tests/db-task-read-contract.test.ts +4 -0
- package/src/tests/db-task-write-contract.test.ts +2 -0
- package/src/tests/docs-index-footprint.test.js +2 -2
- package/src/tests/runner-harness-telemetry-env.test.ts +6 -0
- package/src/tests/status.test.ts +158 -9
- package/src/tests/task-lineage.test.ts +180 -0
- package/src/tests/telemetry-init.test.ts +62 -5
- package/src/tests/user-token-rest-auth.test.ts +38 -0
- package/src/tools/app-rows.ts +5 -0
- package/templates/skills/apps/SKILL.md +3 -2
- package/templates/skills/apps/content.md +3 -2
package/src/http/status.ts
CHANGED
|
@@ -197,7 +197,7 @@ export type AutomationStatus = z.infer<typeof AutomationStatusSchema>;
|
|
|
197
197
|
* - `broken` — harness or workers blocking (creds missing, no live workers ever).
|
|
198
198
|
* - `degraded` — at least one optional integration `unverified`/`configured`
|
|
199
199
|
* while another is configured, OR harness creds present but
|
|
200
|
-
* never
|
|
200
|
+
* the latest live test failed or never ran (`configured`).
|
|
201
201
|
* - `ok` — harness + workers `verified`; no integration left in
|
|
202
202
|
* `configured` state.
|
|
203
203
|
*/
|
|
@@ -237,12 +237,12 @@ export const TestConnectionResponseSchema = z.object({
|
|
|
237
237
|
/**
|
|
238
238
|
* Read all worker reports for a given harness provider and reduce them to a
|
|
239
239
|
* single milestone-grade rollup. Reports are joined from `agents.cred_status`
|
|
240
|
-
* (migration 055) — no provider-adapter code runs here.
|
|
240
|
+
* (migration 055) — no provider-adapter code runs here. Offline agents are
|
|
241
|
+
* excluded: `workers` and `reports` count online agents only.
|
|
241
242
|
*
|
|
242
|
-
* `verified` ⇐
|
|
243
|
-
* is fresher than `getCredVerifyTtlMs()`.
|
|
243
|
+
* `verified` ⇐ the provider's most recent live test passed, whatever its age.
|
|
244
244
|
* `configured` ⇐ at least one worker has `ready: true` (presence check
|
|
245
|
-
* passed) but
|
|
245
|
+
* passed) but the latest live test failed or none ever ran.
|
|
246
246
|
* `unverified` ⇐ no worker reported, or all reporting workers have
|
|
247
247
|
* `ready: false`.
|
|
248
248
|
*/
|
|
@@ -258,14 +258,6 @@ export interface CredRollup {
|
|
|
258
258
|
oldestReportAgeMs: number | null;
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
-
function getCredVerifyTtlMs(): number {
|
|
262
|
-
const raw = process.env.SWARM_VERIFY_TTL_MS;
|
|
263
|
-
if (!raw) return 3_600_000; // 1h default — matches pre-refactor behavior.
|
|
264
|
-
const parsed = Number.parseInt(raw, 10);
|
|
265
|
-
if (Number.isNaN(parsed) || parsed <= 0) return 3_600_000;
|
|
266
|
-
return parsed;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
261
|
/**
|
|
270
262
|
* Compatibility stub. The pre-refactor in-memory test-connection cache is
|
|
271
263
|
* gone — credential state now lives on agent rows. Tests still call this
|
|
@@ -276,7 +268,11 @@ export function _resetTestConnectionCache(): void {
|
|
|
276
268
|
}
|
|
277
269
|
|
|
278
270
|
export async function rollupCredStatusForProvider(provider: string): Promise<CredRollup> {
|
|
279
|
-
|
|
271
|
+
// An offline agent keeps its last cred_status after `/close`, so only online
|
|
272
|
+
// agents decide the rollup; a stale failure must not override a live pass.
|
|
273
|
+
const agents = (await listAgentsWithCredStatusByProvider(provider)).filter(
|
|
274
|
+
(a) => a.status !== "offline",
|
|
275
|
+
);
|
|
280
276
|
const reports = agents.map((a) => a.credStatus).filter((s): s is AgentCredStatus => s != null);
|
|
281
277
|
|
|
282
278
|
if (reports.length === 0) {
|
|
@@ -291,23 +287,19 @@ export async function rollupCredStatusForProvider(provider: string): Promise<Cre
|
|
|
291
287
|
};
|
|
292
288
|
}
|
|
293
289
|
|
|
294
|
-
//
|
|
295
|
-
//
|
|
296
|
-
|
|
290
|
+
// The provider's latest live test decides, whatever its age. Workers run the
|
|
291
|
+
// test at boot and re-run it only when credentials change, so an old pass is
|
|
292
|
+
// the normal state of a long-running worker, not a missing check.
|
|
297
293
|
const now = Date.now();
|
|
298
|
-
const
|
|
299
|
-
report.liveTest?.ok === true && now - (report.liveTest?.testedAt ?? 0) < ttl;
|
|
300
|
-
const passing = reports
|
|
301
|
-
.filter(isFreshPassingReport)
|
|
302
|
-
.sort((a, b) => (b.liveTest?.testedAt ?? 0) - (a.liveTest?.testedAt ?? 0));
|
|
294
|
+
const passing = reports.filter((r) => r.liveTest?.ok === true);
|
|
303
295
|
const anyLive = reports
|
|
304
296
|
.filter((r) => r.liveTest != null)
|
|
305
297
|
.sort((a, b) => (b.liveTest?.testedAt ?? 0) - (a.liveTest?.testedAt ?? 0));
|
|
306
|
-
const latestLiveTest =
|
|
298
|
+
const latestLiveTest = anyLive[0]?.liveTest ?? null;
|
|
307
299
|
|
|
308
300
|
const anyReady = reports.some((r) => r.ready);
|
|
309
301
|
const state: CredRollupState =
|
|
310
|
-
|
|
302
|
+
latestLiveTest?.ok === true ? "verified" : anyReady ? "configured" : "unverified";
|
|
311
303
|
|
|
312
304
|
// For UI hints, pick the most-recent missing[] from a not-ready report.
|
|
313
305
|
const latestNotReady = reports
|
|
@@ -349,23 +341,19 @@ function buildIdentity(): StatusIdentity {
|
|
|
349
341
|
// ─── Setup milestones ────────────────────────────────────────────────────────
|
|
350
342
|
|
|
351
343
|
/**
|
|
352
|
-
*
|
|
353
|
-
*
|
|
354
|
-
* "1 worker · live test ok"
|
|
355
|
-
* "2 workers · presence ok, awaiting live test"
|
|
356
|
-
* "missing: OPENAI_API_KEY"
|
|
344
|
+
* One short phrase for a provider that needs attention, e.g. "live test
|
|
345
|
+
* failed" or "missing: OPENAI_API_KEY". A verified provider gets none.
|
|
357
346
|
*/
|
|
358
|
-
function describeRoll(roll: CredRollup): string {
|
|
347
|
+
function describeRoll(roll: CredRollup): string | null {
|
|
348
|
+
if (roll.state === "verified") return null;
|
|
359
349
|
if (roll.workers === 0) return "no workers";
|
|
360
|
-
if (roll.reports === 0)
|
|
361
|
-
|
|
350
|
+
if (roll.reports === 0) return "no credential report";
|
|
351
|
+
if (roll.state === "configured") {
|
|
352
|
+
return roll.latestLiveTest?.ok === false ? "live test failed" : "not live-tested";
|
|
362
353
|
}
|
|
363
|
-
const w = `${roll.workers} ${roll.workers === 1 ? "worker" : "workers"}`;
|
|
364
|
-
if (roll.state === "verified") return `${w} · live test ok`;
|
|
365
|
-
if (roll.state === "configured") return `${w} · presence ok, awaiting live test`;
|
|
366
354
|
return roll.latestMissing.length > 0
|
|
367
355
|
? `missing: ${roll.latestMissing.join(", ")}`
|
|
368
|
-
: "
|
|
356
|
+
: "credentials blocked";
|
|
369
357
|
}
|
|
370
358
|
|
|
371
359
|
/**
|
|
@@ -375,7 +363,7 @@ function describeRoll(roll: CredRollup): string {
|
|
|
375
363
|
* workers via migration 054/055), runs the cred-status rollup per provider,
|
|
376
364
|
* and aggregates:
|
|
377
365
|
*
|
|
378
|
-
* `verified` — every provider
|
|
366
|
+
* `verified` — every provider's latest live test passed.
|
|
379
367
|
* `configured` — every provider has at least `configured`, ≥1 not verified.
|
|
380
368
|
* `unverified` — any provider has `unverified` (no reports OR all-blocked).
|
|
381
369
|
*
|
|
@@ -398,13 +386,25 @@ async function harnessMilestone(): Promise<SetupMilestone> {
|
|
|
398
386
|
}
|
|
399
387
|
|
|
400
388
|
const perProvider: { provider: z.infer<typeof ProviderNameSchema>; roll: CredRollup }[] = [];
|
|
389
|
+
let recognised = 0;
|
|
401
390
|
for (const { provider } of fleet) {
|
|
402
391
|
const parsed = ProviderNameSchema.safeParse(provider);
|
|
403
392
|
if (!parsed.success) continue;
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
393
|
+
recognised++;
|
|
394
|
+
const roll = await rollupCredStatusForProvider(parsed.data);
|
|
395
|
+
// A provider whose agents are all offline has nothing live to judge.
|
|
396
|
+
if (roll.workers === 0) continue;
|
|
397
|
+
perProvider.push({ provider: parsed.data, roll });
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (recognised > 0 && perProvider.length === 0) {
|
|
401
|
+
return {
|
|
402
|
+
id: "harness",
|
|
403
|
+
label: "Harness configured",
|
|
404
|
+
state: "unverified",
|
|
405
|
+
hint: "No agents online. Start a worker to run a live credential test.",
|
|
406
|
+
action_url: "/agents",
|
|
407
|
+
};
|
|
408
408
|
}
|
|
409
409
|
|
|
410
410
|
if (perProvider.length === 0) {
|
|
@@ -424,7 +424,13 @@ async function harnessMilestone(): Promise<SetupMilestone> {
|
|
|
424
424
|
? "configured"
|
|
425
425
|
: "unverified";
|
|
426
426
|
|
|
427
|
-
const hint =
|
|
427
|
+
const hint =
|
|
428
|
+
perProvider
|
|
429
|
+
.flatMap((p) => {
|
|
430
|
+
const phrase = describeRoll(p.roll);
|
|
431
|
+
return phrase ? [`${p.provider}: ${phrase}`] : [];
|
|
432
|
+
})
|
|
433
|
+
.join(" · ") || undefined;
|
|
428
434
|
const singleProvider = perProvider.length === 1 ? perProvider[0]?.provider : undefined;
|
|
429
435
|
|
|
430
436
|
return {
|
|
@@ -848,7 +854,7 @@ export async function handleStatus(
|
|
|
848
854
|
if (roll.workers === 0) {
|
|
849
855
|
json(res, {
|
|
850
856
|
ok: false,
|
|
851
|
-
error: `No workers
|
|
857
|
+
error: `No online workers with HARNESS_PROVIDER=${provider}. Start a worker — its boot loop will run a live test and report it here.`,
|
|
852
858
|
latency_ms: 0,
|
|
853
859
|
});
|
|
854
860
|
return true;
|
package/src/http/tasks.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
getSteeringMessagesForTask,
|
|
21
21
|
getTaskAttachments,
|
|
22
22
|
getTaskById,
|
|
23
|
+
getTaskLineage,
|
|
23
24
|
getTasksCount,
|
|
24
25
|
markSteeringDelivered,
|
|
25
26
|
markSteeringHandled,
|
|
@@ -29,6 +30,7 @@ import {
|
|
|
29
30
|
resumeTask,
|
|
30
31
|
settleSupersededTaskDependents,
|
|
31
32
|
supersedeTask,
|
|
33
|
+
TASK_LINEAGE_LIMITS,
|
|
32
34
|
updateAgentStatusFromCapacity,
|
|
33
35
|
updateTaskClaudeSessionId,
|
|
34
36
|
updateTaskProgress,
|
|
@@ -578,6 +580,33 @@ const getTask = route({
|
|
|
578
580
|
},
|
|
579
581
|
});
|
|
580
582
|
|
|
583
|
+
const getTaskLineageRoute = route({
|
|
584
|
+
method: "get",
|
|
585
|
+
path: "/api/tasks/{id}/lineage",
|
|
586
|
+
pattern: ["api", "tasks", null, "lineage"],
|
|
587
|
+
session: { taskParam: "id" },
|
|
588
|
+
summary: "Get the tree a task belongs to (ancestors and descendants)",
|
|
589
|
+
description: `Follows \`parentTaskId\` up to the topmost ancestor, then returns every descendant of that root as slim task rows, the task's own subtree first. Bounded: at most ${TASK_LINEAGE_LIMITS.maxAncestors} hops up, \`maxDepth\` levels down and about twice \`maxNodes\` rows; \`truncated\` is true when any task in the tree is missing from the response.`,
|
|
590
|
+
tags: ["Tasks"],
|
|
591
|
+
params: z.object({ id: z.string() }),
|
|
592
|
+
query: z.object({
|
|
593
|
+
maxNodes: z.coerce.number().int().min(1).max(TASK_LINEAGE_LIMITS.maxNodes).optional(),
|
|
594
|
+
maxDepth: z.coerce.number().int().min(1).max(TASK_LINEAGE_LIMITS.maxDepth).optional(),
|
|
595
|
+
}),
|
|
596
|
+
responses: {
|
|
597
|
+
200: {
|
|
598
|
+
description: "The lineage tree as a flat list linked by `parentTaskId`",
|
|
599
|
+
schema: z.object({
|
|
600
|
+
rootTaskId: z.string(),
|
|
601
|
+
tasks: z.array(AgentTaskSummarySchema.extend({ workflowRunId: z.string().optional() })),
|
|
602
|
+
truncated: z.boolean(),
|
|
603
|
+
}),
|
|
604
|
+
},
|
|
605
|
+
403: { description: "A user caller cannot read the task's session" },
|
|
606
|
+
404: { description: "Task not found" },
|
|
607
|
+
},
|
|
608
|
+
});
|
|
609
|
+
|
|
581
610
|
const updateTaskProgressRoute = route({
|
|
582
611
|
method: "post",
|
|
583
612
|
path: "/api/tasks/{id}/progress",
|
|
@@ -1121,6 +1150,8 @@ export async function handleTasks(
|
|
|
1121
1150
|
offeredTo: parsed.body.offeredTo || undefined,
|
|
1122
1151
|
dir: parsed.body.dir || undefined,
|
|
1123
1152
|
parentTaskId: parsed.body.parentTaskId || undefined,
|
|
1153
|
+
// Human chat starts a new output contract; agent children keep inheriting.
|
|
1154
|
+
inheritParentOutputSchema: principal.kind === "agent",
|
|
1124
1155
|
source: parsed.body.source || "api",
|
|
1125
1156
|
outputSchema: parsed.body.outputSchema || undefined,
|
|
1126
1157
|
contextKey: parsed.body.contextKey || undefined,
|
|
@@ -1615,6 +1646,22 @@ export async function handleTasks(
|
|
|
1615
1646
|
return true;
|
|
1616
1647
|
}
|
|
1617
1648
|
|
|
1649
|
+
if (getTaskLineageRoute.match(req.method, pathSegments)) {
|
|
1650
|
+
const parsed = await getTaskLineageRoute.parse(req, res, pathSegments, queryParams);
|
|
1651
|
+
if (!parsed) return true;
|
|
1652
|
+
// Every task in the tree shares the session root, so the path posture covers them all.
|
|
1653
|
+
const lineage = await getTaskLineage(parsed.params.id, {
|
|
1654
|
+
maxNodes: parsed.query.maxNodes,
|
|
1655
|
+
maxDepth: parsed.query.maxDepth,
|
|
1656
|
+
});
|
|
1657
|
+
if (!lineage) {
|
|
1658
|
+
jsonError(res, "Task not found", 404);
|
|
1659
|
+
return true;
|
|
1660
|
+
}
|
|
1661
|
+
getTaskLineageRoute.respond(res, 200, lineage);
|
|
1662
|
+
return true;
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1618
1665
|
if (updateTaskProgressRoute.match(req.method, pathSegments)) {
|
|
1619
1666
|
const parsed = await updateTaskProgressRoute.parse(req, res, pathSegments, queryParams);
|
|
1620
1667
|
if (!parsed) return true;
|
|
@@ -359,7 +359,7 @@ const copilotTargetProfile: AcpTargetProfile = {
|
|
|
359
359
|
},
|
|
360
360
|
};
|
|
361
361
|
|
|
362
|
-
/** Qwen Code's `--auth-type` choices (0.25.
|
|
362
|
+
/** Qwen Code's `--auth-type` choices (0.25.3). `qwen-oauth` needs a browser, so it is left out. */
|
|
363
363
|
const QWEN_AUTH_TYPES = ["openai", "openai-responses", "anthropic", "gemini", "vertex-ai"] as const;
|
|
364
364
|
|
|
365
365
|
// Qwen Code is a Gemini CLI fork: QWEN_SYSTEM_MD replaces its built-in prompt
|
|
@@ -44,7 +44,7 @@ import type {
|
|
|
44
44
|
* default; the image installs exactly this version and the per-task settings
|
|
45
45
|
* set `amp.updates.mode: "disabled"`. Bump it deliberately, with a live run.
|
|
46
46
|
*/
|
|
47
|
-
export const AMP_PACKAGE = "@ampcode/cli@0.0.
|
|
47
|
+
export const AMP_PACKAGE = "@ampcode/cli@0.0.1792411243-gb8cffc";
|
|
48
48
|
|
|
49
49
|
/** MCP server name. Amp exposes its tools as `agent_swarm` / `store_progress` (dashes become underscores). */
|
|
50
50
|
const AMP_MCP_SERVER_NAME = "agent-swarm";
|
package/src/telemetry.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* - Opt-out via ANONYMIZED_TELEMETRY=false
|
|
5
5
|
* - Fire-and-forget: never throws, never blocks
|
|
6
|
-
* - No DB and no external services (global fetch +
|
|
6
|
+
* - No DB and no external services (global fetch + built-in APIs only)
|
|
7
7
|
* - Importable from both API server and workers
|
|
8
8
|
* - Every event is schema_version 2: a top-level `context` identity envelope
|
|
9
9
|
* plus properties typed against the proxy's event catalog
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* catalog fails `tsc`, and the proxy rejects it at ingest.
|
|
12
12
|
*/
|
|
13
13
|
import { randomUUID } from "node:crypto";
|
|
14
|
+
import { existsSync } from "node:fs";
|
|
14
15
|
import pkg from "../package.json";
|
|
15
16
|
import { isSlackConfigured } from "./slack/config";
|
|
16
17
|
import {
|
|
@@ -591,14 +592,24 @@ function isCloudDeployment(): boolean {
|
|
|
591
592
|
return raw === "true" || raw === "1";
|
|
592
593
|
}
|
|
593
594
|
|
|
594
|
-
|
|
595
|
+
let cachedIsGitCheckout: boolean | undefined;
|
|
596
|
+
|
|
597
|
+
export function getTelemetryEnvironment(packageRoot = new URL("../", import.meta.url)): string {
|
|
595
598
|
const explicit = process.env.DESPLEGA_TELEMETRY_ENV?.trim();
|
|
596
599
|
if (explicit) return explicit;
|
|
597
600
|
|
|
598
601
|
// Do not default from NODE_ENV: shipped Bun/npm installs can report
|
|
599
602
|
// "development" even when the operator did not choose a telemetry cohort.
|
|
600
603
|
if (getNodeEnv() === "test") return "test";
|
|
601
|
-
|
|
604
|
+
// Git checkouts (including worktrees) are development; shipped packages omit .git.
|
|
605
|
+
if (cachedIsGitCheckout === undefined) {
|
|
606
|
+
try {
|
|
607
|
+
cachedIsGitCheckout = existsSync(new URL(".git", packageRoot));
|
|
608
|
+
} catch {
|
|
609
|
+
cachedIsGitCheckout = false;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
return cachedIsGitCheckout ? "development" : "production";
|
|
602
613
|
}
|
|
603
614
|
|
|
604
615
|
/**
|
|
@@ -741,6 +752,7 @@ function emit(
|
|
|
741
752
|
* Do not call from production code.
|
|
742
753
|
*/
|
|
743
754
|
export function _resetTelemetryStateForTests(): void {
|
|
755
|
+
cachedIsGitCheckout = undefined;
|
|
744
756
|
installationId = null;
|
|
745
757
|
installedAt = null;
|
|
746
758
|
ingestObserver = null;
|
|
@@ -217,6 +217,31 @@ test("rejects invalid filters, sorts, values, source projections, join keys, and
|
|
|
217
217
|
expect((await call("app-rows-list", {}, "")).isError).toBe(true);
|
|
218
218
|
});
|
|
219
219
|
|
|
220
|
+
test("app-rows-list rejects equals on a json column, like REST filters and named queries", async () => {
|
|
221
|
+
const jsonApp = await createApp({
|
|
222
|
+
name: "Row tools json",
|
|
223
|
+
definition: {
|
|
224
|
+
...definition,
|
|
225
|
+
models: { note: { columns: { title: { kind: "string" }, payload: { kind: "json" } } } },
|
|
226
|
+
},
|
|
227
|
+
});
|
|
228
|
+
const created = await call("app-row-create", {
|
|
229
|
+
appId: jsonApp.id,
|
|
230
|
+
values: { title: "json", payload: { x: 1 } },
|
|
231
|
+
});
|
|
232
|
+
expect(created.isError).not.toBe(true);
|
|
233
|
+
|
|
234
|
+
const listed = await call("app-rows-list", { appId: jsonApp.id, equals: { payload: "x" } });
|
|
235
|
+
expect(listed.isError).toBe(true);
|
|
236
|
+
expect(listed.structuredContent).toMatchObject({
|
|
237
|
+
issues: [{ path: "equals.payload", message: "json columns cannot be filtered" }],
|
|
238
|
+
});
|
|
239
|
+
// A scalar column on the same model still filters.
|
|
240
|
+
const byTitle = await call("app-rows-list", { appId: jsonApp.id, equals: { title: "json" } });
|
|
241
|
+
expect(byTitle.isError).not.toBe(true);
|
|
242
|
+
expect(byTitle.structuredContent.total).toBe(1);
|
|
243
|
+
});
|
|
244
|
+
|
|
220
245
|
test("enforces row, bulk, filter, and limit caps before writing", async () => {
|
|
221
246
|
await expect(
|
|
222
247
|
call("app-rows-create", { rows: Array.from({ length: 501 }, () => ({ title: "too-many" })) }),
|