agentplane 0.2.25 → 0.3.1
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/README.md +3 -1
- package/assets/AGENTS.md +123 -526
- package/assets/agents/UPGRADER.json +10 -9
- package/assets/framework.manifest.json +112 -7
- package/assets/policy/check-routing.mjs +180 -0
- package/assets/policy/dod.code.md +25 -0
- package/assets/policy/dod.core.md +32 -0
- package/assets/policy/dod.docs.md +32 -0
- package/assets/policy/examples/migration-note.md +6 -0
- package/assets/policy/examples/pr-note.md +16 -0
- package/assets/policy/examples/unit-test-pattern.md +19 -0
- package/assets/policy/governance.md +37 -0
- package/assets/policy/incidents.md +36 -0
- package/assets/policy/security.must.md +7 -0
- package/assets/policy/workflow.branch_pr.md +34 -0
- package/assets/policy/workflow.direct.md +46 -0
- package/assets/policy/workflow.md +9 -0
- package/assets/policy/workflow.release.md +31 -0
- package/assets/policy/workflow.upgrade.md +20 -0
- package/bin/agentplane.js +47 -57
- package/bin/dist-guard.js +124 -0
- package/dist/.build-manifest.json +11 -0
- package/dist/agents/agents-template.d.ts +7 -0
- package/dist/agents/agents-template.d.ts.map +1 -1
- package/dist/agents/agents-template.js +41 -2
- package/dist/backends/task-backend/local-backend.d.ts +2 -0
- package/dist/backends/task-backend/local-backend.d.ts.map +1 -1
- package/dist/backends/task-backend/local-backend.js +12 -1
- package/dist/backends/task-backend/redmine/mapping.d.ts.map +1 -1
- package/dist/backends/task-backend/redmine/mapping.js +26 -1
- package/dist/backends/task-backend/redmine-backend.d.ts +4 -0
- package/dist/backends/task-backend/redmine-backend.d.ts.map +1 -1
- package/dist/backends/task-backend/redmine-backend.js +92 -9
- package/dist/backends/task-backend/shared/types.d.ts +1 -0
- package/dist/backends/task-backend/shared/types.d.ts.map +1 -1
- package/dist/backends/task-index.d.ts.map +1 -1
- package/dist/backends/task-index.js +8 -1
- package/dist/cli/command-guide.d.ts.map +1 -1
- package/dist/cli/command-guide.js +39 -17
- package/dist/cli/command-snippets.d.ts +24 -0
- package/dist/cli/command-snippets.d.ts.map +1 -0
- package/dist/cli/command-snippets.js +23 -0
- package/dist/cli/reason-codes.d.ts +9 -0
- package/dist/cli/reason-codes.d.ts.map +1 -0
- package/dist/cli/reason-codes.js +79 -0
- package/dist/cli/recipes-bundled.d.ts +1 -0
- package/dist/cli/recipes-bundled.d.ts.map +1 -1
- package/dist/cli/recipes-bundled.js +4 -1
- package/dist/cli/run-cli/command-catalog.d.ts +1 -1
- package/dist/cli/run-cli/command-catalog.d.ts.map +1 -1
- package/dist/cli/run-cli/command-catalog.js +40 -1
- package/dist/cli/run-cli/commands/config.d.ts +5 -0
- package/dist/cli/run-cli/commands/config.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/config.js +86 -1
- package/dist/cli/run-cli/commands/core.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/core.js +57 -2
- package/dist/cli/run-cli/commands/ide.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/ide.js +8 -3
- package/dist/cli/run-cli/commands/init/recipes.d.ts +5 -1
- package/dist/cli/run-cli/commands/init/recipes.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init/recipes.js +24 -4
- package/dist/cli/run-cli/commands/init/ui.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init/ui.js +1 -2
- package/dist/cli/run-cli/commands/init/write-agents.d.ts +2 -0
- package/dist/cli/run-cli/commands/init/write-agents.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init/write-agents.js +24 -5
- package/dist/cli/run-cli/commands/init/write-workflow.d.ts +12 -0
- package/dist/cli/run-cli/commands/init/write-workflow.d.ts.map +1 -0
- package/dist/cli/run-cli/commands/init/write-workflow.js +58 -0
- package/dist/cli/run-cli/commands/init.d.ts +4 -1
- package/dist/cli/run-cli/commands/init.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init.js +126 -48
- package/dist/cli/run-cli.d.ts.map +1 -1
- package/dist/cli/run-cli.js +195 -8
- package/dist/commands/backend/sync.command.d.ts.map +1 -1
- package/dist/commands/backend/sync.command.js +7 -6
- package/dist/commands/backend.d.ts.map +1 -1
- package/dist/commands/backend.js +2 -0
- package/dist/commands/doctor.run.d.ts.map +1 -1
- package/dist/commands/doctor.run.js +107 -16
- package/dist/commands/guard/impl/commands.d.ts.map +1 -1
- package/dist/commands/guard/impl/commands.js +12 -6
- package/dist/commands/recipes/impl/commands/install.d.ts.map +1 -1
- package/dist/commands/recipes/impl/commands/install.js +36 -13
- package/dist/commands/recipes/impl/scenario.d.ts.map +1 -1
- package/dist/commands/recipes/impl/scenario.js +25 -0
- package/dist/commands/recipes/impl/types.d.ts +4 -0
- package/dist/commands/recipes/impl/types.d.ts.map +1 -1
- package/dist/commands/release/apply.command.d.ts.map +1 -1
- package/dist/commands/release/apply.command.js +9 -4
- package/dist/commands/release/plan.command.d.ts.map +1 -1
- package/dist/commands/release/plan.command.js +9 -3
- package/dist/commands/scenario/impl/commands.d.ts.map +1 -1
- package/dist/commands/scenario/impl/commands.js +74 -3
- package/dist/commands/scenario/impl/report.d.ts +8 -0
- package/dist/commands/scenario/impl/report.d.ts.map +1 -1
- package/dist/commands/scenario/impl/report.js +1 -0
- package/dist/commands/shared/reconcile-check.d.ts +7 -0
- package/dist/commands/shared/reconcile-check.d.ts.map +1 -0
- package/dist/commands/shared/reconcile-check.js +60 -0
- package/dist/commands/sync.command.d.ts.map +1 -1
- package/dist/commands/sync.command.js +9 -2
- package/dist/commands/task/add.d.ts.map +1 -1
- package/dist/commands/task/add.js +32 -0
- package/dist/commands/task/doc.command.d.ts.map +1 -1
- package/dist/commands/task/doc.command.js +1 -0
- package/dist/commands/task/finish.d.ts.map +1 -1
- package/dist/commands/task/finish.js +11 -1
- package/dist/commands/task/list.d.ts.map +1 -1
- package/dist/commands/task/list.js +2 -1
- package/dist/commands/task/list.spec.d.ts.map +1 -1
- package/dist/commands/task/list.spec.js +7 -0
- package/dist/commands/task/new.d.ts.map +1 -1
- package/dist/commands/task/new.js +41 -4
- package/dist/commands/task/next.d.ts.map +1 -1
- package/dist/commands/task/next.js +2 -1
- package/dist/commands/task/next.spec.d.ts.map +1 -1
- package/dist/commands/task/next.spec.js +7 -0
- package/dist/commands/task/plan.d.ts.map +1 -1
- package/dist/commands/task/plan.js +7 -1
- package/dist/commands/task/search.d.ts.map +1 -1
- package/dist/commands/task/search.js +2 -1
- package/dist/commands/task/search.spec.d.ts.map +1 -1
- package/dist/commands/task/search.spec.js +7 -0
- package/dist/commands/task/shared.d.ts +14 -0
- package/dist/commands/task/shared.d.ts.map +1 -1
- package/dist/commands/task/shared.js +58 -1
- package/dist/commands/task/start-ready.js +1 -1
- package/dist/commands/task/verify-record.d.ts.map +1 -1
- package/dist/commands/task/verify-record.js +2 -0
- package/dist/commands/upgrade.command.d.ts.map +1 -1
- package/dist/commands/upgrade.command.js +2 -2
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +263 -294
- package/dist/commands/workflow-build.command.d.ts +8 -0
- package/dist/commands/workflow-build.command.d.ts.map +1 -0
- package/dist/commands/workflow-build.command.js +103 -0
- package/dist/commands/workflow-playbook.command.d.ts +10 -0
- package/dist/commands/workflow-playbook.command.d.ts.map +1 -0
- package/dist/commands/workflow-playbook.command.js +173 -0
- package/dist/commands/workflow-restore.command.d.ts +5 -0
- package/dist/commands/workflow-restore.command.d.ts.map +1 -0
- package/dist/commands/workflow-restore.command.js +30 -0
- package/dist/commands/workflow.command.d.ts +6 -0
- package/dist/commands/workflow.command.d.ts.map +1 -0
- package/dist/commands/workflow.command.js +36 -0
- package/dist/harness/dynamic-tool-contract.d.ts +29 -0
- package/dist/harness/dynamic-tool-contract.d.ts.map +1 -0
- package/dist/harness/dynamic-tool-contract.js +86 -0
- package/dist/harness/hooks-lifecycle.d.ts +27 -0
- package/dist/harness/hooks-lifecycle.d.ts.map +1 -0
- package/dist/harness/hooks-lifecycle.js +67 -0
- package/dist/harness/index.d.ts +9 -0
- package/dist/harness/index.d.ts.map +1 -0
- package/dist/harness/index.js +8 -0
- package/dist/harness/reconcile.d.ts +37 -0
- package/dist/harness/reconcile.d.ts.map +1 -0
- package/dist/harness/reconcile.js +42 -0
- package/dist/harness/retry-policy.d.ts +31 -0
- package/dist/harness/retry-policy.d.ts.map +1 -0
- package/dist/harness/retry-policy.js +33 -0
- package/dist/harness/scheduler.d.ts +18 -0
- package/dist/harness/scheduler.d.ts.map +1 -0
- package/dist/harness/scheduler.js +55 -0
- package/dist/harness/state-machine.d.ts +17 -0
- package/dist/harness/state-machine.d.ts.map +1 -0
- package/dist/harness/state-machine.js +70 -0
- package/dist/harness/token-accounting.d.ts +19 -0
- package/dist/harness/token-accounting.d.ts.map +1 -0
- package/dist/harness/token-accounting.js +77 -0
- package/dist/harness/workspace-safety.d.ts +14 -0
- package/dist/harness/workspace-safety.d.ts.map +1 -0
- package/dist/harness/workspace-safety.js +62 -0
- package/dist/recipes/bundled-recipes.d.ts +4 -0
- package/dist/recipes/bundled-recipes.d.ts.map +1 -1
- package/dist/recipes/bundled-recipes.js +11 -0
- package/dist/shared/errors.d.ts +6 -0
- package/dist/shared/errors.d.ts.map +1 -1
- package/dist/shared/errors.js +1 -0
- package/dist/shared/policy-gateway.d.ts +15 -0
- package/dist/shared/policy-gateway.d.ts.map +1 -0
- package/dist/shared/policy-gateway.js +49 -0
- package/dist/shared/protected-paths.d.ts.map +1 -1
- package/dist/shared/protected-paths.js +1 -0
- package/dist/shared/runtime-artifacts.d.ts +2 -2
- package/dist/shared/runtime-artifacts.d.ts.map +1 -1
- package/dist/shared/runtime-artifacts.js +4 -0
- package/dist/workflow-runtime/build.d.ts +4 -0
- package/dist/workflow-runtime/build.d.ts.map +1 -0
- package/dist/workflow-runtime/build.js +126 -0
- package/dist/workflow-runtime/enforcement.d.ts +3 -0
- package/dist/workflow-runtime/enforcement.d.ts.map +1 -0
- package/dist/workflow-runtime/enforcement.js +10 -0
- package/dist/workflow-runtime/file-ops.d.ts +11 -0
- package/dist/workflow-runtime/file-ops.d.ts.map +1 -0
- package/dist/workflow-runtime/file-ops.js +248 -0
- package/dist/workflow-runtime/fix.d.ts +9 -0
- package/dist/workflow-runtime/fix.d.ts.map +1 -0
- package/dist/workflow-runtime/fix.js +107 -0
- package/dist/workflow-runtime/index.d.ts +11 -0
- package/dist/workflow-runtime/index.d.ts.map +1 -0
- package/dist/workflow-runtime/index.js +10 -0
- package/dist/workflow-runtime/markdown.d.ts +10 -0
- package/dist/workflow-runtime/markdown.d.ts.map +1 -0
- package/dist/workflow-runtime/markdown.js +147 -0
- package/dist/workflow-runtime/observability.d.ts +12 -0
- package/dist/workflow-runtime/observability.d.ts.map +1 -0
- package/dist/workflow-runtime/observability.js +14 -0
- package/dist/workflow-runtime/paths.d.ts +3 -0
- package/dist/workflow-runtime/paths.d.ts.map +1 -0
- package/dist/workflow-runtime/paths.js +11 -0
- package/dist/workflow-runtime/template.d.ts +7 -0
- package/dist/workflow-runtime/template.d.ts.map +1 -0
- package/dist/workflow-runtime/template.js +94 -0
- package/dist/workflow-runtime/types.d.ts +68 -0
- package/dist/workflow-runtime/types.d.ts.map +1 -0
- package/dist/workflow-runtime/types.js +1 -0
- package/dist/workflow-runtime/validate.d.ts +8 -0
- package/dist/workflow-runtime/validate.d.ts.map +1 -0
- package/dist/workflow-runtime/validate.js +331 -0
- package/package.json +3 -3
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Workflow: release
|
|
2
|
+
|
|
3
|
+
Use this module when task touches release/version/publish flows.
|
|
4
|
+
|
|
5
|
+
## Required sequence
|
|
6
|
+
|
|
7
|
+
1. CHECKPOINT A: confirm clean tracked tree and approved scope.
|
|
8
|
+
2. CHECKPOINT B: generate release plan and freeze version/tag target.
|
|
9
|
+
3. Generate release notes with complete human-readable coverage of all task-level changes.
|
|
10
|
+
4. Run release prepublish checks.
|
|
11
|
+
5. CHECKPOINT C: apply release and push/tag only after all gates pass.
|
|
12
|
+
6. Record release evidence (commands, outputs, resulting version/tag).
|
|
13
|
+
|
|
14
|
+
## Command contract
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
git status --short --untracked-files=no
|
|
18
|
+
agentplane task plan set <task-id> --text "Release plan: version=<v>, tag=<t>, scope=<...>" --updated-by <ROLE>
|
|
19
|
+
agentplane task plan approve <task-id> --by ORCHESTRATOR
|
|
20
|
+
agentplane release plan --patch
|
|
21
|
+
agentplane release apply --push --yes
|
|
22
|
+
agentplane verify <task-id> --ok|--rework --by <ROLE> --note "Release checks: ..."
|
|
23
|
+
agentplane finish <task-id> --author <ROLE> --body "Verified: release" --result "Release <v> published" --commit <git-rev> --close-commit
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Constraints
|
|
27
|
+
|
|
28
|
+
- MUST NOT perform irreversible release actions before explicit approval.
|
|
29
|
+
- MUST NOT skip parity/version checks.
|
|
30
|
+
- MUST NOT bypass required notes validation.
|
|
31
|
+
- MUST stop and request re-approval if release scope/tag/version changes.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Workflow: upgrade
|
|
2
|
+
|
|
3
|
+
Use this module when task runs `agentplane upgrade` or touches `.agentplane/.upgrade/**`.
|
|
4
|
+
|
|
5
|
+
## Required sequence
|
|
6
|
+
|
|
7
|
+
1. Run upgrade command and capture run directory.
|
|
8
|
+
2. Read upgrade review report:
|
|
9
|
+
- agent mode: `.agentplane/.upgrade/agent/<runId>/review.json`
|
|
10
|
+
- auto mode: `.agentplane/.upgrade/last-review.json`
|
|
11
|
+
3. Apply upgrade as replace-all for managed files (`agentplane upgrade --auto`), excluding task data paths.
|
|
12
|
+
4. For `.agentplane/policy/incidents.md`, keep existing local content and append incoming policy content (never replace non-empty local incidents file).
|
|
13
|
+
5. Ensure the upgrade produced a dedicated upgrade commit with version in commit message.
|
|
14
|
+
6. Verify policy/agent consistency and routing checks.
|
|
15
|
+
7. Record run path and reviewed files in task notes.
|
|
16
|
+
|
|
17
|
+
## Minimum verification
|
|
18
|
+
|
|
19
|
+
- `node .agentplane/policy/check-routing.mjs`
|
|
20
|
+
- `agentplane agents`
|
package/bin/agentplane.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { stat } from "node:fs/promises";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { distExists, isPackageBuildFresh } from "./dist-guard.js";
|
|
5
6
|
|
|
6
7
|
async function exists(p) {
|
|
7
8
|
try {
|
|
@@ -35,47 +36,18 @@ async function maybeWarnGlobalBinaryInRepoCheckout() {
|
|
|
35
36
|
);
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
function
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (/\.(unit\.)?test\.[cm]?ts$/.test(normalized)) return true;
|
|
45
|
-
if (/\.(unit\.)?test\.tsx$/.test(normalized)) return true;
|
|
39
|
+
function isHooksRunCommitMsgInvocation(argv) {
|
|
40
|
+
const args = argv.slice(2).map((value) => String(value ?? "").trim());
|
|
41
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
42
|
+
if (args[i] !== "hooks") continue;
|
|
43
|
+
return args[i + 1] === "run" && args[i + 2] === "commit-msg";
|
|
44
|
+
}
|
|
46
45
|
return false;
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const stack = [dir];
|
|
53
|
-
while (stack.length > 0) {
|
|
54
|
-
const current = stack.pop();
|
|
55
|
-
if (!current) continue;
|
|
56
|
-
let entries;
|
|
57
|
-
try {
|
|
58
|
-
entries = await readdir(current, { withFileTypes: true });
|
|
59
|
-
} catch {
|
|
60
|
-
continue;
|
|
61
|
-
}
|
|
62
|
-
for (const entry of entries) {
|
|
63
|
-
const abs = path.join(current, entry.name);
|
|
64
|
-
if (entry.isDirectory()) {
|
|
65
|
-
stack.push(abs);
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
if (!entry.isFile()) continue;
|
|
69
|
-
if (isTestLikePath(abs)) continue;
|
|
70
|
-
try {
|
|
71
|
-
const s = await stat(abs);
|
|
72
|
-
if (s.mtimeMs > newest) newest = s.mtimeMs;
|
|
73
|
-
} catch {
|
|
74
|
-
// ignore
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return newest;
|
|
48
|
+
function isPathInside(baseDir, targetPath) {
|
|
49
|
+
const rel = path.relative(path.resolve(baseDir), path.resolve(targetPath));
|
|
50
|
+
return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel));
|
|
79
51
|
}
|
|
80
52
|
|
|
81
53
|
async function assertDistUpToDate() {
|
|
@@ -85,8 +57,7 @@ async function assertDistUpToDate() {
|
|
|
85
57
|
if (!inRepo) return true;
|
|
86
58
|
|
|
87
59
|
const allowStale = (process.env.AGENTPLANE_DEV_ALLOW_STALE_DIST ?? "").trim() === "1";
|
|
88
|
-
|
|
89
|
-
if (!(await exists(agentplaneDistDir))) {
|
|
60
|
+
if (!(await distExists(agentplaneRoot))) {
|
|
90
61
|
process.stderr.write(
|
|
91
62
|
"error: agentplane dist is missing for this repo checkout.\n" +
|
|
92
63
|
"Fix:\n" +
|
|
@@ -97,29 +68,48 @@ async function assertDistUpToDate() {
|
|
|
97
68
|
return false;
|
|
98
69
|
}
|
|
99
70
|
|
|
100
|
-
const agentplaneSrcDir = path.join(agentplaneRoot, "src");
|
|
101
|
-
const agentplaneSrcNewest = await newestMtimeMsInDir(agentplaneSrcDir);
|
|
102
|
-
const agentplaneDistNewest = await newestMtimeMsInDir(agentplaneDistDir);
|
|
103
|
-
const isStaleAgentplane = agentplaneSrcNewest > agentplaneDistNewest;
|
|
104
|
-
|
|
105
|
-
// If we're in the monorepo, also check core dist because the CLI imports it.
|
|
106
71
|
const repoRoot = path.resolve(agentplaneRoot, "..", "..");
|
|
107
72
|
const coreRoot = path.join(repoRoot, "packages", "core");
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
73
|
+
const checks = [
|
|
74
|
+
{
|
|
75
|
+
name: "agentplane",
|
|
76
|
+
root: agentplaneRoot,
|
|
77
|
+
watchedPaths: ["src", "bin/agentplane.js", "bin/dist-guard.js"],
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
if (await exists(path.join(coreRoot, "src")))
|
|
81
|
+
checks.push({ name: "core", root: coreRoot, watchedPaths: ["src"] });
|
|
82
|
+
|
|
83
|
+
const staleReasons = [];
|
|
84
|
+
for (const check of checks) {
|
|
85
|
+
const result = await isPackageBuildFresh(check.root, { watchedPaths: check.watchedPaths });
|
|
86
|
+
if (!result.ok) {
|
|
87
|
+
const detail =
|
|
88
|
+
Array.isArray(result.changedPaths) && result.changedPaths.length > 0
|
|
89
|
+
? `(${result.changedPaths.slice(0, 5).join(", ")}${result.changedPaths.length > 5 ? ", ..." : ""})`
|
|
90
|
+
: "";
|
|
91
|
+
staleReasons.push(`${check.name}:${result.reason}${detail}`);
|
|
92
|
+
}
|
|
115
93
|
}
|
|
116
94
|
|
|
117
|
-
if (
|
|
95
|
+
if (staleReasons.length > 0 && !allowStale) {
|
|
96
|
+
const runningInsideCheckout = isPathInside(repoRoot, process.cwd());
|
|
97
|
+
if (!runningInsideCheckout) {
|
|
98
|
+
process.stderr.write(
|
|
99
|
+
"warning: linked development binary has a stale build, but current working directory is outside the agentplane checkout.\n" +
|
|
100
|
+
"proceeding with existing dist output.\n" +
|
|
101
|
+
`detected: ${staleReasons.join(", ")}\n` +
|
|
102
|
+
"tip: rebuild (`bun run --filter=@agentplaneorg/core build && bun run --filter=agentplane build`) or reinstall from npm for stable global usage.\n",
|
|
103
|
+
);
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
|
|
118
107
|
process.stderr.write(
|
|
119
|
-
"error: refusing to run a stale repo build (
|
|
108
|
+
"error: refusing to run a stale repo build (manifest/git quick-check failed).\n" +
|
|
120
109
|
"Fix:\n" +
|
|
121
110
|
" bun run --filter=@agentplaneorg/core build\n" +
|
|
122
111
|
" bun run --filter=agentplane build\n" +
|
|
112
|
+
`Detected: ${staleReasons.join(", ")}\n` +
|
|
123
113
|
"Override (not recommended): set AGENTPLANE_DEV_ALLOW_STALE_DIST=1\n",
|
|
124
114
|
);
|
|
125
115
|
process.exitCode = 2;
|
|
@@ -130,5 +120,5 @@ async function assertDistUpToDate() {
|
|
|
130
120
|
}
|
|
131
121
|
|
|
132
122
|
await maybeWarnGlobalBinaryInRepoCheckout();
|
|
133
|
-
const ok = await assertDistUpToDate();
|
|
123
|
+
const ok = isHooksRunCommitMsgInvocation(process.argv) ? true : await assertDistUpToDate();
|
|
134
124
|
if (ok) await import("../dist/cli.js");
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { readFile, stat } from "node:fs/promises";
|
|
4
|
+
|
|
5
|
+
async function exists(p) {
|
|
6
|
+
try {
|
|
7
|
+
await stat(p);
|
|
8
|
+
return true;
|
|
9
|
+
} catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async function readJsonIfExists(p) {
|
|
15
|
+
let raw = "";
|
|
16
|
+
try {
|
|
17
|
+
raw = await readFile(p, "utf8");
|
|
18
|
+
} catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(raw);
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function resolveGitHead(cwd) {
|
|
29
|
+
try {
|
|
30
|
+
return execFileSync("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf8" }).trim() || null;
|
|
31
|
+
} catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function listGitPaths(cwd, args) {
|
|
37
|
+
try {
|
|
38
|
+
const out = execFileSync("git", args, { cwd, encoding: "utf8" });
|
|
39
|
+
return out
|
|
40
|
+
.split(/\r?\n/u)
|
|
41
|
+
.map((line) => line.trim())
|
|
42
|
+
.filter(Boolean);
|
|
43
|
+
} catch {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function uniqueSorted(values) {
|
|
49
|
+
return [...new Set(values)].toSorted((a, b) => a.localeCompare(b));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function workingTreeChangedPaths(cwd, watchedPaths) {
|
|
53
|
+
const lines = listGitPaths(cwd, [
|
|
54
|
+
"status",
|
|
55
|
+
"--porcelain",
|
|
56
|
+
"--untracked-files=all",
|
|
57
|
+
"--",
|
|
58
|
+
...watchedPaths,
|
|
59
|
+
]);
|
|
60
|
+
return uniqueSorted(lines.map((line) => line.slice(3).trim()).filter(Boolean));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function committedChangedPathsSince(cwd, fromGitHead, watchedPaths) {
|
|
64
|
+
if (!fromGitHead) return [];
|
|
65
|
+
return uniqueSorted(
|
|
66
|
+
listGitPaths(cwd, ["diff", "--name-only", `${fromGitHead}..HEAD`, "--", ...watchedPaths]),
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function fileMtimeMs(p) {
|
|
71
|
+
try {
|
|
72
|
+
const s = await stat(p);
|
|
73
|
+
if (!s.isFile()) return null;
|
|
74
|
+
return s.mtimeMs;
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export async function isPackageBuildFresh(packageRoot, options = {}) {
|
|
81
|
+
const watchedPaths = options.watchedPaths ?? ["src"];
|
|
82
|
+
const manifestPath = path.join(packageRoot, "dist", ".build-manifest.json");
|
|
83
|
+
const manifest = await readJsonIfExists(manifestPath);
|
|
84
|
+
if (!manifest || manifest.schema_version !== 1) {
|
|
85
|
+
return { ok: false, reason: "manifest_missing", changedPaths: [] };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const currentHead = resolveGitHead(packageRoot);
|
|
89
|
+
const changedPaths = uniqueSorted([
|
|
90
|
+
...committedChangedPathsSince(packageRoot, manifest.git_head, watchedPaths),
|
|
91
|
+
...workingTreeChangedPaths(packageRoot, watchedPaths),
|
|
92
|
+
]);
|
|
93
|
+
|
|
94
|
+
if (changedPaths.length > 0) {
|
|
95
|
+
return { ok: false, reason: "watched_paths_changed", changedPaths };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const srcCliMtimeMs = await fileMtimeMs(path.join(packageRoot, "src", "cli.ts"));
|
|
99
|
+
const srcIndexMtimeMs = await fileMtimeMs(path.join(packageRoot, "src", "index.ts"));
|
|
100
|
+
if (
|
|
101
|
+
typeof manifest.src_cli_mtime_ms === "number" &&
|
|
102
|
+
typeof srcCliMtimeMs === "number" &&
|
|
103
|
+
srcCliMtimeMs > manifest.src_cli_mtime_ms
|
|
104
|
+
) {
|
|
105
|
+
return { ok: false, reason: "src_cli_newer_than_manifest", changedPaths: [] };
|
|
106
|
+
}
|
|
107
|
+
if (
|
|
108
|
+
typeof manifest.src_index_mtime_ms === "number" &&
|
|
109
|
+
typeof srcIndexMtimeMs === "number" &&
|
|
110
|
+
srcIndexMtimeMs > manifest.src_index_mtime_ms
|
|
111
|
+
) {
|
|
112
|
+
return { ok: false, reason: "src_index_newer_than_manifest", changedPaths: [] };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (manifest.git_head && currentHead && manifest.git_head !== currentHead) {
|
|
116
|
+
return { ok: true, reason: "fresh_after_non_runtime_head_change", changedPaths: [] };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return { ok: true, reason: "fresh", changedPaths: [] };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export async function distExists(packageRoot) {
|
|
123
|
+
return await exists(path.join(packageRoot, "dist"));
|
|
124
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"package_dir": "/home/runner/work/agentplane/agentplane/packages/agentplane",
|
|
4
|
+
"generated_at": "2026-03-06T15:25:37.651Z",
|
|
5
|
+
"git_head": "1be96fc47916b76925f9bc59ce7d24176216a87f",
|
|
6
|
+
"src_cli_mtime_ms": 1772810682734.0005,
|
|
7
|
+
"src_index_mtime_ms": null,
|
|
8
|
+
"dist_cli_mtime_ms": 1772810737168.81,
|
|
9
|
+
"dist_index_mtime_ms": null,
|
|
10
|
+
"tsbuildinfo_mtime_ms": 1772810737234.8098
|
|
11
|
+
}
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
import { type PolicyGatewayFlavor } from "../shared/policy-gateway.js";
|
|
1
2
|
export type WorkflowMode = "direct" | "branch_pr";
|
|
2
3
|
type AgentTemplate = {
|
|
3
4
|
fileName: string;
|
|
4
5
|
contents: string;
|
|
5
6
|
};
|
|
7
|
+
export type PolicyTemplate = {
|
|
8
|
+
relativePath: string;
|
|
9
|
+
contents: string;
|
|
10
|
+
};
|
|
6
11
|
export declare function loadAgentsTemplate(): Promise<string>;
|
|
7
12
|
export declare function loadAgentTemplates(): Promise<AgentTemplate[]>;
|
|
13
|
+
export declare function loadPolicyTemplates(): Promise<PolicyTemplate[]>;
|
|
8
14
|
export declare function filterAgentsByWorkflow(template: string, workflow: WorkflowMode): string;
|
|
15
|
+
export declare function loadPolicyGatewayTemplate(flavor: PolicyGatewayFlavor): Promise<string>;
|
|
9
16
|
export {};
|
|
10
17
|
//# sourceMappingURL=agents-template.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents-template.d.ts","sourceRoot":"","sources":["../../src/agents/agents-template.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agents-template.d.ts","sourceRoot":"","sources":["../../src/agents/agents-template.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,6BAA6B,CAAC;AAUrC,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,WAAW,CAAC;AAElD,KAAK,aAAa,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAC5D,MAAM,MAAM,cAAc,GAAG;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAwCxE,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAE1D;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAanE;AAsBD,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAerE;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,MAAM,CASvF;AAED,wBAAsB,yBAAyB,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAI5F"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { readdir, readFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { policyGatewayFileName, renderPolicyGatewayTemplateText, } from "../shared/policy-gateway.js";
|
|
4
5
|
const AGENTS_TEMPLATE_URL = new URL("../../assets/AGENTS.md", import.meta.url);
|
|
5
6
|
const AGENTS_DIR_URL = new URL("../../assets/agents/", import.meta.url);
|
|
7
|
+
const POLICY_DIR_URL = new URL("../../assets/policy/", import.meta.url);
|
|
6
8
|
const HEADING_RE = /^(#+)\s+(.*)$/;
|
|
7
9
|
function ensureTrailingNewline(text) {
|
|
8
10
|
return text.endsWith("\n") ? text : `${text}\n`;
|
|
@@ -41,8 +43,7 @@ function removeSections(lines, titles) {
|
|
|
41
43
|
return lines.filter((_line, index) => !shouldRemove.has(index));
|
|
42
44
|
}
|
|
43
45
|
export async function loadAgentsTemplate() {
|
|
44
|
-
|
|
45
|
-
return ensureTrailingNewline(text.trimEnd());
|
|
46
|
+
return loadPolicyGatewayTemplate("codex");
|
|
46
47
|
}
|
|
47
48
|
export async function loadAgentTemplates() {
|
|
48
49
|
const dirPath = fileURLToPath(AGENTS_DIR_URL);
|
|
@@ -56,6 +57,39 @@ export async function loadAgentTemplates() {
|
|
|
56
57
|
}
|
|
57
58
|
return templates;
|
|
58
59
|
}
|
|
60
|
+
async function listFilesRecursive(dirPath, relPrefix = "") {
|
|
61
|
+
const entries = await readdir(dirPath, { withFileTypes: true });
|
|
62
|
+
const sorted = entries.toSorted((a, b) => a.name.localeCompare(b.name));
|
|
63
|
+
const files = [];
|
|
64
|
+
for (const entry of sorted) {
|
|
65
|
+
// Ignore editor/OS hidden metadata files.
|
|
66
|
+
if (entry.name.startsWith("."))
|
|
67
|
+
continue;
|
|
68
|
+
const absPath = path.join(dirPath, entry.name);
|
|
69
|
+
const relPath = relPrefix ? `${relPrefix}/${entry.name}` : entry.name;
|
|
70
|
+
if (entry.isDirectory()) {
|
|
71
|
+
files.push(...(await listFilesRecursive(absPath, relPath)));
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (entry.isFile())
|
|
75
|
+
files.push(relPath);
|
|
76
|
+
}
|
|
77
|
+
return files;
|
|
78
|
+
}
|
|
79
|
+
export async function loadPolicyTemplates() {
|
|
80
|
+
const dirPath = fileURLToPath(POLICY_DIR_URL);
|
|
81
|
+
const relFiles = await listFilesRecursive(dirPath);
|
|
82
|
+
const templates = [];
|
|
83
|
+
for (const relFile of relFiles) {
|
|
84
|
+
const filePath = path.join(dirPath, relFile);
|
|
85
|
+
const contents = await readFile(filePath, "utf8");
|
|
86
|
+
templates.push({
|
|
87
|
+
relativePath: relFile.replaceAll("\\", "/"),
|
|
88
|
+
contents: ensureTrailingNewline(contents.trimEnd()),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return templates;
|
|
92
|
+
}
|
|
59
93
|
export function filterAgentsByWorkflow(template, workflow) {
|
|
60
94
|
const lines = template.replaceAll("\r\n", "\n").split("\n");
|
|
61
95
|
const removeTitles = workflow === "direct"
|
|
@@ -64,3 +98,8 @@ export function filterAgentsByWorkflow(template, workflow) {
|
|
|
64
98
|
const filtered = removeSections(lines, removeTitles);
|
|
65
99
|
return ensureTrailingNewline(filtered.join("\n").trimEnd());
|
|
66
100
|
}
|
|
101
|
+
export async function loadPolicyGatewayTemplate(flavor) {
|
|
102
|
+
const text = await readFile(AGENTS_TEMPLATE_URL, "utf8");
|
|
103
|
+
const rendered = renderPolicyGatewayTemplateText(text, policyGatewayFileName(flavor));
|
|
104
|
+
return ensureTrailingNewline(rendered.trimEnd());
|
|
105
|
+
}
|
|
@@ -3,6 +3,7 @@ export declare class LocalBackend implements TaskBackend {
|
|
|
3
3
|
id: string;
|
|
4
4
|
root: string;
|
|
5
5
|
updatedBy: string;
|
|
6
|
+
private lastListWarnings;
|
|
6
7
|
constructor(settings?: {
|
|
7
8
|
dir?: string;
|
|
8
9
|
updatedBy?: string;
|
|
@@ -12,6 +13,7 @@ export declare class LocalBackend implements TaskBackend {
|
|
|
12
13
|
attempts: number;
|
|
13
14
|
}): Promise<string>;
|
|
14
15
|
listTasks(): Promise<TaskData[]>;
|
|
16
|
+
getLastListWarnings(): string[];
|
|
15
17
|
getTask(taskId: string): Promise<TaskData | null>;
|
|
16
18
|
getTasks(taskIds: string[]): Promise<(TaskData | null)[]>;
|
|
17
19
|
getTaskDoc(taskId: string): Promise<string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-backend.d.ts","sourceRoot":"","sources":["../../../src/backends/task-backend/local-backend.ts"],"names":[],"mappings":"AAqBA,OAAO,EAiBL,KAAK,WAAW,EAChB,KAAK,QAAQ,EACd,MAAM,aAAa,CAAC;AAErB,qBAAa,YAAa,YAAW,WAAW;IAC9C,EAAE,SAAW;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"local-backend.d.ts","sourceRoot":"","sources":["../../../src/backends/task-backend/local-backend.ts"],"names":[],"mappings":"AAqBA,OAAO,EAiBL,KAAK,WAAW,EAChB,KAAK,QAAQ,EACd,MAAM,aAAa,CAAC;AAErB,qBAAa,YAAa,YAAW,WAAW;IAC9C,EAAE,SAAW;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,gBAAgB,CAAgB;gBAE5B,QAAQ,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE;IAKrD,cAAc,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAqB3E,SAAS,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAwHtC,mBAAmB,IAAI,MAAM,EAAE;IAIzB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAoBjD,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC;IAKzD,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAO3C,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAyExC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB1E,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBvE,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAO5C,cAAc,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAoF/D,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAIzD"}
|
|
@@ -9,6 +9,7 @@ export class LocalBackend {
|
|
|
9
9
|
id = "local";
|
|
10
10
|
root;
|
|
11
11
|
updatedBy;
|
|
12
|
+
lastListWarnings = [];
|
|
12
13
|
constructor(settings) {
|
|
13
14
|
this.root = path.resolve(settings?.dir ?? ".agentplane/tasks");
|
|
14
15
|
this.updatedBy = settings?.updatedBy ?? DEFAULT_DOC_UPDATED_BY;
|
|
@@ -38,6 +39,7 @@ export class LocalBackend {
|
|
|
38
39
|
}
|
|
39
40
|
async listTasks() {
|
|
40
41
|
const tasks = [];
|
|
42
|
+
const warnings = [];
|
|
41
43
|
const entries = await readdir(this.root, { withFileTypes: true }).catch(() => []);
|
|
42
44
|
const indexPath = resolveTaskIndexPath(this.root);
|
|
43
45
|
const cachedIndex = await loadTaskIndex(indexPath);
|
|
@@ -65,6 +67,7 @@ export class LocalBackend {
|
|
|
65
67
|
stats = await stat(readme);
|
|
66
68
|
}
|
|
67
69
|
catch {
|
|
70
|
+
warnings.push(`skip:${dirName}: missing_or_unreadable_readme`);
|
|
68
71
|
return null;
|
|
69
72
|
}
|
|
70
73
|
if (!stats.isFile())
|
|
@@ -79,6 +82,7 @@ export class LocalBackend {
|
|
|
79
82
|
text = await readFile(readme, "utf8");
|
|
80
83
|
}
|
|
81
84
|
catch {
|
|
85
|
+
warnings.push(`skip:${dirName}: unreadable_readme`);
|
|
82
86
|
return null;
|
|
83
87
|
}
|
|
84
88
|
let parsed;
|
|
@@ -86,11 +90,14 @@ export class LocalBackend {
|
|
|
86
90
|
parsed = parseTaskReadme(text);
|
|
87
91
|
}
|
|
88
92
|
catch {
|
|
93
|
+
warnings.push(`skip:${dirName}: invalid_readme_frontmatter`);
|
|
89
94
|
return null;
|
|
90
95
|
}
|
|
91
96
|
const fm = parsed.frontmatter;
|
|
92
|
-
if (!isRecord(fm) || Object.keys(fm).length === 0)
|
|
97
|
+
if (!isRecord(fm) || Object.keys(fm).length === 0) {
|
|
98
|
+
warnings.push(`skip:${dirName}: empty_or_invalid_frontmatter`);
|
|
93
99
|
return null;
|
|
100
|
+
}
|
|
94
101
|
const taskId = (typeof fm.id === "string" ? fm.id : dirName).trim();
|
|
95
102
|
const task = taskRecordToData({
|
|
96
103
|
id: taskId,
|
|
@@ -141,8 +148,12 @@ export class LocalBackend {
|
|
|
141
148
|
// Best-effort cache; ignore failures.
|
|
142
149
|
}
|
|
143
150
|
}
|
|
151
|
+
this.lastListWarnings = warnings;
|
|
144
152
|
return tasks;
|
|
145
153
|
}
|
|
154
|
+
getLastListWarnings() {
|
|
155
|
+
return [...this.lastListWarnings];
|
|
156
|
+
}
|
|
146
157
|
async getTask(taskId) {
|
|
147
158
|
const readme = taskReadmePath(this.root, taskId);
|
|
148
159
|
let text = "";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mapping.d.ts","sourceRoot":"","sources":["../../../../src/backends/task-backend/redmine/mapping.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,QAAQ,EACd,MAAM,cAAc,CAAC;AAMtB,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASjE;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIhE;
|
|
1
|
+
{"version":3,"file":"mapping.d.ts","sourceRoot":"","sources":["../../../../src/backends/task-backend/redmine/mapping.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,QAAQ,EACd,MAAM,cAAc,CAAC;AAMtB,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASjE;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIhE;AA2BD,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAChC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,GAAG,QAAQ,GAAG,IAAI,CAwElB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,IAAI,EAAE,QAAQ,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC7F,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAyC1B"}
|
|
@@ -23,6 +23,31 @@ export function doneRatioForStatus(status) {
|
|
|
23
23
|
return 100;
|
|
24
24
|
return 0;
|
|
25
25
|
}
|
|
26
|
+
function inferStatusFromIssue(issue) {
|
|
27
|
+
const statusVal = isRecord(issue.status) ? issue.status : null;
|
|
28
|
+
const statusName = toStringSafe(statusVal?.name).trim().toLowerCase();
|
|
29
|
+
const doneRatio = typeof issue.done_ratio === "number" ? issue.done_ratio : null;
|
|
30
|
+
const isClosed = statusVal?.is_closed === true;
|
|
31
|
+
// Redmine defaults (without explicit status_map) commonly use these ids.
|
|
32
|
+
const statusId = typeof statusVal?.id === "number" ? statusVal.id : null;
|
|
33
|
+
if (statusId === 2)
|
|
34
|
+
return "DOING";
|
|
35
|
+
if (statusId === 3 || statusId === 5 || statusId === 6)
|
|
36
|
+
return "DONE";
|
|
37
|
+
if (isClosed || (doneRatio !== null && doneRatio >= 100))
|
|
38
|
+
return "DONE";
|
|
39
|
+
if (statusName.includes("progress") || statusName.includes("doing"))
|
|
40
|
+
return "DOING";
|
|
41
|
+
if (statusName.includes("done") ||
|
|
42
|
+
statusName.includes("closed") ||
|
|
43
|
+
statusName.includes("resolved") ||
|
|
44
|
+
statusName.includes("complete")) {
|
|
45
|
+
return "DONE";
|
|
46
|
+
}
|
|
47
|
+
if (doneRatio !== null && doneRatio > 0)
|
|
48
|
+
return "DOING";
|
|
49
|
+
return "TODO";
|
|
50
|
+
}
|
|
26
51
|
export function issueToTask(opts) {
|
|
27
52
|
const taskId = opts.taskIdOverride ?? customFieldValue(opts.issue, opts.customFields.task_id);
|
|
28
53
|
if (!taskId)
|
|
@@ -31,7 +56,7 @@ export function issueToTask(opts) {
|
|
|
31
56
|
const statusId = statusVal && typeof statusVal.id === "number" ? statusVal.id : null;
|
|
32
57
|
const status = statusId !== null && opts.reverseStatus.has(statusId)
|
|
33
58
|
? opts.reverseStatus.get(statusId)
|
|
34
|
-
:
|
|
59
|
+
: inferStatusFromIssue(opts.issue);
|
|
35
60
|
const verifyVal = customFieldValue(opts.issue, opts.customFields.verify);
|
|
36
61
|
const commitVal = customFieldValue(opts.issue, opts.customFields.commit);
|
|
37
62
|
const docVal = customFieldValue(opts.issue, opts.customFields.doc);
|
|
@@ -25,6 +25,7 @@ export declare class RedmineBackend implements TaskBackend {
|
|
|
25
25
|
cache: LocalBackend | null;
|
|
26
26
|
issueCache: Map<string, Record<string, unknown>>;
|
|
27
27
|
reverseStatus: Map<number, string>;
|
|
28
|
+
inferredStatusByTaskStatus: Map<string, number> | null;
|
|
28
29
|
constructor(settings: RedmineSettings, opts: {
|
|
29
30
|
cache?: LocalBackend | null;
|
|
30
31
|
});
|
|
@@ -62,6 +63,9 @@ export declare class RedmineBackend implements TaskBackend {
|
|
|
62
63
|
private setIssueCustomFieldValue;
|
|
63
64
|
private listTasksRemote;
|
|
64
65
|
private issueFromPayload;
|
|
66
|
+
private inferStatusIdForTaskStatus;
|
|
67
|
+
private loadInferredStatusByTaskStatus;
|
|
68
|
+
private selectInferredStatus;
|
|
65
69
|
private findIssueByTaskId;
|
|
66
70
|
private issueToTask;
|
|
67
71
|
private taskToIssuePayload;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redmine-backend.d.ts","sourceRoot":"","sources":["../../../src/backends/task-backend/redmine-backend.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AA2BvD,OAAO,EAkBL,KAAK,WAAW,EAChB,KAAK,QAAQ,EAEd,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,qBAAa,cAAe,YAAW,WAAW;IAChD,EAAE,SAAa;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IAC3B,UAAU,uCAA8C;IACxD,aAAa,sBAA6B;
|
|
1
|
+
{"version":3,"file":"redmine-backend.d.ts","sourceRoot":"","sources":["../../../src/backends/task-backend/redmine-backend.ts"],"names":[],"mappings":"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"}
|