engineering-memory 1.11.4 → 1.11.6
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/dispatcher/sections.mjs +2 -0
- package/package.json +29 -29
- package/runtime/dist/src/config.js +2 -0
- package/runtime/dist/src/git/git-inspector.js +41 -2
- package/runtime/dist/src/git/verification-gate.js +40 -1
- package/runtime/dist/src/index.js +15 -1
- package/runtime/dist/src/mcp/onboarding-tools.js +39 -1
- package/runtime/dist/src/mcp/server.js +2 -0
- package/runtime/dist/src/mcp/tool-definitions.js +13 -10
- package/runtime/dist/src/mcp/worktree-tools.js +455 -0
- package/runtime/dist/src/project/project-intake.js +9 -2
- package/runtime/dist/src/runtime/api-client.js +4 -0
- package/runtime/dist/src/runtime/branch-preferences.js +53 -0
- package/runtime/dist/src/runtime/bridge-service.js +398 -13
- package/runtime/dist/src/runtime/task-branch-store.js +1 -1
- package/runtime/dist/src/runtime/worktree-policy.js +37 -0
- package/runtime/dist/src/runtime/worktree-pool.js +905 -0
- package/runtime/dist/src/utilities/local-mutex.js +37 -0
- package/skill/SKILL.md +1 -1
- package/skill/references/lifecycle.md +52 -4
- package/skill/references/project-onboarding.md +4 -0
- package/skill/references/questionnaires.md +21 -0
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
|
@@ -246,3 +254,43 @@ version is not automatically raised; projects opt in by starting a source-bound
|
|
|
246
254
|
## Offline source context
|
|
247
255
|
|
|
248
256
|
An unexpired cached context pack may be used for implementation. The bridge records checkpoints in its outbox. Permanent proposal review, strict verification, task close, and Git commit require the backend and synchronization of the relevant task deliveries. An unrelated task or repository queue does not block this task; account switching and logout still require all deliveries to be resolved. Commit receipts are retained per task and worktree and still require an online attestation for the selected closed task and exact staged content.
|
|
257
|
+
|
|
258
|
+
## Reuse before allocating another directory
|
|
259
|
+
|
|
260
|
+
Before starting a write task, call `worktree.list` with the bound repository. It reconciles managed
|
|
261
|
+
Git checkouts with local records. Then let `task.branch` choose the smallest safe slot; do not guess
|
|
262
|
+
a new worktree number or create a directory yourself. Allocation also performs discovery when the
|
|
263
|
+
caller omitted the listing. Old unregistered managed checkouts count toward the limit and remain
|
|
264
|
+
protected because their previous ownership and delivery are unknown. A clean checkout alone is
|
|
265
|
+
insufficient proof of availability.
|
|
266
|
+
|
|
267
|
+
When prior work has finished, call `worktree.reconcile` on that checkout with `releaseUnowned:true`
|
|
268
|
+
and the conversation language. Its native question binds the decision to the checkout, source and
|
|
269
|
+
ownership generation. Cancellation leaves it protected. Git reservation, dirty files, unfinished
|
|
270
|
+
Git operations and pending work are checked again before release. A changed source requires a new
|
|
271
|
+
inspection and answer. This recovery never deletes files or branches or interrupts another agent.
|
|
272
|
+
|
|
273
|
+
If the running client predates the pool tools, inspect `git worktree list` and the existing task
|
|
274
|
+
reservations before any explicit allocation. Do not treat an unavailable tool or an empty registry
|
|
275
|
+
as an empty filesystem. Preserve uncertain checkouts and report the client limitation.
|
|
276
|
+
|
|
277
|
+
## Network and generation evidence
|
|
278
|
+
|
|
279
|
+
`network` means tests of the changed network/contract behavior, not a connection to a live provider.
|
|
280
|
+
Use local contract tests and controlled responses for the applicable success, errors, timeout,
|
|
281
|
+
retry and cancellation behavior. Report the real runner command, for example
|
|
282
|
+
`mvn -B -Dtest=CardDepositServiceTest test` or `./gradlew test --tests CardDepositServiceTest`;
|
|
283
|
+
the class name need not contain a special keyword. Report `network` only when that suite actually
|
|
284
|
+
covers the changed contract. A command match cannot establish behavioral coverage by itself.
|
|
285
|
+
Source searches, static analyzers, `echo` and a successful `curl` request do not replace these tests.
|
|
286
|
+
Never rename a command or invent a passing result to satisfy a category.
|
|
287
|
+
|
|
288
|
+
Handwritten files under `service`/`services` do not automatically require a separate network category,
|
|
289
|
+
and handwritten `model`/`models` files do not automatically require code generation. Explicit
|
|
290
|
+
network paths and generated `.g.dart`/`.freezed.dart` files retain their gates. On code tasks,
|
|
291
|
+
additional applicable `network` and `codegen` evidence is accepted; all submitted evidence must pass.
|
|
292
|
+
Read-only validation requirements are unchanged. Test commands that explicitly skip tests cannot
|
|
293
|
+
serve as test or network evidence. A live environment is a separate check when the task requires it.
|
|
294
|
+
|
|
295
|
+
If the user later reconsiders a preserved legacy checkout, repeat `worktree.reconcile` with a new
|
|
296
|
+
`decisionAttempt`; never reinterpret the previous preserve answer as approval.
|
|
@@ -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,24 @@ 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.
|
|
265
|
+
|
|
266
|
+
## Legacy worktree availability
|
|
267
|
+
|
|
268
|
+
Use `worktree.list` before deciding another directory is needed. An unregistered legacy checkout
|
|
269
|
+
has unknown prior ownership and delivery, even if Git reports clean. `worktree.reconcile` with
|
|
270
|
+
`releaseUnowned:true` and `language` opens the native availability question for that exact checkout,
|
|
271
|
+
source commit and generation. The user confirms prior work and delivery have finished; current Git
|
|
272
|
+
safety checks still decide whether reuse is possible. Cancellation or choosing to preserve does not
|
|
273
|
+
release it. Resume the same form via the same operation. A changed source/generation needs a fresh
|
|
274
|
+
decision, and an old answer cannot release a newly owned task.
|
|
275
|
+
|
|
276
|
+
If the user later reconsiders a preserved legacy checkout, repeat `worktree.reconcile` with a new
|
|
277
|
+
`decisionAttempt`; never reinterpret the previous preserve answer as approval.
|