@xopcai/xopc 0.0.172 → 0.0.174
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/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-C3Y-bESI.js → activity-store-CyEDJeIt.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CPyev9P7.js → agent-avatar-dicebear-DF7Bol6I.js} +1 -1
- package/dist/gateway/static/root/assets/agents-BVxEFPQ5.js +2 -0
- package/dist/gateway/static/root/assets/{api-B7qEr_Rw.js → api-DYunqroX.js} +1 -1
- package/dist/gateway/static/root/assets/api-DwyUxpgY.js +1 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-Br_9-7fs.js → app-management-settings-panel-B4xJyvDu.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-uyLcRPai.js → appearance-settings-B2PQxRiu.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-BtIgd82S.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-B19REnR5.js → archive-plugin-DWhBmmjD.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-DLWCC4Yi.js → attachment-load-BOpZfa_I.js} +1 -1
- package/dist/gateway/static/root/assets/{automation-suggestion-card-ky5S5lly.js → automation-suggestion-card-Byu3I7Rs.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-CG_SCH5b.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-CtPEzLlo.js → binary-plugins-6AG1qatz.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-CQVR4Xij.js → block-editor-CJhrn98_.js} +5 -5
- package/dist/gateway/static/root/assets/browser-settings-page-CfLqPWZC.js +8 -0
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-CimCGbhq.js → browser-workflow-inputs-CBVb4mt9.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-DewuCw3p.js → browser-workflows-page-Cq4XUKbu.js} +2 -2
- package/dist/gateway/static/root/assets/capabilities-settings-panel-DCJmm6cR.js +7 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-B5RTs-Az.js → capability-presets-api-hbW4NAKO.js} +1 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-CnkAYvWI.js +1 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-Czu0YzIZ.js → channel-recipient-api-CzMjHb17.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-DtqqFpDn.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-C-5yHbc0.js +1 -0
- package/dist/gateway/static/root/assets/{connector-logo-Di3gnR_D.js → connector-logo-B9Au6gMZ.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-CaHfs8YF.js +2 -0
- package/dist/gateway/static/root/assets/copy-VueTIC2x.js +1 -0
- package/dist/gateway/static/root/assets/desktop-pet-CvFMKYdb.js +1 -0
- package/dist/gateway/static/root/assets/{desktop-pet-settings-C3L6AI8_.js → desktop-pet-settings-CNff5TFb.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-Dvq4iG6P.js → directory-picker-path-field-Bf956uo-.js} +1 -1
- package/dist/gateway/static/root/assets/dreaming-settings-CHM8FE1g.js +3 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-BecQjU0J.js → extension-debug-page-ZqM_0eUs.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BeVkPSm-.js → extension-page-D4hvXOMM.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-DMoo2mKx.js → extension-settings-page-GsqxaJjA.js} +1 -1
- package/dist/gateway/static/root/assets/focus-detail-page-CE6uwrl1.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-config-api-Bthb3_6v.js → gateway-config-api-B4THmgnS.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-Bh8nPvJQ.js → gateway-settings-CPv-MxGE.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-D3USVm9D.js → gateway-startup-retry-MP3K71pP.js} +1 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-DAeb82xP.js +1 -0
- package/dist/gateway/static/root/assets/goal-detail-page-CwLSp01r.js +4 -0
- package/dist/gateway/static/root/assets/{goals-config-api-C_2QWBtb.js → goals-config-api-DCcDuIjG.js} +1 -1
- package/dist/gateway/static/root/assets/goals-page-DvJQ6_4M.js +2 -0
- package/dist/gateway/static/root/assets/{goals-settings-DhL643tc.js → goals-settings-o9QMXvNq.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-COVFwp7C.js → heartbeat-settings-DixwpXnH.js} +1 -1
- package/dist/gateway/static/root/assets/{image-generation-api-BNQlnwpU.js → image-generation-api-BOGH9FGi.js} +1 -1
- package/dist/gateway/static/root/assets/index-CfXiRNN5.css +1 -0
- package/dist/gateway/static/root/assets/index-eyttVNS_.js +212 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-DfdJRJVy.js → keyboard-shortcuts-settings-D4o4ZPF6.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-CPcfqn_A.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-BvCPOgoi.js → local-apps-page-GzMmpO7G.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-BP0vD37A.js → locale-store-CAuhEGCn.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-DXABWCZp.js +7 -0
- package/dist/gateway/static/root/assets/{markdown-split-YO1rDk9m.js → markdown-split-CIX8D1pv.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-CU_RRf-q.js → media-plugins-Bp3eIA45.js} +1 -1
- package/dist/gateway/static/root/assets/messages-BiBdO1-O.js +3 -0
- package/dist/gateway/static/root/assets/{notes-page-CeFiOK3S.js → notes-page-RVFiYAoO.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-DgJzZRX3.js +4 -0
- package/dist/gateway/static/root/assets/{page-tabs-tiHmRJUA.js → page-tabs-BGAYH3Ef.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-CU6XgaCz.js → preview-open-alternatives-BM6pDkHp.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-Dn4_qor4.js → product-open-page-BiMetEmn.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-DF7F70Vg.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-Cw3jyi5s.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-ChAJsaNY.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-edDUIbXo.js → save-bar-controls-BdjV8MK5.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-DqJO_5Yb.js → schedule-field-ChlqXU46.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-CMh0jzy5.js → schema-form-DDKf5ZSH.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-BxZIxt7z.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-DcDLS0xV.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-Bb0Bc3nJ.js → settings-form-section-CPG0KGVs.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-DQhADvz1.js → settings-loading-skeleton-DRSDHucM.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-b0M5HukN.js → settings-page-CeB7_xD0.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-layout-hvjtIjvh.js → settings-page-layout-BENrkwd0.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-4Xa9NA7v.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-rbeaOpTg.js → share-preview-page-DIzczJkG.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-BpN0o5Cf.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-DvF2UAaL.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-CGKXpNfy.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-BHo_hgnL.js → system-settings-panel-Dp4d5Q1B.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-C3KnnjcU.js → theme-store-CbGc1laW.js} +1 -1
- package/dist/gateway/static/root/assets/{time-picker-D-G-uwVJ.js → time-picker-BhgCeDuO.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-DtRnG-YI.js → typed-models-lib-DwPk3OPL.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-CWWItX2g.js → use-channel-catalog-CXrEu2dw.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-Dy_fKAK_.js +1 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-BTnltQHZ.js → voice-api-key-field-DFoA79LB.js} +1 -1
- package/dist/gateway/static/root/assets/work-discovery-page-BWkjb1NK.js +1 -0
- package/dist/gateway/static/root/assets/work-item-detail-page-DLBNFse5.js +1 -0
- package/dist/gateway/static/root/assets/work-page-Bn5RXMIE.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-D7vKChFZ.js → workflow-run-setup-panel-BuniGPO0.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-_vFhRrAl.js +11 -0
- package/dist/gateway/static/root/index.html +7 -7
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +3 -1
- package/dist/src/agent/agent-manager.js +4 -3
- package/dist/src/agent/capabilities/definitions.d.ts +2 -1
- package/dist/src/agent/capabilities/definitions.js +3 -1
- package/dist/src/agent/prompt/sections/tooling.js +4 -0
- package/dist/src/agent/service.d.ts +2 -1
- package/dist/src/agent/service.js +26 -0
- package/dist/src/agent/skills/hub-pull.js +1 -1
- package/dist/src/agent/skills/index.js +1 -1
- package/dist/src/agent/skills/install-target.js +1 -1
- package/dist/src/agent/skills/marketplace/adapters/clawhub/adapter.d.ts +64 -0
- package/dist/src/agent/skills/marketplace/adapters/clawhub/adapter.js +27 -18
- package/dist/src/agent/skills/marketplace/adapters/store/adapter.js +1 -1
- package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.js +1 -1
- package/dist/src/agent/skills/marketplace/search.d.ts +46 -0
- package/dist/src/agent/skills/marketplace/search.js +193 -0
- package/dist/src/agent/skills/skill-tool-gating.js +2 -1
- package/dist/src/agent/tools/delegate-tool.js +2 -0
- package/dist/src/agent/tools/factory.d.ts +4 -2
- package/dist/src/agent/tools/factory.js +11 -5
- package/dist/src/agent/tools/index.d.ts +2 -1
- package/dist/src/agent/tools/index.js +2 -1
- package/dist/src/agent/tools/skill-install-tool.d.ts +17 -0
- package/dist/src/agent/tools/skill-install-tool.js +76 -8
- package/dist/src/agent/tools/skills-marketplace-search-tool.d.ts +17 -0
- package/dist/src/agent/tools/skills-marketplace-search-tool.js +77 -0
- package/dist/src/browser/providers/cloakbrowser.js +1 -1
- package/dist/src/capabilities/store-connector.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/extensions/api.js +1 -1
- package/dist/src/extensions/install.js +1 -1
- package/dist/src/focuses/candidate-repository.d.ts +15 -0
- package/dist/src/focuses/candidate-repository.js +91 -0
- package/dist/src/focuses/index.d.ts +7 -0
- package/dist/src/focuses/index.js +7 -0
- package/dist/src/focuses/insight-repository.d.ts +22 -0
- package/dist/src/focuses/insight-repository.js +77 -0
- package/dist/src/focuses/prompts.d.ts +2 -0
- package/dist/src/focuses/prompts.js +18 -0
- package/dist/src/focuses/reconciler.d.ts +5 -0
- package/dist/src/focuses/reconciler.js +26 -0
- package/dist/src/focuses/repository.d.ts +61 -0
- package/dist/src/focuses/repository.js +214 -0
- package/dist/src/focuses/run-processor.d.ts +18 -0
- package/dist/src/focuses/run-processor.js +162 -0
- package/dist/src/focuses/service.d.ts +42 -0
- package/dist/src/focuses/service.js +241 -0
- package/dist/src/focuses/types.d.ts +89 -0
- package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
- package/dist/src/gateway/agent-builtin-tools.js +2 -0
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/hono/routes/commands-skills.js +2 -2
- package/dist/src/gateway/hono/routes/focuses.d.ts +3 -0
- package/dist/src/gateway/hono/routes/focuses.js +319 -0
- package/dist/src/gateway/hono/routes/home.js +15 -17
- package/dist/src/gateway/hono/routes/index.js +2 -0
- package/dist/src/gateway/hono/routes/projects.js +2 -103
- package/dist/src/gateway/hono/routes/work-discovery.js +0 -239
- package/dist/src/gateway/service/marketplace-service.js +1 -1
- package/dist/src/gateway/service.d.ts +1 -1
- package/dist/src/gateway/service.js +15 -11
- package/dist/src/storage/sqlite/migrations/066_first_class_focuses.sql +126 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/work-discovery/index.d.ts +0 -2
- package/dist/src/work-discovery/index.js +1 -3
- package/dist/src/work-discovery/service.d.ts +0 -30
- package/dist/src/work-discovery/service.js +1 -35
- package/dist/src/work-discovery/thread-service.d.ts +5 -0
- package/dist/src/work-discovery/thread-service.js +36 -88
- package/package.json +1 -1
- package/skills/tools/find-skills/SKILL.md +18 -428
- package/dist/gateway/static/root/assets/agents-Bf_kK2Ay.js +0 -2
- package/dist/gateway/static/root/assets/apps-page-DXFCP5-1.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-D8pT1o2O.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-Bav_skKN.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-BHaYYo9E.js +0 -7
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-BgchTh81.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-BP0e62wt.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-DBWKfeGe.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-CC5kh0de.js +0 -2
- package/dist/gateway/static/root/assets/desktop-pet-D-ZUNHhn.js +0 -1
- package/dist/gateway/static/root/assets/dreaming-settings-D9i54kWO.js +0 -3
- package/dist/gateway/static/root/assets/goal-create-dialog-Dp0AyDHI.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-CNt7nrdS.js +0 -4
- package/dist/gateway/static/root/assets/goals-page-Bm_NZFiZ.js +0 -2
- package/dist/gateway/static/root/assets/index-C_XSKOH6.css +0 -1
- package/dist/gateway/static/root/assets/index-DUasAutC.js +0 -212
- package/dist/gateway/static/root/assets/local-app-workbench-page-DZwkD1co.js +0 -2
- package/dist/gateway/static/root/assets/logs-page-dNL0Y1dA.js +0 -7
- package/dist/gateway/static/root/assets/messages-BWtP5TFz.js +0 -3
- package/dist/gateway/static/root/assets/notes-workbench-B8MKxpZb.js +0 -4
- package/dist/gateway/static/root/assets/project-detail-page-CWBuuX-S.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-BJSsLsXH.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-DXJDb8vB.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-DeHpWgxM.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-Cf-TEYUd.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-BFyfed_g.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-CYnH9sTt.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-Cr8_m-jS.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-Chtc1xDO.js +0 -2
- package/dist/gateway/static/root/assets/user-context-page-D7qMR26X.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-page-CpqFZze9.js +0 -1
- package/dist/gateway/static/root/assets/work-item-detail-page-t4dXpGC0.js +0 -1
- package/dist/gateway/static/root/assets/work-page-BXwDKiMZ.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-Bos9HyqT.js +0 -11
- package/dist/src/proactive/calendar-signals.d.ts +0 -4
- package/dist/src/proactive/calendar-signals.js +0 -120
- package/dist/src/proactive/focus-service.d.ts +0 -62
- package/dist/src/proactive/focus-service.js +0 -173
- package/dist/src/proactive/index.d.ts +0 -7
- package/dist/src/proactive/index.js +0 -7
- package/dist/src/proactive/insight-repository.d.ts +0 -21
- package/dist/src/proactive/insight-repository.js +0 -109
- package/dist/src/proactive/run-processor.d.ts +0 -19
- package/dist/src/proactive/run-processor.js +0 -146
- package/dist/src/proactive/trial-expiry-reconciler.d.ts +0 -5
- package/dist/src/proactive/trial-expiry-reconciler.js +0 -30
- package/dist/src/proactive/types.d.ts +0 -66
- package/dist/src/proactive/value-score.d.ts +0 -13
- package/dist/src/proactive/value-score.js +0 -30
- package/dist/src/proactive/watch-repository.d.ts +0 -28
- package/dist/src/proactive/watch-repository.js +0 -129
- package/dist/src/work-discovery/governance.d.ts +0 -25
- package/dist/src/work-discovery/governance.js +0 -96
- package/dist/src/work-discovery/thread-repository.d.ts +0 -34
- package/dist/src/work-discovery/thread-repository.js +0 -112
- /package/dist/src/{proactive → focuses}/types.js +0 -0
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { createFocusActivity, listFocusActivities } from "../../../focuses/repository.js";
|
|
2
|
+
import { acceptFocusCandidate, listFocusCandidates, setFocusCandidateStatus } from "../../../focuses/candidate-repository.js";
|
|
3
|
+
import { getFocusInsight, listFocusInsights, setFocusInsightStatus } from "../../../focuses/insight-repository.js";
|
|
4
|
+
import { FocusService } from "../../../focuses/service.js";
|
|
5
|
+
import "../../../focuses/index.js";
|
|
6
|
+
//#region src/gateway/hono/routes/focuses.ts
|
|
7
|
+
const FOCUS_STATUSES = [
|
|
8
|
+
"active",
|
|
9
|
+
"paused",
|
|
10
|
+
"completed"
|
|
11
|
+
];
|
|
12
|
+
const MONITOR_KINDS = ["progress", "external_changes"];
|
|
13
|
+
function stringField(body, field) {
|
|
14
|
+
if (!body || typeof body !== "object") return "";
|
|
15
|
+
const value = body[field];
|
|
16
|
+
return typeof value === "string" ? value.trim() : "";
|
|
17
|
+
}
|
|
18
|
+
function stringArrayField(body, field) {
|
|
19
|
+
if (!body || typeof body !== "object") return void 0;
|
|
20
|
+
const value = body[field];
|
|
21
|
+
if (!Array.isArray(value)) return void 0;
|
|
22
|
+
return [...new Set(value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean))];
|
|
23
|
+
}
|
|
24
|
+
function registerFocusRoutes(authenticated, deps) {
|
|
25
|
+
const focuses = new FocusService(deps.service.automationServiceInstance);
|
|
26
|
+
const limited = deps.strictRateLimitMiddleware;
|
|
27
|
+
authenticated.get("/api/focuses", (c) => {
|
|
28
|
+
const requested = c.req.query("status")?.split(",").map((item) => item.trim()).filter(Boolean) ?? [];
|
|
29
|
+
const statuses = requested.length > 0 ? requested.filter((item) => FOCUS_STATUSES.includes(item)) : void 0;
|
|
30
|
+
if (requested.length > 0 && statuses?.length !== requested.length) return c.json({
|
|
31
|
+
ok: false,
|
|
32
|
+
error: "Invalid focus status"
|
|
33
|
+
}, 400);
|
|
34
|
+
return c.json({
|
|
35
|
+
ok: true,
|
|
36
|
+
focuses: focuses.list(statuses)
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
authenticated.post("/api/focuses", limited, async (c) => {
|
|
40
|
+
const body = await c.req.json().catch(() => null);
|
|
41
|
+
const title = stringField(body, "title");
|
|
42
|
+
if (!title) return c.json({
|
|
43
|
+
ok: false,
|
|
44
|
+
error: "Focus title is required"
|
|
45
|
+
}, 400);
|
|
46
|
+
const focus = focuses.create({
|
|
47
|
+
title,
|
|
48
|
+
summary: stringField(body, "summary"),
|
|
49
|
+
...stringArrayField(body, "projectIds") ? { projectIds: stringArrayField(body, "projectIds") } : {},
|
|
50
|
+
...stringField(body, "goalId") ? { goalId: stringField(body, "goalId") } : {}
|
|
51
|
+
});
|
|
52
|
+
deps.service.emit("focus.created", { focus });
|
|
53
|
+
return c.json({
|
|
54
|
+
ok: true,
|
|
55
|
+
focus
|
|
56
|
+
}, 201);
|
|
57
|
+
});
|
|
58
|
+
authenticated.get("/api/focuses/:focusId", (c) => {
|
|
59
|
+
const focus = focuses.get(c.req.param("focusId"));
|
|
60
|
+
return focus ? c.json({
|
|
61
|
+
ok: true,
|
|
62
|
+
focus
|
|
63
|
+
}) : c.json({
|
|
64
|
+
ok: false,
|
|
65
|
+
error: "Focus not found"
|
|
66
|
+
}, 404);
|
|
67
|
+
});
|
|
68
|
+
authenticated.patch("/api/focuses/:focusId", limited, async (c) => {
|
|
69
|
+
const body = await c.req.json().catch(() => null);
|
|
70
|
+
const requestedStatus = stringField(body, "status");
|
|
71
|
+
if (requestedStatus && !FOCUS_STATUSES.includes(requestedStatus)) return c.json({
|
|
72
|
+
ok: false,
|
|
73
|
+
error: "Invalid focus status"
|
|
74
|
+
}, 400);
|
|
75
|
+
try {
|
|
76
|
+
const title = stringField(body, "title");
|
|
77
|
+
const hasSummary = typeof body?.summary === "string";
|
|
78
|
+
const projectIds = stringArrayField(body, "projectIds");
|
|
79
|
+
let focus = Boolean(title || hasSummary || projectIds) ? focuses.update(c.req.param("focusId"), {
|
|
80
|
+
...title ? { title } : {},
|
|
81
|
+
...hasSummary ? { summary: stringField(body, "summary") } : {},
|
|
82
|
+
...projectIds ? { projectIds } : {}
|
|
83
|
+
}) : focuses.get(c.req.param("focusId"));
|
|
84
|
+
if (focus && requestedStatus) focus = await focuses.setStatus(c.req.param("focusId"), requestedStatus);
|
|
85
|
+
if (!focus) return c.json({
|
|
86
|
+
ok: false,
|
|
87
|
+
error: "Focus not found"
|
|
88
|
+
}, 404);
|
|
89
|
+
deps.service.emit("focus.updated", { focus });
|
|
90
|
+
return c.json({
|
|
91
|
+
ok: true,
|
|
92
|
+
focus
|
|
93
|
+
});
|
|
94
|
+
} catch (error) {
|
|
95
|
+
return c.json({
|
|
96
|
+
ok: false,
|
|
97
|
+
error: error instanceof Error ? error.message : String(error)
|
|
98
|
+
}, 400);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
authenticated.delete("/api/focuses/:focusId", limited, async (c) => {
|
|
102
|
+
try {
|
|
103
|
+
if (!await focuses.remove(c.req.param("focusId"))) return c.json({
|
|
104
|
+
ok: false,
|
|
105
|
+
error: "Focus not found"
|
|
106
|
+
}, 404);
|
|
107
|
+
deps.service.emit("focus.deleted", { focusId: c.req.param("focusId") });
|
|
108
|
+
return c.json({ ok: true });
|
|
109
|
+
} catch (error) {
|
|
110
|
+
return c.json({
|
|
111
|
+
ok: false,
|
|
112
|
+
error: error instanceof Error ? error.message : String(error)
|
|
113
|
+
}, 500);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
authenticated.put("/api/focuses/:focusId/monitors/:kind", limited, async (c) => {
|
|
117
|
+
const kind = c.req.param("kind");
|
|
118
|
+
if (!MONITOR_KINDS.includes(kind)) return c.json({
|
|
119
|
+
ok: false,
|
|
120
|
+
error: "Invalid monitor kind"
|
|
121
|
+
}, 400);
|
|
122
|
+
const body = await c.req.json().catch(() => null);
|
|
123
|
+
const enabled = body && typeof body === "object" ? body.enabled : void 0;
|
|
124
|
+
if (typeof enabled !== "boolean") return c.json({
|
|
125
|
+
ok: false,
|
|
126
|
+
error: "enabled must be a boolean"
|
|
127
|
+
}, 400);
|
|
128
|
+
const everyMs = body && typeof body === "object" && body.cadence && typeof body.cadence === "object" ? Number(body.cadence.everyMs) : void 0;
|
|
129
|
+
try {
|
|
130
|
+
const result = await focuses.configureMonitor({
|
|
131
|
+
focusId: c.req.param("focusId"),
|
|
132
|
+
kind,
|
|
133
|
+
enabled,
|
|
134
|
+
...Number.isFinite(everyMs) ? { cadence: {
|
|
135
|
+
kind: "interval",
|
|
136
|
+
everyMs
|
|
137
|
+
} } : {}
|
|
138
|
+
});
|
|
139
|
+
deps.service.emit("focus.monitor.updated", {
|
|
140
|
+
focusId: c.req.param("focusId"),
|
|
141
|
+
monitor: result.monitor
|
|
142
|
+
});
|
|
143
|
+
return c.json({
|
|
144
|
+
ok: true,
|
|
145
|
+
...result
|
|
146
|
+
}, result.initialRunId ? 202 : 200);
|
|
147
|
+
} catch (error) {
|
|
148
|
+
return c.json({
|
|
149
|
+
ok: false,
|
|
150
|
+
error: error instanceof Error ? error.message : String(error)
|
|
151
|
+
}, 400);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
authenticated.post("/api/focuses/:focusId/monitors/:kind/run", limited, async (c) => {
|
|
155
|
+
const kind = c.req.param("kind");
|
|
156
|
+
if (!MONITOR_KINDS.includes(kind)) return c.json({
|
|
157
|
+
ok: false,
|
|
158
|
+
error: "Invalid monitor kind"
|
|
159
|
+
}, 400);
|
|
160
|
+
try {
|
|
161
|
+
const run = await focuses.runMonitorNow(c.req.param("focusId"), kind);
|
|
162
|
+
deps.service.emit("focus.run.updated", {
|
|
163
|
+
focusId: c.req.param("focusId"),
|
|
164
|
+
kind,
|
|
165
|
+
run
|
|
166
|
+
});
|
|
167
|
+
return c.json({
|
|
168
|
+
ok: true,
|
|
169
|
+
run
|
|
170
|
+
}, 202);
|
|
171
|
+
} catch (error) {
|
|
172
|
+
return c.json({
|
|
173
|
+
ok: false,
|
|
174
|
+
error: error instanceof Error ? error.message : String(error)
|
|
175
|
+
}, 400);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
authenticated.get("/api/focuses/:focusId/activities", (c) => c.json({
|
|
179
|
+
ok: true,
|
|
180
|
+
activities: listFocusActivities({
|
|
181
|
+
focusId: c.req.param("focusId"),
|
|
182
|
+
...Number.isFinite(Number(c.req.query("before"))) ? { before: Number(c.req.query("before")) } : {},
|
|
183
|
+
...Number.isFinite(Number(c.req.query("limit"))) ? { limit: Number(c.req.query("limit")) } : {}
|
|
184
|
+
})
|
|
185
|
+
}));
|
|
186
|
+
authenticated.get("/api/focuses/:focusId/insights", (c) => c.json({
|
|
187
|
+
ok: true,
|
|
188
|
+
insights: listFocusInsights({
|
|
189
|
+
focusId: c.req.param("focusId"),
|
|
190
|
+
limit: Number(c.req.query("limit")) || 20
|
|
191
|
+
})
|
|
192
|
+
}));
|
|
193
|
+
authenticated.post("/api/focuses/:focusId/insights/:insightId/dismiss", limited, (c) => {
|
|
194
|
+
const insight = getFocusInsight(c.req.param("insightId"));
|
|
195
|
+
if (!insight || insight.focusId !== c.req.param("focusId")) return c.json({
|
|
196
|
+
ok: false,
|
|
197
|
+
error: "Insight not found"
|
|
198
|
+
}, 404);
|
|
199
|
+
const updated = setFocusInsightStatus(insight.id, "dismissed", "unread");
|
|
200
|
+
if (!updated) return c.json({
|
|
201
|
+
ok: false,
|
|
202
|
+
error: "Insight was already handled"
|
|
203
|
+
}, 409);
|
|
204
|
+
createFocusActivity({
|
|
205
|
+
focusId: insight.focusId,
|
|
206
|
+
monitorId: insight.monitorId,
|
|
207
|
+
type: "insight_dismissed",
|
|
208
|
+
summary: insight.title,
|
|
209
|
+
details: { insightId: insight.id }
|
|
210
|
+
});
|
|
211
|
+
deps.service.emit("focus.insight.updated", { insight: updated });
|
|
212
|
+
return c.json({
|
|
213
|
+
ok: true,
|
|
214
|
+
insight: updated
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
authenticated.post("/api/focuses/:focusId/insights/:insightId/investigate", limited, async (c) => {
|
|
218
|
+
const insight = getFocusInsight(c.req.param("insightId"));
|
|
219
|
+
const focus = focuses.get(c.req.param("focusId"));
|
|
220
|
+
if (!insight || !focus || insight.focusId !== focus.id) return c.json({
|
|
221
|
+
ok: false,
|
|
222
|
+
error: "Insight not found"
|
|
223
|
+
}, 404);
|
|
224
|
+
const claimed = setFocusInsightStatus(insight.id, "approved", "unread");
|
|
225
|
+
if (!claimed) return c.json({
|
|
226
|
+
ok: false,
|
|
227
|
+
error: "Insight was already handled"
|
|
228
|
+
}, 409);
|
|
229
|
+
let automationId;
|
|
230
|
+
try {
|
|
231
|
+
const automation = await deps.service.automationServiceInstance.create({
|
|
232
|
+
name: `Investigate: ${insight.title}`.slice(0, 200),
|
|
233
|
+
description: `User-approved investigation for focus insight ${insight.id}.`,
|
|
234
|
+
...focus.projectIds[0] ? { projectId: focus.projectIds[0] } : {},
|
|
235
|
+
trigger: { kind: "manual" },
|
|
236
|
+
action: {
|
|
237
|
+
kind: "agent",
|
|
238
|
+
instruction: [
|
|
239
|
+
"Investigate this user-approved focus insight in read-only mode.",
|
|
240
|
+
`Focus: ${focus.title}`,
|
|
241
|
+
`Observed change: ${insight.summary}`,
|
|
242
|
+
`Why it matters: ${insight.whyItMatters}`,
|
|
243
|
+
`Next step: ${insight.nextAction}`,
|
|
244
|
+
`Evidence: ${JSON.stringify(insight.evidence)}`,
|
|
245
|
+
"Return a concise result with evidence. Do not modify files or external systems."
|
|
246
|
+
].join("\n"),
|
|
247
|
+
timeoutSeconds: 300
|
|
248
|
+
},
|
|
249
|
+
safety: { mode: "suggest_only" },
|
|
250
|
+
afterRun: { kind: "none" },
|
|
251
|
+
reliability: {
|
|
252
|
+
timeoutSeconds: 300,
|
|
253
|
+
disableAfterConsecutiveFailures: 1
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
automationId = automation.id;
|
|
257
|
+
const run = await deps.service.automationServiceInstance.runNow(automation.id);
|
|
258
|
+
createFocusActivity({
|
|
259
|
+
focusId: focus.id,
|
|
260
|
+
monitorId: insight.monitorId,
|
|
261
|
+
type: "insight_approved",
|
|
262
|
+
summary: insight.title,
|
|
263
|
+
details: {
|
|
264
|
+
insightId: insight.id,
|
|
265
|
+
automationId,
|
|
266
|
+
runId: run.id
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
deps.service.emit("focus.insight.updated", {
|
|
270
|
+
insight: claimed,
|
|
271
|
+
investigationRunId: run.id
|
|
272
|
+
});
|
|
273
|
+
return c.json({
|
|
274
|
+
ok: true,
|
|
275
|
+
insight: claimed,
|
|
276
|
+
automationId,
|
|
277
|
+
runId: run.id
|
|
278
|
+
}, 202);
|
|
279
|
+
} catch (error) {
|
|
280
|
+
if (automationId) await deps.service.automationServiceInstance.remove(automationId);
|
|
281
|
+
setFocusInsightStatus(insight.id, "unread", "approved");
|
|
282
|
+
return c.json({
|
|
283
|
+
ok: false,
|
|
284
|
+
error: error instanceof Error ? error.message : String(error)
|
|
285
|
+
}, 500);
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
authenticated.get("/api/focus-candidates", (c) => c.json({
|
|
289
|
+
ok: true,
|
|
290
|
+
candidates: listFocusCandidates()
|
|
291
|
+
}));
|
|
292
|
+
authenticated.post("/api/focus-candidates/:candidateId/accept", limited, (c) => {
|
|
293
|
+
const focus = acceptFocusCandidate(c.req.param("candidateId"));
|
|
294
|
+
if (!focus) return c.json({
|
|
295
|
+
ok: false,
|
|
296
|
+
error: "Focus candidate not found"
|
|
297
|
+
}, 404);
|
|
298
|
+
const detail = focuses.get(focus.id);
|
|
299
|
+
deps.service.emit("focus.created", { focus: detail });
|
|
300
|
+
return c.json({
|
|
301
|
+
ok: true,
|
|
302
|
+
focus: detail
|
|
303
|
+
}, 201);
|
|
304
|
+
});
|
|
305
|
+
authenticated.post("/api/focus-candidates/:candidateId/dismiss", limited, (c) => {
|
|
306
|
+
const candidate = setFocusCandidateStatus(c.req.param("candidateId"), "dismissed");
|
|
307
|
+
if (!candidate) return c.json({
|
|
308
|
+
ok: false,
|
|
309
|
+
error: "Focus candidate not found"
|
|
310
|
+
}, 404);
|
|
311
|
+
deps.service.emit("focus.candidate.updated", { candidate });
|
|
312
|
+
return c.json({
|
|
313
|
+
ok: true,
|
|
314
|
+
candidate
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
//#endregion
|
|
319
|
+
export { registerFocusRoutes };
|
|
@@ -3,10 +3,6 @@ import "../../../storage/sqlite/index.js";
|
|
|
3
3
|
import { GoalService } from "../../../goals/goal-service.js";
|
|
4
4
|
import "../../../goals/index.js";
|
|
5
5
|
import { listGatewayAgents } from "../../agents-admin.js";
|
|
6
|
-
import { listFocusCalendarSignals } from "../../../proactive/calendar-signals.js";
|
|
7
|
-
import { FocusService } from "../../../proactive/focus-service.js";
|
|
8
|
-
import { listProactiveInsights } from "../../../proactive/insight-repository.js";
|
|
9
|
-
import "../../../proactive/index.js";
|
|
10
6
|
import { WorkItemService } from "../../../work-items/work-item-service.js";
|
|
11
7
|
import "../../../work-items/index.js";
|
|
12
8
|
import { getTunnelService } from "../../../tunnel/tunnel-service.js";
|
|
@@ -160,7 +156,6 @@ function buildHomeBriefing(input) {
|
|
|
160
156
|
function registerHomeRoutes(authenticated, deps) {
|
|
161
157
|
const { service } = deps;
|
|
162
158
|
const goals = new GoalService();
|
|
163
|
-
const focuses = new FocusService(service.automationServiceInstance);
|
|
164
159
|
authenticated.get("/api/home", async (c) => {
|
|
165
160
|
const notes = service.notesServiceInstance;
|
|
166
161
|
const sessions = service.sessions;
|
|
@@ -171,8 +166,7 @@ function registerHomeRoutes(authenticated, deps) {
|
|
|
171
166
|
const health = service.getHealth();
|
|
172
167
|
const workItems = new WorkItemService();
|
|
173
168
|
const nowMs = Date.now();
|
|
174
|
-
const
|
|
175
|
-
const [recentlyOpened, inbox, pendingTasks, recentSessions, workflowRuns, automations, automationRuns, projects, allWorkItems, activeGoals, connectorApprovals, proactiveInsights, calendarSignals] = await Promise.all([
|
|
169
|
+
const [recentlyOpened, inbox, pendingTasks, recentSessions, workflowRuns, automations, automationRuns, projects, allWorkItems, activeGoals, connectorApprovals] = await Promise.all([
|
|
176
170
|
notes.listNotes({
|
|
177
171
|
sortBy: "lastOpenedAt",
|
|
178
172
|
sortOrder: "desc",
|
|
@@ -189,9 +183,10 @@ function registerHomeRoutes(authenticated, deps) {
|
|
|
189
183
|
limit: 10
|
|
190
184
|
}),
|
|
191
185
|
sessions.listSessions({
|
|
186
|
+
channel: "webchat",
|
|
192
187
|
sortBy: "updatedAt",
|
|
193
188
|
sortOrder: "desc",
|
|
194
|
-
limit:
|
|
189
|
+
limit: 50
|
|
195
190
|
}),
|
|
196
191
|
workflowRunStore.listRunSummaries(20),
|
|
197
192
|
service.automationServiceInstance.list(),
|
|
@@ -211,14 +206,15 @@ function registerHomeRoutes(authenticated, deps) {
|
|
|
211
206
|
principalId: "local-owner",
|
|
212
207
|
status: "pending",
|
|
213
208
|
limit: 100
|
|
214
|
-
}))
|
|
215
|
-
Promise.resolve(listProactiveInsights({
|
|
216
|
-
status: ["unread"],
|
|
217
|
-
limit: 10
|
|
218
|
-
})),
|
|
219
|
-
Promise.resolve(listFocusCalendarSignals(focusViews, nowMs))
|
|
209
|
+
}))
|
|
220
210
|
]);
|
|
221
211
|
const projectsById = new Map(projects.items.map((project) => [project.id, project]));
|
|
212
|
+
const workChats = recentSessions.items.filter((session) => (session.messageCount ?? 0) > 0).map((session) => ({
|
|
213
|
+
key: session.key,
|
|
214
|
+
name: session.name || "Conversation",
|
|
215
|
+
updatedAt: session.updatedAt,
|
|
216
|
+
active: sessions.getActiveRun(session.key).active
|
|
217
|
+
}));
|
|
222
218
|
const activeWorkItems = allWorkItems.items.filter((item) => item.status !== "done" && item.status !== "cancelled").sort((left, right) => {
|
|
223
219
|
return workItemAttentionRank(left, nowMs) - workItemAttentionRank(right, nowMs) || right.updatedAt - left.updatedAt;
|
|
224
220
|
});
|
|
@@ -325,7 +321,7 @@ function registerHomeRoutes(authenticated, deps) {
|
|
|
325
321
|
inboxCount: inbox.total,
|
|
326
322
|
pendingTasks: pendingTasks.items,
|
|
327
323
|
pendingTaskCount: pendingTasks.total,
|
|
328
|
-
recentSessions: recentSessions.items,
|
|
324
|
+
recentSessions: recentSessions.items.slice(0, 5),
|
|
329
325
|
activeAgent: defaultAgent ? {
|
|
330
326
|
id: defaultAgent.id,
|
|
331
327
|
name: defaultAgent.name,
|
|
@@ -350,8 +346,10 @@ function registerHomeRoutes(authenticated, deps) {
|
|
|
350
346
|
},
|
|
351
347
|
briefing,
|
|
352
348
|
decisions,
|
|
353
|
-
|
|
354
|
-
|
|
349
|
+
chats: {
|
|
350
|
+
running: workChats.filter((chat) => chat.active),
|
|
351
|
+
recent: workChats.filter((chat) => !chat.active).slice(0, 8)
|
|
352
|
+
},
|
|
355
353
|
work: {
|
|
356
354
|
attentionCount: activeWorkItems.filter((item) => workItemAttentionRank(item, nowMs) < 3).length,
|
|
357
355
|
overdueCount: activeWorkItems.filter((item) => item.dueAt != null && item.dueAt < nowMs).length,
|
|
@@ -11,6 +11,7 @@ import { registerInteractionStateRoutes } from "./interaction-state.js";
|
|
|
11
11
|
import { registerComposerHistoryRoutes } from "./composer-history.js";
|
|
12
12
|
import { registerLocalAppsRoutes } from "./local-apps.js";
|
|
13
13
|
import { registerWorkDiscoveryRoutes } from "./work-discovery.js";
|
|
14
|
+
import { registerFocusRoutes } from "./focuses.js";
|
|
14
15
|
import { mountAppLazyRoutePrefixes, registerAuthenticatedLazyRouteFallback } from "./lazy-fallback.js";
|
|
15
16
|
//#region src/gateway/hono/routes/index.ts
|
|
16
17
|
function registerCoreAuthenticatedRoutes(authenticated, deps) {
|
|
@@ -22,6 +23,7 @@ function registerCoreAuthenticatedRoutes(authenticated, deps) {
|
|
|
22
23
|
registerProjectsRoutes(authenticated, deps);
|
|
23
24
|
registerLocalAppsRoutes(authenticated, deps);
|
|
24
25
|
registerWorkDiscoveryRoutes(authenticated, deps);
|
|
26
|
+
registerFocusRoutes(authenticated, deps);
|
|
25
27
|
registerSearchRoutes(authenticated, deps);
|
|
26
28
|
registerMobileRoutes(authenticated, deps);
|
|
27
29
|
registerTaskOutcomeRoutes(authenticated, deps);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getSqliteDatabase
|
|
1
|
+
import { getSqliteDatabase } from "../../../storage/sqlite/transaction.js";
|
|
2
2
|
import { getSessionMetadata } from "../../../storage/sqlite/session-repository.js";
|
|
3
3
|
import { loadTranscriptRowsForSession } from "../../../storage/sqlite/transcript-repository.js";
|
|
4
4
|
import { listMemoryRecords, upsertMemoryRecord } from "../../../storage/sqlite/memory-records-repository.js";
|
|
@@ -7,8 +7,7 @@ import { ActivityService } from "../../../activity/service.js";
|
|
|
7
7
|
import "../../../activity/index.js";
|
|
8
8
|
import { buildSessionKey, init_session_key } from "../../../routing/session-key.js";
|
|
9
9
|
import { resolveEffectiveAgentProfile } from "../../../config/agent-profile.js";
|
|
10
|
-
import { GoalService
|
|
11
|
-
import { draftGoalContract } from "../../../goals/goal-contract-draft.js";
|
|
10
|
+
import { GoalService } from "../../../goals/goal-service.js";
|
|
12
11
|
import "../../../goals/index.js";
|
|
13
12
|
import { ProjectWorkspaceConflictError, ProjectWorkspaceMissingError } from "../../../projects/workspace-project.js";
|
|
14
13
|
import { isValidProjectAgentId, normalizeProjectAgentId, resolveProjectAgentId } from "../../../projects/project-agent.js";
|
|
@@ -27,10 +26,6 @@ import { readFile, readdir, realpath, stat, writeFile } from "node:fs/promises";
|
|
|
27
26
|
//#region src/gateway/hono/routes/projects.ts
|
|
28
27
|
init_session_key();
|
|
29
28
|
const log = createGatewayRouteLogger("Projects");
|
|
30
|
-
const DELEGATED_OUTCOME_MAX_LENGTH = 12e3;
|
|
31
|
-
function inferDelegatedWorkName(outcome) {
|
|
32
|
-
return (outcome.split(/\r?\n/).map((line) => line.trim()).find(Boolean) ?? outcome.trim()).replace(/^[#*\-\s]+/, "").replace(/[。.!!??]+$/, "").trim().slice(0, 72) || "Untitled work";
|
|
33
|
-
}
|
|
34
29
|
function parseProjectStatus(raw) {
|
|
35
30
|
return raw === "active" || raw === "paused" || raw === "archived" ? raw : void 0;
|
|
36
31
|
}
|
|
@@ -379,102 +374,6 @@ function registerProjectsRoutes(authenticated, deps) {
|
|
|
379
374
|
const activity = new ActivityService();
|
|
380
375
|
const goals = new GoalService();
|
|
381
376
|
const workItems = new WorkItemService();
|
|
382
|
-
authenticated.post("/api/projects/delegate", async (c) => {
|
|
383
|
-
const body = await c.req.json().catch(() => ({}));
|
|
384
|
-
const outcome = textField(body, "outcome")?.trim() ?? "";
|
|
385
|
-
if (!outcome) return c.json({
|
|
386
|
-
ok: false,
|
|
387
|
-
error: "Missing outcome"
|
|
388
|
-
}, 400);
|
|
389
|
-
if (outcome.length > DELEGATED_OUTCOME_MAX_LENGTH) return c.json({
|
|
390
|
-
ok: false,
|
|
391
|
-
error: `Outcome exceeds ${DELEGATED_OUTCOME_MAX_LENGTH} characters`
|
|
392
|
-
}, 400);
|
|
393
|
-
const name = textField(body, "name")?.trim().slice(0, 72) || inferDelegatedWorkName(outcome);
|
|
394
|
-
const uiLocale = normalizeGoalUiLocale(body.uiLocale);
|
|
395
|
-
const defaultAgentId = inferSuggestedProjectDefaultAgentId({
|
|
396
|
-
config: service.currentConfig,
|
|
397
|
-
name,
|
|
398
|
-
description: outcome,
|
|
399
|
-
projectKind: "auto"
|
|
400
|
-
});
|
|
401
|
-
if (!isValidProjectAgentId(service.currentConfig, defaultAgentId)) return c.json({
|
|
402
|
-
ok: false,
|
|
403
|
-
error: "Default agent not found"
|
|
404
|
-
}, 400);
|
|
405
|
-
const contractDraft = await draftGoalContract({
|
|
406
|
-
title: name,
|
|
407
|
-
context: outcome,
|
|
408
|
-
uiLocale,
|
|
409
|
-
modelRef: service.currentConfig.goals?.judgeModelRef
|
|
410
|
-
});
|
|
411
|
-
let created;
|
|
412
|
-
try {
|
|
413
|
-
created = runSqliteWriteTransaction(() => {
|
|
414
|
-
const project = service.projects.create({
|
|
415
|
-
name,
|
|
416
|
-
description: outcome,
|
|
417
|
-
defaultAgentId,
|
|
418
|
-
projectKind: "auto",
|
|
419
|
-
brief: outcome
|
|
420
|
-
});
|
|
421
|
-
const goal = goals.create({
|
|
422
|
-
title: name,
|
|
423
|
-
description: outcome,
|
|
424
|
-
agentId: defaultAgentId,
|
|
425
|
-
priority: "normal",
|
|
426
|
-
uiLocale,
|
|
427
|
-
source: "api",
|
|
428
|
-
projectId: project.id,
|
|
429
|
-
contract: contractDraft.contract,
|
|
430
|
-
config: service.currentConfig
|
|
431
|
-
});
|
|
432
|
-
const detailedGoal = goals.setContextMessage({
|
|
433
|
-
goalId: goal.id,
|
|
434
|
-
text: outcome
|
|
435
|
-
});
|
|
436
|
-
if (!detailedGoal) throw new Error("Goal context could not be saved");
|
|
437
|
-
return {
|
|
438
|
-
project,
|
|
439
|
-
goal: detailedGoal
|
|
440
|
-
};
|
|
441
|
-
});
|
|
442
|
-
} catch (error) {
|
|
443
|
-
log.warn({
|
|
444
|
-
err: error,
|
|
445
|
-
phase: "delegate_create"
|
|
446
|
-
}, `Delegated work could not be created: ${error instanceof Error ? error.message : String(error)}`);
|
|
447
|
-
return c.json({
|
|
448
|
-
ok: false,
|
|
449
|
-
error: error instanceof Error ? error.message : String(error)
|
|
450
|
-
}, 400);
|
|
451
|
-
}
|
|
452
|
-
let queued;
|
|
453
|
-
let executionWarning;
|
|
454
|
-
try {
|
|
455
|
-
queued = service.enqueueGoalRun(created.goal.id, { source: "api" });
|
|
456
|
-
} catch (error) {
|
|
457
|
-
executionWarning = error instanceof Error ? error.message : String(error);
|
|
458
|
-
log.warn({
|
|
459
|
-
err: error,
|
|
460
|
-
projectId: created.project.id,
|
|
461
|
-
goalId: created.goal.id,
|
|
462
|
-
phase: "delegate_enqueue"
|
|
463
|
-
}, `Delegated work was saved but could not be queued: ${executionWarning}`);
|
|
464
|
-
}
|
|
465
|
-
return c.json({
|
|
466
|
-
ok: true,
|
|
467
|
-
project: enrichProjectWorkspace(service, created.project),
|
|
468
|
-
goal: created.goal,
|
|
469
|
-
contractGenerated: contractDraft.generated,
|
|
470
|
-
contractWarning: contractDraft.warning,
|
|
471
|
-
execution: {
|
|
472
|
-
status: queued ? "queued" : "saved",
|
|
473
|
-
queueItem: queued,
|
|
474
|
-
warning: executionWarning
|
|
475
|
-
}
|
|
476
|
-
}, 201);
|
|
477
|
-
});
|
|
478
377
|
authenticated.post("/api/projects", async (c) => {
|
|
479
378
|
const body = await c.req.json().catch(() => ({}));
|
|
480
379
|
const name = textField(body, "name")?.trim();
|