@andyqiu/codeforge 0.5.13 → 0.5.15
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/bin/codeforge.mjs +1 -1
- package/dist/index.js +41 -21
- package/package.json +5 -10
- package/scripts/sync-agent-models.mjs +8 -0
package/bin/codeforge.mjs
CHANGED
|
@@ -115,7 +115,7 @@ function installOpencode({ scope, dryRun, extraArgs, quiet = false }) {
|
|
|
115
115
|
if (dryRun) flagArgs.push("--dry-run")
|
|
116
116
|
}
|
|
117
117
|
const all = [...baseArgs, ...flagArgs, ...(extraArgs ?? [])]
|
|
118
|
-
log(`opencode: ${cmd} ${all.join(" ")}`)
|
|
118
|
+
if (!quiet) log(`opencode: ${cmd} ${all.join(" ")}`)
|
|
119
119
|
const r = spawnSync(cmd, all, { stdio: quiet ? "pipe" : "inherit", cwd: REPO_ROOT })
|
|
120
120
|
if (quiet && r.status !== 0) {
|
|
121
121
|
if (r.stderr) process.stderr.write(r.stderr)
|
package/dist/index.js
CHANGED
|
@@ -13269,8 +13269,8 @@ async function mergeSessionBack(opts) {
|
|
|
13269
13269
|
});
|
|
13270
13270
|
throw new Error(`mergeSessionBack: squash merge 失败(已 reset 主仓兜底): ${err.message}`);
|
|
13271
13271
|
}
|
|
13272
|
-
const
|
|
13273
|
-
if (
|
|
13272
|
+
const buildScript = await getBuildScript(mainRoot);
|
|
13273
|
+
if (buildScript) {
|
|
13274
13274
|
const stagedRaw = await runGit2(mainRoot, [
|
|
13275
13275
|
"diff",
|
|
13276
13276
|
"--cached",
|
|
@@ -13281,18 +13281,18 @@ async function mergeSessionBack(opts) {
|
|
|
13281
13281
|
const canSkipDevOnce = await shouldSkipDevOnce(mainRoot, stagedPaths);
|
|
13282
13282
|
if (canSkipDevOnce) {
|
|
13283
13283
|
const sourceCount = stagedPaths.filter((p) => /^(plugins|lib|src)\//.test(p) && !/\.(md|test\.ts)$/.test(p)).length;
|
|
13284
|
-
console.log(`[session-worktree] skip
|
|
13284
|
+
console.log(`[session-worktree] skip ${buildScript}: dist 已是最新(${sourceCount} staged 源文件 mtime <= dist mtime)`);
|
|
13285
13285
|
} else {
|
|
13286
13286
|
try {
|
|
13287
|
-
await runCmd("npm", ["run",
|
|
13287
|
+
await runCmd("npm", ["run", buildScript], mainRoot);
|
|
13288
13288
|
} catch (err) {
|
|
13289
13289
|
await runGit2(mainRoot, ["reset", "--hard", "HEAD"]).catch(() => {});
|
|
13290
13290
|
const msg = err instanceof Error ? err.message : String(err);
|
|
13291
|
-
throw new Error(
|
|
13291
|
+
throw new Error(`${buildScript} 失败已 reset 主仓: ${msg}`);
|
|
13292
13292
|
}
|
|
13293
13293
|
}
|
|
13294
13294
|
} else {
|
|
13295
|
-
console.
|
|
13295
|
+
console.warn(`[session-worktree] skip build step: neither build:dev nor dev:once configured in ${mainRoot}/package.json`);
|
|
13296
13296
|
}
|
|
13297
13297
|
const squashedRaw = await runGit2(wt, ["log", "--format=%s", `${baseSha}..HEAD`]);
|
|
13298
13298
|
const squashedCommits = squashedRaw.split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
@@ -13430,6 +13430,13 @@ async function packageHasScript(mainRoot, scriptName) {
|
|
|
13430
13430
|
return false;
|
|
13431
13431
|
}
|
|
13432
13432
|
}
|
|
13433
|
+
async function getBuildScript(mainRoot) {
|
|
13434
|
+
if (await packageHasScript(mainRoot, "build:dev"))
|
|
13435
|
+
return "build:dev";
|
|
13436
|
+
if (await packageHasScript(mainRoot, "dev:once"))
|
|
13437
|
+
return "dev:once";
|
|
13438
|
+
return null;
|
|
13439
|
+
}
|
|
13433
13440
|
async function shouldSkipDevOnce(mainRoot, stagedPaths) {
|
|
13434
13441
|
let distMtimeSec;
|
|
13435
13442
|
try {
|
|
@@ -21355,23 +21362,27 @@ var RISK_PATTERNS = [
|
|
|
21355
21362
|
},
|
|
21356
21363
|
{
|
|
21357
21364
|
tag: "write_secrets",
|
|
21358
|
-
|
|
21359
|
-
|
|
21365
|
+
kinds: ["bash", "edit"],
|
|
21366
|
+
re: /(?:^|[\s/"'])(id_[edr]sa|secret\.json|\.env(?:\.\w+)?)(?:$|[\s"'/])|[\w./-]+\.(?:pem|p12)(?:$|[\s"'])|\.ssh\/id_/i,
|
|
21367
|
+
matchOn: ["command", "filePath", "path", "target"]
|
|
21360
21368
|
},
|
|
21361
21369
|
{
|
|
21362
21370
|
tag: "write_etc",
|
|
21363
21371
|
kinds: ["bash", "edit"],
|
|
21364
|
-
re: /(?:^|\s|"|')\/etc
|
|
21372
|
+
re: /(?:^|\s|"|')\/etc\//,
|
|
21373
|
+
matchOn: ["command", "filePath", "path"]
|
|
21365
21374
|
},
|
|
21366
21375
|
{
|
|
21367
21376
|
tag: "write_usr",
|
|
21368
21377
|
kinds: ["bash", "edit"],
|
|
21369
|
-
re: /(?:^|\s|"|')\/usr
|
|
21378
|
+
re: /(?:^|\s|"|')\/usr\//,
|
|
21379
|
+
matchOn: ["command", "filePath", "path"]
|
|
21370
21380
|
},
|
|
21371
21381
|
{
|
|
21372
21382
|
tag: "write_root_home",
|
|
21373
21383
|
kinds: ["bash", "edit"],
|
|
21374
|
-
re: /(?:^|\s|"|')(\/root|\/home\/root)
|
|
21384
|
+
re: /(?:^|\s|"|')(\/root|\/home\/root)\//,
|
|
21385
|
+
matchOn: ["command", "filePath", "path"]
|
|
21375
21386
|
},
|
|
21376
21387
|
{
|
|
21377
21388
|
tag: "internal_url",
|
|
@@ -21774,7 +21785,7 @@ import * as zlib from "node:zlib";
|
|
|
21774
21785
|
// lib/version-injected.ts
|
|
21775
21786
|
function getInjectedVersion() {
|
|
21776
21787
|
try {
|
|
21777
|
-
const v = "0.5.
|
|
21788
|
+
const v = "0.5.15";
|
|
21778
21789
|
if (typeof v === "string" && /^\d+\.\d+\.\d+/.test(v)) {
|
|
21779
21790
|
return v;
|
|
21780
21791
|
}
|
|
@@ -23054,14 +23065,18 @@ var handler24 = workflowEngineServer;
|
|
|
23054
23065
|
import path27 from "node:path";
|
|
23055
23066
|
var PLUGIN_NAME25 = "session-worktree-guard";
|
|
23056
23067
|
logLifecycle(PLUGIN_NAME25, "import", {});
|
|
23057
|
-
var WRITE_INTENT_RE = />(?![=&])|\btee\b|\brm\b|\bmv\b|\bcp\b|\bmkdir\b|\btouch\b|\bchmod\b|\bchown\b|\bln\b/;
|
|
23058
|
-
var READ_ONLY_COMMANDS = /^\s*(?:ls|cat|head|tail|grep|rg|find|fd|wc|stat|file|which|whereis|echo|pwd|cd|pushd|popd|env|printenv|type|less|more|sort|uniq|awk|tr|cut|jq|date|whoami|id|uname|git(?:\s+-C\s+\S+)?\s+(?:log|show|diff|status|branch|tag|remote|config\s+--get|rev-parse|rev-list|ls-files|ls-tree|cat-file|describe|reflog|blame|shortlog|name-rev|symbolic-ref|merge-base|worktree\s+list|stash\s+list|stash\s+show))\b/;
|
|
23059
|
-
var SIDE_EFFECT_TOKEN_RE = />(?![=&])|\|\s*tee\b|\btee\b/;
|
|
23068
|
+
var WRITE_INTENT_RE = />(?![=&])(?!\s*\/dev\/(?:null|stdout|stderr|fd\/\d+)\b)|\btee\b|\brm\b|\bmv\b|\bcp\b|\bmkdir\b|\btouch\b|\bchmod\b|\bchown\b|\bln\b/;
|
|
23069
|
+
var READ_ONLY_COMMANDS = /^\s*(?:ls|cat|head|tail|grep|rg|find|fd|wc|stat|file|which|whereis|echo|pwd|cd|pushd|popd|env|printenv|type|less|more|sort|uniq|awk|tr|cut|jq|date|whoami|id|uname|node|npx|tsc|diff|python3?|git(?:\s+-C\s+\S+)?\s+(?:log|show|diff|status|branch|tag|remote|config\s+--get|rev-parse|rev-list|ls-files|ls-tree|cat-file|describe|reflog|blame|shortlog|name-rev|symbolic-ref|merge-base|worktree\s+list|stash\s+list|stash\s+show))\b/;
|
|
23070
|
+
var SIDE_EFFECT_TOKEN_RE = />(?![=&])(?!\s*\/dev\/(?:null|stdout|stderr|fd\/\d+)\b)|\|\s*tee\b|\btee\b/;
|
|
23060
23071
|
function isReadOnlyBashCommand(command) {
|
|
23061
23072
|
if (!READ_ONLY_COMMANDS.test(command))
|
|
23062
23073
|
return false;
|
|
23063
23074
|
if (SIDE_EFFECT_TOKEN_RE.test(command))
|
|
23064
23075
|
return false;
|
|
23076
|
+
for (const re of INTERPRETER_WRITE_RES) {
|
|
23077
|
+
if (re.test(command))
|
|
23078
|
+
return false;
|
|
23079
|
+
}
|
|
23065
23080
|
return true;
|
|
23066
23081
|
}
|
|
23067
23082
|
var INTERPRETER_WRITE_RES = [
|
|
@@ -23069,6 +23084,9 @@ var INTERPRETER_WRITE_RES = [
|
|
|
23069
23084
|
/node.*writeFile/,
|
|
23070
23085
|
/perl.*>/
|
|
23071
23086
|
];
|
|
23087
|
+
function stripCommitMessageArgs(command) {
|
|
23088
|
+
return command.replace(/(?:^|\s)(?:-m|--message|-F|--file)(?:=|\s+)("[^"]*"|'[^']*')/g, " ");
|
|
23089
|
+
}
|
|
23072
23090
|
function escapeRegex2(s) {
|
|
23073
23091
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
23074
23092
|
}
|
|
@@ -23157,13 +23175,14 @@ function commandContainsMainRootExcludingWorktree(command, mainRoot, worktreePat
|
|
|
23157
23175
|
function detectBashWriteIntent(command, mainRoot) {
|
|
23158
23176
|
if (isReadOnlyBashCommand(command))
|
|
23159
23177
|
return false;
|
|
23160
|
-
|
|
23178
|
+
const sanitized = stripCommitMessageArgs(command);
|
|
23179
|
+
if (WRITE_INTENT_RE.test(sanitized))
|
|
23161
23180
|
return true;
|
|
23162
23181
|
for (const re of INTERPRETER_WRITE_RES) {
|
|
23163
|
-
if (re.test(
|
|
23182
|
+
if (re.test(sanitized))
|
|
23164
23183
|
return true;
|
|
23165
23184
|
}
|
|
23166
|
-
if (buildGitVcsWriteRegex(mainRoot).test(
|
|
23185
|
+
if (buildGitVcsWriteRegex(mainRoot).test(sanitized))
|
|
23167
23186
|
return true;
|
|
23168
23187
|
return false;
|
|
23169
23188
|
}
|
|
@@ -23177,13 +23196,14 @@ function isWriteOperation(toolName, argsObj, mainRoot) {
|
|
|
23177
23196
|
return false;
|
|
23178
23197
|
if (isReadOnlyBashCommand(command))
|
|
23179
23198
|
return false;
|
|
23180
|
-
|
|
23199
|
+
const sanitized = stripCommitMessageArgs(command);
|
|
23200
|
+
if (WRITE_INTENT_RE.test(sanitized))
|
|
23181
23201
|
return true;
|
|
23182
23202
|
for (const re of INTERPRETER_WRITE_RES) {
|
|
23183
|
-
if (re.test(
|
|
23203
|
+
if (re.test(sanitized))
|
|
23184
23204
|
return true;
|
|
23185
23205
|
}
|
|
23186
|
-
if (mainRoot && buildGitVcsWriteRegex(mainRoot).test(
|
|
23206
|
+
if (mainRoot && buildGitVcsWriteRegex(mainRoot).test(sanitized))
|
|
23187
23207
|
return true;
|
|
23188
23208
|
return false;
|
|
23189
23209
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@andyqiu/codeforge",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.15",
|
|
4
4
|
"description": "CodeForge — opencode 的零侵入扩展包",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"build:types": "tsc -p tsconfig.build.json --emitDeclarationOnly",
|
|
34
34
|
"build:watch": "node ./scripts/build-with-version.mjs --watch",
|
|
35
35
|
"dev": "node ./scripts/dev-sync.mjs --watch",
|
|
36
|
-
"dev
|
|
36
|
+
"build:dev": "node ./scripts/dev-sync.mjs",
|
|
37
37
|
"dev-sync": "node ./scripts/dev-sync.mjs",
|
|
38
38
|
"dev-sync:watch": "node ./scripts/dev-sync.mjs --watch",
|
|
39
39
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
@@ -72,14 +72,9 @@
|
|
|
72
72
|
"replay": "node ./scripts/codeforge-replay.mjs",
|
|
73
73
|
"release": "node ./scripts/release.mjs",
|
|
74
74
|
"release:dry": "node ./scripts/release.mjs --dry-run",
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"publish:dry": "bash ./scripts/publish.sh --dry-run",
|
|
79
|
-
"publish:win:patch": "powershell -NoProfile -ExecutionPolicy Bypass -File ./scripts/publish.ps1",
|
|
80
|
-
"publish:win:minor": "powershell -NoProfile -ExecutionPolicy Bypass -File ./scripts/publish.ps1 -Minor",
|
|
81
|
-
"publish:win:major": "powershell -NoProfile -ExecutionPolicy Bypass -File ./scripts/publish.ps1 -Major",
|
|
82
|
-
"publish:win:dry": "powershell -NoProfile -ExecutionPolicy Bypass -File ./scripts/publish.ps1 -DryRun",
|
|
75
|
+
"release:patch": "node ./scripts/release.mjs patch",
|
|
76
|
+
"release:minor": "node ./scripts/release.mjs minor",
|
|
77
|
+
"release:major": "node ./scripts/release.mjs major",
|
|
83
78
|
"prepublishOnly": "npm run build && npm run typecheck && npm test",
|
|
84
79
|
"prepare": "husky"
|
|
85
80
|
},
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
import { promises as fs } from "node:fs"
|
|
26
26
|
import * as path from "node:path"
|
|
27
27
|
import * as url from "node:url"
|
|
28
|
+
import { syncToGlobalOpencode } from "./dev-sync.mjs"
|
|
28
29
|
|
|
29
30
|
const args = new Set(process.argv.slice(2))
|
|
30
31
|
const CHECK = args.has("--check")
|
|
@@ -99,6 +100,13 @@ async function main() {
|
|
|
99
100
|
process.exit(1)
|
|
100
101
|
}
|
|
101
102
|
}
|
|
103
|
+
|
|
104
|
+
// 写盘完成后,把更新后的 agents/*.md 同步到 ~/.config/opencode/agents/
|
|
105
|
+
// 仅在非 DRY/CHECK 模式且有 .codeforge/.dev-marker 时生效(dev-sync.mjs 内部检查 marker)
|
|
106
|
+
if (!DRY && summary.changed.length > 0) {
|
|
107
|
+
console.log("[sync-models] 同步已更新 agents/*.md -> 全局 opencode (ADR:dev-sync-to-global)")
|
|
108
|
+
await syncToGlobalOpencode({ projectRoot: ROOT, dryRun: false })
|
|
109
|
+
}
|
|
102
110
|
}
|
|
103
111
|
|
|
104
112
|
/**
|