@agentplaneorg/core 0.1.3 → 0.1.5

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.
Files changed (52) hide show
  1. package/README.md +16 -3
  2. package/dist/commit/commit-policy.d.ts.map +1 -0
  3. package/dist/{config.d.ts → config/config.d.ts} +1 -0
  4. package/dist/config/config.d.ts.map +1 -0
  5. package/dist/config/config.js +124 -0
  6. package/dist/fs/atomic-write.d.ts +2 -0
  7. package/dist/fs/atomic-write.d.ts.map +1 -0
  8. package/dist/fs/atomic-write.js +9 -0
  9. package/dist/git/base-branch.d.ts.map +1 -0
  10. package/dist/{base-branch.js → git/base-branch.js} +1 -1
  11. package/dist/git/git-utils.d.ts.map +1 -0
  12. package/dist/{git-utils.js → git/git-utils.js} +1 -1
  13. package/dist/index.d.ts +12 -9
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +12 -9
  16. package/dist/project/project-root.d.ts.map +1 -0
  17. package/dist/tasks/task-doc.d.ts +16 -0
  18. package/dist/tasks/task-doc.d.ts.map +1 -0
  19. package/dist/tasks/task-doc.js +326 -0
  20. package/dist/tasks/task-id.d.ts +9 -0
  21. package/dist/tasks/task-id.d.ts.map +1 -0
  22. package/dist/tasks/task-id.js +28 -0
  23. package/dist/tasks/task-readme.d.ts.map +1 -0
  24. package/dist/{task-store.d.ts → tasks/task-store.d.ts} +2 -0
  25. package/dist/tasks/task-store.d.ts.map +1 -0
  26. package/dist/tasks/task-store.js +212 -0
  27. package/dist/tasks/tasks-export.d.ts.map +1 -0
  28. package/dist/{tasks-export.js → tasks/tasks-export.js} +5 -4
  29. package/dist/{tasks-lint.d.ts → tasks/tasks-lint.d.ts} +1 -1
  30. package/dist/tasks/tasks-lint.d.ts.map +1 -0
  31. package/dist/{tasks-lint.js → tasks/tasks-lint.js} +2 -2
  32. package/package.json +3 -1
  33. package/dist/base-branch.d.ts.map +0 -1
  34. package/dist/commit-policy.d.ts.map +0 -1
  35. package/dist/config.d.ts.map +0 -1
  36. package/dist/config.js +0 -237
  37. package/dist/git-utils.d.ts.map +0 -1
  38. package/dist/project-root.d.ts.map +0 -1
  39. package/dist/task-readme.d.ts.map +0 -1
  40. package/dist/task-store.d.ts.map +0 -1
  41. package/dist/task-store.js +0 -353
  42. package/dist/tasks-export.d.ts.map +0 -1
  43. package/dist/tasks-lint.d.ts.map +0 -1
  44. /package/dist/{commit-policy.d.ts → commit/commit-policy.d.ts} +0 -0
  45. /package/dist/{commit-policy.js → commit/commit-policy.js} +0 -0
  46. /package/dist/{base-branch.d.ts → git/base-branch.d.ts} +0 -0
  47. /package/dist/{git-utils.d.ts → git/git-utils.d.ts} +0 -0
  48. /package/dist/{project-root.d.ts → project/project-root.d.ts} +0 -0
  49. /package/dist/{project-root.js → project/project-root.js} +0 -0
  50. /package/dist/{task-readme.d.ts → tasks/task-readme.d.ts} +0 -0
  51. /package/dist/{task-readme.js → tasks/task-readme.js} +0 -0
  52. /package/dist/{tasks-export.d.ts → tasks/tasks-export.d.ts} +0 -0
package/README.md CHANGED
@@ -9,18 +9,31 @@ for project discovery, config handling, task readme parsing, and task export/lin
9
9
 
10
10
  If you are an end-user, install the CLI instead: https://www.npmjs.com/package/agentplane
11
11
 
12
- ## Install
12
+ ## 5-minute start (CLI)
13
+
14
+ ```bash
15
+ npm install -g agentplane
16
+ agentplane init
17
+ agentplane quickstart
18
+ agentplane task new --title "First task" --description "Describe the change" --priority med --owner ORCHESTRATOR --tag docs
19
+ agentplane verify <task-id>
20
+ agentplane finish <task-id>
21
+ ```
22
+
23
+ ## For library usage
24
+
25
+ ### Install
13
26
 
14
27
  ```bash
15
28
  npm install @agentplaneorg/core
16
29
  ```
17
30
 
18
- ## Requirements
31
+ ### Requirements
19
32
 
20
33
  - Node.js >= 20
