engineering-memory 1.11.9 → 1.11.11

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.
Files changed (35) hide show
  1. package/dispatcher/sections.mjs +7 -2
  2. package/install/codex-approval.mjs +457 -0
  3. package/install/files.mjs +5 -1
  4. package/install/installer.mjs +24 -1
  5. package/package.json +1 -1
  6. package/runtime/build.json +1 -1
  7. package/runtime/dist/src/config.js +2 -0
  8. package/runtime/dist/src/git/git-inspector.js +114 -4
  9. package/runtime/dist/src/git/verification-gate.js +30 -17
  10. package/runtime/dist/src/mcp/onboarding-tools.js +110 -16
  11. package/runtime/dist/src/mcp/questionnaire-tools.js +99 -15
  12. package/runtime/dist/src/mcp/tool-annotations.js +112 -0
  13. package/runtime/dist/src/mcp/tool-definitions.js +150 -29
  14. package/runtime/dist/src/mcp/worktree-tools.js +395 -236
  15. package/runtime/dist/src/project/repository.js +26 -8
  16. package/runtime/dist/src/runtime/active-context-store.js +3 -0
  17. package/runtime/dist/src/runtime/api-client.js +1 -0
  18. package/runtime/dist/src/runtime/branch-preferences.js +0 -19
  19. package/runtime/dist/src/runtime/bridge-service.js +1320 -246
  20. package/runtime/dist/src/runtime/offline-outbox.js +33 -158
  21. package/runtime/dist/src/runtime/phase-timer.js +26 -0
  22. package/runtime/dist/src/runtime/privacy-detector.js +263 -0
  23. package/runtime/dist/src/runtime/questionnaire-store.js +210 -49
  24. package/runtime/dist/src/runtime/recovery-error.js +3 -1
  25. package/runtime/dist/src/runtime/runtime-entry.js +8 -0
  26. package/runtime/dist/src/runtime/runtime-host.js +1 -3
  27. package/runtime/dist/src/runtime/task-branch-store.js +17 -1
  28. package/runtime/dist/src/runtime/task-start.js +281 -0
  29. package/runtime/dist/src/runtime/worktree-pool.js +374 -26
  30. package/runtime/dist/src/utilities/process.js +1 -0
  31. package/skill/SKILL.md +3 -3
  32. package/skill/references/lifecycle.md +59 -19
  33. package/skill/references/memory-updates.md +9 -3
  34. package/skill/references/project-onboarding.md +19 -2
  35. package/skill/references/questionnaires.md +86 -15
