@unbrained/pm-cli 2026.3.9 → 2026.5.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/.agents/pm/extensions/.managed-extensions.json +42 -0
- package/.agents/pm/extensions/beads/index.js +109 -0
- package/.agents/pm/extensions/beads/manifest.json +7 -0
- package/{dist/cli/commands/beads.js → .agents/pm/extensions/beads/runtime.js} +167 -56
- package/.agents/pm/extensions/beads/runtime.ts +702 -0
- package/.agents/pm/extensions/todos/index.js +126 -0
- package/.agents/pm/extensions/todos/manifest.json +7 -0
- package/{dist/extensions/builtins/todos/import-export.js → .agents/pm/extensions/todos/runtime.js} +39 -29
- package/.agents/pm/extensions/todos/runtime.ts +568 -0
- package/AGENTS.md +212 -94
- package/CHANGELOG.md +399 -0
- package/CODE_OF_CONDUCT.md +42 -0
- package/CONTRIBUTING.md +144 -0
- package/PRD.md +522 -173
- package/README.md +996 -495
- package/SECURITY.md +51 -0
- package/dist/cli/commands/activity.d.ts +5 -0
- package/dist/cli/commands/activity.js +66 -3
- package/dist/cli/commands/activity.js.map +1 -1
- package/dist/cli/commands/aggregate.d.ts +54 -0
- package/dist/cli/commands/aggregate.js +181 -0
- package/dist/cli/commands/aggregate.js.map +1 -0
- package/dist/cli/commands/append.js +4 -1
- package/dist/cli/commands/append.js.map +1 -1
- package/dist/cli/commands/calendar.d.ts +109 -0
- package/dist/cli/commands/calendar.js +797 -0
- package/dist/cli/commands/calendar.js.map +1 -0
- package/dist/cli/commands/claim.d.ts +5 -1
- package/dist/cli/commands/claim.js +42 -21
- package/dist/cli/commands/claim.js.map +1 -1
- package/dist/cli/commands/close.d.ts +1 -0
- package/dist/cli/commands/close.js +54 -5
- package/dist/cli/commands/close.js.map +1 -1
- package/dist/cli/commands/comments-audit.d.ts +91 -0
- package/dist/cli/commands/comments-audit.js +195 -0
- package/dist/cli/commands/comments-audit.js.map +1 -0
- package/dist/cli/commands/comments.d.ts +1 -0
- package/dist/cli/commands/comments.js +70 -21
- package/dist/cli/commands/comments.js.map +1 -1
- package/dist/cli/commands/completion.d.ts +10 -4
- package/dist/cli/commands/completion.js +1240 -193
- package/dist/cli/commands/completion.js.map +1 -1
- package/dist/cli/commands/config.d.ts +35 -3
- package/dist/cli/commands/config.js +968 -13
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/context.d.ts +86 -0
- package/dist/cli/commands/context.js +299 -0
- package/dist/cli/commands/context.js.map +1 -0
- package/dist/cli/commands/contracts.d.ts +78 -0
- package/dist/cli/commands/contracts.js +920 -0
- package/dist/cli/commands/contracts.js.map +1 -0
- package/dist/cli/commands/create.d.ts +48 -14
- package/dist/cli/commands/create.js +1331 -160
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/commands/dedupe-audit.d.ts +81 -0
- package/dist/cli/commands/dedupe-audit.js +330 -0
- package/dist/cli/commands/dedupe-audit.js.map +1 -0
- package/dist/cli/commands/deps.d.ts +52 -0
- package/dist/cli/commands/deps.js +204 -0
- package/dist/cli/commands/deps.js.map +1 -0
- package/dist/cli/commands/docs.d.ts +19 -0
- package/dist/cli/commands/docs.js +212 -13
- package/dist/cli/commands/docs.js.map +1 -1
- package/dist/cli/commands/extension.d.ts +122 -0
- package/dist/cli/commands/extension.js +1850 -0
- package/dist/cli/commands/extension.js.map +1 -0
- package/dist/cli/commands/files.d.ts +52 -1
- package/dist/cli/commands/files.js +443 -13
- package/dist/cli/commands/files.js.map +1 -1
- package/dist/cli/commands/gc.d.ts +11 -1
- package/dist/cli/commands/gc.js +89 -11
- package/dist/cli/commands/gc.js.map +1 -1
- package/dist/cli/commands/get.d.ts +13 -0
- package/dist/cli/commands/get.js +35 -3
- package/dist/cli/commands/get.js.map +1 -1
- package/dist/cli/commands/health.d.ts +10 -2
- package/dist/cli/commands/health.js +774 -23
- package/dist/cli/commands/health.js.map +1 -1
- package/dist/cli/commands/history.d.ts +20 -0
- package/dist/cli/commands/history.js +152 -6
- package/dist/cli/commands/history.js.map +1 -1
- package/dist/cli/commands/index.d.ts +16 -3
- package/dist/cli/commands/index.js +16 -3
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/init.d.ts +7 -2
- package/dist/cli/commands/init.js +137 -5
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/learnings.d.ts +17 -0
- package/dist/cli/commands/learnings.js +129 -0
- package/dist/cli/commands/learnings.js.map +1 -0
- package/dist/cli/commands/list.d.ts +29 -1
- package/dist/cli/commands/list.js +292 -56
- package/dist/cli/commands/list.js.map +1 -1
- package/dist/cli/commands/normalize.d.ts +51 -0
- package/dist/cli/commands/normalize.js +298 -0
- package/dist/cli/commands/normalize.js.map +1 -0
- package/dist/cli/commands/notes.d.ts +17 -0
- package/dist/cli/commands/notes.js +129 -0
- package/dist/cli/commands/notes.js.map +1 -0
- package/dist/cli/commands/reindex.d.ts +1 -0
- package/dist/cli/commands/reindex.js +208 -32
- package/dist/cli/commands/reindex.js.map +1 -1
- package/dist/cli/commands/restore.js +164 -30
- package/dist/cli/commands/restore.js.map +1 -1
- package/dist/cli/commands/search.d.ts +14 -1
- package/dist/cli/commands/search.js +479 -85
- package/dist/cli/commands/search.js.map +1 -1
- package/dist/cli/commands/stats.js +26 -10
- package/dist/cli/commands/stats.js.map +1 -1
- package/dist/cli/commands/templates.d.ts +26 -0
- package/dist/cli/commands/templates.js +179 -0
- package/dist/cli/commands/templates.js.map +1 -0
- package/dist/cli/commands/test-all.d.ts +19 -1
- package/dist/cli/commands/test-all.js +161 -13
- package/dist/cli/commands/test-all.js.map +1 -1
- package/dist/cli/commands/test-runs.d.ts +63 -0
- package/dist/cli/commands/test-runs.js +179 -0
- package/dist/cli/commands/test-runs.js.map +1 -0
- package/dist/cli/commands/test.d.ts +75 -1
- package/dist/cli/commands/test.js +1360 -41
- package/dist/cli/commands/test.js.map +1 -1
- package/dist/cli/commands/update-many.d.ts +57 -0
- package/dist/cli/commands/update-many.js +631 -0
- package/dist/cli/commands/update-many.js.map +1 -0
- package/dist/cli/commands/update.d.ts +30 -0
- package/dist/cli/commands/update.js +1393 -84
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/commands/validate.d.ts +30 -0
- package/dist/cli/commands/validate.js +1140 -0
- package/dist/cli/commands/validate.js.map +1 -0
- package/dist/cli/error-guidance.d.ts +33 -0
- package/dist/cli/error-guidance.js +337 -0
- package/dist/cli/error-guidance.js.map +1 -0
- package/dist/cli/extension-command-options.d.ts +1 -0
- package/dist/cli/extension-command-options.js +92 -0
- package/dist/cli/extension-command-options.js.map +1 -1
- package/dist/cli/help-content.d.ts +20 -0
- package/dist/cli/help-content.js +543 -0
- package/dist/cli/help-content.js.map +1 -0
- package/dist/cli/main.js +3648 -467
- package/dist/cli/main.js.map +1 -1
- package/dist/core/extensions/index.d.ts +13 -1
- package/dist/core/extensions/index.js +108 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/item-fields.d.ts +2 -0
- package/dist/core/extensions/item-fields.js +79 -0
- package/dist/core/extensions/item-fields.js.map +1 -0
- package/dist/core/extensions/loader.d.ts +322 -9
- package/dist/core/extensions/loader.js +911 -20
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runtime-registrations.d.ts +5 -0
- package/dist/core/extensions/runtime-registrations.js +51 -0
- package/dist/core/extensions/runtime-registrations.js.map +1 -0
- package/dist/core/history/history-stream-policy.d.ts +20 -0
- package/dist/core/history/history-stream-policy.js +53 -0
- package/dist/core/history/history-stream-policy.js.map +1 -0
- package/dist/core/history/history.js +90 -1
- package/dist/core/history/history.js.map +1 -1
- package/dist/core/item/id.d.ts +1 -0
- package/dist/core/item/id.js +10 -3
- package/dist/core/item/id.js.map +1 -1
- package/dist/core/item/index.d.ts +1 -0
- package/dist/core/item/index.js +1 -0
- package/dist/core/item/index.js.map +1 -1
- package/dist/core/item/item-format.d.ts +11 -5
- package/dist/core/item/item-format.js +532 -28
- package/dist/core/item/item-format.js.map +1 -1
- package/dist/core/item/parent-reference-policy.d.ts +6 -0
- package/dist/core/item/parent-reference-policy.js +32 -0
- package/dist/core/item/parent-reference-policy.js.map +1 -0
- package/dist/core/item/parse.d.ts +5 -0
- package/dist/core/item/parse.js +216 -19
- package/dist/core/item/parse.js.map +1 -1
- package/dist/core/item/sprint-release-format.d.ts +6 -0
- package/dist/core/item/sprint-release-format.js +33 -0
- package/dist/core/item/sprint-release-format.js.map +1 -0
- package/dist/core/item/status.d.ts +3 -0
- package/dist/core/item/status.js +24 -0
- package/dist/core/item/status.js.map +1 -0
- package/dist/core/item/type-registry.d.ts +37 -0
- package/dist/core/item/type-registry.js +706 -0
- package/dist/core/item/type-registry.js.map +1 -0
- package/dist/core/lock/lock.d.ts +1 -1
- package/dist/core/lock/lock.js +101 -12
- package/dist/core/lock/lock.js.map +1 -1
- package/dist/core/output/command-aware.d.ts +1 -0
- package/dist/core/output/command-aware.js +394 -0
- package/dist/core/output/command-aware.js.map +1 -0
- package/dist/core/output/output.d.ts +3 -0
- package/dist/core/output/output.js +124 -6
- package/dist/core/output/output.js.map +1 -1
- package/dist/core/schema/runtime-field-filters.d.ts +3 -0
- package/dist/core/schema/runtime-field-filters.js +39 -0
- package/dist/core/schema/runtime-field-filters.js.map +1 -0
- package/dist/core/schema/runtime-field-values.d.ts +8 -0
- package/dist/core/schema/runtime-field-values.js +154 -0
- package/dist/core/schema/runtime-field-values.js.map +1 -0
- package/dist/core/schema/runtime-schema.d.ts +68 -0
- package/dist/core/schema/runtime-schema.js +554 -0
- package/dist/core/schema/runtime-schema.js.map +1 -0
- package/dist/core/search/cache.d.ts +13 -1
- package/dist/core/search/cache.js +123 -14
- package/dist/core/search/cache.js.map +1 -1
- package/dist/core/search/semantic-defaults.d.ts +6 -0
- package/dist/core/search/semantic-defaults.js +120 -0
- package/dist/core/search/semantic-defaults.js.map +1 -0
- package/dist/core/search/vector-stores.js +3 -1
- package/dist/core/search/vector-stores.js.map +1 -1
- package/dist/core/shared/command-types.d.ts +2 -0
- package/dist/core/shared/conflict-markers.d.ts +7 -0
- package/dist/core/shared/conflict-markers.js +27 -0
- package/dist/core/shared/conflict-markers.js.map +1 -0
- package/dist/core/shared/constants.d.ts +15 -4
- package/dist/core/shared/constants.js +146 -1
- package/dist/core/shared/constants.js.map +1 -1
- package/dist/core/shared/errors.d.ts +10 -1
- package/dist/core/shared/errors.js +3 -1
- package/dist/core/shared/errors.js.map +1 -1
- package/dist/core/shared/text-normalization.d.ts +4 -0
- package/dist/core/shared/text-normalization.js +33 -0
- package/dist/core/shared/text-normalization.js.map +1 -0
- package/dist/core/shared/time.d.ts +3 -2
- package/dist/core/shared/time.js +109 -11
- package/dist/core/shared/time.js.map +1 -1
- package/dist/core/store/index.d.ts +1 -0
- package/dist/core/store/index.js +1 -0
- package/dist/core/store/index.js.map +1 -1
- package/dist/core/store/item-format-migration.d.ts +9 -0
- package/dist/core/store/item-format-migration.js +87 -0
- package/dist/core/store/item-format-migration.js.map +1 -0
- package/dist/core/store/item-store.d.ts +13 -4
- package/dist/core/store/item-store.js +243 -52
- package/dist/core/store/item-store.js.map +1 -1
- package/dist/core/store/paths.d.ts +21 -3
- package/dist/core/store/paths.js +59 -4
- package/dist/core/store/paths.js.map +1 -1
- package/dist/core/store/settings.d.ts +14 -1
- package/dist/core/store/settings.js +463 -7
- package/dist/core/store/settings.js.map +1 -1
- package/dist/core/telemetry/consent.d.ts +2 -0
- package/dist/core/telemetry/consent.js +79 -0
- package/dist/core/telemetry/consent.js.map +1 -0
- package/dist/core/telemetry/runtime.d.ts +38 -0
- package/dist/core/telemetry/runtime.js +733 -0
- package/dist/core/telemetry/runtime.js.map +1 -0
- package/dist/core/test/background-runs.d.ts +117 -0
- package/dist/core/test/background-runs.js +760 -0
- package/dist/core/test/background-runs.js.map +1 -0
- package/dist/core/test/item-test-run-tracking.d.ts +9 -0
- package/dist/core/test/item-test-run-tracking.js +50 -0
- package/dist/core/test/item-test-run-tracking.js.map +1 -0
- package/dist/sdk/cli-contracts.d.ts +92 -0
- package/dist/sdk/cli-contracts.js +2357 -0
- package/dist/sdk/cli-contracts.js.map +1 -0
- package/dist/sdk/index.d.ts +34 -0
- package/dist/sdk/index.js +23 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/types.d.ts +204 -4
- package/dist/types.js +56 -1
- package/dist/types.js.map +1 -1
- package/docs/ARCHITECTURE.md +369 -40
- package/docs/EXTENSIONS.md +454 -49
- package/docs/RELEASING.md +68 -19
- package/docs/SDK.md +123 -0
- package/docs/examples/starter-extension/README.md +48 -0
- package/docs/examples/starter-extension/index.js +191 -0
- package/docs/examples/starter-extension/manifest.json +17 -0
- package/docs/examples/starter-extension/package.json +10 -0
- package/package.json +33 -6
- package/scripts/install.ps1 +2 -1
- package/scripts/install.sh +2 -1
- package/.pi/extensions/pm-cli/index.ts +0 -778
- package/dist/cli/commands/beads.d.ts +0 -15
- package/dist/cli/commands/beads.js.map +0 -1
- package/dist/cli/commands/install.d.ts +0 -18
- package/dist/cli/commands/install.js +0 -87
- package/dist/cli/commands/install.js.map +0 -1
- package/dist/core/extensions/builtins.d.ts +0 -3
- package/dist/core/extensions/builtins.js +0 -47
- package/dist/core/extensions/builtins.js.map +0 -1
- package/dist/extensions/builtins/beads/index.d.ts +0 -8
- package/dist/extensions/builtins/beads/index.js +0 -29
- package/dist/extensions/builtins/beads/index.js.map +0 -1
- package/dist/extensions/builtins/todos/import-export.d.ts +0 -26
- package/dist/extensions/builtins/todos/import-export.js.map +0 -1
- package/dist/extensions/builtins/todos/index.d.ts +0 -8
- package/dist/extensions/builtins/todos/index.js +0 -38
- package/dist/extensions/builtins/todos/index.js.map +0 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"updated_at": "2026-04-25T17:01:49.273Z",
|
|
4
|
+
"entries": [
|
|
5
|
+
{
|
|
6
|
+
"name": "builtin-beads-import",
|
|
7
|
+
"directory": "beads",
|
|
8
|
+
"scope": "project",
|
|
9
|
+
"manifest_version": "0.1.0",
|
|
10
|
+
"manifest_entry": "./index.js",
|
|
11
|
+
"capabilities": [
|
|
12
|
+
"commands",
|
|
13
|
+
"schema"
|
|
14
|
+
],
|
|
15
|
+
"installed_at": "2026-04-25T17:01:49.268Z",
|
|
16
|
+
"updated_at": "2026-04-25T17:01:49.268Z",
|
|
17
|
+
"source": {
|
|
18
|
+
"kind": "local",
|
|
19
|
+
"input": "builtin-beads-import",
|
|
20
|
+
"location": "/home/steve/GITHUB_RELEASE/pm-cli/.agents/pm/extensions/beads"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"name": "builtin-todos-import-export",
|
|
25
|
+
"directory": "todos",
|
|
26
|
+
"scope": "project",
|
|
27
|
+
"manifest_version": "0.1.0",
|
|
28
|
+
"manifest_entry": "./index.js",
|
|
29
|
+
"capabilities": [
|
|
30
|
+
"commands",
|
|
31
|
+
"schema"
|
|
32
|
+
],
|
|
33
|
+
"installed_at": "2026-04-25T17:01:49.268Z",
|
|
34
|
+
"updated_at": "2026-04-25T17:01:49.268Z",
|
|
35
|
+
"source": {
|
|
36
|
+
"kind": "local",
|
|
37
|
+
"input": "builtin-todos-import-export",
|
|
38
|
+
"location": "/home/steve/GITHUB_RELEASE/pm-cli/.agents/pm/extensions/todos"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
3
|
+
|
|
4
|
+
const PM_PACKAGE_ROOT_ENV = "PM_CLI_PACKAGE_ROOT";
|
|
5
|
+
|
|
6
|
+
export const manifest = {
|
|
7
|
+
name: "builtin-beads-import",
|
|
8
|
+
version: "0.1.0",
|
|
9
|
+
entry: "./index.js",
|
|
10
|
+
priority: 0,
|
|
11
|
+
capabilities: ["commands", "schema"],
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function asOptionalString(value) {
|
|
15
|
+
return typeof value === "string" ? value : undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function asBoolean(value) {
|
|
19
|
+
return typeof value === "boolean" ? value : undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function toBeadsImportOptions(options) {
|
|
23
|
+
return {
|
|
24
|
+
file: asOptionalString(options.file),
|
|
25
|
+
author: asOptionalString(options.author),
|
|
26
|
+
message: asOptionalString(options.message),
|
|
27
|
+
preserveSourceIds: asBoolean(options.preserveSourceIds),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function resolvePackageRootCandidates() {
|
|
32
|
+
const candidates = [];
|
|
33
|
+
const envRoot = process.env[PM_PACKAGE_ROOT_ENV];
|
|
34
|
+
if (typeof envRoot === "string" && envRoot.trim().length > 0) {
|
|
35
|
+
candidates.push(path.resolve(envRoot.trim()));
|
|
36
|
+
}
|
|
37
|
+
const argvEntry = typeof process.argv[1] === "string" ? process.argv[1].trim() : "";
|
|
38
|
+
if (argvEntry.length > 0) {
|
|
39
|
+
const resolvedEntry = path.resolve(argvEntry);
|
|
40
|
+
const entryDir = path.dirname(resolvedEntry);
|
|
41
|
+
candidates.push(path.resolve(entryDir, ".."));
|
|
42
|
+
candidates.push(path.resolve(entryDir, "../.."));
|
|
43
|
+
candidates.push(path.resolve(entryDir, "../../.."));
|
|
44
|
+
}
|
|
45
|
+
return [...new Set(candidates)];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function loadRuntimeModule() {
|
|
49
|
+
const attempted = [];
|
|
50
|
+
for (const packageRoot of resolvePackageRootCandidates()) {
|
|
51
|
+
const modulePath = path.join(packageRoot, ".agents", "pm", "extensions", "beads", "runtime.js");
|
|
52
|
+
attempted.push(modulePath);
|
|
53
|
+
try {
|
|
54
|
+
return await import(pathToFileURL(modulePath).href);
|
|
55
|
+
} catch {
|
|
56
|
+
// Try the next package-root candidate.
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
throw new Error(
|
|
60
|
+
"Unable to resolve bundled beads extension runtime module. " +
|
|
61
|
+
`Tried: ${attempted.join(", ")}. Ensure PM_CLI_PACKAGE_ROOT points to an installed pm package root.`,
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function runBeadsImportFromRuntime(options, global) {
|
|
66
|
+
const runtime = await loadRuntimeModule();
|
|
67
|
+
if (typeof runtime.runBeadsImport !== "function") {
|
|
68
|
+
throw new Error('Bundled beads runtime module is missing runBeadsImport().');
|
|
69
|
+
}
|
|
70
|
+
return runtime.runBeadsImport(options, global);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function activate(api) {
|
|
74
|
+
api.registerCommand({
|
|
75
|
+
name: "beads import",
|
|
76
|
+
description: "Import Beads JSONL records into pm items.",
|
|
77
|
+
flags: [
|
|
78
|
+
{
|
|
79
|
+
long: "--file",
|
|
80
|
+
value_name: "path",
|
|
81
|
+
value_type: "string",
|
|
82
|
+
description: "Path to the Beads JSONL source file.",
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
long: "--author",
|
|
86
|
+
value_name: "author",
|
|
87
|
+
value_type: "string",
|
|
88
|
+
description: "Override import mutation author.",
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
long: "--message",
|
|
92
|
+
value_name: "text",
|
|
93
|
+
value_type: "string",
|
|
94
|
+
description: "Override import history message.",
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
long: "--preserve-source-ids",
|
|
98
|
+
value_type: "boolean",
|
|
99
|
+
description: "Preserve source IDs from Beads payload records when possible.",
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
run: async (context) => runBeadsImportFromRuntime(toBeadsImportOptions(context.options), context.global),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export default {
|
|
107
|
+
manifest,
|
|
108
|
+
activate,
|
|
109
|
+
};
|
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { pathExists, removeFileIfExists, writeFileAtomic } from "
|
|
4
|
-
import { runActiveOnReadHooks, runActiveOnWriteHooks } from "
|
|
5
|
-
import { appendHistoryEntry, createHistoryEntry } from "
|
|
6
|
-
import { generateItemId, normalizeItemId } from "
|
|
7
|
-
import { canonicalDocument, normalizeFrontMatter, serializeItemDocument } from "
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
|
|
3
|
+
import { pathExists, removeFileIfExists, writeFileAtomic } from "../../../../dist/core/fs/fs-utils.js";
|
|
4
|
+
import { getActiveExtensionRegistrations, runActiveOnReadHooks, runActiveOnWriteHooks } from "../../../../dist/core/extensions/index.js";
|
|
5
|
+
import { appendHistoryEntry, createHistoryEntry } from "../../../../dist/core/history/history.js";
|
|
6
|
+
import { generateItemId, normalizeItemId, normalizeRawItemId } from "../../../../dist/core/item/id.js";
|
|
7
|
+
import { canonicalDocument, normalizeFrontMatter, serializeItemDocument } from "../../../../dist/core/item/item-format.js";
|
|
8
|
+
import { normalizeStatusInput } from "../../../../dist/core/item/status.js";
|
|
9
|
+
import { resolveItemTypeRegistry } from "../../../../dist/core/item/type-registry.js";
|
|
10
|
+
import { parseTags } from "../../../../dist/core/item/parse.js";
|
|
11
|
+
import { acquireLock } from "../../../../dist/core/lock/lock.js";
|
|
12
|
+
import { EXIT_CODE } from "../../../../dist/core/shared/constants.js";
|
|
13
|
+
import { PmCliError } from "../../../../dist/core/shared/errors.js";
|
|
14
|
+
import { isTimestampLiteral, nowIso } from "../../../../dist/core/shared/time.js";
|
|
15
|
+
import { locateItem } from "../../../../dist/core/store/item-store.js";
|
|
16
|
+
import { getHistoryPath, getItemPath, getSettingsPath, resolvePmRoot } from "../../../../dist/core/store/paths.js";
|
|
17
|
+
import { readSettings } from "../../../../dist/core/store/settings.js";
|
|
18
|
+
import { DEPENDENCY_KIND_VALUES } from "../../../../dist/types/index.js";
|
|
19
|
+
const PRIMARY_AUTO_DISCOVERY_FILES = [
|
|
20
|
+
".beads/issues.jsonl",
|
|
21
|
+
"issues.jsonl",
|
|
22
|
+
];
|
|
23
|
+
const UNSAFE_AUTO_DISCOVERY_FILES = [
|
|
24
|
+
".beads/sync_base.jsonl",
|
|
25
|
+
"sync_base.jsonl",
|
|
26
|
+
];
|
|
17
27
|
function toNonEmptyString(value) {
|
|
18
28
|
if (typeof value !== "string") {
|
|
19
29
|
return undefined;
|
|
@@ -26,11 +36,10 @@ function toIsoString(value) {
|
|
|
26
36
|
if (!raw) {
|
|
27
37
|
return undefined;
|
|
28
38
|
}
|
|
29
|
-
|
|
30
|
-
if (!Number.isFinite(timestamp)) {
|
|
39
|
+
if (!isTimestampLiteral(raw)) {
|
|
31
40
|
return undefined;
|
|
32
41
|
}
|
|
33
|
-
return
|
|
42
|
+
return raw;
|
|
34
43
|
}
|
|
35
44
|
function toEstimatedMinutes(value) {
|
|
36
45
|
if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
|
|
@@ -71,37 +80,75 @@ function toTags(value) {
|
|
|
71
80
|
return [];
|
|
72
81
|
}
|
|
73
82
|
function toItemType(value) {
|
|
74
|
-
const
|
|
83
|
+
const raw = toNonEmptyString(value);
|
|
84
|
+
const normalized = raw?.toLowerCase();
|
|
75
85
|
switch (normalized) {
|
|
76
86
|
case "epic":
|
|
77
|
-
return "Epic";
|
|
87
|
+
return { type: "Epic" };
|
|
78
88
|
case "feature":
|
|
79
|
-
return "Feature";
|
|
89
|
+
return { type: "Feature" };
|
|
80
90
|
case "task":
|
|
81
|
-
return "Task";
|
|
91
|
+
return { type: "Task" };
|
|
82
92
|
case "chore":
|
|
83
|
-
return "Chore";
|
|
93
|
+
return { type: "Chore" };
|
|
84
94
|
case "issue":
|
|
85
|
-
return "Issue";
|
|
95
|
+
return { type: "Issue" };
|
|
96
|
+
case "bug":
|
|
97
|
+
return { type: "Issue", sourceType: raw };
|
|
98
|
+
case "event":
|
|
99
|
+
return { type: "Task", sourceType: raw };
|
|
86
100
|
default:
|
|
87
|
-
return "Task";
|
|
101
|
+
return { type: "Task", sourceType: raw };
|
|
88
102
|
}
|
|
89
103
|
}
|
|
90
104
|
function toStatus(value) {
|
|
91
|
-
const normalized = toNonEmptyString(value)
|
|
92
|
-
if (normalized
|
|
93
|
-
|
|
105
|
+
const normalized = toNonEmptyString(value);
|
|
106
|
+
if (normalized) {
|
|
107
|
+
const canonical = normalizeStatusInput(normalized);
|
|
108
|
+
if (canonical) {
|
|
109
|
+
return canonical;
|
|
110
|
+
}
|
|
94
111
|
}
|
|
95
112
|
return "open";
|
|
96
113
|
}
|
|
97
114
|
function toDependencyKind(value) {
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
115
|
+
const raw = toNonEmptyString(value);
|
|
116
|
+
const normalized = raw?.toLowerCase();
|
|
117
|
+
if (!normalized) {
|
|
118
|
+
return { kind: "related" };
|
|
119
|
+
}
|
|
120
|
+
const preserveIfChanged = (kind) => ({
|
|
121
|
+
kind,
|
|
122
|
+
sourceKind: normalized === kind ? undefined : raw,
|
|
123
|
+
});
|
|
124
|
+
if (DEPENDENCY_KIND_VALUES.includes(normalized)) {
|
|
125
|
+
return preserveIfChanged(normalized);
|
|
126
|
+
}
|
|
127
|
+
switch (normalized) {
|
|
128
|
+
case "parent-child":
|
|
129
|
+
return preserveIfChanged("parent_child");
|
|
130
|
+
case "child-of":
|
|
131
|
+
return preserveIfChanged("child_of");
|
|
132
|
+
case "related-to":
|
|
133
|
+
case "relates-to":
|
|
134
|
+
return preserveIfChanged("related_to");
|
|
135
|
+
case "discovered-from":
|
|
136
|
+
return preserveIfChanged("discovered_from");
|
|
137
|
+
case "blocked-by":
|
|
138
|
+
return preserveIfChanged("blocked_by");
|
|
139
|
+
case "incident-from":
|
|
140
|
+
return preserveIfChanged("incident_from");
|
|
141
|
+
default:
|
|
142
|
+
return {
|
|
143
|
+
kind: "related",
|
|
144
|
+
sourceKind: raw,
|
|
145
|
+
};
|
|
101
146
|
}
|
|
102
|
-
return "related";
|
|
103
147
|
}
|
|
104
|
-
function
|
|
148
|
+
function normalizeImportedId(id, prefix, preserveSourceIds) {
|
|
149
|
+
return preserveSourceIds ? normalizeRawItemId(id) : normalizeItemId(id, prefix);
|
|
150
|
+
}
|
|
151
|
+
function toDependencies(value, fallbackCreatedAt, prefix, preserveSourceIds) {
|
|
105
152
|
if (!Array.isArray(value)) {
|
|
106
153
|
return undefined;
|
|
107
154
|
}
|
|
@@ -113,7 +160,7 @@ function toDependencies(value, fallbackCreatedAt, prefix) {
|
|
|
113
160
|
continue;
|
|
114
161
|
}
|
|
115
162
|
dependencies.push({
|
|
116
|
-
id:
|
|
163
|
+
id: normalizeImportedId(id, prefix, preserveSourceIds),
|
|
117
164
|
kind: "related",
|
|
118
165
|
created_at: fallbackCreatedAt,
|
|
119
166
|
});
|
|
@@ -127,11 +174,13 @@ function toDependencies(value, fallbackCreatedAt, prefix) {
|
|
|
127
174
|
if (!id) {
|
|
128
175
|
continue;
|
|
129
176
|
}
|
|
177
|
+
const dependencyKind = toDependencyKind(candidate.type ?? candidate.kind);
|
|
130
178
|
dependencies.push({
|
|
131
|
-
id:
|
|
132
|
-
kind:
|
|
179
|
+
id: normalizeImportedId(id, prefix, preserveSourceIds),
|
|
180
|
+
kind: dependencyKind.kind,
|
|
133
181
|
created_at: toIsoString(candidate.created_at) ?? fallbackCreatedAt,
|
|
134
|
-
author: toNonEmptyString(candidate.author),
|
|
182
|
+
author: toNonEmptyString(candidate.author) ?? toNonEmptyString(candidate.created_by),
|
|
183
|
+
source_kind: dependencyKind.sourceKind,
|
|
135
184
|
});
|
|
136
185
|
}
|
|
137
186
|
return dependencies.length > 0 ? dependencies : undefined;
|
|
@@ -319,22 +368,76 @@ function emptyDocument() {
|
|
|
319
368
|
function resolveInputPath(rawPath) {
|
|
320
369
|
return path.isAbsolute(rawPath) ? rawPath : path.resolve(process.cwd(), rawPath);
|
|
321
370
|
}
|
|
371
|
+
async function readStdin() {
|
|
372
|
+
if (process.stdin.isTTY === true) {
|
|
373
|
+
throw new PmCliError('--file value "-" requires piped stdin input. Pipe JSONL content into the command, or end manual stdin with Ctrl+D (Unix/macOS) or Ctrl+Z then Enter (Windows).', EXIT_CODE.USAGE);
|
|
374
|
+
}
|
|
375
|
+
return await new Promise((resolve, reject) => {
|
|
376
|
+
let raw = "";
|
|
377
|
+
process.stdin.setEncoding("utf8");
|
|
378
|
+
process.stdin.on("data", (chunk) => {
|
|
379
|
+
raw += chunk;
|
|
380
|
+
});
|
|
381
|
+
process.stdin.on("end", () => resolve(raw));
|
|
382
|
+
process.stdin.on("error", reject);
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
async function resolveBeadsSource(rawPath) {
|
|
386
|
+
const explicitSource = toNonEmptyString(rawPath);
|
|
387
|
+
if (explicitSource) {
|
|
388
|
+
if (explicitSource === "-") {
|
|
389
|
+
return {
|
|
390
|
+
source: "-",
|
|
391
|
+
raw: await readStdin(),
|
|
392
|
+
warnings: [],
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
const explicitPath = resolveInputPath(explicitSource);
|
|
396
|
+
if (!(await pathExists(explicitPath))) {
|
|
397
|
+
throw new PmCliError(`Beads source file not found at ${explicitPath}`, EXIT_CODE.NOT_FOUND);
|
|
398
|
+
}
|
|
399
|
+
return {
|
|
400
|
+
source: explicitSource,
|
|
401
|
+
sourcePath: explicitPath,
|
|
402
|
+
raw: await fs.readFile(explicitPath, "utf8"),
|
|
403
|
+
warnings: [],
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
for (const candidate of PRIMARY_AUTO_DISCOVERY_FILES) {
|
|
407
|
+
const candidatePath = resolveInputPath(candidate);
|
|
408
|
+
if (await pathExists(candidatePath)) {
|
|
409
|
+
return {
|
|
410
|
+
source: candidate,
|
|
411
|
+
sourcePath: candidatePath,
|
|
412
|
+
raw: await fs.readFile(candidatePath, "utf8"),
|
|
413
|
+
warnings: candidate === PRIMARY_AUTO_DISCOVERY_FILES[0] ? [] : [`beads_import_source_autodiscovered:${candidate}`],
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
for (const candidate of UNSAFE_AUTO_DISCOVERY_FILES) {
|
|
418
|
+
const candidatePath = resolveInputPath(candidate);
|
|
419
|
+
if (await pathExists(candidatePath)) {
|
|
420
|
+
throw new PmCliError(`Beads auto-discovery found ${candidatePath}, but sync_base snapshots may be partial. Export a full Beads JSONL file and pass --file <path> (or --file - for stdin).`, EXIT_CODE.NOT_FOUND);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
throw new PmCliError(`Beads source file not found. Checked ${PRIMARY_AUTO_DISCOVERY_FILES.join(", ")}. Use --file <path> or --file - for stdin.`, EXIT_CODE.NOT_FOUND);
|
|
424
|
+
}
|
|
322
425
|
export async function runBeadsImport(options, global) {
|
|
323
426
|
const pmRoot = resolvePmRoot(process.cwd(), global.path);
|
|
324
427
|
await ensureInitHasRun(pmRoot);
|
|
325
428
|
const settings = await readSettings(pmRoot);
|
|
326
|
-
const
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
throw new PmCliError(`Beads source file not found at ${sourcePath}`, EXIT_CODE.NOT_FOUND);
|
|
330
|
-
}
|
|
331
|
-
const raw = await fs.readFile(sourcePath, "utf8");
|
|
429
|
+
const typeRegistry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
|
|
430
|
+
const preserveSourceIds = options.preserveSourceIds === true;
|
|
431
|
+
const { source, sourcePath, raw, warnings: sourceWarnings } = await resolveBeadsSource(options.file);
|
|
332
432
|
const warnings = [
|
|
333
|
-
...
|
|
433
|
+
...sourceWarnings,
|
|
434
|
+
];
|
|
435
|
+
if (sourcePath) {
|
|
436
|
+
warnings.push(...(await runActiveOnReadHooks({
|
|
334
437
|
path: sourcePath,
|
|
335
438
|
scope: "project",
|
|
336
|
-
}))
|
|
337
|
-
|
|
439
|
+
})));
|
|
440
|
+
}
|
|
338
441
|
const lines = raw.split(/\r?\n/);
|
|
339
442
|
const author = selectAuthor(toNonEmptyString(options.author), settings.author_default);
|
|
340
443
|
const message = toNonEmptyString(options.message) ?? "Import from Beads JSONL";
|
|
@@ -371,26 +474,34 @@ export async function runBeadsImport(options, global) {
|
|
|
371
474
|
const createdAt = toIsoString(record.created_at) ?? nowIso();
|
|
372
475
|
const updatedAt = toIsoString(record.updated_at) ?? createdAt;
|
|
373
476
|
const id = toNonEmptyString(record.id)
|
|
374
|
-
?
|
|
477
|
+
? normalizeImportedId(toNonEmptyString(record.id), settings.id_prefix, preserveSourceIds)
|
|
375
478
|
: await generateItemId(pmRoot, settings.id_prefix);
|
|
376
|
-
const
|
|
479
|
+
const typeMapping = toItemType(record.issue_type ?? record.type);
|
|
480
|
+
const type = typeMapping.type;
|
|
481
|
+
const closedAt = toIsoString(record.closed_at);
|
|
482
|
+
const assignee = toNonEmptyString(record.assignee) ?? toNonEmptyString(record.owner);
|
|
377
483
|
const frontMatter = normalizeFrontMatter({
|
|
378
484
|
id,
|
|
379
485
|
title,
|
|
380
486
|
description: toNonEmptyString(record.description) ?? "",
|
|
381
487
|
type,
|
|
488
|
+
source_type: typeMapping.sourceType,
|
|
382
489
|
status: toStatus(record.status),
|
|
383
490
|
priority: toPriority(record.priority),
|
|
384
491
|
tags: toTags(record.tags ?? record.labels),
|
|
385
492
|
created_at: createdAt,
|
|
386
493
|
updated_at: updatedAt,
|
|
387
|
-
deadline: toIsoString(record.deadline),
|
|
388
|
-
|
|
494
|
+
deadline: toIsoString(record.due_at ?? record.deadline),
|
|
495
|
+
closed_at: closedAt,
|
|
496
|
+
assignee,
|
|
497
|
+
source_owner: toNonEmptyString(record.owner),
|
|
389
498
|
author: toNonEmptyString(record.author) ?? toNonEmptyString(record.created_by) ?? author,
|
|
390
499
|
estimated_minutes: toEstimatedMinutes(record.estimated_minutes),
|
|
391
500
|
acceptance_criteria: toNonEmptyString(record.acceptance_criteria),
|
|
392
|
-
|
|
393
|
-
|
|
501
|
+
design: toNonEmptyString(record.design),
|
|
502
|
+
external_ref: toNonEmptyString(record.external_ref),
|
|
503
|
+
close_reason: toNonEmptyString(record.close_reason),
|
|
504
|
+
dependencies: toDependencies(record.dependencies, createdAt, settings.id_prefix, preserveSourceIds),
|
|
394
505
|
comments: toLogEntries(record.comments, createdAt, author),
|
|
395
506
|
notes: toLogEntries(record.notes, createdAt, author),
|
|
396
507
|
learnings: toLogEntries(record.learnings, createdAt, author),
|
|
@@ -412,17 +523,18 @@ export async function runBeadsImport(options, global) {
|
|
|
412
523
|
front_matter: frontMatter,
|
|
413
524
|
body: finalBody,
|
|
414
525
|
});
|
|
415
|
-
const
|
|
416
|
-
if (
|
|
526
|
+
const existing = await locateItem(pmRoot, id, settings.id_prefix, settings.item_format, typeRegistry.type_to_folder);
|
|
527
|
+
if (existing) {
|
|
417
528
|
warnings.push(`beads_import_item_exists:${id}`);
|
|
418
529
|
skipped += 1;
|
|
419
530
|
continue;
|
|
420
531
|
}
|
|
532
|
+
const itemPath = getItemPath(pmRoot, type, id, settings.item_format, typeRegistry.type_to_folder);
|
|
421
533
|
const historyPath = getHistoryPath(pmRoot, id);
|
|
422
534
|
try {
|
|
423
535
|
const releaseLock = await acquireLock(pmRoot, id, settings.locks.ttl_seconds, author);
|
|
424
536
|
try {
|
|
425
|
-
await writeFileAtomic(itemPath, serializeItemDocument(afterDocument));
|
|
537
|
+
await writeFileAtomic(itemPath, serializeItemDocument(afterDocument, { format: settings.item_format }));
|
|
426
538
|
try {
|
|
427
539
|
const entry = createHistoryEntry({
|
|
428
540
|
nowIso: nowIso(),
|
|
@@ -471,5 +583,4 @@ export async function runBeadsImport(options, global) {
|
|
|
471
583
|
ids,
|
|
472
584
|
warnings,
|
|
473
585
|
};
|
|
474
|
-
}
|
|
475
|
-
//# sourceMappingURL=beads.js.map
|
|
586
|
+
}
|