engineering-memory 1.11.4 → 1.11.5

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.
@@ -0,0 +1,37 @@
1
+ import { createServer } from 'node:net';
2
+ import { performance } from 'node:perf_hooks';
3
+ import { sha256 } from './hash.js';
4
+ import { BridgeRecoveryError } from '../runtime/recovery-error.js';
5
+ export async function localMutex(identity, work, timeoutMs = 60000) {
6
+ const port = 20000 + (parseInt(sha256(identity).slice(0, 8), 16) % 30000);
7
+ const deadline = performance.now() + timeoutMs;
8
+ let server;
9
+ for (;;) {
10
+ server = createServer((socket) => socket.destroy());
11
+ try {
12
+ await new Promise((resolve, reject) => {
13
+ server.once('error', reject);
14
+ server.listen({ host: '127.0.0.1', port, exclusive: true }, () => {
15
+ server.removeListener('error', reject);
16
+ resolve();
17
+ });
18
+ });
19
+ break;
20
+ }
21
+ catch (error) {
22
+ server.close();
23
+ if (error.code !== 'EADDRINUSE')
24
+ throw error;
25
+ if (performance.now() >= deadline)
26
+ throw new BridgeRecoveryError('The local worktree registry is busy. Retry reconciliation; no ownership was changed.', 'worktree.reconcile');
27
+ await new Promise((resolve) => setTimeout(resolve, 25 + Math.floor(Math.random() * 25)));
28
+ }
29
+ }
30
+ try {
31
+ return await work();
32
+ }
33
+ finally {
34
+ await new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve())));
35
+ }
36
+ }
37
+ //# sourceMappingURL=local-mutex.js.map
package/skill/SKILL.md CHANGED
@@ -19,7 +19,7 @@ Do not block independent task work on `memory.propose_revision` drafting, submis
19
19
  2. Call `session.entry` before answering anything in a repository, and act on what it reports before the message itself: sign in when it says so, ask for organization and project when nothing has been decided, and stay completely silent about Engineering Memory in a repository where the user switched it off. Record every one of those answers with `session.set_decision`, and only ever from something the user actually said.
20
20
  3. Before planning or editing, call `session.bootstrap`. After compaction, a new chat, interruption, or handoff, call `session.resume` first.
21
21
  4. Open the task in `read_only` mode for review, diagnosis, planning, or reporting that does not authorize writes; use `scaffold` mode only to apply organization architecture templates to a new project; otherwise use `write` mode. Do read-only discovery, then record the discovery checkpoint.
22
- 5. For a write task, call `context.prepare_change` with the intended paths and record the pre-edit checkpoint before the first edit. Do not edit paths outside the active lease. A read-only task must not acquire a change lease unless the user expands the task to writing and the bridge performs the explicit mode transition.
22
+ 5. Before a new write/scaffold task, use the native `task.branch` base choice and managed worktree allocation. Use its returned repoRoot for all commands, renew ownership during real activity, pause on handoff, and preserve pending delivery after close. Read the worktree section in lifecycle.md. For a write task, call `context.prepare_change` with the intended paths and record the pre-edit checkpoint before the first edit. Do not edit paths outside the active lease. A read-only task must not acquire a change lease unless the user expands the task to writing and the bridge performs the explicit mode transition.
23
23
  6. Use the returned context pack as the engineering authority for the task. Use `memory.query` only for targeted missing context, and `memory.history` to read why the records you are changing became what they are before you design against them.
24
24
  7. Record phase, correction, validation, and handoff checkpoints at the required moments. Declare the task's discretionary decisions on the validation-before checkpoint, and when a task repeats a shape, have the first unit reviewed before writing the rest.
25
25
  8. For a write task, reconcile every changed screen and component. Propose revisions when semantics changed; otherwise record an explicit no-semantic-memory-change reconciliation.
@@ -10,11 +10,19 @@ An archived project is recoverable state, not a missing or conflicting binding.
10
10
 
11
11
  For a bound repository, call `session.bootstrap` before producing a plan or changing files. Supply the current repository root, project ID, task ID or stable local task slug, objective, task kind, task mode, and current Git diff hash. Use `read_only` for review, diagnosis, planning, or reporting without write authority; use `scaffold` when the task applies organization architecture templates to a new project; use `write` when the request authorizes repository changes. The bridge records the read-only Git diff hash as the immutable task baseline, including a pre-existing dirty worktree. Use the returned task ID, task version, context session ID, pinned revisions, project profile, engineering rules, prior task documents, quality gates, and current deviations.
