engineering-memory 1.11.3 → 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.
@@ -6,15 +6,23 @@ Sign-in decides nothing beyond who the user is. The organization and the project
6
6
 
7
7
  Use the binding returned by `session.entry` as the authority. The bridge stores the selected project and repository identity under `~/.engineering-memory/origins/<api-hash>/project-bindings/`, outside the installed runtime and working tree. It imports a legacy `.engineering-memory/project.json` once, preserving its schema and exact backend fingerprint for existing tasks and receipts. It leaves that file unchanged; after migration the file is optional and may be removed through the repository's normal Git workflow. New bindings never create it. A checkout that never imported the marker still finds a project bound under the older identity: the bridge presents that identity alongside the current one and stores whichever the backend confirms. Never infer a selection from a directory or remote, and never edit binding records by hand. Separate clones or a changed remote require a new explicit selection; worktrees of the same checkout share the local binding.
8
8
 
9
- An archived project is recoverable state, not a missing or conflicting binding. When an owner receives `project.restore`, use the `projectId` and `expectedVersion` in its data and call that operation before retrying. A non-owner receives `project.member_list` instead: list the members, identify a project owner and explain that the owner must restore the exact project before this session can retry. Use `project.list` with `includeArchived: true` when an owner must first select the archived project. Never create or bind a replacement project to escape archive state.
9
+ An archived project is recoverable state, not a missing or conflicting binding. When an owner receives `project.restore`, use the `projectId` and `expectedVersion` in its data and call that operation before retrying. A non-owner receives `project.member_list` instead: check the available roles and explain that project-owner authority is required to restore this exact project before retrying. Do not name a person or disclose contact details. Use `project.list` with `includeArchived: true` when an owner must first select the archived project. Never create or bind a replacement project to escape archive state.
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,13 +59,13 @@ 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
 
58
66
  ### Administration, product management and QA
59
67
 
60
- Administrative authority and work discipline are independent. Organization admins can manage projects, assignments, repository URLs and work items in their organization. A global admin has those rights only in organizations they actively belong to. Ordinary users need a live explicit project assignment. Fullstack/backend/web/mobile/frontend disciplines govern implementation, while project overrides do not grant administration.
68
+ Administrative authority and work discipline are independent. Organization admins can manage projects, assignments, repository URLs and work items in their organization. A global admin has those rights only in organizations they actively belong to. Ordinary users need a live explicit project assignment. Active organization administrators, including a global admin with live membership in that organization, inherit contributor access to its projects without a separate project grant. Fullstack/backend/web/mobile/frontend disciplines still govern implementation, while project overrides do not grant administration.
61
69
 
62
70
  An assigned product manager can create, edit, assign, archive and restore work items through the work_item tools. Designer work includes design context and requirement participation; it does not grant general application code leases. A tester can create an unassigned bug and record `work_item.record_test` evidence, then track it with `work_item.test_results`. QA evidence must contain no credentials, PII or production payloads and must identify the exact requirement version. A passed result never silently marks the requirement done. Organization administration separately permits backlog management regardless of discipline.
63
71
 
@@ -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
@@ -48,7 +48,7 @@ A new organization is not empty. It reads the product engineering core immediate
48
48
 
49
49
  Once the organization is chosen, call `project.list` and offer that organization's projects, with **create a new project** last. Ignore projects belonging to other organizations; a listing that mixes them is how work lands in the wrong place. Creating one follows the unbound-repository flow below.
50
50
 
51
- The normal list omits archived projects. If repository entry, setup, binding or task open reports `project.restore`, use the project id and expected version returned with that refusal and restore it before continuing. If it reports `project.member_list`, the current member cannot restore the project: call that operation, identify the project owners in its result and tell the user which owner must perform the versioned restore. If an owner does not yet have the project id and expected version, call `project.list` with `includeArchived: true` and let them select the archived project. Archive state never authorizes creating a duplicate project.
51
+ The normal list omits archived projects. If repository entry, setup, binding or task open reports `project.restore`, use the project id and expected version returned with that refusal and restore it before continuing. If it reports `project.member_list`, the current member cannot restore the project: call that operation to check the available roles and explain that the versioned restore requires project-owner authority. Do not identify a person, reconstruct an identity from an account identifier or disclose contact details. If an owner does not yet have the project id and expected version, call `project.list` with `includeArchived: true` and let them select the archived project. Archive state never authorizes creating a duplicate project.
52
52
 
53
53
  Ask both questions again whenever a chat starts in a repository whose binding you have not confirmed in this session.
54
54
 
@@ -99,6 +99,8 @@ fail, and raw secrets, headers, customer payloads and PII are excluded.
99
99
 
100
100
  ## Project Membership
101
101
 
102
+ Member tools expose opaque account identifiers and roles, not names or email addresses. Do not reconstruct a person's identity, search for their contact details, or repeat personal data when explaining an access refusal. Describe the required role and the current caller's available operation. Use a user-supplied account address only for the membership operation they explicitly requested; do not echo it into routine explanations, task memory or questionnaires. Organization administrators already inherit contributor access within their organization; do not offer to add them to every project to fix development access. Work discipline and live organization membership still apply.
103
+
102
104
  Ask for the registered email and intended role. Show owner, maintainer, member, and reader effects. Confirm before calling `project.member_add`. A project grant is valid only while the same account belongs to the parent organization. If the call reports `organization.member_upsert`, do not retry the project write: an organization owner must first confirm the organization role and discipline and call that recovery. When the current account is not an organization owner, explain that coordination requirement instead of pretending the project grant succeeded. Retry `project.member_add` only after the parent grant exists.
103
105
 
104
106
  ## Branch
@@ -252,3 +254,11 @@ are written by the agent in the same language; pass language for the native help
252
254
  An existing exact-request questionnaire retains its original wording and answer across updates and
253
255
  restart, including an older English form. Resume that question rather than silently replacing or
254
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.