@aopslab/aops-server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +6 -0
- package/README.md +21 -0
- package/aops-server-runtime.json +11 -0
- package/build/client/_app/immutable/chunks/2_TffmqH.js +1 -0
- package/build/client/_app/immutable/chunks/3DOfIKW0.js +1 -0
- package/build/client/_app/immutable/chunks/B2EkC-sy.js +1 -0
- package/build/client/_app/immutable/chunks/CMkIcmi1.js +2 -0
- package/build/client/_app/immutable/chunks/rqnVXeyB.js +1 -0
- package/build/client/_app/immutable/chunks/sZYZbj9W.js +1 -0
- package/build/client/_app/immutable/chunks/wbPk3Yxo.js +81 -0
- package/build/client/_app/immutable/entry/app.C7STLTX8.js +2 -0
- package/build/client/_app/immutable/entry/start.BC94hOaC.js +1 -0
- package/build/client/_app/immutable/nodes/0.BYBfjxZ5.js +1 -0
- package/build/client/_app/immutable/nodes/1.BNXFXajG.js +1 -0
- package/build/client/_app/version.json +1 -0
- package/build/env.js +70 -0
- package/build/env.js.map +1 -0
- package/build/handler.js +16 -0
- package/build/handler.js.map +1 -0
- package/build/index.js +139 -0
- package/build/index.js.map +1 -0
- package/build/server/chunks/0-RfB6m2nq.js +7 -0
- package/build/server/chunks/0-RfB6m2nq.js.map +1 -0
- package/build/server/chunks/1-_gg8Q0UT.js +9 -0
- package/build/server/chunks/1-_gg8Q0UT.js.map +1 -0
- package/build/server/chunks/_server.ts-6276EQIF.js +44 -0
- package/build/server/chunks/_server.ts-6276EQIF.js.map +1 -0
- package/build/server/chunks/_server.ts-B59WFQzX.js +174 -0
- package/build/server/chunks/_server.ts-B59WFQzX.js.map +1 -0
- package/build/server/chunks/_server.ts-BauJsLZI.js +40 -0
- package/build/server/chunks/_server.ts-BauJsLZI.js.map +1 -0
- package/build/server/chunks/_server.ts-BnGzJw2-.js +81 -0
- package/build/server/chunks/_server.ts-BnGzJw2-.js.map +1 -0
- package/build/server/chunks/_server.ts-CP7qM24V.js +34 -0
- package/build/server/chunks/_server.ts-CP7qM24V.js.map +1 -0
- package/build/server/chunks/_server.ts-Cbq_u99d.js +9 -0
- package/build/server/chunks/_server.ts-Cbq_u99d.js.map +1 -0
- package/build/server/chunks/_server.ts-Ch8fPT-o.js +92 -0
- package/build/server/chunks/_server.ts-Ch8fPT-o.js.map +1 -0
- package/build/server/chunks/_server.ts-Cv-yaXZI.js +7 -0
- package/build/server/chunks/_server.ts-Cv-yaXZI.js.map +1 -0
- package/build/server/chunks/_server.ts-D6lBwOON.js +34 -0
- package/build/server/chunks/_server.ts-D6lBwOON.js.map +1 -0
- package/build/server/chunks/_server.ts-D84K3pp9.js +11 -0
- package/build/server/chunks/_server.ts-D84K3pp9.js.map +1 -0
- package/build/server/chunks/_server.ts-DNzU1ToA.js +277 -0
- package/build/server/chunks/_server.ts-DNzU1ToA.js.map +1 -0
- package/build/server/chunks/_server.ts-DQQnw77t.js +17 -0
- package/build/server/chunks/_server.ts-DQQnw77t.js.map +1 -0
- package/build/server/chunks/_server.ts-DSxr5l15.js +18 -0
- package/build/server/chunks/_server.ts-DSxr5l15.js.map +1 -0
- package/build/server/chunks/_server.ts-DZYokvuR.js +80 -0
- package/build/server/chunks/_server.ts-DZYokvuR.js.map +1 -0
- package/build/server/chunks/_server.ts-Dcqwpz2t.js +144 -0
- package/build/server/chunks/_server.ts-Dcqwpz2t.js.map +1 -0
- package/build/server/chunks/_server.ts-Di9VJnF4.js +81 -0
- package/build/server/chunks/_server.ts-Di9VJnF4.js.map +1 -0
- package/build/server/chunks/_server.ts-FBEHFT8b.js +33 -0
- package/build/server/chunks/_server.ts-FBEHFT8b.js.map +1 -0
- package/build/server/chunks/_server.ts-gZytCuiJ.js +10 -0
- package/build/server/chunks/_server.ts-gZytCuiJ.js.map +1 -0
- package/build/server/chunks/_server.ts-tNULLyEO.js +261 -0
- package/build/server/chunks/_server.ts-tNULLyEO.js.map +1 -0
- package/build/server/chunks/agent-gateway-runtime-DTZ4SxaC.js +2598 -0
- package/build/server/chunks/agent-gateway-runtime-DTZ4SxaC.js.map +1 -0
- package/build/server/chunks/aops-runtime-config-wpVmg7T-.js +179 -0
- package/build/server/chunks/aops-runtime-config-wpVmg7T-.js.map +1 -0
- package/build/server/chunks/discovery-D9JnSgfu.js +894 -0
- package/build/server/chunks/discovery-D9JnSgfu.js.map +1 -0
- package/build/server/chunks/error.svelte-DgUOqi-L.js +45 -0
- package/build/server/chunks/error.svelte-DgUOqi-L.js.map +1 -0
- package/build/server/chunks/handler-BN3-p5rP.js +1733 -0
- package/build/server/chunks/handler-BN3-p5rP.js.map +1 -0
- package/build/server/chunks/hooks.server-C4wxiH5m.js +52 -0
- package/build/server/chunks/hooks.server-C4wxiH5m.js.map +1 -0
- package/build/server/chunks/index.js-nbqdVuWC.js +10698 -0
- package/build/server/chunks/index.js-nbqdVuWC.js.map +1 -0
- package/build/server/chunks/manifest.js-_Re-Wj-y.js +167 -0
- package/build/server/chunks/manifest.js-_Re-Wj-y.js.map +1 -0
- package/build/server/chunks/plugin-error-normalize-Bq14Qbz3.js +297 -0
- package/build/server/chunks/plugin-error-normalize-Bq14Qbz3.js.map +1 -0
- package/build/server/chunks/project-alias-DqE2v58Q.js +29 -0
- package/build/server/chunks/project-alias-DqE2v58Q.js.map +1 -0
- package/build/server/chunks/registry-5amIZito.js +289 -0
- package/build/server/chunks/registry-5amIZito.js.map +1 -0
- package/build/server/chunks/request-base-url-BDdrsaga.js +24 -0
- package/build/server/chunks/request-base-url-BDdrsaga.js.map +1 -0
- package/build/server/chunks/request-context-tNeFQjgb.js +422 -0
- package/build/server/chunks/request-context-tNeFQjgb.js.map +1 -0
- package/build/server/chunks/xf-result-BRDjvftr.js +17 -0
- package/build/server/chunks/xf-result-BRDjvftr.js.map +1 -0
- package/build/shims.js +33 -0
- package/build/shims.js.map +1 -0
- package/cockpit/.vite/manifest.json +198 -0
- package/cockpit/assets/dm-sans-latin-400-normal-BwCSEQnW.woff +0 -0
- package/cockpit/assets/dm-sans-latin-400-normal-CW0RaeGs.woff2 +0 -0
- package/cockpit/assets/dm-sans-latin-500-normal-B9HHJjqV.woff2 +0 -0
- package/cockpit/assets/dm-sans-latin-500-normal-Dr3UlScf.woff +0 -0
- package/cockpit/assets/dm-sans-latin-700-normal-CUSSCpQX.woff +0 -0
- package/cockpit/assets/dm-sans-latin-700-normal-DvUfVpUG.woff2 +0 -0
- package/cockpit/assets/dm-sans-latin-ext-400-normal-BjWJ59Pq.woff +0 -0
- package/cockpit/assets/dm-sans-latin-ext-400-normal-BtiwyxMk.woff2 +0 -0
- package/cockpit/assets/dm-sans-latin-ext-500-normal-BJfUCQsA.woff2 +0 -0
- package/cockpit/assets/dm-sans-latin-ext-500-normal-DR84L5F-.woff +0 -0
- package/cockpit/assets/dm-sans-latin-ext-700-normal-BLI3TTWz.woff +0 -0
- package/cockpit/assets/dm-sans-latin-ext-700-normal-CJIcxD6K.woff2 +0 -0
- package/cockpit/assets/index-DDswO4B1.css +1 -0
- package/cockpit/assets/index-bovtnZ98.js +18 -0
- package/cockpit/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
- package/cockpit/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
- package/cockpit/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
- package/cockpit/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
- package/cockpit/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
- package/cockpit/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/cockpit/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
- package/cockpit/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
- package/cockpit/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
- package/cockpit/assets/outfit-latin-400-normal-BGsTXAXT.woff2 +0 -0
- package/cockpit/assets/outfit-latin-400-normal-DMwTpYkH.woff +0 -0
- package/cockpit/assets/outfit-latin-600-normal-B7SfZ07L.woff2 +0 -0
- package/cockpit/assets/outfit-latin-600-normal-BEfTtDA7.woff +0 -0
- package/cockpit/assets/outfit-latin-ext-400-normal-5tcqmc2S.woff2 +0 -0
- package/cockpit/assets/outfit-latin-ext-400-normal-DHm7mdGe.woff +0 -0
- package/cockpit/assets/outfit-latin-ext-600-normal-B85nYjL1.woff2 +0 -0
- package/cockpit/assets/outfit-latin-ext-600-normal-CWJcPgd7.woff +0 -0
- package/cockpit/assets/unbounded-cyrillic-600-normal-B-s5c2Kn.woff +0 -0
- package/cockpit/assets/unbounded-cyrillic-600-normal-DW6uzIMB.woff2 +0 -0
- package/cockpit/assets/unbounded-latin-600-normal-BPdB_PEv.woff +0 -0
- package/cockpit/assets/unbounded-latin-600-normal-oRSANpZr.woff2 +0 -0
- package/cockpit/assets/unbounded-latin-ext-600-normal-0iZLtTDV.woff2 +0 -0
- package/cockpit/assets/unbounded-latin-ext-600-normal-ClMPf-bu.woff +0 -0
- package/cockpit/assets/unbounded-vietnamese-600-normal-BzfrgZ_C.woff +0 -0
- package/cockpit/assets/unbounded-vietnamese-600-normal-Cx2bTSHN.woff2 +0 -0
- package/cockpit/community.module-inventory.json +2389 -0
- package/cockpit/index.html +14 -0
- package/community-postgres.json +13 -0
- package/migrations/agentspace/0000_thin_carlie_cooper.sql +764 -0
- package/migrations/agentspace/meta/0000_snapshot.json +6885 -0
- package/migrations/agentspace/meta/_journal.json +13 -0
- package/migrations/chatv3/0000_dry_ego.sql +218 -0
- package/migrations/chatv3/0001_nosy_obadiah_stane.sql +35 -0
- package/migrations/chatv3/0002_narrow_darkhawk.sql +4 -0
- package/migrations/chatv3/0003_damp_zarek.sql +2 -0
- package/migrations/chatv3/0004_nervous_martin_li.sql +60 -0
- package/migrations/chatv3/0005_chatv3_server_encrypted_mode.sql +1 -0
- package/migrations/chatv3/meta/0000_snapshot.json +1887 -0
- package/migrations/chatv3/meta/0001_snapshot.json +2175 -0
- package/migrations/chatv3/meta/0002_snapshot.json +2229 -0
- package/migrations/chatv3/meta/0003_snapshot.json +2241 -0
- package/migrations/chatv3/meta/0004_snapshot.json +2746 -0
- package/migrations/chatv3/meta/_journal.json +48 -0
- package/migrations/docman/0000_curvy_valeria_richards.sql +257 -0
- package/migrations/docman/0001_massive_risque.sql +2 -0
- package/migrations/docman/0002_simple_logan.sql +50 -0
- package/migrations/docman/0003_quick_index.sql +45 -0
- package/migrations/docman/0004_known_summary.sql +9 -0
- package/migrations/docman/0005_vector_signal.sql +9 -0
- package/migrations/docman/0006_document_version_current_invariant.sql +15 -0
- package/migrations/docman/meta/_journal.json +55 -0
- package/migrations/projectman/0000_smooth_klaw.sql +257 -0
- package/migrations/projectman/0001_worthless_zodiak.sql +9 -0
- package/migrations/projectman/0002_board_rename.sql +108 -0
- package/migrations/projectman/0003_review_request.sql +62 -0
- package/migrations/projectman/0004_review_request_idempotency.sql +3 -0
- package/migrations/projectman/0005_allow_multi_sprint_per_task.sql +1 -0
- package/migrations/projectman/meta/_journal.json +48 -0
- package/migrations/sys/0000_loose_praxagora.sql +31 -0
- package/migrations/sys/0001_awesome_ronan.sql +2 -0
- package/migrations/sys/0002_steady_maximus.sql +2 -0
- package/migrations/sys/0003_escalating_rate_limiter.sql +2 -0
- package/migrations/sys/0004_rate_limiter_timestamptz.sql +22 -0
- package/migrations/sys/0005_sys_counters.sql +21 -0
- package/migrations/sys/meta/_journal.json +48 -0
- package/npm-shrinkwrap.json +4375 -0
- package/package.json +62 -0
- package/runtime/agentspace-host-adapter.mjs +64 -0
- package/runtime/agentspace-tooling.mjs +389 -0
- package/runtime/docman-host-adapter.mjs +177 -0
- package/runtime/docman-policy.mjs +450 -0
- package/runtime/docman-tooling.mjs +20 -0
- package/runtime/projectman-host-adapter.mjs +597 -0
- package/runtime/scope-context.mjs +99 -0
- package/scripts/community-host.mjs +626 -0
- package/scripts/community-migration-policy-v1.json +296 -0
|
@@ -0,0 +1,597 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { createProjectmanPlugin as createBaseProjectmanPlugin } from '@aopslab/domain-host-plugin-projectman'
|
|
3
|
+
import {
|
|
4
|
+
clearProjectmanKitEnvConfigCache,
|
|
5
|
+
clearProjectmanKitOperationCaches,
|
|
6
|
+
runProjectmanKitOperationByTypedId,
|
|
7
|
+
} from '@aopslab/domain-kit-projectman'
|
|
8
|
+
import { runAgentspaceKitOperationByTypedId } from '@aopslab/domain-kit-agentspace'
|
|
9
|
+
import {
|
|
10
|
+
applyProjectmanRuntimeEnv,
|
|
11
|
+
resolveProjectmanRuntimeConfig,
|
|
12
|
+
} from '@aopslab/domain-runtime-config-projectman'
|
|
13
|
+
import { createAgentspaceScopeResolver, toNonEmptyString } from './scope-context.mjs'
|
|
14
|
+
|
|
15
|
+
const DEFAULT_RESUME_MEMORY_LIMIT = 8
|
|
16
|
+
const DEFAULT_RESUME_MEMORY_CANDIDATE_LIMIT = 48
|
|
17
|
+
const OPEN_ISSUE_STATUSES = new Set(['open', 'triaged', 'in_progress'])
|
|
18
|
+
const OPEN_FEEDBACK_STATUSES = new Set(['new', 'triaged', 'planned'])
|
|
19
|
+
let projectmanHostedRuntimeEnvReady = false
|
|
20
|
+
let projectmanHostedStorageReadyPromise = null
|
|
21
|
+
|
|
22
|
+
function assertProjectmanHostRuntimeStorage(runtime) {
|
|
23
|
+
if (runtime?.repoUrlSource === 'default-sqlite' || runtime?.repoDialect === 'sqlite') {
|
|
24
|
+
throw new Error(
|
|
25
|
+
'projectman_host_runtime_storage_unbound:Set PROJECTMAN_REPO_URL, PROJECTMAN_PG_URL, AOPS_REPO_URL, or AOPS_PG_URL to PostgreSQL before starting AOPS server.',
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function ensureProjectmanHostedRuntimeEnv(options = {}) {
|
|
31
|
+
if (projectmanHostedRuntimeEnvReady) return
|
|
32
|
+
|
|
33
|
+
clearProjectmanKitEnvConfigCache()
|
|
34
|
+
clearProjectmanKitOperationCaches()
|
|
35
|
+
|
|
36
|
+
const repoUrlOverride =
|
|
37
|
+
toNonEmptyString(process.env.PROJECTMAN_REPO_URL) ??
|
|
38
|
+
toNonEmptyString(process.env.PROJECTMAN_SQLITE_URL) ??
|
|
39
|
+
toNonEmptyString(process.env.PROJECTMAN_PG_URL) ??
|
|
40
|
+
toNonEmptyString(process.env.AOPS_REPO_URL) ??
|
|
41
|
+
toNonEmptyString(process.env.AOPS_SQLITE_URL) ??
|
|
42
|
+
toNonEmptyString(process.env.AOPS_PG_URL)
|
|
43
|
+
|
|
44
|
+
const runtime = resolveProjectmanRuntimeConfig(
|
|
45
|
+
{
|
|
46
|
+
repoUrl: repoUrlOverride,
|
|
47
|
+
projectId: options.defaultProjectId,
|
|
48
|
+
},
|
|
49
|
+
process.env,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
assertProjectmanHostRuntimeStorage(runtime)
|
|
53
|
+
|
|
54
|
+
applyProjectmanRuntimeEnv(
|
|
55
|
+
{
|
|
56
|
+
runtimeMode: runtime.runtimeMode,
|
|
57
|
+
repoUrl: runtime.repoUrl,
|
|
58
|
+
repoDialect: runtime.repoDialect,
|
|
59
|
+
projectId: runtime.projectId,
|
|
60
|
+
},
|
|
61
|
+
process.env,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
clearProjectmanKitEnvConfigCache()
|
|
65
|
+
clearProjectmanKitOperationCaches()
|
|
66
|
+
if (process.env.AOPS_DB_BOOTSTRAP_MODE !== 'explicit') {
|
|
67
|
+
throw new Error('community_strict_bootstrap_mode_required');
|
|
68
|
+
}
|
|
69
|
+
projectmanHostedStorageReadyPromise = Promise.resolve();
|
|
70
|
+
projectmanHostedRuntimeEnvReady = true
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function ensureProjectmanHostedStorageReady() {
|
|
74
|
+
if (projectmanHostedStorageReadyPromise) {
|
|
75
|
+
await projectmanHostedStorageReadyPromise
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function toStringArray(values) {
|
|
80
|
+
if (!Array.isArray(values)) return []
|
|
81
|
+
return values.map((item) => String(item ?? '').trim()).filter(Boolean)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function toArray(value) {
|
|
85
|
+
return Array.isArray(value) ? value : []
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function compactRecord(value) {
|
|
89
|
+
return Object.fromEntries(Object.entries(toRecord(value)).filter(([, item]) => item !== undefined))
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function uniqueStrings(values) {
|
|
93
|
+
const seen = new Set()
|
|
94
|
+
const result = []
|
|
95
|
+
for (const value of values) {
|
|
96
|
+
const normalized = toNonEmptyString(value)
|
|
97
|
+
if (!normalized || seen.has(normalized)) continue
|
|
98
|
+
seen.add(normalized)
|
|
99
|
+
result.push(normalized)
|
|
100
|
+
}
|
|
101
|
+
return result
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function toRecord(value) {
|
|
105
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return {}
|
|
106
|
+
return value
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const projectmanScopeResolver = createAgentspaceScopeResolver({
|
|
110
|
+
runAgentspaceOperation: runAgentspaceKitOperationByTypedId,
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
async function resolveProjectOwnerContext(projectId) {
|
|
114
|
+
const owner = await projectmanScopeResolver.resolveProjectContext(projectId)
|
|
115
|
+
if (owner.scopeId) return owner
|
|
116
|
+
const safeProjectId = toNonEmptyString(projectId)
|
|
117
|
+
return {
|
|
118
|
+
...owner,
|
|
119
|
+
projectId: owner.projectId ?? safeProjectId,
|
|
120
|
+
scopeId: owner.scopeId ?? safeProjectId,
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function toImportance(value) {
|
|
125
|
+
if (typeof value === 'number' && Number.isFinite(value)) return value
|
|
126
|
+
if (typeof value === 'string' && value.trim()) {
|
|
127
|
+
const parsed = Number(value)
|
|
128
|
+
if (Number.isFinite(parsed)) return parsed
|
|
129
|
+
}
|
|
130
|
+
return undefined
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function unwrapData(value) {
|
|
134
|
+
const record = toRecord(value)
|
|
135
|
+
if (Object.prototype.hasOwnProperty.call(record, 'data')) {
|
|
136
|
+
return record.data
|
|
137
|
+
}
|
|
138
|
+
return value
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function toResultArray(value) {
|
|
142
|
+
const data = unwrapData(value)
|
|
143
|
+
if (Array.isArray(data)) return data
|
|
144
|
+
const record = toRecord(data)
|
|
145
|
+
if (Array.isArray(record.items)) return record.items
|
|
146
|
+
return []
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function isNotCompletedMicrotask(item) {
|
|
150
|
+
const status = toNonEmptyString(item?.status)?.toLowerCase()
|
|
151
|
+
return status !== 'completed' && status !== 'cancelled'
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function isActiveSprint(item) {
|
|
155
|
+
const status = toNonEmptyString(item?.status)?.toLowerCase()
|
|
156
|
+
return status !== 'completed' && status !== 'cancelled'
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function isOpenIssue(item) {
|
|
160
|
+
const status = toNonEmptyString(item?.status)?.toLowerCase()
|
|
161
|
+
return !!status && OPEN_ISSUE_STATUSES.has(status)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function isOpenFeedback(item) {
|
|
165
|
+
const status = toNonEmptyString(item?.status)?.toLowerCase()
|
|
166
|
+
return !!status && OPEN_FEEDBACK_STATUSES.has(status)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function pickPrimaryResumeMicrotask(items) {
|
|
170
|
+
const rows = toArray(items)
|
|
171
|
+
return (
|
|
172
|
+
rows.find((item) => toNonEmptyString(item?.status)?.toLowerCase() === 'doing') ??
|
|
173
|
+
rows.find((item) => toNonEmptyString(item?.status)?.toLowerCase() === 'blocked') ??
|
|
174
|
+
rows.find((item) => toNonEmptyString(item?.id)) ??
|
|
175
|
+
null
|
|
176
|
+
)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function pickPrimaryEntity(items) {
|
|
180
|
+
return toArray(items).find((item) => toNonEmptyString(item?.id)) ?? null
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function buildResumeSubject(type, id, label) {
|
|
184
|
+
const subject = compactRecord({
|
|
185
|
+
type: toNonEmptyString(type),
|
|
186
|
+
id: toNonEmptyString(id),
|
|
187
|
+
label: toNonEmptyString(label),
|
|
188
|
+
})
|
|
189
|
+
return Object.keys(subject).length > 0 ? subject : undefined
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function appendSourceReference(sourceTypes, sourceIds, type, id) {
|
|
193
|
+
const safeType = toNonEmptyString(type)
|
|
194
|
+
const safeId = toNonEmptyString(id)
|
|
195
|
+
if (!safeType || !safeId) return
|
|
196
|
+
sourceTypes.push(safeType)
|
|
197
|
+
sourceIds.push(safeId)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function appendMicrotaskLineageSourceRefs(sourceTypes, sourceIds, microtask, options = {}) {
|
|
201
|
+
appendSourceReference(sourceTypes, sourceIds, 'projectman.microtask', microtask?.id)
|
|
202
|
+
if (options.includeSprint !== false) {
|
|
203
|
+
appendSourceReference(sourceTypes, sourceIds, 'projectman.sprint', microtask?.sprintId)
|
|
204
|
+
}
|
|
205
|
+
appendSourceReference(sourceTypes, sourceIds, 'projectman.kanban-task', microtask?.kanbanTaskId)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function buildProjectmanMemoryTags({ baseTags = [], projectId, sprintId, phaseId, kanbanTaskId, microtaskId }) {
|
|
209
|
+
return uniqueStrings([
|
|
210
|
+
...toStringArray(baseTags),
|
|
211
|
+
projectId ? `project:${projectId}` : undefined,
|
|
212
|
+
sprintId ? `sprint:${sprintId}` : undefined,
|
|
213
|
+
phaseId ? `phase:${phaseId}` : undefined,
|
|
214
|
+
kanbanTaskId ? `kanban-task:${kanbanTaskId}` : undefined,
|
|
215
|
+
microtaskId ? `microtask:${microtaskId}` : undefined,
|
|
216
|
+
])
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function buildProjectmanMemoryMeta({
|
|
220
|
+
projectId,
|
|
221
|
+
subjectType,
|
|
222
|
+
subjectId,
|
|
223
|
+
subjectTitle,
|
|
224
|
+
sprintId,
|
|
225
|
+
phaseId,
|
|
226
|
+
kanbanTaskId,
|
|
227
|
+
microtaskId,
|
|
228
|
+
nextAction,
|
|
229
|
+
nextReadRefs,
|
|
230
|
+
validationState,
|
|
231
|
+
sourceRefs,
|
|
232
|
+
extra,
|
|
233
|
+
}) {
|
|
234
|
+
return compactRecord({
|
|
235
|
+
projectId: toNonEmptyString(projectId),
|
|
236
|
+
subjectType: toNonEmptyString(subjectType),
|
|
237
|
+
subjectId: toNonEmptyString(subjectId),
|
|
238
|
+
subjectTitle: toNonEmptyString(subjectTitle),
|
|
239
|
+
sprintId: toNonEmptyString(sprintId),
|
|
240
|
+
phaseId: toNonEmptyString(phaseId),
|
|
241
|
+
kanbanTaskId: toNonEmptyString(kanbanTaskId),
|
|
242
|
+
microtaskId: toNonEmptyString(microtaskId),
|
|
243
|
+
nextAction: toNonEmptyString(nextAction),
|
|
244
|
+
nextReadRefs: toArray(nextReadRefs),
|
|
245
|
+
validationState: toNonEmptyString(validationState),
|
|
246
|
+
sourceRefs: toArray(sourceRefs),
|
|
247
|
+
synchronizedAt: new Date().toISOString(),
|
|
248
|
+
...compactRecord(toRecord(extra)),
|
|
249
|
+
})
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function buildProjectmanResumeMemoryRetrieval({ activeSprints, incompleteMicrotasks, openIssues, openFeedback }) {
|
|
253
|
+
const primaryMicrotask = pickPrimaryResumeMicrotask(incompleteMicrotasks)
|
|
254
|
+
const primarySprint = pickPrimaryEntity(activeSprints)
|
|
255
|
+
const primaryIssue = pickPrimaryEntity(openIssues)
|
|
256
|
+
const primaryFeedback = pickPrimaryEntity(openFeedback)
|
|
257
|
+
|
|
258
|
+
let query = 'resume project context'
|
|
259
|
+
let runtimeProfile = 'planning'
|
|
260
|
+
let subject
|
|
261
|
+
|
|
262
|
+
const sourceTypes = []
|
|
263
|
+
const sourceIds = []
|
|
264
|
+
|
|
265
|
+
if (primaryMicrotask) {
|
|
266
|
+
query = 'resume implementation handoff'
|
|
267
|
+
runtimeProfile = 'implementation'
|
|
268
|
+
subject = buildResumeSubject('projectman.microtask', primaryMicrotask.id, primaryMicrotask.title)
|
|
269
|
+
appendMicrotaskLineageSourceRefs(sourceTypes, sourceIds, primaryMicrotask)
|
|
270
|
+
} else if (primarySprint) {
|
|
271
|
+
query = 'resume active sprint context'
|
|
272
|
+
runtimeProfile = 'planning'
|
|
273
|
+
subject = buildResumeSubject('projectman.sprint', primarySprint.id, primarySprint.name)
|
|
274
|
+
appendSourceReference(sourceTypes, sourceIds, 'projectman.sprint', primarySprint.id)
|
|
275
|
+
} else if (primaryIssue) {
|
|
276
|
+
query = 'resume open issue context'
|
|
277
|
+
runtimeProfile = 'investigation'
|
|
278
|
+
subject = buildResumeSubject('projectman.issue', primaryIssue.id, primaryIssue.title)
|
|
279
|
+
appendSourceReference(sourceTypes, sourceIds, 'projectman.issue', primaryIssue.id)
|
|
280
|
+
} else if (primaryFeedback) {
|
|
281
|
+
query = 'resume feedback triage context'
|
|
282
|
+
runtimeProfile = 'feedback-triage'
|
|
283
|
+
subject = buildResumeSubject('projectman.feedback', primaryFeedback.id, primaryFeedback.title)
|
|
284
|
+
appendSourceReference(sourceTypes, sourceIds, 'projectman.feedback', primaryFeedback.id)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (primarySprint && !sourceIds.includes(primarySprint.id)) {
|
|
288
|
+
appendSourceReference(sourceTypes, sourceIds, 'projectman.sprint', primarySprint.id)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return compactRecord({
|
|
292
|
+
query,
|
|
293
|
+
runtimeProfile,
|
|
294
|
+
subject,
|
|
295
|
+
tags: uniqueStrings([
|
|
296
|
+
'phase:memory',
|
|
297
|
+
primaryMicrotask ? 'resume:implementation' : undefined,
|
|
298
|
+
primarySprint ? 'resume:sprint' : undefined,
|
|
299
|
+
primaryIssue ? 'resume:issue' : undefined,
|
|
300
|
+
primaryFeedback ? 'resume:feedback' : undefined,
|
|
301
|
+
]),
|
|
302
|
+
sourceTypes: uniqueStrings(sourceTypes),
|
|
303
|
+
sourceIds: uniqueStrings(sourceIds),
|
|
304
|
+
candidateLimit: DEFAULT_RESUME_MEMORY_CANDIDATE_LIMIT,
|
|
305
|
+
})
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function shouldWritebackOnSprintCompletion(operationId, input, output) {
|
|
309
|
+
if (operationId !== 'sprint.update') return false
|
|
310
|
+
const requestedStatus = toNonEmptyString(input?.status)?.toLowerCase()
|
|
311
|
+
if (requestedStatus !== 'completed') return false
|
|
312
|
+
const updatedStatus = toNonEmptyString(output?.status)?.toLowerCase()
|
|
313
|
+
return updatedStatus === 'completed'
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function shouldWritebackOnMicrotaskCompletion(operationId, input, output) {
|
|
317
|
+
if (operationId !== 'microtask.update') return false
|
|
318
|
+
const requestedStatus = toNonEmptyString(input?.status)?.toLowerCase()
|
|
319
|
+
if (requestedStatus !== 'completed') return false
|
|
320
|
+
const updatedStatus = toNonEmptyString(output?.status)?.toLowerCase()
|
|
321
|
+
return updatedStatus === 'completed'
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function buildMemoryContent(sprint) {
|
|
325
|
+
const sprintName = toNonEmptyString(sprint?.name) ?? 'Unnamed sprint'
|
|
326
|
+
const sprintGoal = toNonEmptyString(sprint?.goal) ?? 'No goal'
|
|
327
|
+
const endedAt = toNonEmptyString(sprint?.endAt)
|
|
328
|
+
if (endedAt) {
|
|
329
|
+
return `Sprint "${sprintName}" completed. Goal: ${sprintGoal}. End date: ${endedAt}.`
|
|
330
|
+
}
|
|
331
|
+
return `Sprint "${sprintName}" completed. Goal: ${sprintGoal}.`
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function buildSummaryText(sprint) {
|
|
335
|
+
const sprintName = toNonEmptyString(sprint?.name) ?? 'Unnamed sprint'
|
|
336
|
+
const sprintGoal = toNonEmptyString(sprint?.goal) ?? 'No goal'
|
|
337
|
+
return `Latest completed sprint: ${sprintName}. Goal: ${sprintGoal}.`
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function ensureTrailingSentence(value) {
|
|
341
|
+
const normalized = toNonEmptyString(value)
|
|
342
|
+
if (!normalized) return undefined
|
|
343
|
+
return /[.!?]$/.test(normalized) ? normalized : `${normalized}.`
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function buildMicrotaskMemoryContent(microtask) {
|
|
347
|
+
const microtaskTitle = toNonEmptyString(microtask?.title) ?? 'Unnamed microtask'
|
|
348
|
+
const notes = toNonEmptyString(microtask?.notes)
|
|
349
|
+
const closedAt = toNonEmptyString(microtask?.closedAt)
|
|
350
|
+
const parts = [`Microtask "${microtaskTitle}" completed.`]
|
|
351
|
+
const noteSentence = ensureTrailingSentence(notes)
|
|
352
|
+
if (noteSentence) parts.push(`Notes: ${noteSentence}`)
|
|
353
|
+
if (closedAt) parts.push(`Closed at: ${closedAt}.`)
|
|
354
|
+
return parts.join(' ')
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
async function listIncompleteMicrotasksForActiveSprints(projectId, activeSprints) {
|
|
358
|
+
return toArray(activeSprints).flatMap((sprint) => {
|
|
359
|
+
const sprintId = toNonEmptyString(sprint?.id)
|
|
360
|
+
return toArray(sprint?.phases).flatMap((phase) =>
|
|
361
|
+
toArray(phase?.microtasks)
|
|
362
|
+
.filter(isNotCompletedMicrotask)
|
|
363
|
+
.map((microtask) => ({
|
|
364
|
+
...toRecord(microtask),
|
|
365
|
+
sprintId: toNonEmptyString(microtask?.sprintId) || sprintId,
|
|
366
|
+
phaseId: toNonEmptyString(microtask?.phaseId) || toNonEmptyString(phase?.id),
|
|
367
|
+
kanbanTaskId: toNonEmptyString(microtask?.kanbanTaskId) || toNonEmptyString(sprint?.kanbanTaskId),
|
|
368
|
+
})),
|
|
369
|
+
)
|
|
370
|
+
})
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export async function buildProjectmanResumeContextPack({ projectId }) {
|
|
374
|
+
const safeProjectId = toNonEmptyString(projectId)
|
|
375
|
+
if (!safeProjectId) {
|
|
376
|
+
throw new Error('missing_project_id_for_resume_context_pack')
|
|
377
|
+
}
|
|
378
|
+
const ownerContext = await resolveProjectOwnerContext(safeProjectId)
|
|
379
|
+
const ownerScopeId = toNonEmptyString(ownerContext.scopeId) ?? safeProjectId
|
|
380
|
+
|
|
381
|
+
const [activeSprintsRaw, issueItemsRaw, feedbackItemsRaw] = await Promise.all([
|
|
382
|
+
runProjectmanKitOperationByTypedId('sprint.list', {
|
|
383
|
+
scopeId: ownerScopeId,
|
|
384
|
+
}),
|
|
385
|
+
runProjectmanKitOperationByTypedId('issue.list', {
|
|
386
|
+
scopeId: ownerScopeId,
|
|
387
|
+
}),
|
|
388
|
+
runProjectmanKitOperationByTypedId('feedback.list', {
|
|
389
|
+
scopeId: ownerScopeId,
|
|
390
|
+
}),
|
|
391
|
+
])
|
|
392
|
+
|
|
393
|
+
const activeSprints = toArray(activeSprintsRaw).filter(isActiveSprint)
|
|
394
|
+
const incompleteMicrotasks = await listIncompleteMicrotasksForActiveSprints(safeProjectId, activeSprints)
|
|
395
|
+
const openIssues = toArray(issueItemsRaw).filter(isOpenIssue)
|
|
396
|
+
const openFeedback = toArray(feedbackItemsRaw).filter(isOpenFeedback)
|
|
397
|
+
const resumePack = toRecord(
|
|
398
|
+
unwrapData(
|
|
399
|
+
await runAgentspaceKitOperationByTypedId('memory-item.build-resume-pack', {
|
|
400
|
+
filter: { scopeId: ownerScopeId, scopeResolution: 'cascade', projectId: safeProjectId },
|
|
401
|
+
retrieval: buildProjectmanResumeMemoryRetrieval({
|
|
402
|
+
activeSprints,
|
|
403
|
+
incompleteMicrotasks,
|
|
404
|
+
openIssues,
|
|
405
|
+
openFeedback,
|
|
406
|
+
}),
|
|
407
|
+
options: { depth: 'light', limit: DEFAULT_RESUME_MEMORY_LIMIT },
|
|
408
|
+
})
|
|
409
|
+
)
|
|
410
|
+
)
|
|
411
|
+
const memoryItems = toResultArray(resumePack.relatedMemory).slice(0, DEFAULT_RESUME_MEMORY_LIMIT)
|
|
412
|
+
const synopsis = toRecord(resumePack.synopsis)
|
|
413
|
+
const bootstrapGuidance = uniqueStrings(toArray(resumePack.bootstrapGuidance)).slice(0, 3)
|
|
414
|
+
|
|
415
|
+
return {
|
|
416
|
+
generatedAt: new Date().toISOString(),
|
|
417
|
+
projectId: safeProjectId,
|
|
418
|
+
synopsis: Object.keys(synopsis).length > 0 ? synopsis : null,
|
|
419
|
+
bootstrapGuidance,
|
|
420
|
+
resumePack: Object.keys(resumePack).length > 0 ? resumePack : null,
|
|
421
|
+
memoryItems,
|
|
422
|
+
activeSprints,
|
|
423
|
+
incompleteMicrotasks,
|
|
424
|
+
openIssues,
|
|
425
|
+
openFeedback,
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
async function writebackSprintCompletionToAops(sprint) {
|
|
430
|
+
const projectId = toNonEmptyString(sprint?.projectId)
|
|
431
|
+
const ownerContext = await resolveProjectOwnerContext(projectId)
|
|
432
|
+
const scopeId = toNonEmptyString(ownerContext.scopeId) ?? projectId
|
|
433
|
+
const sprintId = toNonEmptyString(sprint?.id)
|
|
434
|
+
if (!projectId || !scopeId || !sprintId) return
|
|
435
|
+
|
|
436
|
+
const tags = buildProjectmanMemoryTags({
|
|
437
|
+
baseTags: [
|
|
438
|
+
'phase:memory',
|
|
439
|
+
'phase:closeout',
|
|
440
|
+
'source:projectman',
|
|
441
|
+
...toStringArray(sprint?.tags).map((tag) => `sprint-tag:${tag}`),
|
|
442
|
+
],
|
|
443
|
+
projectId,
|
|
444
|
+
sprintId,
|
|
445
|
+
})
|
|
446
|
+
|
|
447
|
+
await runAgentspaceKitOperationByTypedId('memory-item.add-memory-item', {
|
|
448
|
+
data: {
|
|
449
|
+
scopeId,
|
|
450
|
+
kind: 'closeout',
|
|
451
|
+
durability: 'short',
|
|
452
|
+
content: buildMemoryContent(sprint),
|
|
453
|
+
tags,
|
|
454
|
+
importance: 70,
|
|
455
|
+
sourceType: 'projectman.sprint',
|
|
456
|
+
sourceId: sprintId,
|
|
457
|
+
meta: buildProjectmanMemoryMeta({
|
|
458
|
+
projectId,
|
|
459
|
+
subjectType: 'projectman.sprint',
|
|
460
|
+
subjectId: sprintId,
|
|
461
|
+
subjectTitle: sprint?.name,
|
|
462
|
+
sprintId,
|
|
463
|
+
validationState: toNonEmptyString(sprint?.status),
|
|
464
|
+
extra: {
|
|
465
|
+
sprintName: toNonEmptyString(sprint?.name),
|
|
466
|
+
sprintGoal: toNonEmptyString(sprint?.goal),
|
|
467
|
+
sprintStatus: toNonEmptyString(sprint?.status),
|
|
468
|
+
},
|
|
469
|
+
}),
|
|
470
|
+
},
|
|
471
|
+
})
|
|
472
|
+
|
|
473
|
+
const resumeContextPack = await buildProjectmanResumeContextPack({ projectId })
|
|
474
|
+
const openItems = [
|
|
475
|
+
`Active sprints: ${resumeContextPack.activeSprints.length}`,
|
|
476
|
+
`Incomplete microtasks: ${resumeContextPack.incompleteMicrotasks.length}`,
|
|
477
|
+
`Open issues: ${resumeContextPack.openIssues.length}`,
|
|
478
|
+
`Open feedback: ${resumeContextPack.openFeedback.length}`,
|
|
479
|
+
]
|
|
480
|
+
if (openItems.length > 0) {
|
|
481
|
+
await runAgentspaceKitOperationByTypedId('memory-item.add-memory-item', {
|
|
482
|
+
data: {
|
|
483
|
+
scopeId,
|
|
484
|
+
kind: 'note',
|
|
485
|
+
durability: 'durable',
|
|
486
|
+
content: `${buildSummaryText(sprint)} ${openItems.join('. ')}.`,
|
|
487
|
+
tags: buildProjectmanMemoryTags({
|
|
488
|
+
baseTags: ['phase:memory', 'phase:note', 'source:projectman'],
|
|
489
|
+
projectId,
|
|
490
|
+
sprintId,
|
|
491
|
+
}),
|
|
492
|
+
importance: 50,
|
|
493
|
+
sourceType: 'projectman.sprint',
|
|
494
|
+
sourceId: sprintId,
|
|
495
|
+
meta: buildProjectmanMemoryMeta({
|
|
496
|
+
projectId,
|
|
497
|
+
subjectType: 'projectman.sprint',
|
|
498
|
+
subjectId: sprintId,
|
|
499
|
+
subjectTitle: sprint?.name,
|
|
500
|
+
sprintId,
|
|
501
|
+
extra: { openItems },
|
|
502
|
+
}),
|
|
503
|
+
},
|
|
504
|
+
})
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
async function writebackMicrotaskCompletionToAops(microtask) {
|
|
509
|
+
const projectId = toNonEmptyString(microtask?.projectId)
|
|
510
|
+
const ownerContext = await resolveProjectOwnerContext(projectId)
|
|
511
|
+
const scopeId = toNonEmptyString(ownerContext.scopeId) ?? projectId
|
|
512
|
+
const microtaskId = toNonEmptyString(microtask?.id)
|
|
513
|
+
if (!projectId || !scopeId || !microtaskId) return
|
|
514
|
+
|
|
515
|
+
const sprintId = toNonEmptyString(microtask?.sprintId)
|
|
516
|
+
const phaseId = toNonEmptyString(microtask?.phaseId)
|
|
517
|
+
const kanbanTaskId = toNonEmptyString(microtask?.kanbanTaskId)
|
|
518
|
+
|
|
519
|
+
await runAgentspaceKitOperationByTypedId('memory-item.add-memory-item', {
|
|
520
|
+
data: {
|
|
521
|
+
scopeId,
|
|
522
|
+
kind: 'note',
|
|
523
|
+
content: buildMicrotaskMemoryContent(microtask),
|
|
524
|
+
tags: buildProjectmanMemoryTags({
|
|
525
|
+
baseTags: ['phase:memory', 'phase:closeout', 'source:projectman'],
|
|
526
|
+
projectId,
|
|
527
|
+
sprintId,
|
|
528
|
+
phaseId,
|
|
529
|
+
kanbanTaskId,
|
|
530
|
+
microtaskId,
|
|
531
|
+
}),
|
|
532
|
+
durability: 'short',
|
|
533
|
+
importance: 60,
|
|
534
|
+
sourceType: 'projectman.microtask',
|
|
535
|
+
sourceId: microtaskId,
|
|
536
|
+
meta: buildProjectmanMemoryMeta({
|
|
537
|
+
projectId,
|
|
538
|
+
subjectType: 'projectman.microtask',
|
|
539
|
+
subjectId: microtaskId,
|
|
540
|
+
subjectTitle: microtask?.title,
|
|
541
|
+
sprintId,
|
|
542
|
+
phaseId,
|
|
543
|
+
kanbanTaskId,
|
|
544
|
+
microtaskId,
|
|
545
|
+
validationState: toNonEmptyString(microtask?.status),
|
|
546
|
+
extra: {
|
|
547
|
+
microtaskStatus: toNonEmptyString(microtask?.status),
|
|
548
|
+
notes: toNonEmptyString(microtask?.notes),
|
|
549
|
+
closedAt: toNonEmptyString(microtask?.closedAt),
|
|
550
|
+
},
|
|
551
|
+
}),
|
|
552
|
+
},
|
|
553
|
+
})
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
export function createProjectmanPlugin(options = {}) {
|
|
557
|
+
ensureProjectmanHostedRuntimeEnv(options)
|
|
558
|
+
|
|
559
|
+
const projectmanRunner =
|
|
560
|
+
typeof options.runner === 'function'
|
|
561
|
+
? options.runner
|
|
562
|
+
: (operationId, input) => runProjectmanKitOperationByTypedId(operationId, input)
|
|
563
|
+
|
|
564
|
+
const enableAopsWriteback = options.enableAopsWriteback !== false
|
|
565
|
+
const failOnWritebackError = options.failOnWritebackError === true
|
|
566
|
+
|
|
567
|
+
const wrappedRunner = async (operationId, input) => {
|
|
568
|
+
await ensureProjectmanHostedStorageReady()
|
|
569
|
+
const output = await projectmanRunner(operationId, input)
|
|
570
|
+
|
|
571
|
+
if (enableAopsWriteback) {
|
|
572
|
+
try {
|
|
573
|
+
if (shouldWritebackOnSprintCompletion(operationId, input, output)) {
|
|
574
|
+
await writebackSprintCompletionToAops(output)
|
|
575
|
+
}
|
|
576
|
+
if (shouldWritebackOnMicrotaskCompletion(operationId, input, output)) {
|
|
577
|
+
await writebackMicrotaskCompletionToAops(output)
|
|
578
|
+
}
|
|
579
|
+
} catch (error) {
|
|
580
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
581
|
+
console.warn('[projectman-host-adapter] aops writeback failed', {
|
|
582
|
+
operationId,
|
|
583
|
+
message,
|
|
584
|
+
})
|
|
585
|
+
if (failOnWritebackError) throw error
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
return output
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
return createBaseProjectmanPlugin({
|
|
594
|
+
defaultProjectId: options.defaultProjectId,
|
|
595
|
+
runner: wrappedRunner,
|
|
596
|
+
})
|
|
597
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
export function toNonEmptyString(value) {
|
|
3
|
+
if (typeof value !== 'string') return undefined
|
|
4
|
+
const trimmed = value.trim()
|
|
5
|
+
return trimmed.length > 0 ? trimmed : undefined
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function toRecord(value) {
|
|
9
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return {}
|
|
10
|
+
return value
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function unwrapData(value) {
|
|
14
|
+
const record = toRecord(value)
|
|
15
|
+
if (Object.prototype.hasOwnProperty.call(record, 'data')) {
|
|
16
|
+
return record.data
|
|
17
|
+
}
|
|
18
|
+
return value
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function normalizeScopeResolution(value) {
|
|
22
|
+
return value === 'cascade' || value === 'explicit' ? value : undefined
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function createAgentspaceScopeResolver(params) {
|
|
26
|
+
const projectCache = new Map()
|
|
27
|
+
const runAgentspaceOperation = params.runAgentspaceOperation
|
|
28
|
+
const normalizeScopeId = params.normalizeScopeId ?? toNonEmptyString
|
|
29
|
+
|
|
30
|
+
async function resolveProjectContext(projectId) {
|
|
31
|
+
const normalizedProjectId = toNonEmptyString(projectId)
|
|
32
|
+
if (!normalizedProjectId) {
|
|
33
|
+
return {
|
|
34
|
+
projectId: undefined,
|
|
35
|
+
scopeId: undefined,
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (projectCache.has(normalizedProjectId)) {
|
|
40
|
+
return projectCache.get(normalizedProjectId)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const projectRecord = toRecord(
|
|
44
|
+
unwrapData(
|
|
45
|
+
await runAgentspaceOperation('project.get-by-id', {
|
|
46
|
+
id: normalizedProjectId,
|
|
47
|
+
}).catch(() => null),
|
|
48
|
+
),
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
const context = {
|
|
52
|
+
projectId: normalizedProjectId,
|
|
53
|
+
scopeId: normalizeScopeId(projectRecord.scopeId) ?? toNonEmptyString(projectRecord.id) ?? normalizedProjectId,
|
|
54
|
+
}
|
|
55
|
+
projectCache.set(normalizedProjectId, context)
|
|
56
|
+
return context
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function resolveRequestScope(requestContext = {}, options = {}) {
|
|
60
|
+
const explicitScopeId = normalizeScopeId(requestContext.scopeId)
|
|
61
|
+
const scopeResolution = normalizeScopeResolution(requestContext.scopeResolution)
|
|
62
|
+
|
|
63
|
+
if (explicitScopeId) {
|
|
64
|
+
return {
|
|
65
|
+
projectId: toNonEmptyString(requestContext.projectId),
|
|
66
|
+
scopeId: explicitScopeId,
|
|
67
|
+
scopeResolution,
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const projectContext = await resolveProjectContext(requestContext.projectId)
|
|
72
|
+
if (projectContext.scopeId) {
|
|
73
|
+
return {
|
|
74
|
+
projectId: projectContext.projectId,
|
|
75
|
+
scopeId: projectContext.scopeId,
|
|
76
|
+
scopeResolution,
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const defaultProjectId = toNonEmptyString(options.defaultProjectId)
|
|
81
|
+
const defaultScopeId = normalizeScopeId(options.defaultScopeId)
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
projectId: defaultProjectId ?? projectContext.projectId,
|
|
85
|
+
scopeId: defaultScopeId ?? defaultProjectId ?? projectContext.scopeId,
|
|
86
|
+
scopeResolution,
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function clearCaches() {
|
|
91
|
+
projectCache.clear()
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
resolveProjectContext,
|
|
96
|
+
resolveRequestScope,
|
|
97
|
+
clearCaches,
|
|
98
|
+
}
|
|
99
|
+
}
|