@sabaiway/agent-workflow-kit 3.9.0 → 3.10.0
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/CHANGELOG.md +25 -0
- package/SKILL.md +1 -1
- package/capability.json +1 -1
- package/package.json +1 -1
- package/references/modes/worktrees.md +2 -1
- package/tools/worktrees.mjs +14 -11
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,31 @@ Semantically versioned ([semver](https://semver.org)), newest first. The `versio
|
|
|
4
4
|
is the current release. `upgrade` mode reads a project's `docs/ai/.workflow-version` and applies
|
|
5
5
|
every `migrations/<version>-<slug>.md` newer than it, in semver order.
|
|
6
6
|
|
|
7
|
+
## 3.10.0 — install advice reads the worktree checkout (AD-071)
|
|
8
|
+
|
|
9
|
+
The install advice picked its package manager from MAIN's `package.json` and lockfiles while the
|
|
10
|
+
printed command targets the SATELLITE (`cd <worktree> && <manager> install`) — so a dirty MAIN
|
|
11
|
+
lockfile could push the advice into ambiguity or the wrong manager, and a MAIN advanced past the
|
|
12
|
+
satellite's base steered a satellite it no longer describes. The evidence and the target are now
|
|
13
|
+
the SAME tree:
|
|
14
|
+
|
|
15
|
+
- **Manager evidence reads the worktree's own live checkout** — the `packageManager` field and
|
|
16
|
+
the lockfile scan, the same live lane the dependency-free proof (3.6.0) and the node_modules
|
|
17
|
+
symlink probe already use. MAIN's mutable working tree never steers manager selection; MAIN
|
|
18
|
+
state legitimately steers only the symlink lane (the shared-cache link and its unlink-first
|
|
19
|
+
posture), unchanged.
|
|
20
|
+
- **The contract ships in the worktrees mode doc as one pinned sentence** (a named test locks
|
|
21
|
+
the exact wording): all manifest/lockfile install evidence is read from the worktree's own
|
|
22
|
+
live files at the moment the posture is resolved — deliberately NOT «exactly HEAD», because a
|
|
23
|
+
`post-checkout` hook can shape the checkout before the posture is resolved.
|
|
24
|
+
- **No resume-tolerance smuggling.** The shipped clean-tree `--resume` STOP is pinned byte-exact
|
|
25
|
+
by a real-git test; dirty-resume semantics remain a queued redesign. A satellite behind an
|
|
26
|
+
advanced MAIN now gets advice about ITSELF — pinned by a real-git test where MAIN's lockfile
|
|
27
|
+
advance does not re-steer the satellite's refreshed record.
|
|
28
|
+
- **Honest residual:** a manager signal living only in MAIN's working tree (e.g. an ignored,
|
|
29
|
+
uncommitted lockfile) no longer steers the advice — the checkout is the truth even when that
|
|
30
|
+
yields the npm default.
|
|
31
|
+
|
|
7
32
|
## 3.9.0 — the --include copy door proves what it copies (AD-070)
|
|
8
33
|
|
|
9
34
|
Nothing bound the node the provision copy walk read to the node `--include` preflight approved:
|
package/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: agent-workflow-kit
|
|
|
3
3
|
description: Deploy or upgrade a portable AI-agent memory-and-workflow system in any project. Use when the user wants to bootstrap `docs/ai/` + an entry-point `AGENTS.md` (+ `CLAUDE.md` alias) + cap/archive/index enforcement in a new or existing repo, set up the Memory Map and session protocols, install the docs-rotation pre-commit hook, or run `/agent-workflow-kit` / `/agent-workflow-kit upgrade`. Triggers on phrases like "set up the memory system", "deploy the AI workflow here", "bootstrap docs/ai", "upgrade the workflow".
|
|
4
4
|
disable-model-invocation: true
|
|
5
5
|
metadata:
|
|
6
|
-
version: '3.
|
|
6
|
+
version: '3.10.0'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# agent-workflow-kit
|
package/capability.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sabaiway/agent-workflow-kit",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.10.0",
|
|
4
4
|
"description": "Portable, cross-agent memory & workflow for AI coding agents — Claude Code, Codex, Cursor, Devin Desktop. One command deploys an AGENTS.md entry point + docs/ai context with cap/archive/index enforcement into any repo.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-agents",
|
|
@@ -104,8 +104,9 @@ PLUS the three facts a fresh satellite session cannot derive from its own checko
|
|
|
104
104
|
isolated-install command when the package manager is unambiguous, the honest install-by-hand
|
|
105
105
|
advice when it is not, and — when the provisioned `node_modules` is a SYMLINK into main — the
|
|
106
106
|
unlink-first form, because a plain install through the symlink writes into MAIN and is never
|
|
107
|
-
presented as isolated. When the WORKTREE'S OWN LIVE CHECKOUT is provably dependency-free (its `package.json` declares no dependencies, no `workspaces` field of any shape, no install-lifecycle script, no native-addon manifest, no external workspace manifest beside it — the evidence is what an install run in the satellite would actually read:
|
|
107
|
+
presented as isolated. When the WORKTREE'S OWN LIVE CHECKOUT is provably dependency-free (its `package.json` declares no dependencies, no `workspaces` field of any shape, no install-lifecycle script, no native-addon manifest, no external workspace manifest beside it — the evidence is what an install run in the satellite would actually read: the checkout's LIVE files at the moment the posture is resolved; on `--resume` a dirty tree is then refused by the clean-tree verify, after the record refresh) the record and the default-lane report both state `no install needed — the project declares no dependencies` and print no install command. A workspace tree is NEVER provably install-free — a workspace install materializes member links and `.bin` shims even with zero dependencies — and anything else the tool cannot enumerate (an absent or unparseable `package.json`, a malformed dependency or scripts field, an install-lifecycle script — dependency-free is not install-free) leaves the posture UNKNOWN and keeps the existing advice: a false "nothing to install" is worse than a redundant hint. `--install` remains an EXPLICIT request and is always answered with the
|
|
108
108
|
isolated-install command.
|
|
109
|
+
All manifest/lockfile install evidence — the dependency-free proof AND the package-manager selection (the `packageManager` field, lockfiles) — is read from the worktree's own LIVE files at the moment the posture is resolved (on `--resume` too, where a dirty tree is then refused by the clean-tree verify); MAIN's mutable working tree never steers manager selection.
|
|
109
110
|
|
|
110
111
|
**Honesty:** there is NO preview step on the writers — over-warned by design. The tool never
|
|
111
112
|
commits, never pushes, never runs a subscription CLI. Every content read and regular-file copy
|
package/tools/worktrees.mjs
CHANGED
|
@@ -1374,8 +1374,10 @@ const LOCKFILE_MANAGERS = Object.freeze([
|
|
|
1374
1374
|
const NEUTRAL_INSTALL_ADVICE =
|
|
1375
1375
|
'install command not printed — package manager is ambiguous or unknown; install dependencies in the worktree by hand';
|
|
1376
1376
|
|
|
1377
|
-
|
|
1378
|
-
|
|
1377
|
+
// Advice evidence = the WORKTREE'S OWN LIVE checkout (manifest AND lockfiles): the printed
|
|
1378
|
+
// command runs in the satellite, so what main's working tree happens to hold must not steer it.
|
|
1379
|
+
const resolveInstallAdvice = ({ wtRoot, fs }) => {
|
|
1380
|
+
const pkg = readFileNoFollow(fs, join(wtRoot, 'package.json'));
|
|
1379
1381
|
let manager = null;
|
|
1380
1382
|
let inspectLocks = false;
|
|
1381
1383
|
if (pkg.absent) {
|
|
@@ -1406,7 +1408,7 @@ const resolveInstallAdvice = ({ root, wtRoot, fs }) => {
|
|
|
1406
1408
|
for (const [name, candidate] of LOCKFILE_MANAGERS) {
|
|
1407
1409
|
let st;
|
|
1408
1410
|
try {
|
|
1409
|
-
st = fs.lstat(join(
|
|
1411
|
+
st = fs.lstat(join(wtRoot, name));
|
|
1410
1412
|
} catch (err) {
|
|
1411
1413
|
if (err?.code === 'ENOENT') continue;
|
|
1412
1414
|
return { command: null, instruction: NEUTRAL_INSTALL_ADVICE };
|
|
@@ -1481,9 +1483,10 @@ const declaresNativeBuild = (fs, dir) => lstatNoFollow(fs.lstat, join(dir, 'bind
|
|
|
1481
1483
|
|
|
1482
1484
|
// PROVABLY dependency-free, or nothing — read from the WORKTREE'S OWN LIVE CHECKOUT, never from
|
|
1483
1485
|
// MAIN's mutable working tree: the evidence is what an install run in THIS worktree would actually
|
|
1484
|
-
// read
|
|
1485
|
-
//
|
|
1486
|
-
//
|
|
1486
|
+
// read, taken at the moment the posture is resolved (a post-checkout hook may already have shaped
|
|
1487
|
+
// the checkout; on --resume it follows the session's own edits, in both directions — gained
|
|
1488
|
+
// dependencies revoke the proof, shed ones grant it — the same live lane
|
|
1489
|
+
// as the node_modules symlink probe). A dirty main manifest must neither grant nor revoke a verdict
|
|
1487
1490
|
// about content it does not describe. A `workspaces` field of ANY shape
|
|
1488
1491
|
// is UNKNOWN outright — a workspace install materializes member links and `.bin` shims even with
|
|
1489
1492
|
// zero dependencies, so a workspace tree is never provably install-free. Everything else the tool
|
|
@@ -1512,20 +1515,20 @@ const declaresNoDependencies = ({ wtRoot, fs }) => {
|
|
|
1512
1515
|
// an earlier provision left — an install through it writes into MAIN, and the posture must never
|
|
1513
1516
|
// hide that). Only then may a PROVEN dependency-free checkout short-circuit: a verdict of
|
|
1514
1517
|
// "nothing to install" must not ride an install instruction.
|
|
1515
|
-
const resolveInstallPosture = ({
|
|
1518
|
+
const resolveInstallPosture = ({ wtRoot, dependencyFree, fs }) => {
|
|
1516
1519
|
const nmPath = join(wtRoot, 'node_modules');
|
|
1517
1520
|
const nm = lstatNoFollow(fs.lstat, nmPath);
|
|
1518
1521
|
if (nm !== null && nm.isSymbolicLink()) {
|
|
1519
|
-
const advice = resolveInstallAdvice({
|
|
1522
|
+
const advice = resolveInstallAdvice({ wtRoot, fs });
|
|
1520
1523
|
const separator = advice.command === null ? ' — ' : ' && ';
|
|
1521
1524
|
return `the provisioned node_modules is a symlink into MAIN (an install through it writes into MAIN) — for isolation remove it first: rm ${shellQuoteArg(nmPath)}${separator}${advice.instruction}`;
|
|
1522
1525
|
}
|
|
1523
1526
|
if (dependencyFree) return NO_DEPENDENCIES_POSTURE;
|
|
1524
|
-
return resolveInstallAdvice({
|
|
1527
|
+
return resolveInstallAdvice({ wtRoot, fs }).instruction;
|
|
1525
1528
|
};
|
|
1526
1529
|
|
|
1527
1530
|
const provisionNodeModules = ({ root, rootReal, wtRoot, installFlag, dependencyFree, git, fs, report }) => {
|
|
1528
|
-
const install = resolveInstallAdvice({
|
|
1531
|
+
const install = resolveInstallAdvice({ wtRoot, fs });
|
|
1529
1532
|
if (installFlag) {
|
|
1530
1533
|
const dst = join(wtRoot, 'node_modules');
|
|
1531
1534
|
const existing = lstatNoFollow(fs.lstat, dst);
|
|
@@ -1866,7 +1869,7 @@ const finishProvision = ({ root, rootReal, targetPath, slug, branch, flags, seed
|
|
|
1866
1869
|
includes: includesRecorded,
|
|
1867
1870
|
nodeModules: nodeModulesMode,
|
|
1868
1871
|
vscode: vscodeMode,
|
|
1869
|
-
install: resolveInstallPosture({
|
|
1872
|
+
install: resolveInstallPosture({ wtRoot: targetPath, dependencyFree, fs }),
|
|
1870
1873
|
...orientationFields({ root, slug }),
|
|
1871
1874
|
},
|
|
1872
1875
|
fs,
|