@xopcai/xopc 0.0.147 → 0.0.149
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-DXeSSlw1.js → activity-store-B4s0ipx2.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CFdJKSjY.js → agent-avatar-dicebear-BSccACje.js} +1 -1
- package/dist/gateway/static/root/assets/agents-DZDOcgz5.js +2 -0
- package/dist/gateway/static/root/assets/{api-Bs69B5zA.js → api-BMdUsNCV.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-ag1ViXT_.js → app-management-settings-panel-DrLGhYkI.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-C6iMpwOM.js → appearance-settings-BNasnY9D.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-Cmr-Hvm9.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-Dwi3mIBy.js → archive-plugin-BQ17IK9x.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-BaCDoq40.js → attachment-load-HXvgWHXu.js} +1 -1
- package/dist/gateway/static/root/assets/{automation-suggestion-card-CwqtFgnw.js → automation-suggestion-card-CjIWpsch.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-TWgUAI8t.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-DoAYhsxa.js → binary-plugins-DifWJzNZ.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-Bw72pO7S.js → block-editor-DtRzIkPU.js} +4 -4
- package/dist/gateway/static/root/assets/browser-settings-page-DBsFItW_.js +8 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-vdbAR65Q.js → capability-presets-api-DazKjWW1.js} +1 -1
- package/dist/gateway/static/root/assets/{capability-presets-settings-panel-BAsKbJgm.js → capability-presets-settings-panel-Cvrw4fD1.js} +2 -2
- package/dist/gateway/static/root/assets/{channel-recipient-api-rTG26jpV.js → channel-recipient-api-Bea6if_6.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-BBkzrBYy.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-CuU6ez3y.js +1 -0
- package/dist/gateway/static/root/assets/{connector-logo-DIMP4NWY.js → connector-logo-BjbYbJjQ.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-DLsZCAw7.js +2 -0
- package/dist/gateway/static/root/assets/{desktop-pet-kQq2e0BN.js → desktop-pet-C6V-PHwi.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-B6vtozMY.js → desktop-pet-settings-5Fcz47XQ.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-Dn5-e3v4.js → directory-picker-path-field-C8zZNUzC.js} +1 -1
- package/dist/gateway/static/root/assets/{dreaming-settings-BzwIujPG.js → dreaming-settings-gJSw7Adk.js} +3 -3
- package/dist/gateway/static/root/assets/{extension-debug-page-D_e_hsEy.js → extension-debug-page-DFE5ADJ0.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-D15CWHBd.js → extension-page-CfR-aW8G.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-D4P0n1om.js → extension-settings-page-CFIEbs2L.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-B4qZctjG.js → gateway-config-api-B6M_ra8U.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-BrxzyVW2.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-BpgMunEb.js → gateway-startup-retry-DNA3OOzV.js} +1 -1
- package/dist/gateway/static/root/assets/{goal-create-dialog-DrVHKXHq.js → goal-create-dialog-DRVRLc5Z.js} +1 -1
- package/dist/gateway/static/root/assets/goal-detail-page-8F7NElzP.js +4 -0
- package/dist/gateway/static/root/assets/{goals-config-api-B6YJB_ct.js → goals-config-api-D88opgcs.js} +1 -1
- package/dist/gateway/static/root/assets/goals-page-BaoLiV8G.js +2 -0
- package/dist/gateway/static/root/assets/{goals-settings-BROWCIcL.js → goals-settings-D07UL8Jo.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-CoCwIOIg.js → heartbeat-settings-YCSNOcXC.js} +1 -1
- package/dist/gateway/static/root/assets/{index-CxkNzw3e.js → index-CH7XN6KY.js} +43 -43
- package/dist/gateway/static/root/assets/index-Dfnl9tp_.css +1 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-Bm_AIYQ7.js → keyboard-shortcuts-settings-BHnh5OoY.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-Boe8n4zH.js +2 -0
- package/dist/gateway/static/root/assets/local-apps-page-CKvtLzsF.js +1 -0
- package/dist/gateway/static/root/assets/{locale-store-Bp8joZck.js → locale-store-BneNAR8R.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-Cb4Uptct.js +7 -0
- package/dist/gateway/static/root/assets/{markdown-split-Dy7QpaAz.js → markdown-split-BVSFG99p.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-3Lxliy9D.js → media-plugins-DdOjIVk3.js} +1 -1
- package/dist/gateway/static/root/assets/{messages-CQGpD-dC.js → messages-t1yPaVCt.js} +5 -5
- package/dist/gateway/static/root/assets/models-hub-panel-CNiUKZUV.js +2 -0
- package/dist/gateway/static/root/assets/{notes-page-BJtT4vSf.js → notes-page-ZbLR3awn.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-C9__VkD6.js +4 -0
- package/dist/gateway/static/root/assets/{page-tabs-DKB6RDre.js → page-tabs-DMlQERNg.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-Br_YhYHp.js → preview-open-alternatives-CbiJRPxK.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-CZhuB5kO.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-BOq4WVdR.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-BxGq0ebQ.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-BgIE9BBh.js → save-bar-controls-BZTj3hxl.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-BXDP-oMz.js → schedule-field-CxYDObjT.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-Dhv-SmjG.js → schema-form-CBbXgpKQ.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-B6gSU_Au.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-DwuBL834.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-CUTExnlK.js → settings-collapsible-section-BySKZ8rp.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-CmnDhsf0.js → settings-form-section-CjINay6t.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-B79dq-XY.js → settings-loading-skeleton-vitElc-n.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-Db8uAv3X.js → settings-page-BNrVwuL7.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-layout-DaFwstQw.js → settings-page-layout-HdlQOOqp.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-BJeA4mmk.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-Bi00uXzV.js → share-preview-page-DC-eQONB.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-DB2KYA2_.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-DQtZiejw.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-Pm0fNe_p.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-Cxaph7hW.js → system-settings-panel-CVa90q2f.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-eCTN1RpG.js → theme-store-D1cOpgsy.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-CcZ_tyFY.js → typed-models-lib-DIKF9vpz.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-C4PWbNoi.js → use-channel-catalog-DnvpI0Ys.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-DnLqQyRG.js +1 -0
- package/dist/gateway/static/root/assets/{user-profile-fields-editor-CPOO9Jz5.js → user-profile-fields-editor-y8gTmkPX.js} +1 -1
- package/dist/gateway/static/root/assets/{user-profile-settings-panel-C8cgtSF7.js → user-profile-settings-panel-C3pvqe28.js} +1 -1
- package/dist/gateway/static/root/assets/{utils-CiZK2KwH.js → utils-BK2vwu_3.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-BiFIIWC4.js +1 -0
- package/dist/gateway/static/root/assets/work-discovery-page-D2-_bC0J.js +1 -0
- package/dist/gateway/static/root/assets/work-item-detail-page-B0FPG4eJ.js +1 -0
- package/dist/gateway/static/root/assets/work-page-BDeVxts_.js +1 -0
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-BPzS67fU.js +3 -0
- package/dist/gateway/static/root/assets/workflows-page-xPhmrRLs.js +11 -0
- package/dist/gateway/static/root/index.html +7 -7
- package/dist/package.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/gateway/hono/routes/work-discovery.js +32 -0
- package/dist/src/gateway/hono/routes/work-discovery.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/046_work_discovery_feedback.sql +13 -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.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/work-discovery/analyzer.js +23 -4
- package/dist/src/work-discovery/analyzer.js.map +1 -1
- package/dist/src/work-discovery/index.js +2 -2
- package/dist/src/work-discovery/probe.d.ts +6 -0
- package/dist/src/work-discovery/probe.js +12 -1
- package/dist/src/work-discovery/probe.js.map +1 -1
- package/dist/src/work-discovery/repository.d.ts +7 -1
- package/dist/src/work-discovery/repository.js +35 -2
- package/dist/src/work-discovery/repository.js.map +1 -1
- package/dist/src/work-discovery/service.d.ts +6 -1
- package/dist/src/work-discovery/service.js +64 -5
- package/dist/src/work-discovery/service.js.map +1 -1
- package/dist/src/work-discovery/types.d.ts +21 -0
- package/dist/src/workflows/service/workflow-run-service.js +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/agents-DKjbRpbA.js +0 -2
- package/dist/gateway/static/root/assets/apps-page-CpX3lBFF.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-DlupOxFQ.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-BwLoUBcZ.js +0 -8
- package/dist/gateway/static/root/assets/channels-settings-CxFWy0cE.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-OKlqTtKJ.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-BjQQwX62.js +0 -2
- package/dist/gateway/static/root/assets/gateway-settings-BvndV7TP.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-PHlCwv68.js +0 -4
- package/dist/gateway/static/root/assets/goals-page-Hg9uyO6e.js +0 -2
- package/dist/gateway/static/root/assets/index-DjCSOyaN.css +0 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-BJWFcxwG.js +0 -2
- package/dist/gateway/static/root/assets/local-apps-page-BsiZMrEf.js +0 -1
- package/dist/gateway/static/root/assets/logs-page-DOmK61ey.js +0 -7
- package/dist/gateway/static/root/assets/models-hub-panel-DGCZom4o.js +0 -2
- package/dist/gateway/static/root/assets/notes-workbench-B_bN7cOR.js +0 -4
- package/dist/gateway/static/root/assets/project-detail-page-Dq8JouJj.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-DvfL7fSe.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-DqwMXSXP.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-B_mOZkQk.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-BHGmH6YS.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-BUSEj0KK.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-DzsTYfuX.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-DSsdU081.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-DeB1tQZL.js +0 -2
- package/dist/gateway/static/root/assets/user-context-page-QTVMx_hG.js +0 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-b-YZtvUu.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-page-4zVDOl2G.js +0 -1
- package/dist/gateway/static/root/assets/work-item-detail-page-CHe2tfkc.js +0 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-8SLCYeXE.js +0 -3
- package/dist/gateway/static/root/assets/workflows-page-DEOFqiWn.js +0 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository.js","names":[],"sources":["../../../src/work-discovery/repository.ts"],"sourcesContent":["import type { DatabaseSync } from 'node:sqlite';\n\nimport { requireXopcDatabase } from '../storage/sqlite/connection.js';\nimport { runSqliteWriteTransaction } from '../storage/sqlite/transaction.js';\n\nimport type {\n WorkDiscoveryOnboardingState,\n WorkDiscoveryOnboardingStatus,\n WorkDiscoveryRun,\n} from './types.js';\n\ntype OnboardingRow = {\n status: string;\n active_run_id: string | null;\n completed_at: number | null;\n dismissed_at: number | null;\n updated_at: number;\n};\n\ntype RunRow = {\n id: string;\n idempotency_key: string;\n source: string;\n status: string;\n stage: string | null;\n root_path: string;\n project_id: string;\n session_key: string;\n agent_id: string;\n model_ref: string;\n scan_policy_version: number;\n snapshot_summary_json: string | null;\n result_json: string | null;\n error_code: string | null;\n error_message: string | null;\n created_at: number;\n started_at: number | null;\n completed_at: number | null;\n canceled_at: number | null;\n};\n\nfunction parseJson<T>(value: string | null): T | undefined {\n if (!value) return undefined;\n try {\n return JSON.parse(value) as T;\n } catch {\n return undefined;\n }\n}\n\nfunction onboardingFromRow(row: OnboardingRow): WorkDiscoveryOnboardingState {\n return {\n status: row.status as WorkDiscoveryOnboardingStatus,\n ...(row.active_run_id ? { activeRunId: row.active_run_id } : {}),\n ...(row.completed_at != null ? { completedAt: row.completed_at } : {}),\n ...(row.dismissed_at != null ? { dismissedAt: row.dismissed_at } : {}),\n updatedAt: row.updated_at,\n };\n}\n\nfunction runFromRow(row: RunRow): WorkDiscoveryRun {\n return {\n id: row.id,\n idempotencyKey: row.idempotency_key,\n source: row.source as WorkDiscoveryRun['source'],\n status: row.status as WorkDiscoveryRun['status'],\n ...(row.stage ? { stage: row.stage as WorkDiscoveryRun['stage'] } : {}),\n rootPath: row.root_path,\n projectId: row.project_id,\n sessionKey: row.session_key,\n agentId: row.agent_id,\n modelRef: row.model_ref,\n scanPolicyVersion: row.scan_policy_version,\n ...(parseJson<WorkDiscoveryRun['snapshot']>(row.snapshot_summary_json)\n ? { snapshot: parseJson<WorkDiscoveryRun['snapshot']>(row.snapshot_summary_json) }\n : {}),\n ...(parseJson<WorkDiscoveryRun['result']>(row.result_json)\n ? { result: parseJson<WorkDiscoveryRun['result']>(row.result_json) }\n : {}),\n ...(row.error_code ? { errorCode: row.error_code as WorkDiscoveryRun['errorCode'] } : {}),\n ...(row.error_message ? { errorMessage: row.error_message } : {}),\n createdAt: row.created_at,\n ...(row.started_at != null ? { startedAt: row.started_at } : {}),\n ...(row.completed_at != null ? { completedAt: row.completed_at } : {}),\n ...(row.canceled_at != null ? { canceledAt: row.canceled_at } : {}),\n };\n}\n\nfunction readRun(db: DatabaseSync, clause: string, value: string): WorkDiscoveryRun | null {\n const row = db.prepare(`SELECT * FROM work_discovery_runs WHERE ${clause} = ?`).get(value) as RunRow | undefined;\n return row ? runFromRow(row) : null;\n}\n\nexport function getWorkDiscoveryOnboardingState(): WorkDiscoveryOnboardingState {\n const { db } = requireXopcDatabase();\n const row = db.prepare('SELECT * FROM work_discovery_onboarding WHERE singleton_id = 1').get() as OnboardingRow;\n return onboardingFromRow(row);\n}\n\nexport function setWorkDiscoveryOnboardingState(input: {\n status: WorkDiscoveryOnboardingStatus;\n activeRunId?: string | null;\n nowMs?: number;\n}): WorkDiscoveryOnboardingState {\n const now = input.nowMs ?? Date.now();\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `UPDATE work_discovery_onboarding\n SET status = ?, active_run_id = ?,\n completed_at = CASE WHEN ? = 'completed' THEN ? ELSE completed_at END,\n dismissed_at = CASE WHEN ? = 'dismissed' THEN ? ELSE dismissed_at END,\n updated_at = ?\n WHERE singleton_id = 1`,\n ).run(input.status, input.activeRunId ?? null, input.status, now, input.status, now, now);\n });\n return getWorkDiscoveryOnboardingState();\n}\n\nexport function createWorkDiscoveryRun(run: WorkDiscoveryRun): WorkDiscoveryRun {\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO work_discovery_runs (\n id, idempotency_key, source, status, stage, root_path, project_id, session_key,\n agent_id, model_ref, scan_policy_version, snapshot_summary_json, result_json,\n error_code, error_message, created_at, started_at, completed_at, canceled_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n ).run(\n run.id,\n run.idempotencyKey,\n run.source,\n run.status,\n run.stage ?? null,\n run.rootPath,\n run.projectId,\n run.sessionKey,\n run.agentId,\n run.modelRef,\n run.scanPolicyVersion,\n run.snapshot ? JSON.stringify(run.snapshot) : null,\n run.result ? JSON.stringify(run.result) : null,\n run.errorCode ?? null,\n run.errorMessage ?? null,\n run.createdAt,\n run.startedAt ?? null,\n run.completedAt ?? null,\n run.canceledAt ?? null,\n );\n });\n return getWorkDiscoveryRun(run.id)!;\n}\n\nexport function getWorkDiscoveryRun(id: string): WorkDiscoveryRun | null {\n const { db } = requireXopcDatabase();\n return readRun(db, 'id', id);\n}\n\nexport function getWorkDiscoveryRunByIdempotencyKey(key: string): WorkDiscoveryRun | null {\n const { db } = requireXopcDatabase();\n return readRun(db, 'idempotency_key', key);\n}\n\nexport function updateWorkDiscoveryRun(\n id: string,\n patch: Partial<Pick<\n WorkDiscoveryRun,\n | 'status'\n | 'stage'\n | 'snapshot'\n | 'result'\n | 'errorCode'\n | 'errorMessage'\n | 'startedAt'\n | 'completedAt'\n | 'canceledAt'\n >>,\n): WorkDiscoveryRun | null {\n const existing = getWorkDiscoveryRun(id);\n if (!existing) return null;\n const next = { ...existing, ...patch };\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `UPDATE work_discovery_runs SET\n status = ?, stage = ?, snapshot_summary_json = ?, result_json = ?,\n error_code = ?, error_message = ?, started_at = ?, completed_at = ?, canceled_at = ?\n WHERE id = ?`,\n ).run(\n next.status,\n next.stage ?? null,\n next.snapshot ? JSON.stringify(next.snapshot) : null,\n next.result ? JSON.stringify(next.result) : null,\n next.errorCode ?? null,\n next.errorMessage ?? null,\n next.startedAt ?? null,\n next.completedAt ?? null,\n next.canceledAt ?? null,\n id,\n );\n });\n return getWorkDiscoveryRun(id);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"repository.js","names":[],"sources":["../../../src/work-discovery/repository.ts"],"sourcesContent":["import type { DatabaseSync } from 'node:sqlite';\n\nimport { requireXopcDatabase } from '../storage/sqlite/connection.js';\nimport { runSqliteWriteTransaction } from '../storage/sqlite/transaction.js';\n\nimport type {\n WorkDiscoveryOnboardingState,\n WorkDiscoveryOnboardingStatus,\n WorkDiscoveryFeedback,\n WorkDiscoveryRecognitionDecision,\n WorkDiscoveryRun,\n} from './types.js';\n\ntype OnboardingRow = {\n status: string;\n active_run_id: string | null;\n completed_at: number | null;\n dismissed_at: number | null;\n updated_at: number;\n};\n\ntype RunRow = {\n id: string;\n idempotency_key: string;\n source: string;\n status: string;\n stage: string | null;\n root_path: string;\n project_id: string;\n session_key: string;\n agent_id: string;\n model_ref: string;\n scan_policy_version: number;\n snapshot_summary_json: string | null;\n result_json: string | null;\n error_code: string | null;\n error_message: string | null;\n created_at: number;\n started_at: number | null;\n completed_at: number | null;\n canceled_at: number | null;\n};\n\ntype FeedbackRow = {\n run_id: string;\n recognition_decision: string;\n corrected_intent: string | null;\n created_at: number;\n updated_at: number;\n};\n\nfunction parseJson<T>(value: string | null): T | undefined {\n if (!value) return undefined;\n try {\n return JSON.parse(value) as T;\n } catch {\n return undefined;\n }\n}\n\nfunction onboardingFromRow(row: OnboardingRow): WorkDiscoveryOnboardingState {\n return {\n status: row.status as WorkDiscoveryOnboardingStatus,\n ...(row.active_run_id ? { activeRunId: row.active_run_id } : {}),\n ...(row.completed_at != null ? { completedAt: row.completed_at } : {}),\n ...(row.dismissed_at != null ? { dismissedAt: row.dismissed_at } : {}),\n updatedAt: row.updated_at,\n };\n}\n\nfunction runFromRow(row: RunRow): WorkDiscoveryRun {\n return {\n id: row.id,\n idempotencyKey: row.idempotency_key,\n source: row.source as WorkDiscoveryRun['source'],\n status: row.status as WorkDiscoveryRun['status'],\n ...(row.stage ? { stage: row.stage as WorkDiscoveryRun['stage'] } : {}),\n rootPath: row.root_path,\n projectId: row.project_id,\n sessionKey: row.session_key,\n agentId: row.agent_id,\n modelRef: row.model_ref,\n scanPolicyVersion: row.scan_policy_version,\n ...(parseJson<WorkDiscoveryRun['snapshot']>(row.snapshot_summary_json)\n ? { snapshot: parseJson<WorkDiscoveryRun['snapshot']>(row.snapshot_summary_json) }\n : {}),\n ...(parseJson<WorkDiscoveryRun['result']>(row.result_json)\n ? { result: parseJson<WorkDiscoveryRun['result']>(row.result_json) }\n : {}),\n ...(row.error_code ? { errorCode: row.error_code as WorkDiscoveryRun['errorCode'] } : {}),\n ...(row.error_message ? { errorMessage: row.error_message } : {}),\n createdAt: row.created_at,\n ...(row.started_at != null ? { startedAt: row.started_at } : {}),\n ...(row.completed_at != null ? { completedAt: row.completed_at } : {}),\n ...(row.canceled_at != null ? { canceledAt: row.canceled_at } : {}),\n };\n}\n\nfunction readRun(db: DatabaseSync, clause: string, value: string): WorkDiscoveryRun | null {\n const row = db.prepare(`SELECT * FROM work_discovery_runs WHERE ${clause} = ?`).get(value) as RunRow | undefined;\n if (!row) return null;\n const run = runFromRow(row);\n const feedback = getWorkDiscoveryFeedbackFromDb(db, run.id);\n return feedback ? { ...run, feedback } : run;\n}\n\nfunction feedbackFromRow(row: FeedbackRow): WorkDiscoveryFeedback {\n return {\n runId: row.run_id,\n recognitionDecision: row.recognition_decision as WorkDiscoveryRecognitionDecision,\n ...(row.corrected_intent ? { correctedIntent: row.corrected_intent } : {}),\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n };\n}\n\nfunction getWorkDiscoveryFeedbackFromDb(db: DatabaseSync, runId: string): WorkDiscoveryFeedback | null {\n const row = db.prepare('SELECT * FROM work_discovery_feedback WHERE run_id = ?').get(runId) as FeedbackRow | undefined;\n return row ? feedbackFromRow(row) : null;\n}\n\nexport function getWorkDiscoveryOnboardingState(): WorkDiscoveryOnboardingState {\n const { db } = requireXopcDatabase();\n const row = db.prepare('SELECT * FROM work_discovery_onboarding WHERE singleton_id = 1').get() as OnboardingRow;\n return onboardingFromRow(row);\n}\n\nexport function setWorkDiscoveryOnboardingState(input: {\n status: WorkDiscoveryOnboardingStatus;\n activeRunId?: string | null;\n nowMs?: number;\n}): WorkDiscoveryOnboardingState {\n const now = input.nowMs ?? Date.now();\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `UPDATE work_discovery_onboarding\n SET status = ?, active_run_id = ?,\n completed_at = CASE WHEN ? = 'completed' THEN ? ELSE completed_at END,\n dismissed_at = CASE WHEN ? = 'dismissed' THEN ? ELSE dismissed_at END,\n updated_at = ?\n WHERE singleton_id = 1`,\n ).run(input.status, input.activeRunId ?? null, input.status, now, input.status, now, now);\n });\n return getWorkDiscoveryOnboardingState();\n}\n\nexport function createWorkDiscoveryRun(run: WorkDiscoveryRun): WorkDiscoveryRun {\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO work_discovery_runs (\n id, idempotency_key, source, status, stage, root_path, project_id, session_key,\n agent_id, model_ref, scan_policy_version, snapshot_summary_json, result_json,\n error_code, error_message, created_at, started_at, completed_at, canceled_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n ).run(\n run.id,\n run.idempotencyKey,\n run.source,\n run.status,\n run.stage ?? null,\n run.rootPath,\n run.projectId,\n run.sessionKey,\n run.agentId,\n run.modelRef,\n run.scanPolicyVersion,\n run.snapshot ? JSON.stringify(run.snapshot) : null,\n run.result ? JSON.stringify(run.result) : null,\n run.errorCode ?? null,\n run.errorMessage ?? null,\n run.createdAt,\n run.startedAt ?? null,\n run.completedAt ?? null,\n run.canceledAt ?? null,\n );\n });\n return getWorkDiscoveryRun(run.id)!;\n}\n\nexport function getWorkDiscoveryRun(id: string): WorkDiscoveryRun | null {\n const { db } = requireXopcDatabase();\n return readRun(db, 'id', id);\n}\n\nexport function getWorkDiscoveryRunByIdempotencyKey(key: string): WorkDiscoveryRun | null {\n const { db } = requireXopcDatabase();\n return readRun(db, 'idempotency_key', key);\n}\n\nexport function setWorkDiscoveryFeedback(input: {\n runId: string;\n recognitionDecision: WorkDiscoveryRecognitionDecision;\n correctedIntent?: string;\n nowMs?: number;\n}): WorkDiscoveryFeedback {\n const now = input.nowMs ?? Date.now();\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO work_discovery_feedback (\n run_id, recognition_decision, corrected_intent, created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(run_id) DO UPDATE SET\n recognition_decision = excluded.recognition_decision,\n corrected_intent = excluded.corrected_intent,\n updated_at = excluded.updated_at`,\n ).run(\n input.runId,\n input.recognitionDecision,\n input.correctedIntent ?? null,\n now,\n now,\n );\n });\n const { db } = requireXopcDatabase();\n return getWorkDiscoveryFeedbackFromDb(db, input.runId)!;\n}\n\nexport function updateWorkDiscoveryRun(\n id: string,\n patch: Partial<Pick<\n WorkDiscoveryRun,\n | 'status'\n | 'stage'\n | 'snapshot'\n | 'result'\n | 'errorCode'\n | 'errorMessage'\n | 'startedAt'\n | 'completedAt'\n | 'canceledAt'\n >>,\n): WorkDiscoveryRun | null {\n const existing = getWorkDiscoveryRun(id);\n if (!existing) return null;\n const next = { ...existing, ...patch };\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `UPDATE work_discovery_runs SET\n status = ?, stage = ?, snapshot_summary_json = ?, result_json = ?,\n error_code = ?, error_message = ?, started_at = ?, completed_at = ?, canceled_at = ?\n WHERE id = ?`,\n ).run(\n next.status,\n next.stage ?? null,\n next.snapshot ? JSON.stringify(next.snapshot) : null,\n next.result ? JSON.stringify(next.result) : null,\n next.errorCode ?? null,\n next.errorMessage ?? null,\n next.startedAt ?? null,\n next.completedAt ?? null,\n next.canceledAt ?? null,\n id,\n );\n });\n return getWorkDiscoveryRun(id);\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Config } from '../config/schema.js';
|
|
2
2
|
import type { ProjectService } from '../projects/project-service.js';
|
|
3
3
|
import type { SessionIndex } from '../session/manager.js';
|
|
4
|
-
import type { WorkDiscoveryOnboardingState, WorkDiscoveryRun, WorkDiscoverySource } from './types.js';
|
|
4
|
+
import type { WorkDiscoveryOnboardingState, WorkDiscoveryRecognitionDecision, WorkDiscoveryRun, WorkDiscoverySource } from './types.js';
|
|
5
5
|
export interface WorkDiscoveryServiceOptions {
|
|
6
6
|
projects: ProjectService;
|
|
7
7
|
sessions: SessionIndex;
|
|
@@ -26,5 +26,10 @@ export declare class WorkDiscoveryService {
|
|
|
26
26
|
private execute;
|
|
27
27
|
cancelRun(id: string): WorkDiscoveryRun | null;
|
|
28
28
|
retryRun(id: string): WorkDiscoveryRun | null;
|
|
29
|
+
submitRecognitionFeedback(input: {
|
|
30
|
+
runId: string;
|
|
31
|
+
decision: WorkDiscoveryRecognitionDecision;
|
|
32
|
+
correctedIntent?: string;
|
|
33
|
+
}): Promise<WorkDiscoveryRun | null>;
|
|
29
34
|
selectSuggestion(runId: string, suggestionId: string): WorkDiscoveryRun | null;
|
|
30
35
|
}
|
|
@@ -6,7 +6,7 @@ import { buildSessionKey, init_session_key } from "../routing/session-key.js";
|
|
|
6
6
|
import { getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
|
|
7
7
|
import { previewWorkDiscoveryRoot, probeWorkDiscoveryRoot, summarizeWorkContextSnapshot } from "./probe.js";
|
|
8
8
|
import { analyzeWorkContext, workDiscoveryResultMarkdown } from "./analyzer.js";
|
|
9
|
-
import { createWorkDiscoveryRun, getWorkDiscoveryOnboardingState, getWorkDiscoveryRun, getWorkDiscoveryRunByIdempotencyKey, setWorkDiscoveryOnboardingState, updateWorkDiscoveryRun } from "./repository.js";
|
|
9
|
+
import { createWorkDiscoveryRun, getWorkDiscoveryOnboardingState, getWorkDiscoveryRun, getWorkDiscoveryRunByIdempotencyKey, setWorkDiscoveryFeedback, setWorkDiscoveryOnboardingState, updateWorkDiscoveryRun } from "./repository.js";
|
|
10
10
|
import { randomUUID } from "node:crypto";
|
|
11
11
|
//#region src/work-discovery/service.ts
|
|
12
12
|
init_schema();
|
|
@@ -215,10 +215,6 @@ var WorkDiscoveryService = class {
|
|
|
215
215
|
result: analysis.result,
|
|
216
216
|
completedAt: Date.now()
|
|
217
217
|
});
|
|
218
|
-
if (run.source === "onboarding_selected_directory") setWorkDiscoveryOnboardingState({
|
|
219
|
-
status: "completed",
|
|
220
|
-
activeRunId: run.id
|
|
221
|
-
});
|
|
222
218
|
this.activity.record({
|
|
223
219
|
type: "work_discovery.completed",
|
|
224
220
|
primaryObject: {
|
|
@@ -346,6 +342,69 @@ var WorkDiscoveryService = class {
|
|
|
346
342
|
this.execute(queued, controller.signal);
|
|
347
343
|
return queued;
|
|
348
344
|
}
|
|
345
|
+
async submitRecognitionFeedback(input) {
|
|
346
|
+
const run = getWorkDiscoveryRun(input.runId);
|
|
347
|
+
if (!run || run.status !== "completed" || !run.result) return null;
|
|
348
|
+
const correctedIntent = input.correctedIntent?.trim().slice(0, 2e3);
|
|
349
|
+
if ((input.decision === "corrected" || input.decision === "different_goal") && !correctedIntent) throw new Error("A corrected intent is required for this decision");
|
|
350
|
+
const feedback = setWorkDiscoveryFeedback({
|
|
351
|
+
runId: run.id,
|
|
352
|
+
recognitionDecision: input.decision,
|
|
353
|
+
...correctedIntent ? { correctedIntent } : {}
|
|
354
|
+
});
|
|
355
|
+
if (run.source === "onboarding_selected_directory") setWorkDiscoveryOnboardingState({
|
|
356
|
+
status: input.decision === "dismissed" ? "dismissed" : "completed",
|
|
357
|
+
activeRunId: input.decision === "dismissed" ? null : run.id
|
|
358
|
+
});
|
|
359
|
+
const feedbackText = correctedIntent ? `The user corrected the work discovery understanding: ${correctedIntent}` : input.decision === "confirmed" ? "The user confirmed the work discovery understanding." : "The user left work discovery without confirming the suggested understanding.";
|
|
360
|
+
await this.options.sessions.appendTranscriptContextEntry(run.sessionKey, {
|
|
361
|
+
text: feedbackText,
|
|
362
|
+
data: {
|
|
363
|
+
type: "work_discovery_recognition_feedback",
|
|
364
|
+
runId: run.id,
|
|
365
|
+
decision: input.decision,
|
|
366
|
+
...correctedIntent ? { correctedIntent } : {}
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
this.activity.record({
|
|
370
|
+
type: `work_discovery.recognition_${input.decision}`,
|
|
371
|
+
primaryObject: {
|
|
372
|
+
kind: "project",
|
|
373
|
+
id: run.projectId
|
|
374
|
+
},
|
|
375
|
+
actor: {
|
|
376
|
+
kind: "user",
|
|
377
|
+
sessionKey: run.sessionKey
|
|
378
|
+
},
|
|
379
|
+
source: {
|
|
380
|
+
kind: "gateway_api",
|
|
381
|
+
runId: run.id
|
|
382
|
+
},
|
|
383
|
+
payload: {
|
|
384
|
+
decision: input.decision,
|
|
385
|
+
corrected: Boolean(correctedIntent)
|
|
386
|
+
},
|
|
387
|
+
scopes: [{
|
|
388
|
+
scopeKind: "project",
|
|
389
|
+
scopeId: run.projectId,
|
|
390
|
+
reason: "object_owner"
|
|
391
|
+
}, {
|
|
392
|
+
scopeKind: "session",
|
|
393
|
+
scopeId: run.sessionKey,
|
|
394
|
+
reason: "runtime_context"
|
|
395
|
+
}]
|
|
396
|
+
});
|
|
397
|
+
this.options.emit("work-discovery.recognition-feedback", {
|
|
398
|
+
runId: run.id,
|
|
399
|
+
projectId: run.projectId,
|
|
400
|
+
sessionKey: run.sessionKey,
|
|
401
|
+
decision: input.decision
|
|
402
|
+
});
|
|
403
|
+
return {
|
|
404
|
+
...run,
|
|
405
|
+
feedback
|
|
406
|
+
};
|
|
407
|
+
}
|
|
349
408
|
selectSuggestion(runId, suggestionId) {
|
|
350
409
|
const run = getWorkDiscoveryRun(runId);
|
|
351
410
|
const suggestion = run?.result?.suggestions.find((item) => item.id === suggestionId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","names":[],"sources":["../../../src/work-discovery/service.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport type { Config } from '../config/schema.js';\nimport { getAgentDefaultModelRef } from '../config/schema.js';\nimport { ActivityService } from '../activity/service.js';\nimport type { ProjectService } from '../projects/project-service.js';\nimport { buildSessionKey } from '../routing/session-key.js';\nimport { getDefaultAgentId } from '../routing/resolve-route.js';\nimport type { SessionIndex } from '../session/manager.js';\nimport type { SessionMetadataSeed } from '../storage/sqlite/index.js';\nimport { createLogger } from '../utils/logger.js';\n\nimport { analyzeWorkContext, workDiscoveryResultMarkdown } from './analyzer.js';\nimport {\n createWorkDiscoveryRun,\n getWorkDiscoveryOnboardingState,\n getWorkDiscoveryRun,\n getWorkDiscoveryRunByIdempotencyKey,\n setWorkDiscoveryOnboardingState,\n updateWorkDiscoveryRun,\n} from './repository.js';\nimport {\n probeWorkDiscoveryRoot,\n previewWorkDiscoveryRoot,\n summarizeWorkContextSnapshot,\n WORK_DISCOVERY_SCAN_POLICY_VERSION,\n} from './probe.js';\nimport type {\n WorkDiscoveryErrorCode,\n WorkDiscoveryOnboardingState,\n WorkDiscoveryRun,\n WorkDiscoverySource,\n} from './types.js';\n\nconst log = createLogger('WorkDiscovery');\n\nexport interface WorkDiscoveryServiceOptions {\n projects: ProjectService;\n sessions: SessionIndex;\n getConfig: () => Config;\n emit: (type: string, payload: unknown) => void;\n}\n\nfunction sessionMetadata(agentId: string, peerId: string): SessionMetadataSeed {\n return {\n sourceChannel: 'webchat',\n sourceChatId: ['default', 'direct', peerId].join(':'),\n sessionType: 'chat',\n hiddenFromSessionList: true,\n routing: {\n agentId,\n source: 'webchat',\n accountId: 'default',\n peerKind: 'direct',\n peerId,\n },\n customData: {\n workDiscovery: true,\n genericNewChatShell: false,\n },\n };\n}\n\nfunction errorCode(error: unknown): WorkDiscoveryErrorCode {\n if (error instanceof DOMException && error.name === 'AbortError') return 'canceled';\n const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();\n if (message.includes('api key') || message.includes('model') || message.includes('provider')) return 'model_unavailable';\n if (message.includes('directory') || message.includes('folder') || message.includes('enoent')) return 'folder_unavailable';\n if (message.includes('permission') || message.includes('eacces')) return 'folder_not_readable';\n if (message.includes('json') || message.includes('analysis result')) return 'analysis_invalid';\n if (message.includes('timeout')) return 'analysis_timeout';\n return 'internal_error';\n}\n\nexport class WorkDiscoveryService {\n private readonly abortControllers = new Map<string, AbortController>();\n private readonly activity = new ActivityService();\n\n constructor(private readonly options: WorkDiscoveryServiceOptions) {}\n\n isEnabled(): boolean {\n return this.options.getConfig().experimental?.workDiscoveryOnboarding === true;\n }\n\n getOnboardingState(): WorkDiscoveryOnboardingState {\n return getWorkDiscoveryOnboardingState();\n }\n\n dismissOnboarding(): WorkDiscoveryOnboardingState {\n return setWorkDiscoveryOnboardingState({ status: 'dismissed', activeRunId: null });\n }\n\n getRun(id: string): WorkDiscoveryRun | null {\n return getWorkDiscoveryRun(id);\n }\n\n async startRun(input: {\n rootPath: string;\n source: WorkDiscoverySource;\n idempotencyKey: string;\n }): Promise<WorkDiscoveryRun> {\n const existing = getWorkDiscoveryRunByIdempotencyKey(input.idempotencyKey);\n if (existing) return existing;\n const config = this.options.getConfig();\n const modelRef = getAgentDefaultModelRef(config);\n if (!modelRef) throw new Error('No default model configured');\n\n const preview = await previewWorkDiscoveryRoot(input.rootPath);\n const rootPath = preview.canonicalRootPath;\n const agentId = getDefaultAgentId(config);\n const match = this.options.projects.resolveOrCreateForWorkspacePath({\n workspacePath: rootPath,\n defaultAgentId: agentId,\n autoCreate: true,\n });\n if (!match) throw new Error('Selected folder cannot be used as a project workspace');\n const projectAgentId = match.project.defaultAgentId || agentId;\n const peerId = `work-discovery-${randomUUID()}`;\n const sessionKey = buildSessionKey({\n agentId: projectAgentId,\n source: 'webchat',\n accountId: 'default',\n peerKind: 'direct',\n peerId,\n });\n await this.options.sessions.saveMessages(sessionKey, [], {\n metadata: sessionMetadata(projectAgentId, peerId),\n });\n this.options.projects.attachSession(sessionKey, match.project.id);\n const now = Date.now();\n const run = createWorkDiscoveryRun({\n id: randomUUID(),\n idempotencyKey: input.idempotencyKey,\n source: input.source,\n status: 'queued',\n rootPath,\n projectId: match.project.id,\n sessionKey,\n agentId: projectAgentId,\n modelRef,\n scanPolicyVersion: WORK_DISCOVERY_SCAN_POLICY_VERSION,\n createdAt: now,\n });\n await this.options.sessions.appendTranscriptContextEntry(sessionKey, {\n text: 'Work discovery was explicitly requested for the selected folder.',\n data: {\n type: 'work_discovery',\n runId: run.id,\n rootPath,\n scanPolicyVersion: WORK_DISCOVERY_SCAN_POLICY_VERSION,\n source: input.source,\n },\n });\n if (input.source === 'onboarding_selected_directory') {\n setWorkDiscoveryOnboardingState({ status: 'in_progress', activeRunId: run.id });\n }\n this.activity.record({\n type: 'work_discovery.started',\n primaryObject: { kind: 'project', id: match.project.id, title: match.project.name },\n actor: { kind: 'system' },\n initiator: { kind: 'user', sessionKey },\n source: { kind: 'gateway_api', runId: run.id },\n visibility: 'audit',\n payload: { policyVersion: WORK_DISCOVERY_SCAN_POLICY_VERSION, source: input.source },\n scopes: [\n { scopeKind: 'project', scopeId: match.project.id, reason: 'object_owner' },\n { scopeKind: 'session', scopeId: sessionKey, reason: 'runtime_context' },\n ],\n });\n const controller = new AbortController();\n this.abortControllers.set(run.id, controller);\n void this.execute(run, controller.signal);\n return run;\n }\n\n private publish(run: WorkDiscoveryRun): void {\n const suffix = run.status === 'completed'\n ? 'completed'\n : run.status === 'failed'\n ? 'failed'\n : run.status === 'canceled'\n ? 'canceled'\n : 'progress';\n this.options.emit(`work-discovery.${suffix}`, {\n runId: run.id,\n projectId: run.projectId,\n sessionKey: run.sessionKey,\n status: run.status,\n stage: run.stage,\n ...(run.status === 'completed' ? { result: run.result } : {}),\n });\n }\n\n private async execute(run: WorkDiscoveryRun, signal: AbortSignal): Promise<void> {\n const startedAt = Date.now();\n try {\n let current = updateWorkDiscoveryRun(run.id, {\n status: 'probing',\n stage: 'folder_structure',\n startedAt,\n })!;\n this.publish(current);\n const snapshot = await probeWorkDiscoveryRoot(run.rootPath, signal);\n if (signal.aborted) throw new DOMException('Work discovery canceled', 'AbortError');\n current = updateWorkDiscoveryRun(run.id, {\n status: 'analyzing',\n stage: 'recent_progress',\n snapshot: summarizeWorkContextSnapshot(snapshot),\n })!;\n this.publish(current);\n const analysis = await analyzeWorkContext({ config: this.options.getConfig(), snapshot, signal });\n current = updateWorkDiscoveryRun(run.id, { status: 'analyzing', stage: 'next_steps' })!;\n this.publish(current);\n await this.options.sessions.appendTranscriptCustomMessageEntry(run.sessionKey, {\n customType: 'work-discovery-result',\n content: workDiscoveryResultMarkdown(analysis.result),\n display: true,\n details: { runId: run.id, result: analysis.result },\n });\n const project = this.options.projects.get(run.projectId);\n await this.options.sessions.updateSessionMetadata(run.sessionKey, {\n name: project ? `Continue work on ${project.name}` : 'Continue recent work',\n hiddenFromSessionList: false,\n });\n current = updateWorkDiscoveryRun(run.id, {\n status: 'completed',\n stage: 'next_steps',\n result: analysis.result,\n completedAt: Date.now(),\n })!;\n if (run.source === 'onboarding_selected_directory') {\n setWorkDiscoveryOnboardingState({ status: 'completed', activeRunId: run.id });\n }\n this.activity.record({\n type: 'work_discovery.completed',\n primaryObject: { kind: 'project', id: run.projectId, title: project?.name },\n actor: { kind: 'agent', agentId: run.agentId, sessionKey: run.sessionKey },\n initiator: { kind: 'user', sessionKey: run.sessionKey },\n source: { kind: 'system', runId: run.id },\n payload: {\n policyVersion: run.scanPolicyVersion,\n suggestionCount: analysis.result.suggestions.length,\n lowConfidence: analysis.result.lowConfidence === true,\n },\n scopes: [\n { scopeKind: 'project', scopeId: run.projectId, reason: 'object_owner' },\n { scopeKind: 'session', scopeId: run.sessionKey, reason: 'runtime_context' },\n ],\n });\n this.publish(current);\n this.options.emit('session.transcript_updated', { key: run.sessionKey });\n log.info({ runId: run.id, projectId: run.projectId, sessionKey: run.sessionKey, durationMs: Date.now() - startedAt }, 'Work discovery completed');\n } catch (error) {\n const canceled = signal.aborted || (error instanceof DOMException && error.name === 'AbortError');\n const code = canceled ? 'canceled' : errorCode(error);\n const message = canceled ? 'Analysis canceled' : error instanceof Error ? error.message : String(error);\n const current = updateWorkDiscoveryRun(run.id, {\n status: canceled ? 'canceled' : 'failed',\n errorCode: code,\n errorMessage: message,\n ...(canceled ? { canceledAt: Date.now() } : { completedAt: Date.now() }),\n });\n if (current) this.publish(current);\n this.activity.record({\n type: canceled ? 'work_discovery.canceled' : 'work_discovery.failed',\n primaryObject: { kind: 'project', id: run.projectId },\n actor: { kind: 'system' },\n initiator: { kind: 'user', sessionKey: run.sessionKey },\n source: { kind: 'system', runId: run.id },\n visibility: 'audit',\n payload: { errorCode: code },\n scopes: [\n { scopeKind: 'project', scopeId: run.projectId, reason: 'object_owner' },\n { scopeKind: 'session', scopeId: run.sessionKey, reason: 'runtime_context' },\n ],\n });\n log.warn({ err: error, runId: run.id, projectId: run.projectId, phase: 'analysis', errorCode: code }, `Work discovery failed: ${message}`);\n } finally {\n this.abortControllers.delete(run.id);\n }\n }\n\n cancelRun(id: string): WorkDiscoveryRun | null {\n const run = getWorkDiscoveryRun(id);\n if (!run) return null;\n if (run.status === 'completed' || run.status === 'failed' || run.status === 'canceled') return run;\n this.abortControllers.get(id)?.abort();\n return updateWorkDiscoveryRun(id, {\n status: 'canceled',\n errorCode: 'canceled',\n errorMessage: 'Analysis canceled',\n canceledAt: Date.now(),\n });\n }\n\n retryRun(id: string): WorkDiscoveryRun | null {\n const run = getWorkDiscoveryRun(id);\n if (!run) return null;\n if (run.status !== 'failed' && run.status !== 'canceled') return run;\n const queued = updateWorkDiscoveryRun(id, {\n status: 'queued',\n stage: 'folder_structure',\n errorCode: undefined,\n errorMessage: undefined,\n completedAt: undefined,\n canceledAt: undefined,\n });\n if (!queued) return null;\n const controller = new AbortController();\n this.abortControllers.set(id, controller);\n if (run.source === 'onboarding_selected_directory') {\n setWorkDiscoveryOnboardingState({ status: 'in_progress', activeRunId: id });\n }\n this.publish(queued);\n void this.execute(queued, controller.signal);\n return queued;\n }\n\n selectSuggestion(runId: string, suggestionId: string): WorkDiscoveryRun | null {\n const run = getWorkDiscoveryRun(runId);\n const suggestion = run?.result?.suggestions.find((item) => item.id === suggestionId);\n if (!run || !suggestion) return null;\n this.activity.record({\n type: 'work_discovery.suggestion_selected',\n primaryObject: { kind: 'project', id: run.projectId },\n actor: { kind: 'user', sessionKey: run.sessionKey },\n source: { kind: 'gateway_api', runId },\n payload: { suggestionId, title: suggestion.title },\n scopes: [\n { scopeKind: 'project', scopeId: run.projectId, reason: 'object_owner' },\n { scopeKind: 'session', scopeId: run.sessionKey, reason: 'runtime_context' },\n ],\n });\n return run;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"service.js","names":[],"sources":["../../../src/work-discovery/service.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport type { Config } from '../config/schema.js';\nimport { getAgentDefaultModelRef } from '../config/schema.js';\nimport { ActivityService } from '../activity/service.js';\nimport type { ProjectService } from '../projects/project-service.js';\nimport { buildSessionKey } from '../routing/session-key.js';\nimport { getDefaultAgentId } from '../routing/resolve-route.js';\nimport type { SessionIndex } from '../session/manager.js';\nimport type { SessionMetadataSeed } from '../storage/sqlite/index.js';\nimport { createLogger } from '../utils/logger.js';\n\nimport { analyzeWorkContext, workDiscoveryResultMarkdown } from './analyzer.js';\nimport {\n createWorkDiscoveryRun,\n getWorkDiscoveryOnboardingState,\n getWorkDiscoveryRun,\n getWorkDiscoveryRunByIdempotencyKey,\n setWorkDiscoveryFeedback,\n setWorkDiscoveryOnboardingState,\n updateWorkDiscoveryRun,\n} from './repository.js';\nimport {\n probeWorkDiscoveryRoot,\n previewWorkDiscoveryRoot,\n summarizeWorkContextSnapshot,\n WORK_DISCOVERY_SCAN_POLICY_VERSION,\n} from './probe.js';\nimport type {\n WorkDiscoveryErrorCode,\n WorkDiscoveryOnboardingState,\n WorkDiscoveryRecognitionDecision,\n WorkDiscoveryRun,\n WorkDiscoverySource,\n} from './types.js';\n\nconst log = createLogger('WorkDiscovery');\n\nexport interface WorkDiscoveryServiceOptions {\n projects: ProjectService;\n sessions: SessionIndex;\n getConfig: () => Config;\n emit: (type: string, payload: unknown) => void;\n}\n\nfunction sessionMetadata(agentId: string, peerId: string): SessionMetadataSeed {\n return {\n sourceChannel: 'webchat',\n sourceChatId: ['default', 'direct', peerId].join(':'),\n sessionType: 'chat',\n hiddenFromSessionList: true,\n routing: {\n agentId,\n source: 'webchat',\n accountId: 'default',\n peerKind: 'direct',\n peerId,\n },\n customData: {\n workDiscovery: true,\n genericNewChatShell: false,\n },\n };\n}\n\nfunction errorCode(error: unknown): WorkDiscoveryErrorCode {\n if (error instanceof DOMException && error.name === 'AbortError') return 'canceled';\n const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();\n if (message.includes('api key') || message.includes('model') || message.includes('provider')) return 'model_unavailable';\n if (message.includes('directory') || message.includes('folder') || message.includes('enoent')) return 'folder_unavailable';\n if (message.includes('permission') || message.includes('eacces')) return 'folder_not_readable';\n if (message.includes('json') || message.includes('analysis result')) return 'analysis_invalid';\n if (message.includes('timeout')) return 'analysis_timeout';\n return 'internal_error';\n}\n\nexport class WorkDiscoveryService {\n private readonly abortControllers = new Map<string, AbortController>();\n private readonly activity = new ActivityService();\n\n constructor(private readonly options: WorkDiscoveryServiceOptions) {}\n\n isEnabled(): boolean {\n return this.options.getConfig().experimental?.workDiscoveryOnboarding === true;\n }\n\n getOnboardingState(): WorkDiscoveryOnboardingState {\n return getWorkDiscoveryOnboardingState();\n }\n\n dismissOnboarding(): WorkDiscoveryOnboardingState {\n return setWorkDiscoveryOnboardingState({ status: 'dismissed', activeRunId: null });\n }\n\n getRun(id: string): WorkDiscoveryRun | null {\n return getWorkDiscoveryRun(id);\n }\n\n async startRun(input: {\n rootPath: string;\n source: WorkDiscoverySource;\n idempotencyKey: string;\n }): Promise<WorkDiscoveryRun> {\n const existing = getWorkDiscoveryRunByIdempotencyKey(input.idempotencyKey);\n if (existing) return existing;\n const config = this.options.getConfig();\n const modelRef = getAgentDefaultModelRef(config);\n if (!modelRef) throw new Error('No default model configured');\n\n const preview = await previewWorkDiscoveryRoot(input.rootPath);\n const rootPath = preview.canonicalRootPath;\n const agentId = getDefaultAgentId(config);\n const match = this.options.projects.resolveOrCreateForWorkspacePath({\n workspacePath: rootPath,\n defaultAgentId: agentId,\n autoCreate: true,\n });\n if (!match) throw new Error('Selected folder cannot be used as a project workspace');\n const projectAgentId = match.project.defaultAgentId || agentId;\n const peerId = `work-discovery-${randomUUID()}`;\n const sessionKey = buildSessionKey({\n agentId: projectAgentId,\n source: 'webchat',\n accountId: 'default',\n peerKind: 'direct',\n peerId,\n });\n await this.options.sessions.saveMessages(sessionKey, [], {\n metadata: sessionMetadata(projectAgentId, peerId),\n });\n this.options.projects.attachSession(sessionKey, match.project.id);\n const now = Date.now();\n const run = createWorkDiscoveryRun({\n id: randomUUID(),\n idempotencyKey: input.idempotencyKey,\n source: input.source,\n status: 'queued',\n rootPath,\n projectId: match.project.id,\n sessionKey,\n agentId: projectAgentId,\n modelRef,\n scanPolicyVersion: WORK_DISCOVERY_SCAN_POLICY_VERSION,\n createdAt: now,\n });\n await this.options.sessions.appendTranscriptContextEntry(sessionKey, {\n text: 'Work discovery was explicitly requested for the selected folder.',\n data: {\n type: 'work_discovery',\n runId: run.id,\n rootPath,\n scanPolicyVersion: WORK_DISCOVERY_SCAN_POLICY_VERSION,\n source: input.source,\n },\n });\n if (input.source === 'onboarding_selected_directory') {\n setWorkDiscoveryOnboardingState({ status: 'in_progress', activeRunId: run.id });\n }\n this.activity.record({\n type: 'work_discovery.started',\n primaryObject: { kind: 'project', id: match.project.id, title: match.project.name },\n actor: { kind: 'system' },\n initiator: { kind: 'user', sessionKey },\n source: { kind: 'gateway_api', runId: run.id },\n visibility: 'audit',\n payload: { policyVersion: WORK_DISCOVERY_SCAN_POLICY_VERSION, source: input.source },\n scopes: [\n { scopeKind: 'project', scopeId: match.project.id, reason: 'object_owner' },\n { scopeKind: 'session', scopeId: sessionKey, reason: 'runtime_context' },\n ],\n });\n const controller = new AbortController();\n this.abortControllers.set(run.id, controller);\n void this.execute(run, controller.signal);\n return run;\n }\n\n private publish(run: WorkDiscoveryRun): void {\n const suffix = run.status === 'completed'\n ? 'completed'\n : run.status === 'failed'\n ? 'failed'\n : run.status === 'canceled'\n ? 'canceled'\n : 'progress';\n this.options.emit(`work-discovery.${suffix}`, {\n runId: run.id,\n projectId: run.projectId,\n sessionKey: run.sessionKey,\n status: run.status,\n stage: run.stage,\n ...(run.status === 'completed' ? { result: run.result } : {}),\n });\n }\n\n private async execute(run: WorkDiscoveryRun, signal: AbortSignal): Promise<void> {\n const startedAt = Date.now();\n try {\n let current = updateWorkDiscoveryRun(run.id, {\n status: 'probing',\n stage: 'folder_structure',\n startedAt,\n })!;\n this.publish(current);\n const snapshot = await probeWorkDiscoveryRoot(run.rootPath, signal);\n if (signal.aborted) throw new DOMException('Work discovery canceled', 'AbortError');\n current = updateWorkDiscoveryRun(run.id, {\n status: 'analyzing',\n stage: 'recent_progress',\n snapshot: summarizeWorkContextSnapshot(snapshot),\n })!;\n this.publish(current);\n const analysis = await analyzeWorkContext({ config: this.options.getConfig(), snapshot, signal });\n current = updateWorkDiscoveryRun(run.id, { status: 'analyzing', stage: 'next_steps' })!;\n this.publish(current);\n await this.options.sessions.appendTranscriptCustomMessageEntry(run.sessionKey, {\n customType: 'work-discovery-result',\n content: workDiscoveryResultMarkdown(analysis.result),\n display: true,\n details: { runId: run.id, result: analysis.result },\n });\n const project = this.options.projects.get(run.projectId);\n await this.options.sessions.updateSessionMetadata(run.sessionKey, {\n name: project ? `Continue work on ${project.name}` : 'Continue recent work',\n hiddenFromSessionList: false,\n });\n current = updateWorkDiscoveryRun(run.id, {\n status: 'completed',\n stage: 'next_steps',\n result: analysis.result,\n completedAt: Date.now(),\n })!;\n this.activity.record({\n type: 'work_discovery.completed',\n primaryObject: { kind: 'project', id: run.projectId, title: project?.name },\n actor: { kind: 'agent', agentId: run.agentId, sessionKey: run.sessionKey },\n initiator: { kind: 'user', sessionKey: run.sessionKey },\n source: { kind: 'system', runId: run.id },\n payload: {\n policyVersion: run.scanPolicyVersion,\n suggestionCount: analysis.result.suggestions.length,\n lowConfidence: analysis.result.lowConfidence === true,\n },\n scopes: [\n { scopeKind: 'project', scopeId: run.projectId, reason: 'object_owner' },\n { scopeKind: 'session', scopeId: run.sessionKey, reason: 'runtime_context' },\n ],\n });\n this.publish(current);\n this.options.emit('session.transcript_updated', { key: run.sessionKey });\n log.info({ runId: run.id, projectId: run.projectId, sessionKey: run.sessionKey, durationMs: Date.now() - startedAt }, 'Work discovery completed');\n } catch (error) {\n const canceled = signal.aborted || (error instanceof DOMException && error.name === 'AbortError');\n const code = canceled ? 'canceled' : errorCode(error);\n const message = canceled ? 'Analysis canceled' : error instanceof Error ? error.message : String(error);\n const current = updateWorkDiscoveryRun(run.id, {\n status: canceled ? 'canceled' : 'failed',\n errorCode: code,\n errorMessage: message,\n ...(canceled ? { canceledAt: Date.now() } : { completedAt: Date.now() }),\n });\n if (current) this.publish(current);\n this.activity.record({\n type: canceled ? 'work_discovery.canceled' : 'work_discovery.failed',\n primaryObject: { kind: 'project', id: run.projectId },\n actor: { kind: 'system' },\n initiator: { kind: 'user', sessionKey: run.sessionKey },\n source: { kind: 'system', runId: run.id },\n visibility: 'audit',\n payload: { errorCode: code },\n scopes: [\n { scopeKind: 'project', scopeId: run.projectId, reason: 'object_owner' },\n { scopeKind: 'session', scopeId: run.sessionKey, reason: 'runtime_context' },\n ],\n });\n log.warn({ err: error, runId: run.id, projectId: run.projectId, phase: 'analysis', errorCode: code }, `Work discovery failed: ${message}`);\n } finally {\n this.abortControllers.delete(run.id);\n }\n }\n\n cancelRun(id: string): WorkDiscoveryRun | null {\n const run = getWorkDiscoveryRun(id);\n if (!run) return null;\n if (run.status === 'completed' || run.status === 'failed' || run.status === 'canceled') return run;\n this.abortControllers.get(id)?.abort();\n return updateWorkDiscoveryRun(id, {\n status: 'canceled',\n errorCode: 'canceled',\n errorMessage: 'Analysis canceled',\n canceledAt: Date.now(),\n });\n }\n\n retryRun(id: string): WorkDiscoveryRun | null {\n const run = getWorkDiscoveryRun(id);\n if (!run) return null;\n if (run.status !== 'failed' && run.status !== 'canceled') return run;\n const queued = updateWorkDiscoveryRun(id, {\n status: 'queued',\n stage: 'folder_structure',\n errorCode: undefined,\n errorMessage: undefined,\n completedAt: undefined,\n canceledAt: undefined,\n });\n if (!queued) return null;\n const controller = new AbortController();\n this.abortControllers.set(id, controller);\n if (run.source === 'onboarding_selected_directory') {\n setWorkDiscoveryOnboardingState({ status: 'in_progress', activeRunId: id });\n }\n this.publish(queued);\n void this.execute(queued, controller.signal);\n return queued;\n }\n\n async submitRecognitionFeedback(input: {\n runId: string;\n decision: WorkDiscoveryRecognitionDecision;\n correctedIntent?: string;\n }): Promise<WorkDiscoveryRun | null> {\n const run = getWorkDiscoveryRun(input.runId);\n if (!run || run.status !== 'completed' || !run.result) return null;\n const correctedIntent = input.correctedIntent?.trim().slice(0, 2_000);\n if ((input.decision === 'corrected' || input.decision === 'different_goal') && !correctedIntent) {\n throw new Error('A corrected intent is required for this decision');\n }\n const feedback = setWorkDiscoveryFeedback({\n runId: run.id,\n recognitionDecision: input.decision,\n ...(correctedIntent ? { correctedIntent } : {}),\n });\n if (run.source === 'onboarding_selected_directory') {\n setWorkDiscoveryOnboardingState({\n status: input.decision === 'dismissed' ? 'dismissed' : 'completed',\n activeRunId: input.decision === 'dismissed' ? null : run.id,\n });\n }\n const feedbackText = correctedIntent\n ? `The user corrected the work discovery understanding: ${correctedIntent}`\n : input.decision === 'confirmed'\n ? 'The user confirmed the work discovery understanding.'\n : 'The user left work discovery without confirming the suggested understanding.';\n await this.options.sessions.appendTranscriptContextEntry(run.sessionKey, {\n text: feedbackText,\n data: {\n type: 'work_discovery_recognition_feedback',\n runId: run.id,\n decision: input.decision,\n ...(correctedIntent ? { correctedIntent } : {}),\n },\n });\n this.activity.record({\n type: `work_discovery.recognition_${input.decision}`,\n primaryObject: { kind: 'project', id: run.projectId },\n actor: { kind: 'user', sessionKey: run.sessionKey },\n source: { kind: 'gateway_api', runId: run.id },\n payload: {\n decision: input.decision,\n corrected: Boolean(correctedIntent),\n },\n scopes: [\n { scopeKind: 'project', scopeId: run.projectId, reason: 'object_owner' },\n { scopeKind: 'session', scopeId: run.sessionKey, reason: 'runtime_context' },\n ],\n });\n this.options.emit('work-discovery.recognition-feedback', {\n runId: run.id,\n projectId: run.projectId,\n sessionKey: run.sessionKey,\n decision: input.decision,\n });\n return { ...run, feedback };\n }\n\n selectSuggestion(runId: string, suggestionId: string): WorkDiscoveryRun | null {\n const run = getWorkDiscoveryRun(runId);\n const suggestion = run?.result?.suggestions.find((item) => item.id === suggestionId);\n if (!run || !suggestion) return null;\n this.activity.record({\n type: 'work_discovery.suggestion_selected',\n primaryObject: { kind: 'project', id: run.projectId },\n actor: { kind: 'user', sessionKey: run.sessionKey },\n source: { kind: 'gateway_api', runId },\n payload: { suggestionId, title: suggestion.title },\n scopes: [\n { scopeKind: 'project', scopeId: run.projectId, reason: 'object_owner' },\n { scopeKind: 'session', scopeId: run.sessionKey, reason: 'runtime_context' },\n ],\n });\n return run;\n }\n}\n"],"mappings":"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"}
|
|
@@ -16,20 +16,34 @@ export interface WorkDiscoveryEvidence {
|
|
|
16
16
|
}
|
|
17
17
|
export interface WorkDiscoverySuggestion {
|
|
18
18
|
id: string;
|
|
19
|
+
actionType: 'summarize_recent_work' | 'inspect_related_tests' | 'plan_next_step';
|
|
19
20
|
title: string;
|
|
20
21
|
rationale: string;
|
|
21
22
|
evidence: WorkDiscoveryEvidence[];
|
|
22
23
|
actionPrompt: string;
|
|
23
24
|
confidence: 'high' | 'medium' | 'low';
|
|
25
|
+
expectedOutcome: string;
|
|
26
|
+
estimatedMinutes: number;
|
|
27
|
+
risk: 'analysis' | 'command' | 'file_write';
|
|
28
|
+
verification: string[];
|
|
24
29
|
}
|
|
25
30
|
export interface WorkDiscoveryResult {
|
|
26
31
|
projectSummary: string;
|
|
27
32
|
currentState: string;
|
|
28
33
|
uncertainties: string[];
|
|
29
34
|
suggestions: WorkDiscoverySuggestion[];
|
|
35
|
+
primarySuggestionId?: string;
|
|
30
36
|
lowConfidence?: boolean;
|
|
31
37
|
contextQuestion?: string;
|
|
32
38
|
}
|
|
39
|
+
export type WorkDiscoveryRecognitionDecision = 'confirmed' | 'corrected' | 'different_goal' | 'dismissed';
|
|
40
|
+
export interface WorkDiscoveryFeedback {
|
|
41
|
+
runId: string;
|
|
42
|
+
recognitionDecision: WorkDiscoveryRecognitionDecision;
|
|
43
|
+
correctedIntent?: string;
|
|
44
|
+
createdAt: number;
|
|
45
|
+
updatedAt: number;
|
|
46
|
+
}
|
|
33
47
|
export interface WorkContextDocument {
|
|
34
48
|
relativePath: string;
|
|
35
49
|
modifiedAt?: number;
|
|
@@ -93,6 +107,7 @@ export interface WorkDiscoveryRun {
|
|
|
93
107
|
scanPolicyVersion: number;
|
|
94
108
|
snapshot?: WorkContextSnapshotSummary;
|
|
95
109
|
result?: WorkDiscoveryResult;
|
|
110
|
+
feedback?: WorkDiscoveryFeedback;
|
|
96
111
|
errorCode?: WorkDiscoveryErrorCode;
|
|
97
112
|
errorMessage?: string;
|
|
98
113
|
createdAt: number;
|
|
@@ -108,6 +123,12 @@ export interface WorkDiscoveryPreview {
|
|
|
108
123
|
projectKind: 'coding' | 'general' | 'unknown';
|
|
109
124
|
projectKindConfidence: number;
|
|
110
125
|
markerReasons: string[];
|
|
126
|
+
fingerprint: {
|
|
127
|
+
branch?: string;
|
|
128
|
+
changedFileCount: number;
|
|
129
|
+
recentAreas: string[];
|
|
130
|
+
generatedAt: number;
|
|
131
|
+
};
|
|
111
132
|
provider: string;
|
|
112
133
|
remoteModel: boolean;
|
|
113
134
|
policyVersion: number;
|
|
@@ -4,8 +4,8 @@ import { publishAutomationProductEvent } from "../../automations/product-events.
|
|
|
4
4
|
import { GoalService } from "../../goals/goal-service.js";
|
|
5
5
|
import "../../goals/index.js";
|
|
6
6
|
import { DelegateSubagentRunner } from "../../agent/workflow/subagent-runner.js";
|
|
7
|
-
import { resolveModelRef } from "../../config/agent-typed-models.js";
|
|
8
7
|
import { preflightWorkflowConnectors } from "../../connectors/workflow-preflight.js";
|
|
8
|
+
import { resolveModelRef } from "../../config/agent-typed-models.js";
|
|
9
9
|
import { CatalogWorkflowDefinitionRegistry } from "../registry/catalog-workflow-definition-registry.js";
|
|
10
10
|
import { validateWorkflowJsonSchema } from "../domain/schema-validation.js";
|
|
11
11
|
import { isTerminalWorkflowRunStatus } from "../domain/run.js";
|
package/package.json
CHANGED