engineering-memory 1.11.21 → 1.11.22
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "engineering-memory",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.22",
|
|
4
4
|
"description": "Installs the Engineering Memory skill and its local MCP bridge. Sign in after installing; your organization and project are resolved from your account.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
package/runtime/build.json
CHANGED
|
@@ -689,6 +689,18 @@ export class BridgeService {
|
|
|
689
689
|
(repository.projectId && repository.projectId !== projectId)) {
|
|
690
690
|
throw refuse('The live task belongs to a different project than the one this repository is bound to.', 'project.resolve');
|
|
691
691
|
}
|
|
692
|
+
if (pointer?.closedAt &&
|
|
693
|
+
pointer.worktreeGeneration &&
|
|
694
|
+
this.dependencies.worktreePool &&
|
|
695
|
+
!(await this.dependencies.worktreePool.find(projectId, taskSlug, repository.repoRoot)))
|
|
696
|
+
return asJsonValue({
|
|
697
|
+
taskClosed: true,
|
|
698
|
+
folderReleased: true,
|
|
699
|
+
branch: pointer.branch ?? null,
|
|
700
|
+
...pendingQuestionnairesFields(pendingQuestionnaires),
|
|
701
|
+
repository: publicRepository(repository),
|
|
702
|
+
nextAction: 'This task is closed and its folder has been released, so there is nothing to resume or release. Its branch keeps the committed work; start new work with task.branch.',
|
|
703
|
+
});
|
|
692
704
|
const adoptable = pointer &&
|
|
693
705
|
!pointer.worktreeGeneration &&
|
|
694
706
|
normalizeTaskMode(pointer.mode) !== 'read_only' &&
|
|
@@ -2730,6 +2742,17 @@ export class BridgeService {
|
|
|
2730
2742
|
return asJsonValue({ operation, complete: true, removed: entry.repoRoot });
|
|
2731
2743
|
}
|
|
2732
2744
|
const entry = await pool.forPath(projectId, repository.repoRoot);
|
|
2745
|
+
if ((operation === 'release' || operation === 'cancel_delivery') &&
|
|
2746
|
+
!(await pool.find(projectId, input.externalTaskId, repository.repoRoot)) &&
|
|
2747
|
+
((entry?.phase === 'released' && entry.externalTaskId === input.externalTaskId) ||
|
|
2748
|
+
(await this.dependencies.activeContexts.loadForSlug(repository.repoFingerprint, input.externalTaskId))?.worktreeGeneration === input.generation))
|
|
2749
|
+
return asJsonValue({
|
|
2750
|
+
operation,
|
|
2751
|
+
complete: true,
|
|
2752
|
+
repoRoot: repository.repoRoot,
|
|
2753
|
+
alreadyReleased: true,
|
|
2754
|
+
nextAction: "This task's folder was already released; there is nothing left to release.",
|
|
2755
|
+
});
|
|
2733
2756
|
if (!entry ||
|
|
2734
2757
|
entry.externalTaskId !== input.externalTaskId ||
|
|
2735
2758
|
entry.generation !== input.generation)
|
|
@@ -3,7 +3,10 @@ import { performance } from 'node:perf_hooks';
|
|
|
3
3
|
import { sha256 } from './hash.js';
|
|
4
4
|
import { BridgeRecoveryError } from '../runtime/recovery-error.js';
|
|
5
5
|
export async function localMutex(identity, work, timeoutMs = 60000) {
|
|
6
|
-
const
|
|
6
|
+
const hash = sha256(identity);
|
|
7
|
+
const address = process.platform === 'win32'
|
|
8
|
+
? { path: String.raw `\\.\pipe\engineering-memory-` + hash }
|
|
9
|
+
: { host: '127.0.0.1', port: 20000 + (parseInt(hash.slice(0, 8), 16) % 30000) };
|
|
7
10
|
const deadline = performance.now() + timeoutMs;
|
|
8
11
|
let server;
|
|
9
12
|
for (;;) {
|
|
@@ -11,7 +14,7 @@ export async function localMutex(identity, work, timeoutMs = 60000) {
|
|
|
11
14
|
try {
|
|
12
15
|
await new Promise((resolve, reject) => {
|
|
13
16
|
server.once('error', reject);
|
|
14
|
-
server.listen({
|
|
17
|
+
server.listen({ ...address, exclusive: true }, () => {
|
|
15
18
|
server.removeListener('error', reject);
|
|
16
19
|
resolve();
|
|
17
20
|
});
|
|
@@ -40,7 +40,7 @@ Renew `task.heartbeat` using the exact returned task, path and ownership generat
|
|
|
40
40
|
|
|
41
41
|
Use `task.pause` when work stops or is handed to another client. It preserves task state and files, invalidates the old owner, and allows safe clean directories to be reused. It is not `task.abandon`. Resume reacquires the original directory when possible or uses the retained task branch in another safe directory. `worktree.reconcile` recovers interrupted allocation and validated local ownership records against Git. Never edit the registry, force checkout, stash/reset/clean, remove branches, kill a client or delete a worktree to bypass a refusal.
|
|
42
42
|
|
|
43
|
-
`task.close` retains a managed checkout while changes or delivery remain pending. After delivery, release with `deliveryOutcome:'delivered'` and the current generation. When the user decides not to deliver, call `worktree.release` with `deliveryOutcome:'cancelled'`; the product asks what happens to the folder and saves any changes to a ref. Never run `git restore` or `git clean` yourself to free a worktree, and never report a delivery that did not happen. Dirty/staged/untracked files, pending outbox/intents and unfinished Git operations prevent release. An old release cannot affect a reused directory. User-owned existing directories are never added to automatic cleanup. When the user wants to work in the main folder, they answer that in `task.branch`'s start form; when an open task holds the folder, that option names the task that would move out. A closed or abandoned task stops holding the folder by itself; a task still running in another client keeps it until it is paused there. Never edit or delete the reservation ref by hand.
|
|
43
|
+
`task.close` retains a managed checkout while changes or delivery remain pending. After delivery, release with `deliveryOutcome:'delivered'` and the current generation. Once the task's commits are on a remote branch the pool settles the folder by itself; `worktree.release` then answers `alreadyReleased`, `session.resume` of the closed task answers `folderReleased`, and nothing further is needed. When the user decides not to deliver, call `worktree.release` with `deliveryOutcome:'cancelled'`; the product asks what happens to the folder and saves any changes to a ref. Never run `git restore` or `git clean` yourself to free a worktree, and never report a delivery that did not happen. Dirty/staged/untracked files, pending outbox/intents and unfinished Git operations prevent release. An old release cannot affect a reused directory. User-owned existing directories are never added to automatic cleanup. When the user wants to work in the main folder, they answer that in `task.branch`'s start form; when an open task holds the folder, that option names the task that would move out. A closed or abandoned task stops holding the folder by itself; a task still running in another client keeps it until it is paused there. Never edit or delete the reservation ref by hand.
|
|
44
44
|
|
|
45
45
|
Read-only tasks allocate no worktree. If the user authorizes writing, settle `task.branch` for that same externalTaskId, use the allocated repoRoot, then call `context.prepare_change` with `transitionToWrite`. Its pinned source must still match; choosing a different source requires a new task, never rewriting the original task's source identity. Existing lease, discipline, source-memory, verify and commit gates remain mandatory.
|
|
46
46
|
|