@@ -0,0 +1,281 @@
1
+ import { sha256, stableStringify } from '../utilities/hash.js';
2
+ export function suggestedBranchNames(externalTaskId) {
3
+ const slug = externalTaskId
4
+ .replace(/[^A-Za-z0-9._-]+/g, '-')
5
+ .replace(/\.{2,}/g, '.')
6
+ .replace(/-{2,}/g, '-')
7
+ .replace(/^[-.]+|[-.]+$/g, '')
8
+ .slice(0, 120)
9
+ .replace(/\.lock$/i, '') || 'task';
10
+ const name = 'feature/' + slug;
11
+ return [name, ...[2, 3, 4, 5, 6, 7, 8, 9].map((suffix) => name + '-' + suffix)];
12
+ }
13
+ export function sameHolder(left, right) {
14
+ if (!left || !right)
15
+ return left === right;
16
+ return ((left.taskId ?? left.externalTaskId) === (right.taskId ?? right.externalTaskId) &&
17
+ left.oid === right.oid &&
18
+ (left.generation ?? null) === (right.generation ?? null));
19
+ }
20
+ export function sourceLabel(base, currentBranch) {
21
+ if (base.kind === 'remote')
22
+ return base.remote + '/' + base.branch;
23
+ if (base.kind === 'local')
24
+ return base.ref;
25
+ if (base.kind === 'current')
26
+ return (currentBranch ?? 'HEAD') + (base.commit ? ' (' + base.commit.slice(0, 7) + ')' : '');
27
+ return base.kind;
28
+ }
29
+ export function configuredBase(preferences, role) {
30
+ const selected = preferences.branches[role];
31
+ return selected.answered && selected.remote && selected.branch
32
+ ? { kind: 'remote', remote: selected.remote, branch: selected.branch }
33
+ : null;
34
+ }
35
+ export function taskStartDefinition(facts) {
36
+ const tr = facts.language === 'tr';
37
+ const folder = facts.folder;
38
+ const keepOnly = facts.keepCurrent === true || !facts.currentCommit;
39
+ const here = !keepOnly && !folder.managed && !folder.heldBy && folder.clean;
40
+ const keep = keepOnly || (!folder.managed && !folder.heldBy && !folder.holder);
41
+ const holder = here && folder.holder ? holderIdentity(folder.holder) : null;
42
+ const currentLabel = sourceLabel({ kind: 'current', ...(facts.currentCommit ? { commit: facts.currentCommit } : {}) }, facts.currentBranch);
43
+ const binding = {
44
+ externalTaskId: facts.externalTaskId,
45
+ ...(facts.decisionAttempt ? { decisionAttempt: facts.decisionAttempt } : {}),
46
+ currentCommit: facts.currentCommit,
47
+ holder,
48
+ };
49
+ const questions = [
50
+ {
51
+ id: 'location',
52
+ message: tr ? 'Nerede başlasın?' : 'Where should it start?',
53
+ options: [
54
+ ...(keepOnly
55
+ ? []
56
+ : [{ id: 'worktree', label: tr ? 'Ayrı bir worktree’de' : 'In a separate worktree' }]),
57
+ ...(here
58
+ ? [
59
+ {
60
+ id: 'here',
61
+ label: holder
62
+ ? tr
63
+ ? holder.externalTaskId + ' bu klasörden çıkarılsın, yeni branch burada açılsın'
64
+ : 'Move ' + holder.externalTaskId + ' out and start the new branch here'
65
+ : tr
66
+ ? 'Bu klasörde yeni branch olarak'
67
+ : 'In this folder, as a new branch',
68
+ },
69
+ ]
70
+ : []),
71
+ ...(keep
72
+ ? [
73
+ {
74
+ id: 'keep_current',
75
+ label: tr
76
+ ? 'Burada, ' + currentLabel + ' üzerinde, yeni branch açmadan'
77
+ : 'Here on ' + currentLabel + ', without a new branch',
78
+ },
79
+ ]
80
+ : []),
81
+ { id: 'defer', label: tr ? 'Şimdilik başlatma' : 'Not now' },
82
+ ],
83
+ },
84
+ ];
85
+ if (!keepOnly && !facts.base) {
86
+ const roles = ['development', 'production', 'test']
87
+ .flatMap((role) => {
88
+ const base = configuredBase(facts.preferences, role);
89
+ return base ? [{ role, base }] : [];
90
+ })
91
+ .slice(0, 2);
92
+ const roleOption = ({ role, base }) => ({
93
+ id: role,
94
+ label: base.remote + '/' + base.branch + ' (' + role + ')',
95
+ });
96
+ binding.bases = {
97
+ current: {
98
+ kind: 'current',
99
+ ...(facts.currentCommit ? { commit: facts.currentCommit } : {}),
100
+ },
101
+ ...Object.fromEntries(roles.map(({ role, base }) => [role, base])),
102
+ };
103
+ questions.push({
104
+ id: 'base',
105
+ message: tr ? 'Hangi daldan başlasın?' : 'Which branch should it start from?',
106
+ options: [
107
+ ...roles.slice(0, 1).map(roleOption),
108
+ {
109
+ id: 'current',
110
+ label: tr ? 'Bu klasörün dalı: ' + currentLabel : 'This folder’s branch: ' + currentLabel,
111
+ },
112
+ ...roles.slice(1).map(roleOption),
113
+ { id: 'other', label: tr ? 'Başka bir uzak dal' : 'Another remote branch' },
114
+ ],
115
+ otherAsText: true,
116
+ textField: {
117
+ title: tr ? 'origin üzerindeki dal adı' : 'Branch name on origin',
118
+ maxLength: 255,
119
+ requiredForChoice: 'other',
120
+ },
121
+ });
122
+ }
123
+ else if (!keepOnly)
124
+ binding.base = resolvedBase(facts.base, facts);
125
+ if (!keepOnly && !facts.name) {
126
+ binding.suggestedName = facts.suggestedName;
127
+ questions.push({
128
+ id: 'name',
129
+ message: tr ? 'Yeni branch’in adı ne olsun?' : 'What should the new branch be called?',
130
+ options: [
131
+ { id: 'suggested', label: facts.suggestedName },
132
+ { id: 'custom', label: tr ? 'Başka bir ad' : 'Another name' },
133
+ ],
134
+ textField: {
135
+ title: tr ? 'Branch adı' : 'Branch name',
136
+ maxLength: 255,
137
+ requiredForChoice: 'custom',
138
+ },
139
+ });
140
+ }
141
+ else if (!keepOnly)
142
+ binding.name = facts.name;
143
+ const fixed = [
144
+ ...(here && folder.holder
145
+ ? [
146
+ tr
147
+ ? folder.holder.externalTaskId +
148
+ ' bu klasörü tutuyor (branch ' +
149
+ (folder.holder.branch ?? 'detached HEAD') +
150
+ ', son etkinlik ' +
151
+ (folder.holder.lastCheckpointAt ?? 'bilinmiyor') +
152
+ '). Çıkarılırsa görev açık kalır ve devam ederken ayrı bir worktree’de açılır.'
153
+ : folder.holder.externalTaskId +
154
+ ' holds this folder (branch ' +
155
+ (folder.holder.branch ?? 'detached HEAD') +
156
+ ', last activity ' +
157
+ (folder.holder.lastCheckpointAt ?? 'unknown') +
158
+ '). If it moves out, it stays open and continues in a separate worktree when resumed.',
159
+ ]
160
+ : []),
161
+ ...(binding.base
162
+ ? [
163
+ tr
164
+ ? sourceLabel(binding.base, facts.currentBranch) + ' dalından başlar.'
165
+ : 'It starts from ' + sourceLabel(binding.base, facts.currentBranch) + '.',
166
+ ]
167
+ : []),
168
+ ...(binding.name
169
+ ? [tr ? 'Yeni branch: ' + binding.name + '.' : 'New branch: ' + binding.name + '.']
170
+ : []),
171
+ ...(withheld(folder, keepOnly, tr) ? [withheld(folder, keepOnly, tr)] : []),
172
+ ];
173
+ const content = {
174
+ message: [
175
+ tr
176
+ ? facts.externalTaskId + ' nasıl başlasın? Sen cevaplayana kadar hiçbir şey oluşturulmaz.'
177
+ : facts.externalTaskId +
178
+ ': how should this task start? Nothing is created until you answer.',
179
+ ...fixed,
180
+ ].join(' '),
181
+ language: facts.language,
182
+ questions,
183
+ terminalChoices: [
184
+ { questionId: 'location', choice: 'defer' },
185
+ ...(keep ? [{ questionId: 'location', choice: 'keep_current' }] : []),
186
+ ],
187
+ binding: JSON.parse(JSON.stringify(binding)),
188
+ };
189
+ return { questionnaireId: 'task-start-' + sha256(stableStringify(content)), ...content };
190
+ }
191
+ export function taskStartChoice(record) {
192
+ if (record.status !== 'answered' ||
193
+ !record.questionnaireId.startsWith('task-start-') ||
194
+ !record.answers ||
195
+ !record.binding)
196
+ return null;
197
+ const binding = record.binding;
198
+ const task = {
199
+ externalTaskId: binding.externalTaskId,
200
+ ...(binding.decisionAttempt ? { decisionAttempt: binding.decisionAttempt } : {}),
201
+ };
202
+ const location = record.answers.location?.choice;
203
+ if (location === 'defer')
204
+ return { status: 'deferred', ...task };
205
+ if (location === 'keep_current')
206
+ return {
207
+ status: 'start',
208
+ ...task,
209
+ base: {
210
+ kind: 'current',
211
+ ...(binding.currentCommit ? { commit: binding.currentCommit } : {}),
212
+ },
213
+ name: null,
214
+ keepCurrent: true,
215
+ inPlace: false,
216
+ holder: null,
217
+ };
218
+ if (location !== 'worktree' && location !== 'here')
219
+ return null;
220
+ const baseAnswer = record.answers.base;
221
+ const other = baseAnswer?.choice === 'other' ? baseAnswer.text?.replace(/^origin\//, '') : null;
222
+ const base = binding.base ??
223
+ (other
224
+ ? { kind: 'remote', remote: 'origin', branch: other }
225
+ : baseAnswer
226
+ ? binding.bases?.[baseAnswer.choice]
227
+ : undefined);
228
+ const nameAnswer = record.answers.name;
229
+ const name = binding.name ??
230
+ (nameAnswer?.choice === 'custom'
231
+ ? nameAnswer.text
232
+ : nameAnswer?.choice === 'suggested'
233
+ ? binding.suggestedName
234
+ : undefined);
235
+ if (!base || !name)
236
+ return null;
237
+ return {
238
+ status: 'start',
239
+ ...task,
240
+ base,
241
+ name,
242
+ keepCurrent: false,
243
+ inPlace: location === 'here',
244
+ holder: location === 'here' ? binding.holder : null,
245
+ };
246
+ }
247
+ function resolvedBase(base, facts) {
248
+ if (base.kind === 'current')
249
+ return {
250
+ kind: 'current',
251
+ ...((base.commit ?? facts.currentCommit)
252
+ ? { commit: base.commit ?? facts.currentCommit }
253
+ : {}),
254
+ };
255
+ if (base.kind === 'development' || base.kind === 'production' || base.kind === 'test')
256
+ return configuredBase(facts.preferences, base.kind) ?? base;
257
+ return base;
258
+ }
259
+ function holderIdentity(holder) {
260
+ return {
261
+ externalTaskId: holder.externalTaskId,
262
+ taskId: holder.taskId,
263
+ oid: holder.oid,
264
+ generation: holder.generation,
265
+ };
266
+ }
267
+ function withheld(folder, keepOnly, tr) {
268
+ if (keepOnly || folder.managed || (!folder.heldBy && folder.clean))
269
+ return null;
270
+ if (folder.heldBy)
271
+ return tr
272
+ ? folder.heldBy +
273
+ ' bu klasörde başka bir oturumda hâlâ çalışıyor; yeni branch burada açılamaz. O oturumda duraklatılırsa bu klasör de seçilebilir.'
274
+ : 'Task ' +
275
+ folder.heldBy +
276
+ ' is still running in another client in this folder, so the new branch cannot start here. Once it is paused there, this folder can be chosen too.';
277
+ return tr
278
+ ? 'Bu klasörde kaydedilmemiş değişiklikler var; yeni branch burada açılamaz.'
279
+ : 'This folder has uncommitted changes, so the new branch cannot start here.';
280
+ }
281
+ //# sourceMappingURL=task-start.js.map