( currentDraft: string, input: AppendLocalMemoryProposalInput, )
| 365 | } |
| 366 | |
| 367 | export function appendLocalMemoryProposalDraft( |
| 368 | currentDraft: string, |
| 369 | input: AppendLocalMemoryProposalInput, |
| 370 | ): AppendLocalMemoryProposalResult { |
| 371 | const proposalId = normalizeId(input.proposalId, 'proposal-'); |
| 372 | if (!proposalId) return { ok: false, reason: 'invalid_id' }; |
| 373 | |
| 374 | const title = normalizeManualEntryTitle(input.title); |
| 375 | if (!title) return { ok: false, reason: 'empty_title' }; |
| 376 | |
| 377 | const content = input.content.trim(); |
| 378 | if (!content) return { ok: false, reason: 'empty_content' }; |
| 379 | |
| 380 | const proposedAt = normalizeTimestamp(input.proposedAt); |
| 381 | const tags = normalizeManualEntryTags(input.tags ?? []); |
| 382 | const scope = input.scope === 'session' ? 'session' : 'workspace'; |
| 383 | const sessionId = normalizeScopedSessionId(scope, input.sessionId); |
| 384 | if (sessionId === null) return { ok: false, reason: 'invalid_session_id' }; |
| 385 | const meta = [ |
| 386 | `id=${proposalId}`, |
| 387 | `proposalId=${proposalId}`, |
| 388 | 'origin=extracted', |
| 389 | 'source=chat_extracted', |
| 390 | `proposedAt=${proposedAt}`, |
| 391 | 'status=review_required', |
| 392 | `scope=${scope}`, |
| 393 | ...(sessionId ? [`sessionId=${sessionId}`] : []), |
| 394 | ...(input.sourceTurnId ? [`sourceTurnId=${normalizeMetaValue(input.sourceTurnId)}`] : []), |
| 395 | ...(tags.length > 0 ? [`tags=${tags.join(',')}`] : []), |
| 396 | ].join(' '); |
| 397 | return appendEntrySection(currentDraft, title, meta, content); |
| 398 | } |
| 399 | |
| 400 | export function stableLocalMemoryIdMaterial( |
| 401 | content: string, |
no test coverage detected