agentplane 0.3.6 → 0.3.7
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/dist/.build-manifest.json +106 -96
- package/dist/adapters/task-backend/task-backend-adapter.d.ts +2 -2
- package/dist/adapters/task-backend/task-backend-adapter.d.ts.map +1 -1
- package/dist/adapters/task-backend/task-backend-adapter.js +2 -2
- package/dist/backends/task-backend/local-backend.d.ts +7 -5
- package/dist/backends/task-backend/local-backend.d.ts.map +1 -1
- package/dist/backends/task-backend/local-backend.js +79 -7
- package/dist/backends/task-backend/redmine/env.d.ts +1 -1
- package/dist/backends/task-backend/redmine/env.d.ts.map +1 -1
- package/dist/backends/task-backend/redmine/env.js +3 -0
- package/dist/backends/task-backend/redmine/inspect.d.ts +11 -0
- package/dist/backends/task-backend/redmine/inspect.d.ts.map +1 -0
- package/dist/backends/task-backend/redmine/inspect.js +75 -0
- package/dist/backends/task-backend/redmine/mapping.d.ts.map +1 -1
- package/dist/backends/task-backend/redmine/mapping.js +21 -2
- package/dist/backends/task-backend/redmine/state.d.ts +17 -0
- package/dist/backends/task-backend/redmine/state.d.ts.map +1 -0
- package/dist/backends/task-backend/redmine/state.js +95 -0
- package/dist/backends/task-backend/redmine-backend.d.ts +10 -16
- package/dist/backends/task-backend/redmine-backend.d.ts.map +1 -1
- package/dist/backends/task-backend/redmine-backend.js +205 -15
- package/dist/backends/task-backend/shared/constants.d.ts +1 -1
- package/dist/backends/task-backend/shared/constants.js +1 -1
- package/dist/backends/task-backend/shared/record.d.ts.map +1 -1
- package/dist/backends/task-backend/shared/record.js +20 -1
- package/dist/backends/task-backend/shared/types.d.ts +42 -4
- package/dist/backends/task-backend/shared/types.d.ts.map +1 -1
- package/dist/backends/task-backend/shared.d.ts +1 -1
- package/dist/backends/task-backend/shared.d.ts.map +1 -1
- package/dist/backends/task-backend.d.ts +1 -1
- package/dist/backends/task-backend.d.ts.map +1 -1
- package/dist/backends/task-index.d.ts.map +1 -1
- package/dist/backends/task-index.js +1 -0
- package/dist/cli/run-cli/command-catalog/project.d.ts +1 -1
- package/dist/cli/run-cli/command-catalog/project.d.ts.map +1 -1
- package/dist/cli/run-cli/command-catalog/project.js +3 -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/commands/init/write-env.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init/write-env.js +12 -0
- package/dist/cli/run-cli.test-helpers.d.ts.map +1 -1
- package/dist/cli/run-cli.test-helpers.js +2 -0
- package/dist/commands/backend/sync.command.d.ts +5 -1
- package/dist/commands/backend/sync.command.d.ts.map +1 -1
- package/dist/commands/backend/sync.command.js +67 -3
- package/dist/commands/backend.d.ts +22 -0
- package/dist/commands/backend.d.ts.map +1 -1
- package/dist/commands/backend.js +110 -1
- package/dist/commands/commit.spec.d.ts.map +1 -1
- package/dist/commands/commit.spec.js +30 -6
- package/dist/commands/doctor/workspace.d.ts +8 -0
- package/dist/commands/doctor/workspace.d.ts.map +1 -1
- package/dist/commands/doctor/workspace.js +127 -3
- package/dist/commands/guard/commit.command.d.ts.map +1 -1
- package/dist/commands/guard/commit.command.js +30 -6
- package/dist/commands/guard/impl/allow.d.ts +4 -0
- package/dist/commands/guard/impl/allow.d.ts.map +1 -1
- package/dist/commands/guard/impl/allow.js +14 -3
- package/dist/commands/guard/impl/commands.d.ts.map +1 -1
- package/dist/commands/guard/impl/commands.js +11 -2
- package/dist/commands/shared/task-backend.d.ts +1 -1
- package/dist/commands/shared/task-backend.d.ts.map +1 -1
- package/dist/commands/shared/task-backend.js +9 -0
- package/dist/commands/shared/task-store.d.ts +61 -2
- package/dist/commands/shared/task-store.d.ts.map +1 -1
- package/dist/commands/shared/task-store.js +298 -60
- package/dist/commands/task/block.d.ts.map +1 -1
- package/dist/commands/task/block.js +58 -37
- package/dist/commands/task/close-shared.d.ts.map +1 -1
- package/dist/commands/task/close-shared.js +17 -20
- package/dist/commands/task/comment.d.ts.map +1 -1
- package/dist/commands/task/comment.js +14 -19
- package/dist/commands/task/derive.command.d.ts +1 -0
- package/dist/commands/task/derive.command.d.ts.map +1 -1
- package/dist/commands/task/derive.command.js +15 -2
- package/dist/commands/task/derive.d.ts +1 -0
- package/dist/commands/task/derive.d.ts.map +1 -1
- package/dist/commands/task/derive.js +27 -4
- package/dist/commands/task/doc.d.ts.map +1 -1
- package/dist/commands/task/doc.js +16 -5
- package/dist/commands/task/finish.d.ts.map +1 -1
- package/dist/commands/task/finish.js +41 -41
- package/dist/commands/task/migrate-doc.d.ts +15 -0
- package/dist/commands/task/migrate-doc.d.ts.map +1 -1
- package/dist/commands/task/migrate-doc.js +126 -35
- package/dist/commands/task/new.d.ts.map +1 -1
- package/dist/commands/task/new.js +3 -1
- package/dist/commands/task/plan.js +28 -28
- package/dist/commands/task/set-status.d.ts.map +1 -1
- package/dist/commands/task/set-status.js +104 -61
- package/dist/commands/task/shared/dependencies.d.ts +1 -0
- package/dist/commands/task/shared/dependencies.d.ts.map +1 -1
- package/dist/commands/task/shared/dependencies.js +10 -0
- package/dist/commands/task/shared/docs.js +1 -1
- package/dist/commands/task/shared/transitions.d.ts +17 -0
- package/dist/commands/task/shared/transitions.d.ts.map +1 -1
- package/dist/commands/task/shared/transitions.js +20 -7
- package/dist/commands/task/shared.d.ts +2 -2
- package/dist/commands/task/shared.d.ts.map +1 -1
- package/dist/commands/task/shared.js +2 -2
- package/dist/commands/task/start.d.ts.map +1 -1
- package/dist/commands/task/start.js +33 -28
- package/dist/commands/task/verify-record.d.ts.map +1 -1
- package/dist/commands/task/verify-record.js +32 -32
- package/dist/commands/upgrade/apply.d.ts +2 -0
- package/dist/commands/upgrade/apply.d.ts.map +1 -1
- package/dist/commands/upgrade/apply.js +33 -1
- package/dist/commands/upgrade.command.d.ts.map +1 -1
- package/dist/commands/upgrade.command.js +25 -0
- package/dist/commands/upgrade.d.ts +1 -0
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +34 -0
- package/dist/policy/rules/allowlist.d.ts.map +1 -1
- package/dist/policy/rules/allowlist.js +12 -9
- package/dist/ports/task-backend-port.d.ts +2 -2
- package/dist/ports/task-backend-port.d.ts.map +1 -1
- package/dist/shared/protected-paths.d.ts +10 -0
- package/dist/shared/protected-paths.d.ts.map +1 -1
- package/dist/shared/protected-paths.js +33 -0
- package/package.json +2 -2
|
@@ -7,8 +7,8 @@ import { backendNotSupportedMessage, successMessage } from "../../cli/output.js"
|
|
|
7
7
|
import { CliError } from "../../shared/errors.js";
|
|
8
8
|
import { ensureReconciledBeforeMutation } from "../shared/reconcile-check.js";
|
|
9
9
|
import { loadCommandContext, loadTaskFromContext, } from "../shared/task-backend.js";
|
|
10
|
-
import { backendIsLocalFileBackend, getTaskStore } from "../shared/task-store.js";
|
|
11
|
-
import { appendTaskEvent, extractDocSection, normalizeTaskDocVersion, normalizeVerificationSectionLayout, nowIso, VERIFICATION_RESULTS_BEGIN, VERIFICATION_RESULTS_END, } from "./shared.js";
|
|
10
|
+
import { appendTaskEventIntent, backendIsLocalFileBackend, getTaskStore, setTaskFieldsIntent, setTaskSectionIntent, touchTaskDocMetaIntent, } from "../shared/task-store.js";
|
|
11
|
+
import { appendTaskEvent, decodeEscapedTaskTextNewlines, extractDocSection, normalizeTaskDocVersion, normalizeVerificationSectionLayout, nowIso, VERIFICATION_RESULTS_BEGIN, VERIFICATION_RESULTS_END, } from "./shared.js";
|
|
12
12
|
function appendBetweenMarkers(sectionText, entryText, version) {
|
|
13
13
|
const ensured = normalizeVerificationSectionLayout(sectionText, version);
|
|
14
14
|
const beginIdx = ensured.indexOf(VERIFICATION_RESULTS_BEGIN);
|
|
@@ -65,12 +65,10 @@ async function recordVerificationResult(opts) {
|
|
|
65
65
|
}
|
|
66
66
|
const useStore = backendIsLocalFileBackend(ctx);
|
|
67
67
|
const store = useStore ? getTaskStore(ctx) : null;
|
|
68
|
-
const task = useStore
|
|
69
|
-
? await store.get(opts.taskId)
|
|
70
|
-
: await loadTaskFromContext({ ctx, taskId: opts.taskId });
|
|
68
|
+
const task = useStore ? null : await loadTaskFromContext({ ctx, taskId: opts.taskId });
|
|
71
69
|
const at = nowIso();
|
|
72
70
|
if (useStore) {
|
|
73
|
-
await store.
|
|
71
|
+
await store.mutate(opts.taskId, (current) => {
|
|
74
72
|
const existingDoc = String(current.doc ?? "");
|
|
75
73
|
const baseDoc = ensureDocSections(existingDoc, config.tasks.doc.required_sections);
|
|
76
74
|
const verificationSection = extractDocSection(baseDoc, "Verification") ?? "";
|
|
@@ -93,8 +91,8 @@ async function recordVerificationResult(opts) {
|
|
|
93
91
|
verifyStepsRef,
|
|
94
92
|
});
|
|
95
93
|
const nextVerification = appendBetweenMarkers(verificationSection, entry, docVersion);
|
|
96
|
-
return
|
|
97
|
-
|
|
94
|
+
return [
|
|
95
|
+
setTaskFieldsIntent({
|
|
98
96
|
status: opts.state === "needs_rework" ? "DOING" : current.status,
|
|
99
97
|
commit: opts.state === "needs_rework" ? null : (current.commit ?? null),
|
|
100
98
|
verification: {
|
|
@@ -103,38 +101,37 @@ async function recordVerificationResult(opts) {
|
|
|
103
101
|
updated_by: opts.by,
|
|
104
102
|
note: opts.note,
|
|
105
103
|
},
|
|
106
|
-
},
|
|
107
|
-
|
|
108
|
-
kind: "set-section",
|
|
104
|
+
}),
|
|
105
|
+
setTaskSectionIntent({
|
|
109
106
|
section: "Verification",
|
|
110
107
|
text: nextVerification,
|
|
111
108
|
requiredSections: config.tasks.doc.required_sections,
|
|
112
|
-
},
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
docMeta: { updatedBy: opts.by },
|
|
123
|
-
};
|
|
109
|
+
}),
|
|
110
|
+
appendTaskEventIntent({
|
|
111
|
+
type: "verify",
|
|
112
|
+
at,
|
|
113
|
+
author: opts.by,
|
|
114
|
+
state: opts.state,
|
|
115
|
+
note: opts.note,
|
|
116
|
+
}),
|
|
117
|
+
touchTaskDocMetaIntent({ updatedBy: opts.by }),
|
|
118
|
+
];
|
|
124
119
|
});
|
|
125
120
|
}
|
|
126
121
|
else {
|
|
127
|
-
const
|
|
122
|
+
const remoteTask = task;
|
|
123
|
+
const existingDoc = (typeof remoteTask.doc === "string" ? remoteTask.doc : "") ||
|
|
124
|
+
(await backend.getTaskDoc(remoteTask.id));
|
|
128
125
|
const baseDoc = ensureDocSections(existingDoc ?? "", config.tasks.doc.required_sections);
|
|
129
126
|
const verificationSection = extractDocSection(baseDoc, "Verification") ?? "";
|
|
130
127
|
const verifySteps = extractDocSection(baseDoc, "Verify Steps");
|
|
131
128
|
const verifyStepsHash = verifySteps
|
|
132
129
|
? sha256Hex(verifySteps.replaceAll("\r\n", "\n").trim())
|
|
133
130
|
: null;
|
|
134
|
-
const docVersion = normalizeTaskDocVersion(
|
|
131
|
+
const docVersion = normalizeTaskDocVersion(remoteTask.doc_version);
|
|
135
132
|
const verifyStepsRef = [
|
|
136
133
|
`doc_version=${String(docVersion)}`,
|
|
137
|
-
`doc_updated_at=${String(
|
|
134
|
+
`doc_updated_at=${String(remoteTask.doc_updated_at ?? "missing")}`,
|
|
138
135
|
`excerpt_hash=sha256:${verifyStepsHash ?? "missing"}`,
|
|
139
136
|
].join(", ");
|
|
140
137
|
const entry = renderVerificationEntry({
|
|
@@ -148,12 +145,12 @@ async function recordVerificationResult(opts) {
|
|
|
148
145
|
const nextVerification = appendBetweenMarkers(verificationSection, entry, docVersion);
|
|
149
146
|
const nextDoc = ensureDocSections(setMarkdownSection(baseDoc, "Verification", nextVerification), config.tasks.doc.required_sections);
|
|
150
147
|
await backend.writeTask({
|
|
151
|
-
...
|
|
152
|
-
status: opts.state === "needs_rework" ? "DOING" :
|
|
153
|
-
commit: opts.state === "needs_rework" ? null : (
|
|
148
|
+
...remoteTask,
|
|
149
|
+
status: opts.state === "needs_rework" ? "DOING" : remoteTask.status,
|
|
150
|
+
commit: opts.state === "needs_rework" ? null : (remoteTask.commit ?? null),
|
|
154
151
|
doc: nextDoc,
|
|
155
152
|
doc_updated_by: opts.by,
|
|
156
|
-
events: appendTaskEvent(
|
|
153
|
+
events: appendTaskEvent(remoteTask, {
|
|
157
154
|
type: "verify",
|
|
158
155
|
at,
|
|
159
156
|
author: opts.by,
|
|
@@ -169,9 +166,9 @@ async function recordVerificationResult(opts) {
|
|
|
169
166
|
});
|
|
170
167
|
}
|
|
171
168
|
if (!opts.quiet) {
|
|
172
|
-
const readmePath = path.join(resolved.gitRoot, config.paths.workflow_dir,
|
|
169
|
+
const readmePath = path.join(resolved.gitRoot, config.paths.workflow_dir, opts.taskId, "README.md");
|
|
173
170
|
const relReadmePath = path.relative(resolved.gitRoot, readmePath);
|
|
174
|
-
process.stdout.write(`${successMessage("verified",
|
|
171
|
+
process.stdout.write(`${successMessage("verified", opts.taskId, `state=${opts.state} readme=${relReadmePath}`)}\n`);
|
|
175
172
|
}
|
|
176
173
|
}
|
|
177
174
|
async function resolveVerifyRecordInput(opts) {
|
|
@@ -200,6 +197,9 @@ async function resolveVerifyRecordInput(opts) {
|
|
|
200
197
|
throw mapCoreError(err, { command: opts.command, filePath: opts.file });
|
|
201
198
|
}
|
|
202
199
|
}
|
|
200
|
+
if (typeof details === "string") {
|
|
201
|
+
details = decodeEscapedTaskTextNewlines(details);
|
|
202
|
+
}
|
|
203
203
|
return { by, note, details };
|
|
204
204
|
}
|
|
205
205
|
async function executeVerifyRecordCommand(opts) {
|
|
@@ -7,6 +7,8 @@ export declare function ensureCleanTrackedTreeForUpgrade(gitRoot: string): Promi
|
|
|
7
7
|
export declare function createUpgradeCommit(opts: {
|
|
8
8
|
gitRoot: string;
|
|
9
9
|
paths: string[];
|
|
10
|
+
tasksPath: string;
|
|
11
|
+
workflowDir: string;
|
|
10
12
|
versionLabel: string;
|
|
11
13
|
source: "local_assets" | "upgrade_bundle" | "repo_tarball";
|
|
12
14
|
additions: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/commands/upgrade/apply.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/commands/upgrade/apply.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAUtD,wBAAsB,2BAA2B,CAAC,IAAI,EAAE;IACtD,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,GAAG,OAAO,CAAC,IAAI,CAAC,CAKhB;AAED,wBAAsB,gCAAgC,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BrF;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,cAAc,GAAG,gBAAgB,GAAG,cAAc,CAAC;IAC3D,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB,EAAE,MAAM,CAAC;CAChC,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA8FpD;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CAC/C,GAAG,OAAO,CAAC,IAAI,CAAC,CA2ChB;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,yBAAyB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,2BAA2B,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,mBAAmB,EAAE,OAAO,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,cAAc,GAAG,gBAAgB,GAAG,cAAc,CAAC;IAC3D,aAAa,EAAE,mBAAmB,EAAE,CAAC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,OAAO,CAAC,CA4CnB"}
|
|
@@ -5,6 +5,7 @@ import { backupPath, fileExists } from "../../cli/fs-utils.js";
|
|
|
5
5
|
import { exitCodeForError } from "../../cli/exit-codes.js";
|
|
6
6
|
import { withDiagnosticContext } from "../../shared/diagnostics.js";
|
|
7
7
|
import { CliError } from "../../shared/errors.js";
|
|
8
|
+
import { protectedPathKindForFile } from "../../shared/protected-paths.js";
|
|
8
9
|
import { execFileAsync, gitEnv } from "../shared/git.js";
|
|
9
10
|
async function safeRemovePath(targetPath) {
|
|
10
11
|
try {
|
|
@@ -74,10 +75,41 @@ export async function createUpgradeCommit(opts) {
|
|
|
74
75
|
`Source: ${opts.source}\n` +
|
|
75
76
|
`Managed-Changes: add=${opts.additions}, update=${opts.updates}, unchanged=${opts.unchanged}\n` +
|
|
76
77
|
`Incidents-Appended: ${opts.incidentsAppendedCount}\n`;
|
|
78
|
+
const allow = {
|
|
79
|
+
allowTasks: false,
|
|
80
|
+
allowPolicy: false,
|
|
81
|
+
allowConfig: false,
|
|
82
|
+
allowHooks: false,
|
|
83
|
+
allowCI: false,
|
|
84
|
+
};
|
|
85
|
+
for (const filePath of uniquePaths) {
|
|
86
|
+
const kind = protectedPathKindForFile({
|
|
87
|
+
filePath,
|
|
88
|
+
tasksPath: opts.tasksPath,
|
|
89
|
+
workflowDir: opts.workflowDir,
|
|
90
|
+
});
|
|
91
|
+
if (kind === "tasks")
|
|
92
|
+
allow.allowTasks = true;
|
|
93
|
+
if (kind === "policy")
|
|
94
|
+
allow.allowPolicy = true;
|
|
95
|
+
if (kind === "config")
|
|
96
|
+
allow.allowConfig = true;
|
|
97
|
+
if (kind === "hooks")
|
|
98
|
+
allow.allowHooks = true;
|
|
99
|
+
if (kind === "ci")
|
|
100
|
+
allow.allowCI = true;
|
|
101
|
+
}
|
|
77
102
|
try {
|
|
78
103
|
await execFileAsync("git", ["commit", "-m", subject, "-m", body], {
|
|
79
104
|
cwd: opts.gitRoot,
|
|
80
|
-
env:
|
|
105
|
+
env: {
|
|
106
|
+
...gitEnv(),
|
|
107
|
+
AGENTPLANE_ALLOW_TASKS: allow.allowTasks ? "1" : "0",
|
|
108
|
+
AGENTPLANE_ALLOW_POLICY: allow.allowPolicy ? "1" : "0",
|
|
109
|
+
AGENTPLANE_ALLOW_CONFIG: allow.allowConfig ? "1" : "0",
|
|
110
|
+
AGENTPLANE_ALLOW_HOOKS: allow.allowHooks ? "1" : "0",
|
|
111
|
+
AGENTPLANE_ALLOW_CI: allow.allowCI ? "1" : "0",
|
|
112
|
+
},
|
|
81
113
|
maxBuffer: 10 * 1024 * 1024,
|
|
82
114
|
});
|
|
83
115
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upgrade.command.d.ts","sourceRoot":"","sources":["../../src/commands/upgrade.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvE,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAEnE,MAAM,MAAM,aAAa,GAAG,YAAY,CAAC;AAEzC,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,aAAa,
|
|
1
|
+
{"version":3,"file":"upgrade.command.d.ts","sourceRoot":"","sources":["../../src/commands/upgrade.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvE,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAEnE,MAAM,MAAM,aAAa,GAAG,YAAY,CAAC;AAEzC,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,aAAa,CAwLlD,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,cAAc,CAAC,aAAa,CACsB,CAAC"}
|
|
@@ -72,6 +72,12 @@ export const upgradeSpec = {
|
|
|
72
72
|
default: false,
|
|
73
73
|
description: "Report changes without modifying files.",
|
|
74
74
|
},
|
|
75
|
+
{
|
|
76
|
+
kind: "boolean",
|
|
77
|
+
name: "migrate-task-docs",
|
|
78
|
+
default: false,
|
|
79
|
+
description: "After applying the framework upgrade, migrate legacy task README docs in the same run.",
|
|
80
|
+
},
|
|
75
81
|
{
|
|
76
82
|
kind: "boolean",
|
|
77
83
|
name: "no-backup",
|
|
@@ -115,6 +121,10 @@ export const upgradeSpec = {
|
|
|
115
121
|
cmd: "agentplane upgrade --bundle ./agentplane-upgrade.tar.gz --checksum ./agentplane-upgrade.tar.gz.sha256",
|
|
116
122
|
why: "Upgrade from local bundle files (no network).",
|
|
117
123
|
},
|
|
124
|
+
{
|
|
125
|
+
cmd: "agentplane upgrade --yes --migrate-task-docs",
|
|
126
|
+
why: "Apply the framework upgrade and migrate legacy task README docs in one operator run.",
|
|
127
|
+
},
|
|
118
128
|
],
|
|
119
129
|
parse: (raw) => {
|
|
120
130
|
const noBackup = raw.opts["no-backup"] === true;
|
|
@@ -130,6 +140,7 @@ export const upgradeSpec = {
|
|
|
130
140
|
checksumAsset: raw.opts["checksum-asset"],
|
|
131
141
|
dryRun: raw.opts["dry-run"] === true,
|
|
132
142
|
backup: !noBackup,
|
|
143
|
+
migrateTaskDocs: raw.opts["migrate-task-docs"] === true,
|
|
133
144
|
yes: raw.opts.yes === true,
|
|
134
145
|
};
|
|
135
146
|
},
|
|
@@ -151,6 +162,20 @@ export const upgradeSpec = {
|
|
|
151
162
|
message: "Remote upgrade options (--tag/--source/--asset/--checksum-asset) require --remote.",
|
|
152
163
|
});
|
|
153
164
|
}
|
|
165
|
+
if (p.migrateTaskDocs && p.mode === "agent") {
|
|
166
|
+
throw usageError({
|
|
167
|
+
spec: upgradeSpec,
|
|
168
|
+
command: "upgrade",
|
|
169
|
+
message: "Option --migrate-task-docs cannot be used with --agent.",
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
if (p.migrateTaskDocs && p.dryRun) {
|
|
173
|
+
throw usageError({
|
|
174
|
+
spec: upgradeSpec,
|
|
175
|
+
command: "upgrade",
|
|
176
|
+
message: "Option --migrate-task-docs cannot be used with --dry-run.",
|
|
177
|
+
});
|
|
178
|
+
}
|
|
154
179
|
},
|
|
155
180
|
};
|
|
156
181
|
export const runUpgrade = (ctx, flags) => cmdUpgradeParsed({ cwd: ctx.cwd, rootOverride: ctx.rootOverride, flags });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/commands/upgrade.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/commands/upgrade.ts"],"names":[],"mappings":"AA+CA,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,eAAe,EAAE,OAAO,CAAC;IACzB,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAuMF,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,YAAY,CAAC;CACrB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2kBlB;AAED,OAAO,EACL,kCAAkC,EAClC,qBAAqB,EACrB,iCAAiC,GAClC,MAAM,qBAAqB,CAAC"}
|
package/dist/commands/upgrade.js
CHANGED
|
@@ -11,7 +11,10 @@ import { exitCodeForError } from "../cli/exit-codes.js";
|
|
|
11
11
|
import { warnMessage } from "../cli/output.js";
|
|
12
12
|
import { CliError } from "../shared/errors.js";
|
|
13
13
|
import { ensureWorkflowArtifacts } from "../shared/workflow-artifacts.js";
|
|
14
|
+
import { checkTaskReadmeMigrationState } from "./doctor/workspace.js";
|
|
15
|
+
import { loadCommandContext } from "./shared/task-backend.js";
|
|
14
16
|
import { ensureNetworkApproved } from "./shared/network-approval.js";
|
|
17
|
+
import { migrateTaskDocsInWorkspace } from "./task/migrate-doc.js";
|
|
15
18
|
import { getVersion } from "../meta/version.js";
|
|
16
19
|
import { applyManagedFiles, cleanupAutoUpgradeArtifacts, createUpgradeCommit, ensureCleanTrackedTreeForUpgrade, persistUpgradeState, } from "./upgrade/apply.js";
|
|
17
20
|
import { printUpgradeDryRun, writeUpgradeAgentReview } from "./upgrade/report.js";
|
|
@@ -210,6 +213,12 @@ export async function cmdUpgradeParsed(opts) {
|
|
|
210
213
|
rootOverride: opts.rootOverride ?? null,
|
|
211
214
|
});
|
|
212
215
|
const loaded = await loadConfig(resolved.agentplaneDir);
|
|
216
|
+
const commandCtx = await loadCommandContext({
|
|
217
|
+
cwd: opts.cwd,
|
|
218
|
+
rootOverride: opts.rootOverride ?? null,
|
|
219
|
+
resolvedProject: resolved,
|
|
220
|
+
config: loaded.config,
|
|
221
|
+
});
|
|
213
222
|
if (flags.mode === "auto" && !flags.dryRun) {
|
|
214
223
|
await ensureCleanTrackedTreeForUpgrade(resolved.gitRoot);
|
|
215
224
|
}
|
|
@@ -624,6 +633,21 @@ export async function cmdUpgradeParsed(opts) {
|
|
|
624
633
|
createdBackups,
|
|
625
634
|
toBaselineKey,
|
|
626
635
|
});
|
|
636
|
+
const migratedTaskDocs = flags.migrateTaskDocs
|
|
637
|
+
? await migrateTaskDocsInWorkspace({
|
|
638
|
+
cwd: opts.cwd,
|
|
639
|
+
rootOverride: opts.rootOverride ?? null,
|
|
640
|
+
all: true,
|
|
641
|
+
taskIds: [],
|
|
642
|
+
resolvedProject: resolved,
|
|
643
|
+
config: loaded.config,
|
|
644
|
+
ctx: commandCtx,
|
|
645
|
+
})
|
|
646
|
+
: { changed: 0, changedPaths: [] };
|
|
647
|
+
if (flags.migrateTaskDocs) {
|
|
648
|
+
const details = migratedTaskDocs.changed > 0 ? `changed=${migratedTaskDocs.changed}` : "already current";
|
|
649
|
+
process.stdout.write(`Task README migration: ${details}\n`);
|
|
650
|
+
}
|
|
627
651
|
const hasManagedMutations = additions.length > 0 || updates.length > 0;
|
|
628
652
|
const shouldMutateConfig = await persistUpgradeState({
|
|
629
653
|
agentplaneDir: resolved.agentplaneDir,
|
|
@@ -655,6 +679,7 @@ export async function cmdUpgradeParsed(opts) {
|
|
|
655
679
|
...new Set([
|
|
656
680
|
...additions,
|
|
657
681
|
...updates,
|
|
682
|
+
...migratedTaskDocs.changedPaths,
|
|
658
683
|
...workflowArtifacts.commitPaths,
|
|
659
684
|
...(shouldMutateConfig ? [CONFIG_REL_PATH] : []),
|
|
660
685
|
]),
|
|
@@ -662,6 +687,8 @@ export async function cmdUpgradeParsed(opts) {
|
|
|
662
687
|
const commit = await createUpgradeCommit({
|
|
663
688
|
gitRoot: resolved.gitRoot,
|
|
664
689
|
paths: commitPaths,
|
|
690
|
+
tasksPath: loaded.config.paths.tasks_path,
|
|
691
|
+
workflowDir: loaded.config.paths.workflow_dir,
|
|
665
692
|
versionLabel: upgradeVersionLabel,
|
|
666
693
|
source: bundleLayout,
|
|
667
694
|
additions: additions.length,
|
|
@@ -677,6 +704,13 @@ export async function cmdUpgradeParsed(opts) {
|
|
|
677
704
|
if (commit) {
|
|
678
705
|
process.stdout.write(`Upgrade commit: ${commit.hash.slice(0, 12)} ${commit.subject}\n`);
|
|
679
706
|
}
|
|
707
|
+
const taskReadmeMigrationFindings = await checkTaskReadmeMigrationState(resolved.gitRoot, commandCtx);
|
|
708
|
+
if (taskReadmeMigrationFindings.length > 0) {
|
|
709
|
+
process.stderr.write(`${warnMessage("upgrade post-check: task README migration follow-up detected")}\n`);
|
|
710
|
+
for (const finding of taskReadmeMigrationFindings) {
|
|
711
|
+
process.stderr.write(`- ${finding}\n`);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
680
714
|
return 0;
|
|
681
715
|
}
|
|
682
716
|
finally {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"allowlist.d.ts","sourceRoot":"","sources":["../../../src/policy/rules/allowlist.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE/D,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,YAAY,
|
|
1
|
+
{"version":3,"file":"allowlist.d.ts","sourceRoot":"","sources":["../../../src/policy/rules/allowlist.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE/D,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,YAAY,CAqD9D"}
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import { gitPathIsUnderPrefix, normalizeGitPathPrefix } from "../../shared/git-path.js";
|
|
2
|
-
import {
|
|
2
|
+
import { protectedPathAllowPrefixes } from "../../shared/protected-paths.js";
|
|
3
3
|
import { gitError, okResult } from "../result.js";
|
|
4
4
|
export function allowlistRule(ctx) {
|
|
5
5
|
const allowRaw = ctx.allow?.prefixes ?? [];
|
|
6
6
|
const staged = ctx.git.stagedPaths ?? [];
|
|
7
7
|
const allow = allowRaw.map((p) => normalizeGitPathPrefix(p));
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
:
|
|
15
|
-
|
|
8
|
+
const protectedAllow = protectedPathAllowPrefixes({
|
|
9
|
+
tasksPath: ctx.config.paths.tasks_path,
|
|
10
|
+
workflowDir: ctx.config.paths.workflow_dir,
|
|
11
|
+
taskId: ctx.taskId,
|
|
12
|
+
allowTasks: ctx.allow?.allowTasks === true,
|
|
13
|
+
allowPolicy: ctx.allow?.allowPolicy === true,
|
|
14
|
+
allowConfig: ctx.allow?.allowConfig === true,
|
|
15
|
+
allowHooks: ctx.allow?.allowHooks === true,
|
|
16
|
+
allowCI: ctx.allow?.allowCI === true,
|
|
17
|
+
});
|
|
18
|
+
const effectiveAllow = [...new Set([...allow, ...protectedAllow])];
|
|
16
19
|
if (staged.length === 0) {
|
|
17
20
|
return { ok: false, errors: [gitError("No staged files (git index empty)")], warnings: [] };
|
|
18
21
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { TaskData } from "../backends/task-backend.js";
|
|
1
|
+
import type { TaskData, TaskWriteOptions } from "../backends/task-backend.js";
|
|
2
2
|
export type TaskBackendPort = {
|
|
3
3
|
listTasks(): Promise<TaskData[]>;
|
|
4
4
|
getTask(id: string): Promise<TaskData | null>;
|
|
5
|
-
writeTask(task: TaskData): Promise<void>;
|
|
5
|
+
writeTask(task: TaskData, opts?: TaskWriteOptions): Promise<void>;
|
|
6
6
|
exportProjectionSnapshot(path: string): Promise<void>;
|
|
7
7
|
};
|
|
8
8
|
//# sourceMappingURL=task-backend-port.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-backend-port.d.ts","sourceRoot":"","sources":["../../src/ports/task-backend-port.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"task-backend-port.d.ts","sourceRoot":"","sources":["../../src/ports/task-backend-port.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAE9E,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAC9C,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvD,CAAC"}
|
|
@@ -9,6 +9,16 @@ export declare function taskArtifactPrefixes(opts: {
|
|
|
9
9
|
workflowDir?: string;
|
|
10
10
|
taskId?: string;
|
|
11
11
|
}): string[];
|
|
12
|
+
export declare function protectedPathAllowPrefixes(opts: {
|
|
13
|
+
tasksPath: string;
|
|
14
|
+
workflowDir?: string;
|
|
15
|
+
taskId?: string;
|
|
16
|
+
allowTasks?: boolean;
|
|
17
|
+
allowPolicy?: boolean;
|
|
18
|
+
allowConfig?: boolean;
|
|
19
|
+
allowHooks?: boolean;
|
|
20
|
+
allowCI?: boolean;
|
|
21
|
+
}): string[];
|
|
12
22
|
export declare function getProtectedPathOverride(kind: ProtectedPathKind): ProtectedPathOverride;
|
|
13
23
|
export declare function protectedPathKindForFile(opts: {
|
|
14
24
|
filePath: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protected-paths.d.ts","sourceRoot":"","sources":["../../src/shared/protected-paths.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,IAAI,CAAC;AAE/E,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,iBAAiB,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAYF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,MAAM,EAAE,CAOX;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,iBAAiB,GAAG,qBAAqB,CAkBvF;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,iBAAiB,GAAG,IAAI,CAsC3B"}
|
|
1
|
+
{"version":3,"file":"protected-paths.d.ts","sourceRoot":"","sources":["../../src/shared/protected-paths.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,IAAI,CAAC;AAE/E,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,iBAAiB,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAYF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,MAAM,EAAE,CAOX;AAYD,wBAAgB,0BAA0B,CAAC,IAAI,EAAE;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,MAAM,EAAE,CAkBX;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,iBAAiB,GAAG,qBAAqB,CAkBvF;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,iBAAiB,GAAG,IAAI,CAsC3B"}
|
|
@@ -16,6 +16,39 @@ export function taskArtifactPrefixes(opts) {
|
|
|
16
16
|
out.add(workflowPrefix);
|
|
17
17
|
return [...out].toSorted((a, b) => a.localeCompare(b));
|
|
18
18
|
}
|
|
19
|
+
const POLICY_PATH_PREFIXES = [
|
|
20
|
+
"AGENTS.md",
|
|
21
|
+
"CLAUDE.md",
|
|
22
|
+
"packages/agentplane/assets/AGENTS.md",
|
|
23
|
+
".agentplane/agents",
|
|
24
|
+
];
|
|
25
|
+
const CONFIG_PATH_PREFIXES = [".agentplane/config.json", ".agentplane/backends"];
|
|
26
|
+
const HOOK_PATH_PREFIXES = ["lefthook.yml"];
|
|
27
|
+
const CI_PATH_PREFIXES = [".github/workflows", ".github/actions"];
|
|
28
|
+
export function protectedPathAllowPrefixes(opts) {
|
|
29
|
+
const out = new Set();
|
|
30
|
+
if (opts.allowTasks) {
|
|
31
|
+
for (const prefix of taskArtifactPrefixes(opts))
|
|
32
|
+
out.add(prefix);
|
|
33
|
+
}
|
|
34
|
+
if (opts.allowPolicy) {
|
|
35
|
+
for (const prefix of POLICY_PATH_PREFIXES)
|
|
36
|
+
out.add(prefix);
|
|
37
|
+
}
|
|
38
|
+
if (opts.allowConfig) {
|
|
39
|
+
for (const prefix of CONFIG_PATH_PREFIXES)
|
|
40
|
+
out.add(prefix);
|
|
41
|
+
}
|
|
42
|
+
if (opts.allowHooks) {
|
|
43
|
+
for (const prefix of HOOK_PATH_PREFIXES)
|
|
44
|
+
out.add(prefix);
|
|
45
|
+
}
|
|
46
|
+
if (opts.allowCI) {
|
|
47
|
+
for (const prefix of CI_PATH_PREFIXES)
|
|
48
|
+
out.add(prefix);
|
|
49
|
+
}
|
|
50
|
+
return [...out].toSorted((a, b) => a.localeCompare(b));
|
|
51
|
+
}
|
|
19
52
|
export function getProtectedPathOverride(kind) {
|
|
20
53
|
switch (kind) {
|
|
21
54
|
case "tasks": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentplane",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "Agent Plane CLI for task workflows, recipes, and project automation.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agentplane",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"prepublishOnly": "node ../../scripts/enforce-github-publish.mjs && npm run prepack"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@agentplaneorg/core": "0.3.
|
|
58
|
+
"@agentplaneorg/core": "0.3.7",
|
|
59
59
|
"yauzl": "^2.10.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|