@forwardimpact/libwiki 0.2.18 → 0.2.20
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 +2 -2
- package/src/commands/claim.js +3 -1
- package/src/commands/fix.js +11 -6
- package/src/wiki-sync.js +26 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forwardimpact/libwiki",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.20",
|
|
4
4
|
"description": "Wiki lifecycle primitives — stable memory for agent teams so coordination persists across sessions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"wiki",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@forwardimpact/libeval": "^0.1.49",
|
|
51
51
|
"@forwardimpact/libpreflight": "^0.1.0",
|
|
52
52
|
"@forwardimpact/libutil": "^0.1.0",
|
|
53
|
-
"@forwardimpact/libxmr": "^
|
|
53
|
+
"@forwardimpact/libxmr": "^2.0.0"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@forwardimpact/libmock": "^0.1.0"
|
package/src/commands/claim.js
CHANGED
|
@@ -22,7 +22,9 @@ async function pushWiki(wikiSync, runtime, message) {
|
|
|
22
22
|
if (!wikiSync) return;
|
|
23
23
|
try {
|
|
24
24
|
await wikiSync.inheritIdentity();
|
|
25
|
-
|
|
25
|
+
// claim/release contract is a 1-line MEMORY.md change; the pathspec keeps
|
|
26
|
+
// foreign uncommitted files from parallel writers out of the commit.
|
|
27
|
+
const result = await wikiSync.commitAndPush(message, ["MEMORY.md"]);
|
|
26
28
|
if (result.pushed)
|
|
27
29
|
runtime.proc.stdout.write("push: committed and pushed\n");
|
|
28
30
|
} catch (err) {
|
package/src/commands/fix.js
CHANGED
|
@@ -48,9 +48,10 @@ function invariantContract(findings) {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
|
-
* The opening task: the findings, the invariant contract, and the
|
|
52
|
-
*
|
|
53
|
-
* single
|
|
51
|
+
* The opening task: the findings, the invariant contract, and the things the
|
|
52
|
+
* rule hints don't cover — where trimmed history goes (only existing
|
|
53
|
+
* weekly-log files; rotation owns minting new ones), and to prefer a single
|
|
54
|
+
* Write.
|
|
54
55
|
*/
|
|
55
56
|
function composeTask(findings, wikiRoot, projectRoot) {
|
|
56
57
|
return [
|
|
@@ -62,9 +63,13 @@ function composeTask(findings, wikiRoot, projectRoot) {
|
|
|
62
63
|
`by breaking another:`,
|
|
63
64
|
...invariantContract(findings),
|
|
64
65
|
``,
|
|
65
|
-
`Move history out of an over-budget summary into the agent's
|
|
66
|
-
`file (wiki/<agent>-YYYY-Www.md)
|
|
67
|
-
`
|
|
66
|
+
`Move history out of an over-budget summary into the agent's existing`,
|
|
67
|
+
`weekly-log file or its current part (wiki/<agent>-YYYY-Www[-partN].md) —`,
|
|
68
|
+
`never a new summary section, and never a new file: rotation tooling owns`,
|
|
69
|
+
`when part files are created, so do not mint filenames yourself. If the`,
|
|
70
|
+
`trimmed narrative already exists in the weekly log, replace it in the`,
|
|
71
|
+
`summary with a pointer to that file instead of copying it anywhere.`,
|
|
72
|
+
`Prefer a single Write over many Edits.`,
|
|
68
73
|
].join("\n");
|
|
69
74
|
}
|
|
70
75
|
|
package/src/wiki-sync.js
CHANGED
|
@@ -102,9 +102,13 @@ export class WikiSync {
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
/**
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
/**
|
|
106
|
+
* Whether the wiki working tree has no uncommitted changes, optionally
|
|
107
|
+
* limited to `paths`.
|
|
108
|
+
* @param {string[]} [paths] - Pathspecs to scope the check to.
|
|
109
|
+
*/
|
|
110
|
+
async isClean(paths) {
|
|
111
|
+
const r = await this.#git.status({ cwd: this.#wikiDir, paths });
|
|
108
112
|
return r.stdout.trim() === "";
|
|
109
113
|
}
|
|
110
114
|
|
|
@@ -119,14 +123,27 @@ export class WikiSync {
|
|
|
119
123
|
}
|
|
120
124
|
|
|
121
125
|
/**
|
|
122
|
-
* Stage and commit
|
|
126
|
+
* Stage and commit working-tree changes, then fetch, rebase on
|
|
123
127
|
* origin/master (falling back to a merge with -X ours if the rebase fails),
|
|
124
128
|
* and push if HEAD is ahead of origin/master. The commit gate and the push
|
|
125
129
|
* gate are independent so a clean tree with local commits still pushes.
|
|
130
|
+
*
|
|
131
|
+
* Without `paths` the commit sweeps the whole tree (`fit-wiki push`
|
|
132
|
+
* contract). With `paths` the commit is pathspec-scoped so foreign residue
|
|
133
|
+
* from parallel writers in the shared workspace is never swept in; the
|
|
134
|
+
* rebase and merge fallback then run with --autostash because that residue
|
|
135
|
+
* stays uncommitted in the tree.
|
|
136
|
+
*
|
|
137
|
+
* @param {string} message - The commit message.
|
|
138
|
+
* @param {string[]} [paths] - Pathspecs limiting what gets committed.
|
|
126
139
|
*/
|
|
127
|
-
async commitAndPush(message) {
|
|
128
|
-
if (!(await this.isClean())) {
|
|
129
|
-
|
|
140
|
+
async commitAndPush(message, paths) {
|
|
141
|
+
if (!(await this.isClean(paths))) {
|
|
142
|
+
if (paths?.length) {
|
|
143
|
+
await this.#git.commitPaths(message, paths, { cwd: this.#wikiDir });
|
|
144
|
+
} else {
|
|
145
|
+
await this.#git.commitAll(message, { cwd: this.#wikiDir });
|
|
146
|
+
}
|
|
130
147
|
}
|
|
131
148
|
if (!(await this.#hasCommitsAhead())) {
|
|
132
149
|
return { pushed: false, reason: "clean" };
|
|
@@ -134,12 +151,14 @@ export class WikiSync {
|
|
|
134
151
|
await this.fetch();
|
|
135
152
|
const rebase = await this.#git.rebase("origin/master", {
|
|
136
153
|
cwd: this.#wikiDir,
|
|
154
|
+
autostash: true,
|
|
137
155
|
});
|
|
138
156
|
if (rebase.exitCode !== 0) {
|
|
139
157
|
await this.#git.rebaseAbort({ cwd: this.#wikiDir });
|
|
140
158
|
await this.#git.mergeOursStrategy({
|
|
141
159
|
cwd: this.#wikiDir,
|
|
142
160
|
ref: "origin/master",
|
|
161
|
+
autostash: true,
|
|
143
162
|
});
|
|
144
163
|
}
|
|
145
164
|
// Resolve auth first so a misconfigured `resolveToken` still surfaces; the
|