12
12
 
13
- Every new write or scaffold task settles its branch through the native questionnaire before it opens, including when HEAD is already on a feature branch. Offer a task branch or an explicit choice to stay on the current branch. Call `task.branch` with the exact `externalTaskId` and either `name` or `keepCurrent`, then call `session.bootstrap` in its returned `repoRoot`. An existing branch name checks it out. Creating a branch remains optional; recording the user's choice does not. A read-only task needs no branch decision, but `context.prepare_change` with `transitionToWrite` requires one before editing.
13
+ Before a new write or scaffold task, read `session.entry` and the project Git preferences. If `canManage` is true, ask only the unanswered development/production/test preferences through native forms and save them with `project.set_git_preferences`. Development needs a branch; production/test may explicitly be absent. Their answered flags prevent repeated questions. Other members choose only a task-specific base and continue without changing shared preferences. A later request to change a base updates future tasks only. Branch preferences never label memory sources or change commit/tree applicability.
14
14
 
15
- The choice belongs to that task and worktree, survives retry and client restart, and cannot be consumed by a different task. Reuse an existing answer rather than asking again. A named branch stays fixed through prepare, verify, close and commit; closing never replaces it. Return with `task.branch` using the same task slug and recorded branch when a gate reports a mismatch. Legacy tasks without a recorded branch and tasks explicitly kept on detached HEAD remain compatible; they are not restricted to a named branch. Older clients remain supported during the minimum-version compatibility window.
15
+ Call `task.branch` with the stable `externalTaskId` and `repoRoot`. Its native forms show configured branch names, the current commit, another branch, and the explicit keep-current option. New branches always use a separate managed worktree. Configured remote bases are fetched and their exact commits pinned; after a fetch failure select an explicit local source through a new native decision, never silently use a cached branch. Existing task decisions survive retries and restarts. Resume their recorded branch rather than recreating or resetting it.
16
16
 
17
- Parallel development needs separate working directories. If another task owns the current worktree, offer a separate worktree through the questionnaire. Call `task.branch` with `externalTaskId`, `name`, and `worktreePath`; run bootstrap and all subsequent file, test and Git commands in its returned `repoRoot`. This creates or reuses an appropriate Git worktree and uses the same user-local binding and repository identity without writing a project marker. Never switch another task's working directory. Reservations are shared by clients using the same worktree; close or abandon releases that task's reservation. An interrupted close can release it through resume.
17
+ Use the returned `repoRoot` for **every** file read/write, terminal, context, validation and Git/delivery operation. The user-local pool is shared by Codex and Claude. Managed directories live in the OS Documents folder under `engineeringmemory/<stable-project-folder>/worktrees/<folder>-worktreeN`; do not supply arbitrary `worktreePath` values or create ad-hoc siblings. Independent clones cannot reuse each other's worktrees. `worktree.list` explains which slots are active, inactive but protected, or safely reusable. The versioned backend policy defaults to 50 directories per project/computer, 30-second heartbeats and 10-minute inactivity. Protected inactive directories still count toward the limit. Only a global admin changes `worktree.set_policy`; it is not an environment setting.
18
+
19
+ Renew `task.heartbeat` using the exact returned task, path and ownership generation during actual work and at approximately the cached heartbeat interval during long local commands. The bridge renews while its own task operation is running. Never run a perpetual heartbeat for an idle chat or MCP process. Inactivity never authorizes takeover of a live owner or deletion of files. Before writing after interruption, use `session.resume`; follow any returned worktree redirect and resume there. A stale generation cannot renew, release, verify or commit another owner's work.
20
+
21
+ 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.
22
+
23
+ `task.close` retains a managed checkout while changes or delivery remain pending. Complete only the delivery the user authorized, then use `worktree.release` with `delivered:true` and the current generation. 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. Legacy reservations and already-open unmanaged tasks keep their original lifecycle; they are not forcibly moved.
24
+
25
+ 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.
18
26
 
19
27
  A repository holds as many tasks as the people working in it. Never treat somebody else's unfinished task as a reason this one cannot proceed: no task waits on another task's review, reconciliation, verification or close, and nothing that is already verified or closed is undone by what happens elsewhere. When `session.resume` reports more than one live task for this repository, it lists them and the right move is to ask the user which one this is, never to guess and never to adopt the one that happens to be most recent.
20
28
 
