@siming-org/server 0.3.0 → 0.4.0
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/{chunk-T7QAGG73.js → chunk-XVFWTF42.js} +373 -47
- package/dist/index.js +1 -1
- package/dist/main.js +30 -1
- package/package.json +2 -2
- package/web-dist/assets/index-BDVtljmz.css +1 -0
- package/web-dist/assets/index-D9vR6Pjw.js +122 -0
- package/web-dist/index.html +2 -2
- package/web-dist/assets/index-B_ZlCIgd.css +0 -1
- package/web-dist/assets/index-hBW7IJvz.js +0 -121
|
@@ -235,7 +235,10 @@ import {
|
|
|
235
235
|
SkillCreateSchema,
|
|
236
236
|
SkillUpdateSchema,
|
|
237
237
|
SkillCopySchema,
|
|
238
|
+
AssetSetEnabledSchema,
|
|
238
239
|
OBJECT_ID_HEX,
|
|
240
|
+
assertReferencesDeletable,
|
|
241
|
+
assertReferenceAggregateLimit,
|
|
239
242
|
NotFoundError as NotFoundError2,
|
|
240
243
|
ConflictError as ConflictError2,
|
|
241
244
|
BadRequestError,
|
|
@@ -243,19 +246,26 @@ import {
|
|
|
243
246
|
} from "@siming-org/core";
|
|
244
247
|
var SkillListQuerySchema = z.object({
|
|
245
248
|
projectId: z.string().optional(),
|
|
246
|
-
scope: z.enum(["global", "project"]).optional()
|
|
249
|
+
scope: z.enum(["global", "project"]).optional(),
|
|
250
|
+
q: z.string().trim().min(1).max(100).optional(),
|
|
251
|
+
includeDisabled: z.stringbool().optional()
|
|
247
252
|
}).refine((q) => !(q.scope === "project" && !q.projectId), {
|
|
248
253
|
message: "scope=project requires projectId",
|
|
249
254
|
path: ["projectId"]
|
|
250
255
|
});
|
|
251
256
|
var SkillByNameQuerySchema = z.object({
|
|
252
257
|
scope: z.enum(["global", "project"]).optional(),
|
|
253
|
-
projectId: z.string().regex(OBJECT_ID_HEX).optional()
|
|
258
|
+
projectId: z.string().regex(OBJECT_ID_HEX).optional(),
|
|
259
|
+
includeDisabled: z.stringbool().optional()
|
|
254
260
|
}).superRefine((q, ctx) => {
|
|
255
261
|
if (q.scope === "project" && !q.projectId) {
|
|
256
262
|
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "scope=project requires projectId", path: ["projectId"] });
|
|
257
263
|
}
|
|
258
264
|
});
|
|
265
|
+
function skillToListItem(skill) {
|
|
266
|
+
const { references, ...rest } = skill;
|
|
267
|
+
return { ...rest, referenceCount: references?.length ?? 0 };
|
|
268
|
+
}
|
|
259
269
|
function createSkillRoutes(client) {
|
|
260
270
|
const app = new Hono4();
|
|
261
271
|
const repo = createSkillRepo(client.db());
|
|
@@ -272,15 +282,18 @@ function createSkillRoutes(client) {
|
|
|
272
282
|
};
|
|
273
283
|
app.get("/api/skills", zValidator2("query", SkillListQuerySchema), async (c) => {
|
|
274
284
|
const q = c.req.valid("query");
|
|
285
|
+
const opts = { includeDisabled: q.includeDisabled, q: q.q };
|
|
275
286
|
if (q.scope) {
|
|
276
|
-
return c.json(await repo.listSkillsByScopeFilter(q.scope, q.projectId));
|
|
287
|
+
return c.json((await repo.listSkillsByScopeFilter(q.scope, q.projectId, opts)).map(skillToListItem));
|
|
277
288
|
}
|
|
278
|
-
return c.json(
|
|
289
|
+
return c.json(
|
|
290
|
+
(q.projectId ? await repo.listSkillsByScope(q.projectId, opts) : await repo.listSkills(opts)).map(skillToListItem)
|
|
291
|
+
);
|
|
279
292
|
});
|
|
280
293
|
app.get("/api/skills/:name", zValidator2("query", SkillByNameQuerySchema), async (c) => {
|
|
281
294
|
const name = c.req.param("name");
|
|
282
295
|
const q = c.req.valid("query");
|
|
283
|
-
const skill = await resolveAssetByScope(repo, name, q);
|
|
296
|
+
const skill = await resolveAssetByScope(repo, name, q, { includeDisabled: q.includeDisabled });
|
|
284
297
|
if (!skill) throw new NotFoundError2("skill", name);
|
|
285
298
|
return c.json(skill);
|
|
286
299
|
});
|
|
@@ -294,7 +307,7 @@ function createSkillRoutes(client) {
|
|
|
294
307
|
const name = c.req.param("name");
|
|
295
308
|
const data = c.req.valid("json");
|
|
296
309
|
const q = c.req.valid("query");
|
|
297
|
-
const existing = await resolveAssetByScope(repo, name, q);
|
|
310
|
+
const existing = await resolveAssetByScope(repo, name, q, { includeDisabled: true });
|
|
298
311
|
if (!existing) throw new NotFoundError2("skill", name);
|
|
299
312
|
if (data.category !== void 0) await assertCategoryValid(data.category);
|
|
300
313
|
if (isScopeMutation(existing, data)) {
|
|
@@ -307,6 +320,18 @@ function createSkillRoutes(client) {
|
|
|
307
320
|
if ((data.scope ?? existing.scope) === "project" && effectiveProjectId) {
|
|
308
321
|
await loadProjectForWrite(projectRepo, effectiveProjectId);
|
|
309
322
|
}
|
|
323
|
+
assertReferencesDeletable({
|
|
324
|
+
resource: "skill",
|
|
325
|
+
name,
|
|
326
|
+
existingReferences: existing.references,
|
|
327
|
+
nextReferences: data.references,
|
|
328
|
+
nextMainBody: data.content,
|
|
329
|
+
currentMainBody: existing.content
|
|
330
|
+
});
|
|
331
|
+
assertReferenceAggregateLimit({
|
|
332
|
+
effectiveMainBody: data.content ?? existing.content,
|
|
333
|
+
nextReferences: data.references
|
|
334
|
+
});
|
|
310
335
|
const skill = await repo.updateByNameScoped(name, q.scope ?? "global", q.projectId, data);
|
|
311
336
|
if (!skill) throw new NotFoundError2("skill", name);
|
|
312
337
|
return c.json(skill);
|
|
@@ -315,7 +340,7 @@ function createSkillRoutes(client) {
|
|
|
315
340
|
const name = c.req.param("name");
|
|
316
341
|
const input = c.req.valid("json");
|
|
317
342
|
const q = c.req.valid("query");
|
|
318
|
-
const existing = await resolveAssetByScope(repo, name, q);
|
|
343
|
+
const existing = await resolveAssetByScope(repo, name, q, { includeDisabled: true });
|
|
319
344
|
if (!existing) throw new NotFoundError2("skill", name);
|
|
320
345
|
if (input.newScope === "project") {
|
|
321
346
|
await loadProjectForWrite(projectRepo, input.targetProjectId);
|
|
@@ -331,12 +356,26 @@ function createSkillRoutes(client) {
|
|
|
331
356
|
app.delete("/api/skills/:name", zValidator2("query", SkillByNameQuerySchema), async (c) => {
|
|
332
357
|
const name = c.req.param("name");
|
|
333
358
|
const q = c.req.valid("query");
|
|
334
|
-
const existing = await resolveAssetByScope(repo, name, q);
|
|
359
|
+
const existing = await resolveAssetByScope(repo, name, q, { includeDisabled: true });
|
|
335
360
|
if (!existing) throw new NotFoundError2("skill", name);
|
|
336
361
|
const deleted = await repo.deleteByNameScoped(name, q.scope ?? "global", q.projectId);
|
|
337
362
|
if (!deleted) throw new NotFoundError2("skill", name);
|
|
338
363
|
return c.body(null, 204);
|
|
339
364
|
});
|
|
365
|
+
app.post("/api/skills/:name/enabled", zValidator2("query", SkillByNameQuerySchema), zValidator2("json", AssetSetEnabledSchema), async (c) => {
|
|
366
|
+
const name = c.req.param("name");
|
|
367
|
+
const body = c.req.valid("json");
|
|
368
|
+
const q = c.req.valid("query");
|
|
369
|
+
const existing = await resolveAssetByScope(repo, name, q, { includeDisabled: true });
|
|
370
|
+
if (!existing) throw new NotFoundError2("skill", name);
|
|
371
|
+
const scope = q.scope ?? "global";
|
|
372
|
+
if (scope === "project") {
|
|
373
|
+
await loadProjectForWrite(projectRepo, existing.projectId ?? q.projectId);
|
|
374
|
+
}
|
|
375
|
+
const skill = await repo.updateByNameScoped(name, scope, q.projectId, { enabled: body.enabled });
|
|
376
|
+
if (!skill) throw new NotFoundError2("skill", name);
|
|
377
|
+
return c.json({ name: skill.name, enabled: skill.enabled ?? true });
|
|
378
|
+
});
|
|
340
379
|
return app;
|
|
341
380
|
}
|
|
342
381
|
function isScopeMutation(existing, patch) {
|
|
@@ -344,8 +383,8 @@ function isScopeMutation(existing, patch) {
|
|
|
344
383
|
if (patch.projectId !== void 0 && patch.projectId !== existing.projectId) return true;
|
|
345
384
|
return false;
|
|
346
385
|
}
|
|
347
|
-
async function resolveAssetByScope(repo, name, q) {
|
|
348
|
-
return repo.getByNameScoped(name, q.scope ?? "global", q.projectId);
|
|
386
|
+
async function resolveAssetByScope(repo, name, q, opts) {
|
|
387
|
+
return repo.getByNameScoped(name, q.scope ?? "global", q.projectId, opts);
|
|
349
388
|
}
|
|
350
389
|
|
|
351
390
|
// src/routes/agent.routes.ts
|
|
@@ -353,6 +392,7 @@ import { Hono as Hono5 } from "hono";
|
|
|
353
392
|
import { zValidator as zValidator3 } from "@hono/zod-validator";
|
|
354
393
|
import { z as z2 } from "zod";
|
|
355
394
|
import {
|
|
395
|
+
bumpPatch,
|
|
356
396
|
createAgentRepo,
|
|
357
397
|
createSkillRepo as createSkillRepo2,
|
|
358
398
|
createProjectRepo as createProjectRepo3,
|
|
@@ -360,15 +400,24 @@ import {
|
|
|
360
400
|
AgentCreateSchema,
|
|
361
401
|
AgentUpdateSchema,
|
|
362
402
|
AgentCopySchema,
|
|
403
|
+
AssetSetEnabledSchema as AssetSetEnabledSchema2,
|
|
404
|
+
assertReferencesDeletable as assertReferencesDeletable2,
|
|
405
|
+
assertReferenceAggregateLimit as assertReferenceAggregateLimit2,
|
|
363
406
|
NotFoundError as NotFoundError3,
|
|
364
407
|
ConflictError as ConflictError3,
|
|
365
408
|
BIZ_CODE_MESSAGES as BIZ_CODE_MESSAGES3,
|
|
366
409
|
assertBoundSkillsCompatible,
|
|
367
410
|
assertModelAliasExists
|
|
368
411
|
} from "@siming-org/core";
|
|
412
|
+
function agentToListItem(agent) {
|
|
413
|
+
const { references, ...rest } = agent;
|
|
414
|
+
return { ...rest, referenceCount: references?.length ?? 0 };
|
|
415
|
+
}
|
|
369
416
|
var AgentListQuerySchema = z2.object({
|
|
370
417
|
projectId: z2.string().optional(),
|
|
371
|
-
scope: z2.enum(["global", "project"]).optional()
|
|
418
|
+
scope: z2.enum(["global", "project"]).optional(),
|
|
419
|
+
q: z2.string().trim().min(1).max(100).optional(),
|
|
420
|
+
includeDisabled: z2.stringbool().optional()
|
|
372
421
|
}).refine((q) => !(q.scope === "project" && !q.projectId), {
|
|
373
422
|
message: "scope=project requires projectId",
|
|
374
423
|
path: ["projectId"]
|
|
@@ -381,15 +430,18 @@ function createAgentRoutes(client) {
|
|
|
381
430
|
const aliasRepo = createModelAliasRepo(client.db());
|
|
382
431
|
app.get("/api/agents", zValidator3("query", AgentListQuerySchema), async (c) => {
|
|
383
432
|
const q = c.req.valid("query");
|
|
433
|
+
const opts = { includeDisabled: q.includeDisabled, q: q.q };
|
|
384
434
|
if (q.scope) {
|
|
385
|
-
return c.json(await repo.listAgentsByScopeFilter(q.scope, q.projectId));
|
|
435
|
+
return c.json((await repo.listAgentsByScopeFilter(q.scope, q.projectId, opts)).map(agentToListItem));
|
|
386
436
|
}
|
|
387
|
-
return c.json(
|
|
437
|
+
return c.json(
|
|
438
|
+
(q.projectId ? await repo.listAgentsByScope(q.projectId, opts) : await repo.listAgents(opts)).map(agentToListItem)
|
|
439
|
+
);
|
|
388
440
|
});
|
|
389
441
|
app.get("/api/agents/:name", zValidator3("query", SkillByNameQuerySchema), async (c) => {
|
|
390
442
|
const name = c.req.param("name");
|
|
391
443
|
const q = c.req.valid("query");
|
|
392
|
-
const agent = await resolveAssetByScope(repo, name, q);
|
|
444
|
+
const agent = await resolveAssetByScope(repo, name, q, { includeDisabled: q.includeDisabled });
|
|
393
445
|
if (!agent) throw new NotFoundError3("agent", name);
|
|
394
446
|
return c.json(agent);
|
|
395
447
|
});
|
|
@@ -404,8 +456,12 @@ function createAgentRoutes(client) {
|
|
|
404
456
|
const name = c.req.param("name");
|
|
405
457
|
const data = c.req.valid("json");
|
|
406
458
|
const q = c.req.valid("query");
|
|
407
|
-
const existing = await resolveAssetByScope(repo, name, q);
|
|
459
|
+
const existing = await resolveAssetByScope(repo, name, q, { includeDisabled: true });
|
|
408
460
|
if (!existing) throw new NotFoundError3("agent", name);
|
|
461
|
+
let payload = data;
|
|
462
|
+
if (data["function"] !== void 0 && data["function"] !== existing["function"]) {
|
|
463
|
+
payload = { ...data, version: bumpPatch(data.version ?? existing.version) };
|
|
464
|
+
}
|
|
409
465
|
if (isScopeMutation(existing, data)) {
|
|
410
466
|
throw new ConflictError3("agent", name, {
|
|
411
467
|
bizCode: "SCOPE_IMMUTABLE",
|
|
@@ -427,7 +483,19 @@ function createAgentRoutes(client) {
|
|
|
427
483
|
if (data.model !== void 0) {
|
|
428
484
|
await assertModelAliasExists(aliasRepo, data.model);
|
|
429
485
|
}
|
|
430
|
-
|
|
486
|
+
assertReferencesDeletable2({
|
|
487
|
+
resource: "agent",
|
|
488
|
+
name,
|
|
489
|
+
existingReferences: existing.references,
|
|
490
|
+
nextReferences: data.references,
|
|
491
|
+
nextMainBody: data.systemPrompt,
|
|
492
|
+
currentMainBody: existing.systemPrompt
|
|
493
|
+
});
|
|
494
|
+
assertReferenceAggregateLimit2({
|
|
495
|
+
effectiveMainBody: data.systemPrompt ?? existing.systemPrompt,
|
|
496
|
+
nextReferences: data.references
|
|
497
|
+
});
|
|
498
|
+
const agent = await repo.updateByNameScoped(name, q.scope ?? "global", q.projectId, payload);
|
|
431
499
|
if (!agent) throw new NotFoundError3("agent", name);
|
|
432
500
|
return c.json(agent);
|
|
433
501
|
});
|
|
@@ -435,7 +503,7 @@ function createAgentRoutes(client) {
|
|
|
435
503
|
const name = c.req.param("name");
|
|
436
504
|
const input = c.req.valid("json");
|
|
437
505
|
const q = c.req.valid("query");
|
|
438
|
-
const existing = await resolveAssetByScope(repo, name, q);
|
|
506
|
+
const existing = await resolveAssetByScope(repo, name, q, { includeDisabled: true });
|
|
439
507
|
if (!existing) throw new NotFoundError3("agent", name);
|
|
440
508
|
if (input.newScope === "project") {
|
|
441
509
|
await loadProjectForWrite(projectRepo, input.targetProjectId);
|
|
@@ -452,12 +520,26 @@ function createAgentRoutes(client) {
|
|
|
452
520
|
app.delete("/api/agents/:name", zValidator3("query", SkillByNameQuerySchema), async (c) => {
|
|
453
521
|
const name = c.req.param("name");
|
|
454
522
|
const q = c.req.valid("query");
|
|
455
|
-
const existing = await resolveAssetByScope(repo, name, q);
|
|
523
|
+
const existing = await resolveAssetByScope(repo, name, q, { includeDisabled: true });
|
|
456
524
|
if (!existing) throw new NotFoundError3("agent", name);
|
|
457
525
|
const deleted = await repo.deleteByNameScoped(name, q.scope ?? "global", q.projectId);
|
|
458
526
|
if (!deleted) throw new NotFoundError3("agent", name);
|
|
459
527
|
return c.body(null, 204);
|
|
460
528
|
});
|
|
529
|
+
app.post("/api/agents/:name/enabled", zValidator3("query", SkillByNameQuerySchema), zValidator3("json", AssetSetEnabledSchema2), async (c) => {
|
|
530
|
+
const name = c.req.param("name");
|
|
531
|
+
const body = c.req.valid("json");
|
|
532
|
+
const q = c.req.valid("query");
|
|
533
|
+
const existing = await resolveAssetByScope(repo, name, q, { includeDisabled: true });
|
|
534
|
+
if (!existing) throw new NotFoundError3("agent", name);
|
|
535
|
+
const scope = q.scope ?? "global";
|
|
536
|
+
if (scope === "project") {
|
|
537
|
+
await loadProjectForWrite(projectRepo, existing.projectId ?? q.projectId);
|
|
538
|
+
}
|
|
539
|
+
const agent = await repo.updateByNameScoped(name, scope, q.projectId, { enabled: body.enabled });
|
|
540
|
+
if (!agent) throw new NotFoundError3("agent", name);
|
|
541
|
+
return c.json({ name: agent.name, enabled: agent.enabled ?? true });
|
|
542
|
+
});
|
|
461
543
|
return app;
|
|
462
544
|
}
|
|
463
545
|
|
|
@@ -523,27 +605,44 @@ import { z as z3 } from "zod";
|
|
|
523
605
|
import {
|
|
524
606
|
createDagTemplateRepo,
|
|
525
607
|
createProjectRepo as createProjectRepo4,
|
|
608
|
+
createSkillRepo as createSkillRepo3,
|
|
609
|
+
createAgentRepo as createAgentRepo2,
|
|
610
|
+
createModelAliasRepo as createModelAliasRepo3,
|
|
526
611
|
DagTemplateCreateSchema,
|
|
527
612
|
DagTemplateCopySchema,
|
|
528
613
|
DagTemplateUpdateSchema,
|
|
614
|
+
AssetSetEnabledSchema as AssetSetEnabledSchema3,
|
|
615
|
+
ImportPlanRequestSchema,
|
|
616
|
+
ImportApplyRequestSchema,
|
|
617
|
+
composeExportBundle,
|
|
618
|
+
buildImportPlan,
|
|
619
|
+
applyImport,
|
|
529
620
|
NotFoundError as NotFoundError5,
|
|
530
621
|
ConflictError as ConflictError5,
|
|
531
622
|
BIZ_CODE_MESSAGES as BIZ_CODE_MESSAGES5
|
|
532
623
|
} from "@siming-org/core";
|
|
533
624
|
var DagTemplateListQuerySchema = z3.object({
|
|
534
625
|
projectId: z3.string().optional(),
|
|
535
|
-
name: z3.string().optional()
|
|
626
|
+
name: z3.string().optional(),
|
|
627
|
+
includeDisabled: z3.stringbool().optional()
|
|
536
628
|
});
|
|
537
629
|
function createDagTemplateRoutes(client) {
|
|
538
630
|
const app = new Hono7();
|
|
539
631
|
const repo = createDagTemplateRepo(client.db());
|
|
540
632
|
const projectRepo = createProjectRepo4(client.db());
|
|
633
|
+
const transferDeps = {
|
|
634
|
+
templateRepo: repo,
|
|
635
|
+
skillRepo: createSkillRepo3(client.db()),
|
|
636
|
+
agentRepo: createAgentRepo2(client.db()),
|
|
637
|
+
modelAliasRepo: createModelAliasRepo3(client.db())
|
|
638
|
+
};
|
|
541
639
|
app.get("/api/dag/templates", zValidator5("query", DagTemplateListQuerySchema), async (c) => {
|
|
542
640
|
const q = c.req.valid("query");
|
|
543
641
|
return c.json(
|
|
544
642
|
await repo.listDagTemplates({
|
|
545
643
|
...q.projectId ? { projectId: q.projectId } : {},
|
|
546
|
-
...q.name ? { name: q.name } : {}
|
|
644
|
+
...q.name ? { name: q.name } : {},
|
|
645
|
+
...q.includeDisabled !== void 0 ? { includeDisabled: q.includeDisabled } : {}
|
|
547
646
|
})
|
|
548
647
|
);
|
|
549
648
|
});
|
|
@@ -553,6 +652,16 @@ function createDagTemplateRoutes(client) {
|
|
|
553
652
|
if (!template) throw new NotFoundError5("dag-template", id);
|
|
554
653
|
return c.json(template);
|
|
555
654
|
});
|
|
655
|
+
app.post("/api/dag/templates/:id/enabled", zValidator5("json", AssetSetEnabledSchema3), async (c) => {
|
|
656
|
+
const id = c.req.param("id");
|
|
657
|
+
const body = c.req.valid("json");
|
|
658
|
+
const existing = await repo.getById(id);
|
|
659
|
+
if (!existing) throw new NotFoundError5("dag-template", id);
|
|
660
|
+
await loadProjectForWrite(projectRepo, existing.projectId);
|
|
661
|
+
const template = await repo.update(id, { enabled: body.enabled });
|
|
662
|
+
if (!template) throw new NotFoundError5("dag-template", id);
|
|
663
|
+
return c.json({ id: template.id, name: template.name, enabled: template.enabled ?? true });
|
|
664
|
+
});
|
|
556
665
|
app.post("/api/dag/templates", zValidator5("json", DagTemplateCreateSchema), async (c) => {
|
|
557
666
|
const data = c.req.valid("json");
|
|
558
667
|
await loadProjectForWrite(projectRepo, data.projectId);
|
|
@@ -605,6 +714,20 @@ function createDagTemplateRoutes(client) {
|
|
|
605
714
|
const copy = await repo.copyDagTemplate(id, input.targetProjectId, input.newName);
|
|
606
715
|
return c.json(copy, 201);
|
|
607
716
|
});
|
|
717
|
+
app.get("/api/dag/templates/:id/export", async (c) => {
|
|
718
|
+
const id = c.req.param("id");
|
|
719
|
+
return c.json(await composeExportBundle(transferDeps, id));
|
|
720
|
+
});
|
|
721
|
+
app.post("/api/dag/templates/import/plan", zValidator5("json", ImportPlanRequestSchema), async (c) => {
|
|
722
|
+
const body = c.req.valid("json");
|
|
723
|
+
await loadProjectForWrite(projectRepo, body.targetProjectId);
|
|
724
|
+
return c.json(await buildImportPlan(transferDeps, body.targetProjectId, body.bundle));
|
|
725
|
+
});
|
|
726
|
+
app.post("/api/dag/templates/import/apply", zValidator5("json", ImportApplyRequestSchema), async (c) => {
|
|
727
|
+
const body = c.req.valid("json");
|
|
728
|
+
await loadProjectForWrite(projectRepo, body.targetProjectId);
|
|
729
|
+
return c.json(await applyImport(transferDeps, body.targetProjectId, body.bundle, body.decisions));
|
|
730
|
+
});
|
|
608
731
|
app.delete("/api/dag/templates/:id", async (c) => {
|
|
609
732
|
const id = c.req.param("id");
|
|
610
733
|
const deleted = await repo.delete(id);
|
|
@@ -627,6 +750,11 @@ import {
|
|
|
627
750
|
ApproveRequestSchema,
|
|
628
751
|
PauseRequestSchema,
|
|
629
752
|
ResumeRequestSchema,
|
|
753
|
+
CancelRequestSchema,
|
|
754
|
+
taskProgress,
|
|
755
|
+
excerpt,
|
|
756
|
+
ContextViewSchema,
|
|
757
|
+
CONTEXT_VIEWS,
|
|
630
758
|
ARTIFACT_TYPES,
|
|
631
759
|
NODE_ID_PATTERN,
|
|
632
760
|
createEnumRegistryRepo as createEnumRegistryRepo2,
|
|
@@ -639,6 +767,7 @@ import {
|
|
|
639
767
|
approveTask,
|
|
640
768
|
pauseTask,
|
|
641
769
|
resumeTask,
|
|
770
|
+
cancelTask,
|
|
642
771
|
renderPrompt,
|
|
643
772
|
toNodeInfo,
|
|
644
773
|
toTaskPublic,
|
|
@@ -649,6 +778,7 @@ var TaskListQuerySchema = z4.object({
|
|
|
649
778
|
status: z4.string().optional(),
|
|
650
779
|
track: z4.string().optional(),
|
|
651
780
|
projectId: z4.string().optional(),
|
|
781
|
+
q: z4.string().trim().min(1).max(100).optional(),
|
|
652
782
|
page: z4.coerce.number().int().min(1).default(1),
|
|
653
783
|
limit: z4.coerce.number().int().min(1).max(500).default(20),
|
|
654
784
|
sort: z4.enum(["progress", "createdAt", "updatedAt"]).optional()
|
|
@@ -701,6 +831,30 @@ function normalizeNodeRecords(records) {
|
|
|
701
831
|
}
|
|
702
832
|
return out;
|
|
703
833
|
}
|
|
834
|
+
function stripArtifactContent(records) {
|
|
835
|
+
const out = {};
|
|
836
|
+
for (const [nodeId, record] of Object.entries(records)) {
|
|
837
|
+
out[nodeId] = {
|
|
838
|
+
...record,
|
|
839
|
+
artifacts: record.artifacts.map((a) => {
|
|
840
|
+
if (a.content === void 0) return a;
|
|
841
|
+
const { content: _stripped, ...rest } = a;
|
|
842
|
+
return rest;
|
|
843
|
+
})
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
return out;
|
|
847
|
+
}
|
|
848
|
+
function writeAck(entity, updated, entry, echo) {
|
|
849
|
+
return {
|
|
850
|
+
taskId: entity.taskId,
|
|
851
|
+
updated,
|
|
852
|
+
...entry !== void 0 ? { entry } : {},
|
|
853
|
+
...echo !== void 0 ? { echo } : {},
|
|
854
|
+
updatedAt: entity.updatedAt ?? /* @__PURE__ */ new Date(),
|
|
855
|
+
task: { ...toTaskPublic(entity), projectId: entity.projectId, progress: taskProgress(entity) }
|
|
856
|
+
};
|
|
857
|
+
}
|
|
704
858
|
function createTaskRoutes(client) {
|
|
705
859
|
const app = new Hono8();
|
|
706
860
|
const repo = createTaskRepo(client.db());
|
|
@@ -713,6 +867,7 @@ function createTaskRoutes(client) {
|
|
|
713
867
|
...q.status ? { status: q.status } : {},
|
|
714
868
|
...q.track ? { track: q.track } : {},
|
|
715
869
|
...q.projectId ? { projectId: q.projectId } : {},
|
|
870
|
+
...q.q !== void 0 ? { q: q.q } : {},
|
|
716
871
|
page: q.page,
|
|
717
872
|
limit: q.limit,
|
|
718
873
|
...q.sort ? { sort: q.sort } : {}
|
|
@@ -739,6 +894,12 @@ function createTaskRoutes(client) {
|
|
|
739
894
|
assertTypeTrackCompatible(input.type, input.track);
|
|
740
895
|
const template = await templateRepo.getById(input.dagTemplateId);
|
|
741
896
|
if (!template) throw new NotFoundError6("dag-template", input.dagTemplateId);
|
|
897
|
+
if (template.enabled === false) {
|
|
898
|
+
throw new ConflictError6("task", input.dagTemplateId, {
|
|
899
|
+
bizCode: "TEMPLATE_DISABLED",
|
|
900
|
+
message: BIZ_CODE_MESSAGES6.TEMPLATE_DISABLED
|
|
901
|
+
});
|
|
902
|
+
}
|
|
742
903
|
if (input.projectId && input.projectId !== template.projectId) {
|
|
743
904
|
throw new ConflictError6("task", input.dagTemplateId, {
|
|
744
905
|
bizCode: "TEMPLATE_PROJECT_MISMATCH",
|
|
@@ -747,16 +908,33 @@ function createTaskRoutes(client) {
|
|
|
747
908
|
}
|
|
748
909
|
const resolvedProjectId = input.projectId ?? template.projectId;
|
|
749
910
|
await loadProjectForWrite(projectRepo, resolvedProjectId);
|
|
750
|
-
|
|
911
|
+
const created = await repo.createTask(input, template, resolvedProjectId);
|
|
912
|
+
const firstActive = created.dagInstance.nodes.find(
|
|
913
|
+
(n) => created.dagInstance.nodeStates[n.id]?.status === "active"
|
|
914
|
+
);
|
|
915
|
+
if (!firstActive) {
|
|
916
|
+
throw new BadRequestError2(
|
|
917
|
+
`task has no active node to start (all nodes pruned by skipNodes); \u6A21\u677F ${template.name} \u526A\u679D\u540E\u65E0\u53EF\u5F00\u5DE5\u8282\u70B9\uFF0C\u521B\u5EFA\u88AB\u62D2\u7EDD`
|
|
918
|
+
);
|
|
919
|
+
}
|
|
920
|
+
const response = {
|
|
921
|
+
task: { ...toTaskPublic(created), projectId: created.projectId, progress: taskProgress(created) },
|
|
922
|
+
firstNode: toNodeInfo(firstActive, created)
|
|
923
|
+
};
|
|
924
|
+
return c.json(response, 201);
|
|
751
925
|
});
|
|
752
926
|
app.patch("/api/tasks/:taskId", zValidator6("json", TaskPatchSchema), async (c) => {
|
|
753
927
|
const taskId = c.req.param("taskId");
|
|
754
928
|
const body = c.req.valid("json");
|
|
929
|
+
if (body.title === void 0) {
|
|
930
|
+
throw new BadRequestError2("PATCH /api/tasks/:taskId \u9700\u8981\u81F3\u5C11\u4E00\u4E2A\u53EF\u66F4\u65B0\u5B57\u6BB5\uFF08title\uFF09");
|
|
931
|
+
}
|
|
755
932
|
await assertTaskProjectActive(repo, projectRepo, taskId);
|
|
756
|
-
const patch = {
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
933
|
+
const patch = { title: body.title };
|
|
934
|
+
const updatedTask = await repo.updateTask(taskId, patch);
|
|
935
|
+
return c.json(
|
|
936
|
+
writeAck(updatedTask, ["title"], void 0, [{ path: "title", excerpt: excerpt(updatedTask.title) }])
|
|
937
|
+
);
|
|
760
938
|
});
|
|
761
939
|
app.post("/api/tasks/:taskId/advance", zValidator6("json", AdvanceRequestSchema), async (c) => {
|
|
762
940
|
const taskId = c.req.param("taskId");
|
|
@@ -782,14 +960,31 @@ function createTaskRoutes(client) {
|
|
|
782
960
|
const body = c.req.valid("json");
|
|
783
961
|
await assertTaskProjectActive(repo, projectRepo, taskId);
|
|
784
962
|
const result = await pauseTask(mkDeps(repo), taskId, body.reason);
|
|
785
|
-
return c.json(result,
|
|
963
|
+
return c.json(writeAck(result, ["status", "pausedAt"], void 0, [{ path: "status", excerpt: result.status }]));
|
|
786
964
|
});
|
|
787
965
|
app.post("/api/tasks/:taskId/resume", zValidator6("json", ResumeRequestSchema), async (c) => {
|
|
788
966
|
const taskId = c.req.param("taskId");
|
|
789
967
|
const body = c.req.valid("json");
|
|
790
968
|
await assertTaskProjectActive(repo, projectRepo, taskId);
|
|
791
969
|
const result = await resumeTask(mkDeps(repo), taskId, body.decision);
|
|
792
|
-
return c.json(result,
|
|
970
|
+
return c.json(writeAck(result, ["status"], void 0, [{ path: "status", excerpt: `${result.status}\uFF08\u5DF2\u6062\u590D\u624B\u52A8\u6682\u505C\uFF09` }]));
|
|
971
|
+
});
|
|
972
|
+
app.post("/api/tasks/:taskId/cancel", zValidator6("json", CancelRequestSchema), async (c) => {
|
|
973
|
+
const taskId = c.req.param("taskId");
|
|
974
|
+
const body = c.req.valid("json");
|
|
975
|
+
await assertTaskProjectActive(repo, projectRepo, taskId);
|
|
976
|
+
const result = await cancelTask(mkDeps(repo), taskId, body.reason);
|
|
977
|
+
return c.json(
|
|
978
|
+
writeAck(
|
|
979
|
+
result,
|
|
980
|
+
["status", "pausedAt"],
|
|
981
|
+
void 0,
|
|
982
|
+
[
|
|
983
|
+
{ path: "status", excerpt: result.status },
|
|
984
|
+
...body.reason !== void 0 ? [{ path: "history.reason", excerpt: excerpt(body.reason) }] : []
|
|
985
|
+
]
|
|
986
|
+
)
|
|
987
|
+
);
|
|
793
988
|
});
|
|
794
989
|
app.get("/api/tasks/:taskId/history", async (c) => {
|
|
795
990
|
const taskId = c.req.param("taskId");
|
|
@@ -808,6 +1003,13 @@ function createTaskRoutes(client) {
|
|
|
808
1003
|
});
|
|
809
1004
|
app.get("/api/tasks/:taskId/context", async (c) => {
|
|
810
1005
|
const taskId = c.req.param("taskId");
|
|
1006
|
+
const viewR = ContextViewSchema.safeParse(c.req.query("view") ?? "basic");
|
|
1007
|
+
if (!viewR.success) {
|
|
1008
|
+
throw new BadRequestError2(
|
|
1009
|
+
`context view '${c.req.query("view")}' is invalid. Valid values: ${CONTEXT_VIEWS.join(", ")}`
|
|
1010
|
+
);
|
|
1011
|
+
}
|
|
1012
|
+
const view = viewR.data;
|
|
811
1013
|
const task = await repo.getByTaskId(taskId);
|
|
812
1014
|
if (!task) throw new NotFoundError6("task", taskId);
|
|
813
1015
|
const currentNodeActive = task.status === "active" ? task.dagInstance.nodes.find((n) => n.id === task.currentNode) : void 0;
|
|
@@ -839,7 +1041,7 @@ function createTaskRoutes(client) {
|
|
|
839
1041
|
// (toEntity 不跑 parse 补 default——点路径 $set/$push 只写触及字段,record/doc 内数组
|
|
840
1042
|
// 可能缺键,读侧按字段归一到 schema 目标形状,Web/CLI 消费方拿到的恒为完整形)
|
|
841
1043
|
taskDoc: normalizeTaskDoc(task.doc),
|
|
842
|
-
nodeRecords: normalizeNodeRecords(task.nodeRecords),
|
|
1044
|
+
nodeRecords: view === "basic" ? stripArtifactContent(normalizeNodeRecords(task.nodeRecords)) : normalizeNodeRecords(task.nodeRecords),
|
|
843
1045
|
archNotes: task.archNotes ?? []
|
|
844
1046
|
};
|
|
845
1047
|
return c.json(context);
|
|
@@ -852,28 +1054,49 @@ function createTaskRoutes(client) {
|
|
|
852
1054
|
if (body.what !== void 0) sets["doc.what"] = body.what;
|
|
853
1055
|
if (body.why !== void 0) sets["doc.why"] = body.why;
|
|
854
1056
|
if (body.trackNote !== void 0) sets["doc.trackNote"] = body.trackNote;
|
|
855
|
-
|
|
1057
|
+
const updatedDoc = await repo.updateTaskPaths(taskId, { sets });
|
|
1058
|
+
return c.json(
|
|
1059
|
+
writeAck(
|
|
1060
|
+
updatedDoc,
|
|
1061
|
+
Object.keys(sets),
|
|
1062
|
+
void 0,
|
|
1063
|
+
Object.entries(sets).map(([path, value]) => ({ path, excerpt: excerpt(String(value)) }))
|
|
1064
|
+
)
|
|
1065
|
+
);
|
|
856
1066
|
});
|
|
857
1067
|
app.post("/api/tasks/:taskId/doc/acceptance", zValidator6("json", TextItemSchema), async (c) => {
|
|
858
1068
|
const taskId = c.req.param("taskId");
|
|
859
1069
|
const body = c.req.valid("json");
|
|
860
1070
|
await loadTaskForRecordWrite(repo, projectRepo, taskId);
|
|
861
|
-
|
|
1071
|
+
const updatedAcc = await repo.updateTaskPaths(taskId, { pushes: { "doc.acceptance": body.text } });
|
|
1072
|
+
return c.json(
|
|
1073
|
+
writeAck(updatedAcc, ["doc.acceptance"], void 0, [
|
|
1074
|
+
{ path: "doc.acceptance", excerpt: excerpt(body.text) }
|
|
1075
|
+
])
|
|
1076
|
+
);
|
|
862
1077
|
});
|
|
863
1078
|
app.post("/api/tasks/:taskId/doc/non-goal", zValidator6("json", TextItemSchema), async (c) => {
|
|
864
1079
|
const taskId = c.req.param("taskId");
|
|
865
1080
|
const body = c.req.valid("json");
|
|
866
1081
|
await loadTaskForRecordWrite(repo, projectRepo, taskId);
|
|
867
|
-
|
|
1082
|
+
const updatedNg = await repo.updateTaskPaths(taskId, { pushes: { "doc.nonGoals": body.text } });
|
|
1083
|
+
return c.json(
|
|
1084
|
+
writeAck(updatedNg, ["doc.nonGoals"], void 0, [{ path: "doc.nonGoals", excerpt: excerpt(body.text) }])
|
|
1085
|
+
);
|
|
868
1086
|
});
|
|
869
1087
|
app.patch("/api/tasks/:taskId/records/:nodeId/summary", zValidator6("json", RecordSummarySchema), async (c) => {
|
|
870
1088
|
const taskId = c.req.param("taskId");
|
|
871
1089
|
const nodeId = c.req.param("nodeId");
|
|
872
1090
|
const body = c.req.valid("json");
|
|
873
1091
|
await loadTaskForRecordWrite(repo, projectRepo, taskId, nodeId);
|
|
874
|
-
|
|
1092
|
+
const updatedSummary = await repo.updateTaskPaths(taskId, {
|
|
875
1093
|
sets: { [`nodeRecords.${nodeId}.summary`]: body.summary }
|
|
876
|
-
})
|
|
1094
|
+
});
|
|
1095
|
+
return c.json(
|
|
1096
|
+
writeAck(updatedSummary, [`nodeRecords.${nodeId}.summary`], void 0, [
|
|
1097
|
+
{ path: `nodeRecords.${nodeId}.summary`, excerpt: excerpt(body.summary) }
|
|
1098
|
+
])
|
|
1099
|
+
);
|
|
877
1100
|
});
|
|
878
1101
|
app.post("/api/tasks/:taskId/records/:nodeId/checks", zValidator6("json", CheckAddSchema), async (c) => {
|
|
879
1102
|
const taskId = c.req.param("taskId");
|
|
@@ -886,9 +1109,17 @@ function createTaskRoutes(client) {
|
|
|
886
1109
|
item: body.item,
|
|
887
1110
|
passed: body.passed ?? true
|
|
888
1111
|
};
|
|
889
|
-
|
|
1112
|
+
const updatedCheck = await repo.updateTaskPaths(taskId, {
|
|
890
1113
|
pushes: { [`nodeRecords.${nodeId}.checks`]: check }
|
|
891
|
-
})
|
|
1114
|
+
});
|
|
1115
|
+
return c.json(
|
|
1116
|
+
writeAck(
|
|
1117
|
+
updatedCheck,
|
|
1118
|
+
[`nodeRecords.${nodeId}.checks`],
|
|
1119
|
+
{ id: check.id, kind: "check" },
|
|
1120
|
+
[{ path: `nodeRecords.${nodeId}.checks`, excerpt: excerpt(`${check.item}\uFF08passed=${String(check.passed)}\uFF09`) }]
|
|
1121
|
+
)
|
|
1122
|
+
);
|
|
892
1123
|
});
|
|
893
1124
|
app.patch("/api/tasks/:taskId/records/:nodeId/checks/:checkId", zValidator6("json", CheckPatchSchema), async (c) => {
|
|
894
1125
|
const taskId = c.req.param("taskId");
|
|
@@ -903,10 +1134,15 @@ function createTaskRoutes(client) {
|
|
|
903
1134
|
message: `${BIZ_CODE_MESSAGES6.CHECK_NOT_FOUND}\uFF08node ${nodeId}, check ${checkId}\uFF09`
|
|
904
1135
|
});
|
|
905
1136
|
}
|
|
906
|
-
|
|
1137
|
+
const updatedFlip = await repo.updateTaskPaths(taskId, {
|
|
907
1138
|
sets: { [`nodeRecords.${nodeId}.checks.$[e].passed`]: body.passed },
|
|
908
1139
|
arrayFilters: [{ "e.id": checkId }]
|
|
909
|
-
})
|
|
1140
|
+
});
|
|
1141
|
+
return c.json(
|
|
1142
|
+
writeAck(updatedFlip, [`nodeRecords.${nodeId}.checks.${checkId}.passed`], void 0, [
|
|
1143
|
+
{ path: `nodeRecords.${nodeId}.checks.${checkId}.passed`, excerpt: String(body.passed) }
|
|
1144
|
+
])
|
|
1145
|
+
);
|
|
910
1146
|
});
|
|
911
1147
|
app.post("/api/tasks/:taskId/records/:nodeId/artifacts", zValidator6("json", ArtifactAddSchema), async (c) => {
|
|
912
1148
|
const taskId = c.req.param("taskId");
|
|
@@ -920,9 +1156,24 @@ function createTaskRoutes(client) {
|
|
|
920
1156
|
...body.note !== void 0 ? { note: body.note } : {},
|
|
921
1157
|
...body.content !== void 0 ? { content: body.content } : {}
|
|
922
1158
|
};
|
|
923
|
-
|
|
1159
|
+
const updatedArtifact = await repo.updateTaskPaths(taskId, {
|
|
924
1160
|
pushes: { [`nodeRecords.${nodeId}.artifacts`]: artifact }
|
|
925
|
-
})
|
|
1161
|
+
});
|
|
1162
|
+
return c.json(
|
|
1163
|
+
writeAck(
|
|
1164
|
+
updatedArtifact,
|
|
1165
|
+
[`nodeRecords.${nodeId}.artifacts`],
|
|
1166
|
+
{ id: artifact.id, kind: "artifact" },
|
|
1167
|
+
[
|
|
1168
|
+
{
|
|
1169
|
+
path: `nodeRecords.${nodeId}.artifacts`,
|
|
1170
|
+
excerpt: excerpt(
|
|
1171
|
+
`${artifact.type} ${artifact.path}${body.content !== void 0 ? `\uFF08\u542B\u5168\u6587\u5FEB\u7167 ${body.content.length} \u5B57\u7B26\uFF09` : ""}`
|
|
1172
|
+
)
|
|
1173
|
+
}
|
|
1174
|
+
]
|
|
1175
|
+
)
|
|
1176
|
+
);
|
|
926
1177
|
});
|
|
927
1178
|
app.post("/api/tasks/:taskId/records/:nodeId/confirmations", zValidator6("json", ConfirmAddSchema), async (c) => {
|
|
928
1179
|
const taskId = c.req.param("taskId");
|
|
@@ -934,9 +1185,14 @@ function createTaskRoutes(client) {
|
|
|
934
1185
|
quote: body.quote,
|
|
935
1186
|
at: /* @__PURE__ */ new Date()
|
|
936
1187
|
};
|
|
937
|
-
|
|
1188
|
+
const updatedConfirm = await repo.updateTaskPaths(taskId, {
|
|
938
1189
|
pushes: { [`nodeRecords.${nodeId}.confirmations`]: confirmation }
|
|
939
|
-
})
|
|
1190
|
+
});
|
|
1191
|
+
return c.json(
|
|
1192
|
+
writeAck(updatedConfirm, [`nodeRecords.${nodeId}.confirmations`], { id: confirmation.id, kind: "confirmation" }, [
|
|
1193
|
+
{ path: `nodeRecords.${nodeId}.confirmations`, excerpt: excerpt(confirmation.quote) }
|
|
1194
|
+
])
|
|
1195
|
+
);
|
|
940
1196
|
});
|
|
941
1197
|
app.post("/api/tasks/:taskId/records/:nodeId/decisions", zValidator6("json", DecisionAddSchema), async (c) => {
|
|
942
1198
|
const taskId = c.req.param("taskId");
|
|
@@ -948,25 +1204,40 @@ function createTaskRoutes(client) {
|
|
|
948
1204
|
topic: body.topic,
|
|
949
1205
|
decision: body.decision
|
|
950
1206
|
};
|
|
951
|
-
|
|
1207
|
+
const updatedDecision = await repo.updateTaskPaths(taskId, {
|
|
952
1208
|
pushes: { [`nodeRecords.${nodeId}.decisions`]: decision }
|
|
953
|
-
})
|
|
1209
|
+
});
|
|
1210
|
+
return c.json(
|
|
1211
|
+
writeAck(updatedDecision, [`nodeRecords.${nodeId}.decisions`], { id: decision.id, kind: "decision" }, [
|
|
1212
|
+
{ path: `nodeRecords.${nodeId}.decisions`, excerpt: excerpt(`${decision.topic}: ${decision.decision}`) }
|
|
1213
|
+
])
|
|
1214
|
+
);
|
|
954
1215
|
});
|
|
955
1216
|
app.put("/api/tasks/:taskId/records/:nodeId/review", zValidator6("json", ReviewSetSchema), async (c) => {
|
|
956
1217
|
const taskId = c.req.param("taskId");
|
|
957
1218
|
const nodeId = c.req.param("nodeId");
|
|
958
1219
|
const body = c.req.valid("json");
|
|
959
1220
|
await loadTaskForRecordWrite(repo, projectRepo, taskId, nodeId);
|
|
960
|
-
|
|
1221
|
+
const updatedReview = await repo.updateTaskPaths(taskId, {
|
|
961
1222
|
sets: { [`nodeRecords.${nodeId}.review`]: body }
|
|
962
|
-
})
|
|
1223
|
+
});
|
|
1224
|
+
return c.json(
|
|
1225
|
+
writeAck(updatedReview, [`nodeRecords.${nodeId}.review`], void 0, [
|
|
1226
|
+
{ path: `nodeRecords.${nodeId}.review`, excerpt: `${body.verdict}\uFF08rounds=${String(body.rounds)}, critical=${String(body.critical)}\uFF09` }
|
|
1227
|
+
])
|
|
1228
|
+
);
|
|
963
1229
|
});
|
|
964
1230
|
app.post("/api/tasks/:taskId/archnotes", zValidator6("json", TextItemSchema), async (c) => {
|
|
965
1231
|
const taskId = c.req.param("taskId");
|
|
966
1232
|
const body = c.req.valid("json");
|
|
967
1233
|
const task = await loadTaskForRecordWrite(repo, projectRepo, taskId);
|
|
968
1234
|
const note = { id: generateEntryId((task.archNotes ?? []).map((n) => n.id)), text: body.text, at: /* @__PURE__ */ new Date() };
|
|
969
|
-
|
|
1235
|
+
const updatedNote = await repo.updateTaskPaths(taskId, { pushes: { archNotes: note } });
|
|
1236
|
+
return c.json(
|
|
1237
|
+
writeAck(updatedNote, ["archNotes"], { id: note.id, kind: "archnote" }, [
|
|
1238
|
+
{ path: "archNotes", excerpt: excerpt(note.text) }
|
|
1239
|
+
])
|
|
1240
|
+
);
|
|
970
1241
|
});
|
|
971
1242
|
return app;
|
|
972
1243
|
}
|
|
@@ -1116,7 +1387,7 @@ import { serve } from "@hono/node-server";
|
|
|
1116
1387
|
import { createMongoClient } from "@siming-org/core";
|
|
1117
1388
|
|
|
1118
1389
|
// src/ensure-collections.ts
|
|
1119
|
-
import { EnumRegistrySchema } from "@siming-org/core";
|
|
1390
|
+
import { EnumRegistrySchema, bumpPatch as bumpPatch2 } from "@siming-org/core";
|
|
1120
1391
|
async function ensureCollections(client) {
|
|
1121
1392
|
const db = client.db();
|
|
1122
1393
|
await Promise.all([
|
|
@@ -1132,6 +1403,7 @@ async function ensureCollections(client) {
|
|
|
1132
1403
|
await migrateGateRemovalData(db);
|
|
1133
1404
|
await migrateTaskRecordData(db);
|
|
1134
1405
|
await migrateDagTrackTaskValues(db);
|
|
1406
|
+
await migrateAgentFunctionBackfill(db);
|
|
1135
1407
|
await ensurePostMigrationIndexes(db);
|
|
1136
1408
|
}
|
|
1137
1409
|
var ENUM_REGISTRY_SEEDS = {
|
|
@@ -1174,6 +1446,12 @@ var ENUM_REGISTRY_SEEDS = {
|
|
|
1174
1446
|
scope: [
|
|
1175
1447
|
{ value: "global", label: "\u5168\u5C40", builtin: true },
|
|
1176
1448
|
{ value: "project", label: "\u9879\u76EE", builtin: true }
|
|
1449
|
+
],
|
|
1450
|
+
// T202608260002 C3:schema 固定枚举为消费权威(AgentFunctionSchema),registry 仅展示(仿 pause_type 双轨)——
|
|
1451
|
+
// web 后续经 useEnumEntries('agent_function') 消费;两值 builtin(writer 落盘注入按 reviewer 判定,承重字段)
|
|
1452
|
+
agent_function: [
|
|
1453
|
+
{ value: "reviewer", label: "\u5BA1\u67E5\uFF08\u843D\u76D8\u6CE8\u5165\u4FE1\u606F\u8FB9\u754C\uFF09", builtin: true },
|
|
1454
|
+
{ value: "executor", label: "\u6267\u884C/\u901A\u7528\uFF08\u9ED8\u8BA4\uFF09", builtin: true }
|
|
1177
1455
|
]
|
|
1178
1456
|
};
|
|
1179
1457
|
function buildSeedEntries(seeds) {
|
|
@@ -1258,10 +1536,24 @@ async function ensureSkillCollection(db) {
|
|
|
1258
1536
|
content: { bsonType: "string" },
|
|
1259
1537
|
// N016 F9:category 放宽为任意字符串(枚举注册表为运行时权威,DB 只做类型兜底)
|
|
1260
1538
|
category: { bsonType: "string" },
|
|
1539
|
+
// T202608270002:引用文档(可选,存量单文件资产无此字段合法)——路径规则/上限归应用层 Zod,DB 只做类型级声明
|
|
1540
|
+
references: {
|
|
1541
|
+
bsonType: "array",
|
|
1542
|
+
items: {
|
|
1543
|
+
bsonType: "object",
|
|
1544
|
+
required: ["path", "content"],
|
|
1545
|
+
properties: {
|
|
1546
|
+
path: { bsonType: "string", minLength: 1 },
|
|
1547
|
+
content: { bsonType: "string" }
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
},
|
|
1261
1551
|
// N012 F7:作用域字段(全局 / 项目专用);projectId 仅 scope=project 携带
|
|
1262
1552
|
scope: { enum: ["global", "project"] },
|
|
1263
1553
|
projectId: { bsonType: "string" },
|
|
1264
1554
|
version: { bsonType: "string" },
|
|
1555
|
+
// T202608290001:资产启停(可选——enabled === false 即停用,缺失 = 启用,存量零迁移)
|
|
1556
|
+
enabled: { bsonType: "bool" },
|
|
1265
1557
|
createdAt: { bsonType: "date" },
|
|
1266
1558
|
updatedAt: { bsonType: "date" }
|
|
1267
1559
|
}
|
|
@@ -1288,8 +1580,24 @@ async function ensureAgentCollection(db) {
|
|
|
1288
1580
|
version: { bsonType: "string" },
|
|
1289
1581
|
tools: { bsonType: "array", items: { bsonType: "string" } },
|
|
1290
1582
|
permissions: { bsonType: "array", items: { bsonType: "string" } },
|
|
1583
|
+
// T202608270002:引用文档(可选,存量单文件资产无此字段合法)——路径规则/上限归应用层 Zod,DB 只做类型级声明
|
|
1584
|
+
references: {
|
|
1585
|
+
bsonType: "array",
|
|
1586
|
+
items: {
|
|
1587
|
+
bsonType: "object",
|
|
1588
|
+
required: ["path", "content"],
|
|
1589
|
+
properties: {
|
|
1590
|
+
path: { bsonType: "string", minLength: 1 },
|
|
1591
|
+
content: { bsonType: "string" }
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
},
|
|
1291
1595
|
scope: { enum: ["global", "project"] },
|
|
1292
1596
|
projectId: { bsonType: "string" },
|
|
1597
|
+
// T202608260002:功能类型(可选——存量缺省合法,M12 回填)——取值域归应用层 Zod,DB 只做类型兜底
|
|
1598
|
+
"function": { bsonType: "string" },
|
|
1599
|
+
// T202608290001:资产启停(可选——enabled === false 即停用,缺失 = 启用,存量零迁移)
|
|
1600
|
+
enabled: { bsonType: "bool" },
|
|
1293
1601
|
createdAt: { bsonType: "date" },
|
|
1294
1602
|
updatedAt: { bsonType: "date" }
|
|
1295
1603
|
}
|
|
@@ -1315,6 +1623,8 @@ async function ensureDagTemplateCollection(db) {
|
|
|
1315
1623
|
edges: { bsonType: "array" },
|
|
1316
1624
|
isDefault: { bsonType: "bool" },
|
|
1317
1625
|
version: { bsonType: "string" },
|
|
1626
|
+
// T202608290001:模板启停(可选——enabled === false 即停用,缺失 = 启用,存量零迁移)
|
|
1627
|
+
enabled: { bsonType: "bool" },
|
|
1318
1628
|
createdAt: { bsonType: "date" },
|
|
1319
1629
|
updatedAt: { bsonType: "date" }
|
|
1320
1630
|
}
|
|
@@ -1452,6 +1762,22 @@ async function migrateDagTrackTaskValues(db) {
|
|
|
1452
1762
|
throw new Error("T202608240003 M11 \u8FC1\u79FB\u5931\u8D25\uFF1Adag_track doc \u66F4\u65B0\u672A\u547D\u4E2D\uFF08\u542F\u52A8\u671F\u4E0D\u5E94\u53D1\u751F\uFF09");
|
|
1453
1763
|
}
|
|
1454
1764
|
}
|
|
1765
|
+
async function migrateAgentFunctionBackfill(db) {
|
|
1766
|
+
const coll = db.collection("agents");
|
|
1767
|
+
const docs = await coll.find({ "function": { $exists: false } }, { projection: { version: 1 } }).toArray();
|
|
1768
|
+
if (docs.length === 0) return;
|
|
1769
|
+
console.log(`[siming] T202608260002 M12\uFF1Aagents.function \u56DE\u586B ${docs.length} \u4E2A\uFF08executor + version bump\uFF0C\u9A71\u52A8\u5DF2\u88C5\u73AF\u5883\u91CD\u5199\uFF09`);
|
|
1770
|
+
for (const doc of docs) {
|
|
1771
|
+
const baseVersion = typeof doc.version === "string" ? doc.version : "1.0.0";
|
|
1772
|
+
const result = await coll.updateOne(
|
|
1773
|
+
{ _id: doc._id, "function": { $exists: false } },
|
|
1774
|
+
{ $set: { "function": "executor", version: bumpPatch2(baseVersion) } }
|
|
1775
|
+
);
|
|
1776
|
+
if (result.matchedCount === 0) {
|
|
1777
|
+
throw new Error("T202608260002 M12 \u8FC1\u79FB\u5931\u8D25\uFF1Aagents.function \u56DE\u586B\u672A\u547D\u4E2D\uFF08\u542F\u52A8\u671F\u5355\u8FDB\u7A0B\u4E32\u884C\uFF0C\u4E0D\u5E94\u53D1\u751F\uFF09");
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1455
1781
|
async function ensurePostMigrationIndexes(db) {
|
|
1456
1782
|
const tasks = db.collection("tasks");
|
|
1457
1783
|
const taskIndexes = await tasks.listIndexes().toArray();
|