21
34
  - ESM-only (`type: module`)
22
35
 
23
- ## Usage
36
+ ### Usage
24
37
 
25
38
  ```ts
26
39
  import {
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit-policy.d.ts","sourceRoot":"","sources":["../../src/commit/commit-policy.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAMF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGxD;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,OAAO,CAOlF;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB,GAAG,kBAAkB,CAerB"}
@@ -10,6 +10,7 @@ export type AgentplaneConfig = {
10
10
  approvals: {
11
11
  require_plan: boolean;
12
12
  require_network: boolean;
13
+ require_verify: boolean;
13
14
  };
14
15
  };
15
16
  recipes?: {
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config/config.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,WAAW,CAAC;AAClD,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC;AAE5D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,cAAc,EAAE,CAAC,CAAC;IAClB,aAAa,EAAE,YAAY,CAAC;IAC5B,oBAAoB,EAAE,kBAAkB,CAAC;IACzC,yBAAyB,EAAE,OAAO,CAAC;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE;QACP,SAAS,EAAE;YACT,YAAY,EAAE,OAAO,CAAC;YACtB,eAAe,EAAE,OAAO,CAAC;YACzB,cAAc,EAAE,OAAO,CAAC;SACzB,CAAC;KACH,CAAC;IACF,OAAO,CAAC,EAAE;QACR,eAAe,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;KAC7C,CAAC;IACF,KAAK,EAAE;QACL,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAChC,SAAS,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC1D,KAAK,EAAE;QACL,wBAAwB,EAAE,MAAM,CAAC;QACjC,MAAM,EAAE;YAAE,aAAa,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC;QACpC,GAAG,EAAE;YAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;YAAC,iBAAiB,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC;QACzD,QAAQ,EAAE;YACR,KAAK,EAAE;gBAAE,MAAM,EAAE,MAAM,CAAC;gBAAC,SAAS,EAAE,MAAM,CAAA;aAAE,CAAC;YAC7C,OAAO,EAAE;gBAAE,MAAM,EAAE,MAAM,CAAC;gBAAC,SAAS,EAAE,MAAM,CAAA;aAAE,CAAC;YAC/C,QAAQ,EAAE;gBAAE,MAAM,EAAE,MAAM,CAAC;gBAAC,SAAS,EAAE,MAAM,CAAA;aAAE,CAAC;SACjD,CAAC;KACH,CAAC;IACF,MAAM,EAAE;QAAE,cAAc,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACrC,aAAa,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,gCAAgC,EAAE,OAAO,CAAC;CAC3C,CAAC;AAEF,wBAAgB,aAAa,IAAI,gBAAgB,CAEhD;AA2CD,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,CAU7D;AAID,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,gBAAgB,CAAC;IACzB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9B,CAAC;AAQF,wBAAsB,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAyB7E;AAkBD,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,IAAI,CAgBN;AAED,wBAAsB,UAAU,CAC9B,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,OAAO,CAAC,gBAAgB,CAAC,CAO3B"}
@@ -0,0 +1,124 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import AjvModule from "ajv";
6
+ import AjvFormatsModule from "ajv-formats";
7
+ export function defaultConfig() {
8
+ return structuredClone(DEFAULT_CONFIG);
9
+ }
10
+ function isRecord(value) {
11
+ return !!value && typeof value === "object" && !Array.isArray(value);
12
+ }
13
+ const CONFIG_SCHEMA_URL = new URL("../../../spec/schemas/config.schema.json", import.meta.url);
14
+ const CONFIG_SCHEMA = JSON.parse(readFileSync(fileURLToPath(CONFIG_SCHEMA_URL), "utf8"));
15
+ const Ajv = AjvModule.default ??
16
+ AjvModule;
17
+ const addFormats = AjvFormatsModule.default ??
18
+ AjvFormatsModule;
19
+ const AJV = new Ajv({
20
+ allErrors: true,
21
+ allowUnionTypes: true,
22
+ useDefaults: true,
23
+ strict: false,
24
+ });
25
+ addFormats(AJV);
26
+ const validateSchema = AJV.compile(CONFIG_SCHEMA);
27
+ function formatSchemaErrors(errors) {
28
+ if (!errors || errors.length === 0)
29
+ return "config schema validation failed";
30
+ return AJV.errorsText(errors, { dataVar: "config" });
31
+ }
32
+ export function validateConfig(raw) {
33
+ const candidate = raw && typeof raw === "object" ? structuredClone(raw) : raw;
34
+ if (!validateSchema(candidate)) {
35
+ throw new Error(formatSchemaErrors(validateSchema.errors));
36
+ }
37
+ if (!isRecord(candidate)) {
38
+ throw new Error("config must be an object");
39
+ }
40
+ return candidate;
41
+ }
42
+ const DEFAULT_CONFIG = validateConfig({});
43
+ function toErrnoException(err) {
44
+ if (!err || typeof err !== "object")
45
+ return null;
46
+ if (!("code" in err))
47
+ return null;
48
+ return err;
49
+ }
50
+ export async function loadConfig(agentplaneDir) {
51
+ const filePath = path.join(agentplaneDir, "config.json");
52
+ try {
53
+ const rawText = await readFile(filePath, "utf8");
54
+ const parsed = JSON.parse(rawText);
55
+ const validated = validateConfig(parsed);
56
+ return {
57
+ path: filePath,
58
+ exists: true,
59
+ config: validated,
60
+ raw: parsed,
61
+ };
62
+ }
63
+ catch (err) {
64
+ const errno = toErrnoException(err);
65
+ if (errno?.code === "ENOENT") {
66
+ const def = defaultConfig();
67
+ return {
68
+ path: filePath,
69
+ exists: false,
70
+ config: def,
71
+ raw: def,
72
+ };
73
+ }
74
+ throw err;
75
+ }
76
+ }
77
+ function parseScalar(value) {
78
+ const trimmed = value.trim();
79
+ if (trimmed === "true")
80
+ return true;
81
+ if (trimmed === "false")
82
+ return false;
83
+ if (trimmed === "null")
84
+ return null;
85
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
86
+ try {
87
+ return JSON.parse(trimmed);
88
+ }
89
+ catch {
90
+ return value;
91
+ }
92
+ }
93
+ if (/^-?\d+(?:\.\d+)?$/.test(trimmed))
94
+ return Number(trimmed);
95
+ return value;
96
+ }
97
+ export function setByDottedKey(obj, dottedKey, value) {
98
+ const parts = dottedKey.split(".").filter(Boolean);
99
+ if (parts.length === 0)
100
+ throw new Error("config key must be non-empty");
101
+ let current = obj;
102
+ for (let i = 0; i < parts.length - 1; i++) {
103
+ const part = parts[i];
104
+ if (!part)
105
+ continue;
106
+ const next = current[part];
107
+ if (!isRecord(next)) {
108
+ current[part] = {};
109
+ }
110
+ current = current[part];
111
+ }
112
+ const last = parts.at(-1);
113
+ if (!last)
114
+ throw new Error("config key must be non-empty");
115
+ current[last] = parseScalar(value);
116
+ }
117
+ export async function saveConfig(agentplaneDir, raw) {
118
+ const validated = validateConfig(raw);
119
+ await mkdir(agentplaneDir, { recursive: true });
120
+ const filePath = path.join(agentplaneDir, "config.json");
121
+ const text = `${JSON.stringify(raw, null, 2)}\n`;
122
+ await writeFile(filePath, text, "utf8");
123
+ return validated;
124
+ }
@@ -0,0 +1,2 @@
1
+ export declare function atomicWriteFile(filePath: string, contents: string | Buffer, encoding?: BufferEncoding): Promise<void>;
2
+ //# sourceMappingURL=atomic-write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atomic-write.d.ts","sourceRoot":"","sources":["../../src/fs/atomic-write.ts"],"names":[],"mappings":"AAGA,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GAAG,MAAM,EACzB,QAAQ,GAAE,cAAuB,GAChC,OAAO,CAAC,IAAI,CAAC,CAMf"}
@@ -0,0 +1,9 @@
1
+ import { mkdir, rename, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ export async function atomicWriteFile(filePath, contents, encoding = "utf8") {
4
+ const dir = path.dirname(filePath);
5
+ await mkdir(dir, { recursive: true });
6
+ const tmpPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
7
+ await writeFile(tmpPath, contents, typeof contents === "string" ? encoding : undefined);
8
+ await rename(tmpPath, filePath);
9
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-branch.d.ts","sourceRoot":"","sources":["../../src/git/base-branch.ts"],"names":[],"mappings":"AA0BA,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGzB;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,GAAG,OAAO,CAAC,MAAM,CAAC,CAGlB;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,MAAM,CAAC,CAMlB"}
@@ -1,6 +1,6 @@
1
1
  import { execFile } from "node:child_process";
2
2
  import { promisify } from "node:util";
3
- import { resolveProject } from "./project-root.js";
3
+ import { resolveProject } from "../project/project-root.js";
4
4
  const execFileAsync = promisify(execFile);
5
5
  const DEFAULT_BASE_BRANCH = "main";
6
6
  const GIT_CONFIG_BASE_BRANCH_KEY = "agentplane.baseBranch";
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-utils.d.ts","sourceRoot":"","sources":["../../src/git/git-utils.ts"],"names":[],"mappings":"AAeA,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAGpB;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAcpB"}
@@ -1,6 +1,6 @@
1
1
  import { execFile } from "node:child_process";
2
2
  import { promisify } from "node:util";
3
- import { resolveProject } from "./project-root.js";
3
+ import { resolveProject } from "../project/project-root.js";
4
4
  const execFileAsync = promisify(execFile);
5
5
  async function gitLines(cwd, args) {
6
6
  const { stdout } = await execFileAsync("git", args, { cwd });
package/dist/index.d.ts CHANGED
@@ -1,11 +1,14 @@
1
1
  export declare const CORE_VERSION = "0.0.0";
2
- export { findGitRoot, resolveProject, type ResolvedProject, type ResolveProjectOptions, } from "./project-root.js";
3
- export { defaultConfig, loadConfig, saveConfig, setByDottedKey, validateConfig, type AgentplaneConfig, type LoadedConfig, type StatusCommitPolicy, type WorkflowMode, } from "./config.js";
4
- export { parseTaskReadme, renderTaskFrontmatter, renderTaskReadme, type ParsedTaskReadme, } from "./task-readme.js";
5
- export { createTask, getTasksDir, listTasks, readTask, setTaskDocSection, taskReadmePath, validateTaskDocMetadata, type TaskFrontmatter, type TaskPriority, type TaskRecord, type TaskStatus, } from "./task-store.js";
6
- export { buildTasksExportSnapshot, canonicalTasksPayload, canonicalizeJson, computeTasksChecksum, writeTasksExport, type TasksExportMeta, type TasksExportSnapshot, type TasksExportTask, } from "./tasks-export.js";
7
- export { lintTasksFile, lintTasksSnapshot, readTasksExport, type TasksLintResult, } from "./tasks-lint.js";
8
- export { getBaseBranch, getPinnedBaseBranch, setPinnedBaseBranch } from "./base-branch.js";
9
- export { extractTaskSuffix, isGenericSubject, validateCommitSubject, type CommitPolicyResult, } from "./commit-policy.js";
10
- export { getStagedFiles, getUnstagedFiles } from "./git-utils.js";
2
+ export { findGitRoot, resolveProject, type ResolvedProject, type ResolveProjectOptions, } from "./project/project-root.js";
3
+ export { defaultConfig, loadConfig, saveConfig, setByDottedKey, validateConfig, type AgentplaneConfig, type LoadedConfig, type StatusCommitPolicy, type WorkflowMode, } from "./config/config.js";
4
+ export { parseTaskReadme, renderTaskFrontmatter, renderTaskReadme, type ParsedTaskReadme, } from "./tasks/task-readme.js";
5
+ export { docChanged, ensureDocSections, extractTaskDoc, mergeTaskDoc, normalizeDocSectionName, normalizeTaskDoc, parseDocSections, setMarkdownSection, splitCombinedHeadingLines, } from "./tasks/task-doc.js";
6
+ export { atomicWriteFile } from "./fs/atomic-write.js";
7
+ export { generateTaskId, timestampIdPrefix, TASK_ID_ALPHABET } from "./tasks/task-id.js";
8
+ export { createTask, getTasksDir, listTasks, readTask, setTaskDocSection, taskReadmePath, validateTaskDocMetadata, type TaskFrontmatter, type TaskPriority, type TaskRecord, type TaskStatus, } from "./tasks/task-store.js";
9
+ export { buildTasksExportSnapshot, canonicalTasksPayload, canonicalizeJson, computeTasksChecksum, writeTasksExport, type TasksExportMeta, type TasksExportSnapshot, type TasksExportTask, } from "./tasks/tasks-export.js";
10
+ export { lintTasksFile, lintTasksSnapshot, readTasksExport, type TasksLintResult, } from "./tasks/tasks-lint.js";
11
+ export { getBaseBranch, getPinnedBaseBranch, setPinnedBaseBranch } from "./git/base-branch.js";
12
+ export { extractTaskSuffix, isGenericSubject, validateCommitSubject, type CommitPolicyResult, } from "./commit/commit-policy.js";
13
+ export { getStagedFiles, getUnstagedFiles } from "./git/git-utils.js";
11
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY,UAAU,CAAC;AAEpC,OAAO,EACL,WAAW,EACX,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,qBAAqB,GAC3B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,aAAa,EACb,UAAU,EACV,UAAU,EACV,cAAc,EACd,cAAc,EACd,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,YAAY,GAClB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,gBAAgB,EAChB,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,UAAU,EACV,WAAW,EACX,SAAS,EACT,QAAQ,EACR,iBAAiB,EACjB,cAAc,EACd,uBAAuB,EACvB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,eAAe,GACrB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,KAAK,eAAe,GACrB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE3F,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY,UAAU,CAAC;AAEpC,OAAO,EACL,WAAW,EACX,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,qBAAqB,GAC3B,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,aAAa,EACb,UAAU,EACV,UAAU,EACV,cAAc,EACd,cAAc,EACd,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,YAAY,GAClB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,gBAAgB,EAChB,KAAK,gBAAgB,GACtB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,cAAc,EACd,YAAY,EACZ,uBAAuB,EACvB,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,yBAAyB,GAC1B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEzF,OAAO,EACL,UAAU,EACV,WAAW,EACX,SAAS,EACT,QAAQ,EACR,iBAAiB,EACjB,cAAc,EACd,uBAAuB,EACvB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,eAAe,GACrB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,KAAK,eAAe,GACrB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE/F,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,KAAK,kBAAkB,GACxB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.js CHANGED
@@ -1,10 +1,13 @@
1
1
  export const CORE_VERSION = "0.0.0";
2
- export { findGitRoot, resolveProject, } from "./project-root.js";
3
- export { defaultConfig, loadConfig, saveConfig, setByDottedKey, validateConfig, } from "./config.js";
4
- export { parseTaskReadme, renderTaskFrontmatter, renderTaskReadme, } from "./task-readme.js";
5
- export { createTask, getTasksDir, listTasks, readTask, setTaskDocSection, taskReadmePath, validateTaskDocMetadata, } from "./task-store.js";
6
- export { buildTasksExportSnapshot, canonicalTasksPayload, canonicalizeJson, computeTasksChecksum, writeTasksExport, } from "./tasks-export.js";
7
- export { lintTasksFile, lintTasksSnapshot, readTasksExport, } from "./tasks-lint.js";
8
- export { getBaseBranch, getPinnedBaseBranch, setPinnedBaseBranch } from "./base-branch.js";
9
- export { extractTaskSuffix, isGenericSubject, validateCommitSubject, } from "./commit-policy.js";
10
- export { getStagedFiles, getUnstagedFiles } from "./git-utils.js";
2
+ export { findGitRoot, resolveProject, } from "./project/project-root.js";
3
+ export { defaultConfig, loadConfig, saveConfig, setByDottedKey, validateConfig, } from "./config/config.js";
4
+ export { parseTaskReadme, renderTaskFrontmatter, renderTaskReadme, } from "./tasks/task-readme.js";
5
+ export { docChanged, ensureDocSections, extractTaskDoc, mergeTaskDoc, normalizeDocSectionName, normalizeTaskDoc, parseDocSections, setMarkdownSection, splitCombinedHeadingLines, } from "./tasks/task-doc.js";
6
+ export { atomicWriteFile } from "./fs/atomic-write.js";
7
+ export { generateTaskId, timestampIdPrefix, TASK_ID_ALPHABET } from "./tasks/task-id.js";
8
+ export { createTask, getTasksDir, listTasks, readTask, setTaskDocSection, taskReadmePath, validateTaskDocMetadata, } from "./tasks/task-store.js";
9
+ export { buildTasksExportSnapshot, canonicalTasksPayload, canonicalizeJson, computeTasksChecksum, writeTasksExport, } from "./tasks/tasks-export.js";
10
+ export { lintTasksFile, lintTasksSnapshot, readTasksExport, } from "./tasks/tasks-lint.js";
11
+ export { getBaseBranch, getPinnedBaseBranch, setPinnedBaseBranch } from "./git/base-branch.js";
12
+ export { extractTaskSuffix, isGenericSubject, validateCommitSubject, } from "./commit/commit-policy.js";
13
+ export { getStagedFiles, getUnstagedFiles } from "./git/git-utils.js";
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-root.d.ts","sourceRoot":"","sources":["../../src/project/project-root.ts"],"names":[],"mappings":"AAiBA,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAU1E;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,wBAAsB,cAAc,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC,CAU1F"}
@@ -0,0 +1,16 @@
1
+ export declare function normalizeDocSectionName(section: string): string;
2
+ export declare function splitCombinedHeadingLines(doc: string): string[];
3
+ export declare function normalizeTaskDoc(doc: string): string;
4
+ export declare function extractTaskDoc(body: string): string;
5
+ export declare function mergeTaskDoc(body: string, doc: string): string;
6
+ export declare function docChanged(existing: string, updated: string): boolean;
7
+ export declare function setMarkdownSection(body: string, section: string, text: string): string;
8
+ export declare function ensureDocSections(doc: string, required: string[]): string;
9
+ export declare function parseDocSections(doc: string): {
10
+ sections: Map<string, {
11
+ title: string;
12
+ lines: string[];
13
+ }>;
14
+ order: string[];
15
+ };
16
+ //# sourceMappingURL=task-doc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-doc.d.ts","sourceRoot":"","sources":["../../src/tasks/task-doc.ts"],"names":[],"mappings":"AAIA,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE/D;AAUD,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAiC/D;AA2CD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAwDpD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuBnD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAiC9D;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAErE;AAMD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CA6BtF;AA+DD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAOzE;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG;IAC7C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IAC1D,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB,CAyBA"}
@@ -0,0 +1,326 @@
1
+ const DOC_SECTION_HEADER = "## Summary";
2
+ const DOC_SECTION_HEADER_RE = /^##\s+Summary(?:\s|$|#)/;
3
+ const AUTO_SUMMARY_HEADER = "## Changes Summary (auto)";
4
+ export function normalizeDocSectionName(section) {
5
+ return section.trim().replaceAll(/\s+/g, " ").toLowerCase();
6
+ }
7
+ function normalizeDoc(text) {
8
+ return (text ?? "")
9
+ .split("\n")
10
+ .map((line) => line.replaceAll(/\s+$/gu, ""))
11
+ .join("\n")
12
+ .trim();
13
+ }
14
+ export function splitCombinedHeadingLines(doc) {
15
+ const lines = doc.replaceAll("\r\n", "\n").split("\n");
16
+ const out = [];
17
+ let inFence = false;
18
+ for (const line of lines) {
19
+ const trimmed = line.trimStart();
20
+ if (trimmed.startsWith("```")) {
21
+ inFence = !inFence;
22
+ out.push(line);
23
+ continue;
24
+ }
25
+ if (!inFence && line.includes("## ")) {
26
+ const matches = [...line.matchAll(/##\s+/g)];
27
+ if (matches.length > 1 && matches[0]?.index === 0) {
28
+ let start = 0;
29
+ for (let i = 1; i < matches.length; i += 1) {
30
+ const idx = matches[i]?.index ?? 0;
31
+ const chunk = line.slice(start, idx).trimEnd();
32
+ if (chunk)
33
+ out.push(chunk);
34
+ start = idx;
35
+ }
36
+ const last = line.slice(start).trimEnd();
37
+ if (last)
38
+ out.push(last);
39
+ continue;
40
+ }
41
+ }
42
+ out.push(line);
43
+ }
44
+ return out;
45
+ }
46
+ function normalizeSectionLines(lines) {
47
+ const trimmedLines = [...lines];
48
+ while (trimmedLines.length > 0 && trimmedLines[0]?.trim() === "")
49
+ trimmedLines.shift();
50
+ while (trimmedLines.length > 0 && trimmedLines.at(-1)?.trim() === "")
51
+ trimmedLines.pop();
52
+ const out = [];
53
+ let inFence = false;
54
+ let pendingBlank = false;
55
+ for (const line of trimmedLines) {
56
+ const fenceCheck = line.trimStart();
57
+ if (fenceCheck.startsWith("```")) {
58
+ if (pendingBlank) {
59
+ out.push("");
60
+ pendingBlank = false;
61
+ }
62
+ out.push(line);
63
+ inFence = !inFence;
64
+ continue;
65
+ }
66
+ if (inFence) {
67
+ out.push(line);
68
+ continue;
69
+ }
70
+ if (line.trim() === "") {
71
+ pendingBlank = true;
72
+ continue;
73
+ }
74
+ if (pendingBlank) {
75
+ out.push("");
76
+ pendingBlank = false;
77
+ }
78
+ out.push(line);
79
+ }
80
+ return out;
81
+ }
82
+ export function normalizeTaskDoc(doc) {
83
+ const normalized = doc.replaceAll("\r\n", "\n");
84
+ const trimmed = normalized.replaceAll(/^\n+|\n+$/g, "");
85
+ if (!trimmed)
86
+ return "";
87
+ const lines = splitCombinedHeadingLines(trimmed);
88
+ const sections = new Map();
89
+ const order = [];
90
+ const pendingSeparator = new Set();
91
+ let currentKey = null;
92
+ for (const line of lines) {
93
+ const match = /^##\s+(.*)$/.exec(line.trim());
94
+ if (match) {
95
+ const title = match[1]?.trim() ?? "";
96
+ const key = normalizeDocSectionName(title);
97
+ if (key) {
98
+ const existing = sections.get(key);
99
+ if (existing) {
100
+ if (existing.lines.some((entry) => entry.trim() !== "")) {
101
+ pendingSeparator.add(key);
102
+ }
103
+ }
104
+ else {
105
+ sections.set(key, { title, lines: [] });
106
+ order.push(key);
107
+ }
108
+ currentKey = key;
109
+ continue;
110
+ }
111
+ }
112
+ if (currentKey) {
113
+ const entry = sections.get(currentKey);
114
+ if (!entry)
115
+ continue;
116
+ if (pendingSeparator.has(currentKey) && line.trim() !== "") {
117
+ entry.lines.push("");
118
+ pendingSeparator.delete(currentKey);
119
+ }
120
+ entry.lines.push(line);
121
+ }
122
+ }
123
+ if (order.length === 0)
124
+ return trimmed;
125
+ const out = [];
126
+ for (const key of order) {
127
+ const section = sections.get(key);
128
+ if (!section)
129
+ continue;
130
+ const normalizedLines = normalizeSectionLines(section.lines);
131
+ if (normalizedLines.length > 0) {
132
+ out.push(`## ${section.title}`, "", ...normalizedLines, "");
133
+ }
134
+ else {
135
+ out.push(`## ${section.title}`, "", "");
136
+ }
137
+ }
138
+ return out.join("\n").trimEnd();
139
+ }
140
+ export function extractTaskDoc(body) {
141
+ if (!body)
142
+ return "";
143
+ const lines = body.split("\n");
144
+ let startIdx = null;
145
+ for (const [idx, line] of lines.entries()) {
146
+ if (DOC_SECTION_HEADER_RE.test(line.trim())) {
147
+ startIdx = idx;
148
+ break;
149
+ }
150
+ }
151
+ if (startIdx === null)
152
+ return "";
153
+ if (lines[startIdx]?.trim() !== DOC_SECTION_HEADER) {
154
+ lines[startIdx] = DOC_SECTION_HEADER;
155
+ }
156
+ let endIdx = lines.length;
157
+ for (let idx = startIdx + 1; idx < lines.length; idx += 1) {
158
+ if (lines[idx]?.trim() === AUTO_SUMMARY_HEADER) {
159
+ endIdx = idx;
160
+ break;
161
+ }
162
+ }
163
+ const doc = lines.slice(startIdx, endIdx).join("\n").trimEnd();
164
+ return normalizeTaskDoc(doc);
165
+ }
166
+ export function mergeTaskDoc(body, doc) {
167
+ const docText = normalizeTaskDoc(String(doc ?? ""));
168
+ if (docText) {
169
+ const lines = body ? body.split("\n") : [];
170
+ let prefixIdx = null;
171
+ for (const [idx, line] of lines.entries()) {
172
+ if (DOC_SECTION_HEADER_RE.test(line.trim())) {
173
+ prefixIdx = idx;
174
+ break;
175
+ }
176
+ }
177
+ const prefixText = prefixIdx === null ? "" : lines.slice(0, prefixIdx).join("\n").trimEnd();
178
+ let autoIdx = null;
179
+ for (const [idx, line] of lines.entries()) {
180
+ if (line.trim() === AUTO_SUMMARY_HEADER) {
181
+ autoIdx = idx;
182
+ break;
183
+ }
184
+ }
185
+ const autoBlock = autoIdx === null ? "" : lines.slice(autoIdx).join("\n").trimEnd();
186
+ const parts = [];
187
+ if (prefixText) {
188
+ parts.push(prefixText, "");
189
+ }
190
+ parts.push(docText.trimEnd());
191
+ if (autoBlock) {
192
+ parts.push("", autoBlock);
193
+ }
194
+ return `${parts.join("\n").trimEnd()}\n`;
195
+ }
196
+ return body;
197
+ }
198
+ export function docChanged(existing, updated) {
199
+ return normalizeDoc(existing) !== normalizeDoc(updated);
200
+ }
201
+ function escapeRegExp(text) {
202
+ return text.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw `\\$&`);
203
+ }
204
+ export function setMarkdownSection(body, section, text) {
205
+ const lines = body.replaceAll("\r\n", "\n").split("\n");
206
+ const headingRe = new RegExp(String.raw `^##\s+${escapeRegExp(section)}\s*$`);
207
+ let start = -1;
208
+ let nextHeading = lines.length;
209
+ for (const [i, line] of lines.entries()) {
210
+ if (!line.startsWith("## "))
211
+ continue;
212
+ if (start === -1) {
213
+ if (headingRe.test(line))
214
+ start = i;
215
+ continue;
216
+ }
217
+ nextHeading = i;
218
+ break;
219
+ }
220
+ const newTextLines = text.replaceAll("\r\n", "\n").split("\n");
221
+ const replacement = ["", ...newTextLines, ""];
222
+ if (start === -1) {
223
+ const out = [...lines];
224
+ if (out.length > 0 && out.at(-1)?.trim() !== "")
225
+ out.push("");
226
+ out.push(`## ${section}`, ...replacement);
227
+ return `${out.join("\n")}\n`;
228
+ }
229
+ const out = [...lines.slice(0, start + 1), ...replacement, ...lines.slice(nextHeading)];
230
+ return `${out.join("\n")}\n`;
231
+ }
232
+ function normalizeDocSections(doc, required) {
233
+ const lines = splitCombinedHeadingLines(doc);
234
+ const sections = new Map();
235
+ const order = [];
236
+ const pendingSeparator = new Set();
237
+ let currentKey = null;
238
+ for (const line of lines) {
239
+ const match = /^##\s+(.*)$/.exec(line.trim());
240
+ if (match) {
241
+ const title = match[1]?.trim() ?? "";
242
+ const key = normalizeDocSectionName(title);
243
+ if (key) {
244
+ const existing = sections.get(key);
245
+ if (existing) {
246
+ if (existing.lines.some((entry) => entry.trim() !== "")) {
247
+ pendingSeparator.add(key);
248
+ }
249
+ }
250
+ else {
251
+ sections.set(key, { title, lines: [] });
252
+ order.push(key);
253
+ }
254
+ currentKey = key;
255
+ continue;
256
+ }
257
+ }
258
+ if (currentKey) {
259
+ const entry = sections.get(currentKey);
260
+ if (!entry)
261
+ continue;
262
+ if (pendingSeparator.has(currentKey) && line.trim() !== "") {
263
+ entry.lines.push("");
264
+ pendingSeparator.delete(currentKey);
265
+ }
266
+ entry.lines.push(line);
267
+ }
268
+ }
269
+ const out = [];
270
+ const seen = new Set(order);
271
+ for (const key of order) {
272
+ const section = sections.get(key);
273
+ if (!section)
274
+ continue;
275
+ out.push(`## ${section.title}`);
276
+ if (section.lines.length > 0) {
277
+ out.push(...section.lines);
278
+ }
279
+ else {
280
+ out.push("");
281
+ }
282
+ out.push("");
283
+ }
284
+ for (const requiredSection of required) {
285
+ const requiredKey = normalizeDocSectionName(requiredSection);
286
+ if (seen.has(requiredKey))
287
+ continue;
288
+ out.push(`## ${requiredSection}`, "", "");
289
+ }
290
+ return `${out.join("\n").trimEnd()}\n`;
291
+ }
292
+ export function ensureDocSections(doc, required) {
293
+ const trimmed = doc.trim();
294
+ if (!trimmed) {
295
+ const blocks = required.map((section) => `## ${section}\n`);
296
+ return `${blocks.join("\n").trimEnd()}\n`;
297
+ }
298
+ return normalizeDocSections(doc, required);
299
+ }
300
+ export function parseDocSections(doc) {
301
+ const lines = splitCombinedHeadingLines(doc);
302
+ const sections = new Map();
303
+ const order = [];
304
+ let currentKey = null;
305
+ for (const line of lines) {
306
+ const match = /^##\s+(.*)$/.exec(line.trim());
307
+ if (match) {
308
+ const title = match[1]?.trim() ?? "";
309
+ const key = normalizeDocSectionName(title);
310
+ if (key) {
311
+ if (!sections.has(key)) {
312
+ sections.set(key, { title, lines: [] });
313
+ order.push(key);
314
+ }
315
+ currentKey = key;
316
+ continue;
317
+ }
318
+ }
319
+ if (currentKey) {
320
+ const entry = sections.get(currentKey);
321
+ if (entry)
322
+ entry.lines.push(line);
323
+ }
324
+ }
325
+ return { sections, order };
326
+ }
@@ -0,0 +1,9 @@
1
+ export declare const TASK_ID_ALPHABET = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
2
+ export declare function timestampIdPrefix(date: Date): string;
3
+ export declare function generateTaskId(opts: {
4
+ length: number;
5
+ attempts: number;
6
+ isAvailable?: (taskId: string) => boolean | Promise<boolean>;
7
+ date?: Date;
8
+ }): Promise<string>;
9
+ //# sourceMappingURL=task-id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-id.d.ts","sourceRoot":"","sources":["../../src/tasks/task-id.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,gBAAgB,qCAAqC,CAAC;AAEnE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAOpD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7D,IAAI,CAAC,EAAE,IAAI,CAAC;CACb,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBlB"}