@@ -51,7 +59,7 @@ Before implementation, load `work_item.plan` for the selected requirement and in
51
59
 
52
60
  If another project needs changes beyond the requested scope, explain the concrete missing behavior and use the native questionnaire to ask whether to include it. Do not use a chat instruction or invent approval. An explicit instruction already authorizing both sides is sufficient; reuse it. Call `work_item.confirm_plan` only with that approved scope, the common branch and a short reason. Resume an existing plan rather than asking again. An unavailable project needs administrator coordination; do not infer or bind its repository.
53
61
 
54
- One WorkItem UUID coordinates independent EngineeringTask runs, one per selected repository. Use the recorded branch name (for example `task/kan-101`) in each repository, and a separate worktree for each concurrent task. `task.branch` with the exact externalTaskId records the existing user choice and creates or adopts the branch in a suitable worktree. Use its returned repoRoot for subsequent tools and file commands. Never switch another task's reserved worktree.
62
+ One WorkItem UUID coordinates independent EngineeringTask runs, one per selected repository. Use the recorded branch name (for example `task/kan-101`) in each repository, and a separate worktree for each concurrent task. `task.branch` with the exact externalTaskId records the existing user choice and allocates a new task branch or resumes its recorded worktree. Use its returned repoRoot for subsequent tools and file commands. Never switch another task's reserved worktree.
55
63
 
56
64
  Open each side with the same workItemId and its own repository binding when work reaches that side. Each side has its own lease, reconciliation, verify, close and commit gate. Check `work_item.runs` and sibling checkpoints when handing off; one side completing does not prove all selected projects are complete. A plan's scope and branch cannot change while an implementation run is active. Read-only analysis does not acquire application write rights; its later write transition must satisfy discipline and the confirmed plan.
57
65
 
@@ -26,6 +26,10 @@ design system, navigation, platforms and languages; for Nest/Spring they confirm
26
26
  An explicit absence or deferral is acceptable; a made-up answer is not.
27
27
  The local machine's installed runtime is validation capability, not an architecture preference.
28
28
 
29
+ Greenfield preparation also asks development/production/test branch preferences as separate native questions. The development name is required even before the first commit; production/test allow an explicit absence. `project.initialize` uses the planned development name for a new Git repository and preserves existing files. Pass the same `onboardingRequestKey` to `project.setup` to attach these approved choices to the new project; keep the request key stable on retries. For an existing project, `session.entry` exposes unanswered preferences only to actors allowed to manage them. Do not ask absent production/test branches again after their answered flags are stored.
30
+
31
+ A newly initialized repository may have no commit. For its initial scaffold, choose explicit keepCurrent in the prepared, unowned checkout; no arbitrary base commit is invented and no files are committed automatically. After the first authorized delivery creates a commit, subsequent new branches use managed worktrees. A fresh remote branch can also supply a real committed base if the project already has one remotely.
32
+
29
33
  `project.initialize` only prepares Git for the approved greenfield mode. It supports missing, empty
30
34
  and barely-started non-Git directories without overwriting existing files; parent repositories and
31
35
  symbolic links are protected. Choices persist in user-local Engineering Memory state outside the
@@ -254,3 +254,11 @@ are written by the agent in the same language; pass language for the native help
254
254
  An existing exact-request questionnaire retains its original wording and answer across updates and
255
255
  restart, including an older English form. Resume that question rather than silently replacing or
256
256
  withdrawing it. Language changes never broaden the approved source, mode or previous-run scope.
257
+
258
+ ## Worktree and branch decisions
259
+
260
+ `task.branch` owns native selection of the starting source and branch. Confirmed decisions bind the external task identifier, selected source and branch; fetch resolves the exact immutable commit. A cancelled or dismissed question allocates nothing. Repeat the same call to resume its form. Do not select a different source to recover a timeout. On a remote failure offer an explicit local commit in another native decision. Show actual names from project.git_preferences, never infer develop/test/prod meaning from a branch name.
261
+
262
+ Shared preferences use separate native decisions for development, production and test. Explicitly absent production/test values are answers. Members without canManage receive a task-specific branch choice, never an administrator question they cannot apply. The same task's accepted decision stays valid across Codex/Claude handoff after pause; return to session.resume and the recorded repoRoot.
263
+
264
+ For task.branch and project.set_git_preferences, retries keep the same decisionAttempt (omit it on the first attempt). When the user explicitly reconsiders an answered deferral, use a new positive decisionAttempt to open a fresh native decision. Never reinterpret the old deferral as consent.