@ddtcorex/dsh-maestro-memory 1.0.1
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/CHANGELOG.md +96 -0
- package/LICENSE +21 -0
- package/README.md +448 -0
- package/cordis.patch.yml +13 -0
- package/lib/client.js +756 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +627 -0
- package/lib/index.js.map +1 -0
- package/lib/memory/batch.d.ts +44 -0
- package/lib/memory/batch.d.ts.map +1 -0
- package/lib/memory/batch.js +75 -0
- package/lib/memory/batch.js.map +1 -0
- package/lib/memory/feedback.d.ts +18 -0
- package/lib/memory/feedback.d.ts.map +1 -0
- package/lib/memory/feedback.js +29 -0
- package/lib/memory/feedback.js.map +1 -0
- package/lib/memory/store.d.ts +154 -0
- package/lib/memory/store.d.ts.map +1 -0
- package/lib/memory/store.js +606 -0
- package/lib/memory/store.js.map +1 -0
- package/lib/migration/cli.d.ts +18 -0
- package/lib/migration/cli.d.ts.map +1 -0
- package/lib/migration/cli.js +143 -0
- package/lib/migration/cli.js.map +1 -0
- package/lib/migration/fixture.d.ts +45 -0
- package/lib/migration/fixture.d.ts.map +1 -0
- package/lib/migration/fixture.js +177 -0
- package/lib/migration/fixture.js.map +1 -0
- package/lib/migration/service.d.ts +75 -0
- package/lib/migration/service.d.ts.map +1 -0
- package/lib/migration/service.js +713 -0
- package/lib/migration/service.js.map +1 -0
- package/lib/prompt/snapshot.d.ts +26 -0
- package/lib/prompt/snapshot.d.ts.map +1 -0
- package/lib/prompt/snapshot.js +74 -0
- package/lib/prompt/snapshot.js.map +1 -0
- package/lib/review/queue.d.ts +72 -0
- package/lib/review/queue.d.ts.map +1 -0
- package/lib/review/queue.js +306 -0
- package/lib/review/queue.js.map +1 -0
- package/lib/skills-browser.d.ts +67 -0
- package/lib/skills-browser.d.ts.map +1 -0
- package/lib/skills-browser.js +185 -0
- package/lib/skills-browser.js.map +1 -0
- package/lib/storage/atomic-store.d.ts +211 -0
- package/lib/storage/atomic-store.d.ts.map +1 -0
- package/lib/storage/atomic-store.js +582 -0
- package/lib/storage/atomic-store.js.map +1 -0
- package/lib/storage/layout.d.ts +81 -0
- package/lib/storage/layout.d.ts.map +1 -0
- package/lib/storage/layout.js +162 -0
- package/lib/storage/layout.js.map +1 -0
- package/lib/storage/legacy-format.d.ts +104 -0
- package/lib/storage/legacy-format.d.ts.map +1 -0
- package/lib/storage/legacy-format.js +262 -0
- package/lib/storage/legacy-format.js.map +1 -0
- package/lib/sync/config.d.ts +22 -0
- package/lib/sync/config.d.ts.map +1 -0
- package/lib/sync/config.js +57 -0
- package/lib/sync/config.js.map +1 -0
- package/lib/sync/git.d.ts +97 -0
- package/lib/sync/git.d.ts.map +1 -0
- package/lib/sync/git.js +282 -0
- package/lib/sync/git.js.map +1 -0
- package/lib/sync/index.d.ts +6 -0
- package/lib/sync/index.d.ts.map +1 -0
- package/lib/sync/index.js +6 -0
- package/lib/sync/index.js.map +1 -0
- package/lib/sync/layout.d.ts +15 -0
- package/lib/sync/layout.d.ts.map +1 -0
- package/lib/sync/layout.js +33 -0
- package/lib/sync/layout.js.map +1 -0
- package/lib/sync/merge.d.ts +42 -0
- package/lib/sync/merge.d.ts.map +1 -0
- package/lib/sync/merge.js +159 -0
- package/lib/sync/merge.js.map +1 -0
- package/lib/sync/service.d.ts +70 -0
- package/lib/sync/service.d.ts.map +1 -0
- package/lib/sync/service.js +508 -0
- package/lib/sync/service.js.map +1 -0
- package/lib/todo/store.d.ts +142 -0
- package/lib/todo/store.d.ts.map +1 -0
- package/lib/todo/store.js +452 -0
- package/lib/todo/store.js.map +1 -0
- package/lib/types/client/index.d.ts +7 -0
- package/lib/types/client/index.d.ts.map +1 -0
- package/package.json +63 -0
- package/src/client/index.tsx +994 -0
- package/src/host/index.ts +591 -0
- package/src/host/memory/batch.ts +107 -0
- package/src/host/memory/feedback.ts +36 -0
- package/src/host/memory/store.ts +650 -0
- package/src/host/migration/cli.ts +139 -0
- package/src/host/migration/fixture.ts +218 -0
- package/src/host/migration/service.ts +786 -0
- package/src/host/prompt/snapshot.ts +95 -0
- package/src/host/review/queue.ts +325 -0
- package/src/host/skills-browser.ts +191 -0
- package/src/host/storage/atomic-store.ts +605 -0
- package/src/host/storage/layout.ts +191 -0
- package/src/host/storage/legacy-format.ts +308 -0
- package/src/host/sync/config.ts +67 -0
- package/src/host/sync/git.ts +280 -0
- package/src/host/sync/index.ts +5 -0
- package/src/host/sync/layout.ts +39 -0
- package/src/host/sync/merge.ts +188 -0
- package/src/host/sync/service.ts +494 -0
- package/src/host/todo/store.ts +480 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { MaestroMemoryStore, MemoryTarget } from './store.ts'
|
|
2
|
+
import { buildFeedbackLine, type FeedbackSentiment } from './feedback.ts'
|
|
3
|
+
|
|
4
|
+
/** Targets accepted by MaestroMemoryStore ('global' is a normalized alias of 'memory'). */
|
|
5
|
+
const VALID_TARGETS = new Set<string>(['memory', 'global', 'user', 'project', 'key', 'daily'])
|
|
6
|
+
|
|
7
|
+
export interface BatchEntryInput {
|
|
8
|
+
target: MemoryTarget | string
|
|
9
|
+
content: string
|
|
10
|
+
/** Working directory for project/key tracks. */
|
|
11
|
+
cwd?: string
|
|
12
|
+
/** Explicit day for daily track (YYYY-MM-DD). */
|
|
13
|
+
date?: string
|
|
14
|
+
/** Branch scope csv for key add (e.g. 'main,dev'). */
|
|
15
|
+
branches?: string
|
|
16
|
+
/** One-line summary for key add (progressive disclosure). */
|
|
17
|
+
summary?: string
|
|
18
|
+
/** When set, appends the end-of-turn `[Feedback]` line to the stored content. */
|
|
19
|
+
sentiment?: FeedbackSentiment
|
|
20
|
+
category?: string
|
|
21
|
+
quote?: string
|
|
22
|
+
note?: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type BatchResult =
|
|
26
|
+
| { ok: true; ids: (string | undefined)[] }
|
|
27
|
+
| { ok: false; index: number; error: string }
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Add several entries sequentially through {@link MaestroMemoryStore.add}.
|
|
31
|
+
*
|
|
32
|
+
* Atomicity contract: storage-level writes stay per-file atomic (existing
|
|
33
|
+
* appendEntryAtomicSync), and the batch wraps them with rollback-on-failure —
|
|
34
|
+
* every entry successfully created earlier in this same call is removed again
|
|
35
|
+
* before reporting the failure index. Removal targets the generated `[id:]`
|
|
36
|
+
* token when the track issues ids (key), otherwise the trimmed content itself;
|
|
37
|
+
* remove()'s unique-match guard turns any ambiguity into a reported rollback
|
|
38
|
+
* failure instead of deleting a wrong entry. Entries detected as duplicates
|
|
39
|
+
* are left untouched (they pre-date this call).
|
|
40
|
+
*
|
|
41
|
+
* Unknown targets are rejected up-front per entry so a typo never writes a
|
|
42
|
+
* stray file mid-batch.
|
|
43
|
+
*/
|
|
44
|
+
export function applyBatch(
|
|
45
|
+
store: MaestroMemoryStore,
|
|
46
|
+
entries: BatchEntryInput[],
|
|
47
|
+
): BatchResult {
|
|
48
|
+
const added: { target: MemoryTarget; token: string; cwd?: string; date?: string }[] = []
|
|
49
|
+
const ids: (string | undefined)[] = []
|
|
50
|
+
|
|
51
|
+
for (let i = 0; i < entries.length; i++) {
|
|
52
|
+
const e = entries[i]
|
|
53
|
+
const target = String(e?.target ?? '')
|
|
54
|
+
if (!VALID_TARGETS.has(target)) {
|
|
55
|
+
return fail(store, added, i, `unknown target '${target}'`)
|
|
56
|
+
}
|
|
57
|
+
let content = e.content ?? ''
|
|
58
|
+
if (e.sentiment !== undefined) {
|
|
59
|
+
try {
|
|
60
|
+
content = `${content.trimEnd()} ${buildFeedbackLine({
|
|
61
|
+
sentiment: e.sentiment,
|
|
62
|
+
category: e.category,
|
|
63
|
+
quote: e.quote,
|
|
64
|
+
note: e.note,
|
|
65
|
+
})}`
|
|
66
|
+
} catch (err: any) {
|
|
67
|
+
return fail(store, added, i, err?.message ?? String(err))
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const res = store.add(target as MemoryTarget, content, e.cwd, {
|
|
71
|
+
branches: e.branches,
|
|
72
|
+
summary: e.summary,
|
|
73
|
+
date: e.date,
|
|
74
|
+
})
|
|
75
|
+
if (!res.ok) {
|
|
76
|
+
return fail(store, added, i, res.error)
|
|
77
|
+
}
|
|
78
|
+
ids.push(res.id)
|
|
79
|
+
// Duplicates carry no id and did not modify storage — nothing to roll back.
|
|
80
|
+
if (!res.duplicate) {
|
|
81
|
+
added.push({
|
|
82
|
+
target: target as MemoryTarget,
|
|
83
|
+
// key entries carry a generated id token; other tracks are stored
|
|
84
|
+
// verbatim, so the trimmed stored content is the precise removal token.
|
|
85
|
+
token: res.id !== undefined ? `[id:${res.id}]` : content.trim(),
|
|
86
|
+
cwd: e.cwd,
|
|
87
|
+
date: e.date,
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return { ok: true, ids }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function fail(
|
|
95
|
+
store: MaestroMemoryStore,
|
|
96
|
+
added: { target: MemoryTarget; token: string; cwd?: string; date?: string }[],
|
|
97
|
+
index: number,
|
|
98
|
+
error: string,
|
|
99
|
+
): BatchResult {
|
|
100
|
+
const rollbackFailures: string[] = []
|
|
101
|
+
for (const a of added) {
|
|
102
|
+
const rm = store.remove(a.target, a.token, a.cwd, { date: a.date })
|
|
103
|
+
if (!rm.ok) rollbackFailures.push(`${a.target}:${a.token.slice(0, 24)}`)
|
|
104
|
+
}
|
|
105
|
+
const suffix = rollbackFailures.length ? ` (rollback failed for ${rollbackFailures.join(',')})` : ''
|
|
106
|
+
return { ok: false, index, error: `${error}${suffix}` }
|
|
107
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Sentiments accepted for `[Feedback]` lines — anything else is rejected, never stored. */
|
|
2
|
+
export const FEEDBACK_SENTIMENTS = ['positive', 'negative', 'neutral'] as const
|
|
3
|
+
|
|
4
|
+
export type FeedbackSentiment = typeof FEEDBACK_SENTIMENTS[number]
|
|
5
|
+
|
|
6
|
+
export interface FeedbackInput {
|
|
7
|
+
sentiment: FeedbackSentiment
|
|
8
|
+
category?: string
|
|
9
|
+
quote?: string
|
|
10
|
+
note?: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function escapeValue(value: string): string {
|
|
14
|
+
return String(value).replace(/\\/g, '\\\\').replace(/"/g, '\\"')
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Format the end-of-turn feedback contract as one trailing line:
|
|
19
|
+
* `[Feedback] sentiment=positive; category="…"; quote="…"; note="…"`.
|
|
20
|
+
*
|
|
21
|
+
* Absent optional fields are omitted; unknown sentiments throw so callers can
|
|
22
|
+
* fail atomically instead of persisting an invalid marker.
|
|
23
|
+
*/
|
|
24
|
+
export function buildFeedbackLine(feedback: FeedbackInput): string {
|
|
25
|
+
if (!feedback || feedback.sentiment === undefined || feedback.sentiment === null) {
|
|
26
|
+
throw new Error('feedback sentiment is required')
|
|
27
|
+
}
|
|
28
|
+
if (!FEEDBACK_SENTIMENTS.includes(feedback.sentiment)) {
|
|
29
|
+
throw new Error(`unknown feedback sentiment '${String(feedback.sentiment)}'`)
|
|
30
|
+
}
|
|
31
|
+
const parts: string[] = [`sentiment=${feedback.sentiment}`]
|
|
32
|
+
if (feedback.category !== undefined) parts.push(`category="${escapeValue(feedback.category)}"`)
|
|
33
|
+
if (feedback.quote !== undefined) parts.push(`quote="${escapeValue(feedback.quote)}"`)
|
|
34
|
+
if (feedback.note !== undefined) parts.push(`note="${escapeValue(feedback.note)}"`)
|
|
35
|
+
return `[Feedback] ${parts.join('; ')}`
|
|
36
|
+
}
|