jg-plans 0.1.0 → 0.2.0

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 (48) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +8 -8
  3. package/api/README.md +75 -12
  4. package/cli/README.md +24 -6
  5. package/dist/cli/arguments.js +18 -3
  6. package/dist/cli/commands.js +76 -17
  7. package/dist/cli/types.d.ts +3 -1
  8. package/dist/documents/fingerprints.d.ts +19 -0
  9. package/dist/documents/fingerprints.js +56 -0
  10. package/dist/documents/index.d.ts +2 -1
  11. package/dist/documents/index.js +1 -0
  12. package/dist/documents/milestones.js +44 -33
  13. package/dist/documents/plan.js +33 -68
  14. package/dist/documents/types.d.ts +22 -0
  15. package/dist/documents/utilities.d.ts +16 -2
  16. package/dist/documents/utilities.js +105 -4
  17. package/dist/edits/index.d.ts +2 -0
  18. package/dist/edits/index.js +2 -1
  19. package/dist/edits/preparations.d.ts +30 -0
  20. package/dist/edits/preparations.js +159 -0
  21. package/dist/edits/types.d.ts +14 -0
  22. package/dist/edits/utilities.d.ts +1 -0
  23. package/dist/edits/utilities.js +9 -2
  24. package/dist/errors/constants.d.ts +3 -1
  25. package/dist/errors/constants.js +4 -0
  26. package/dist/files/documents.d.ts +46 -0
  27. package/dist/files/documents.js +176 -0
  28. package/dist/files/index.d.ts +3 -1
  29. package/dist/files/index.js +2 -0
  30. package/dist/files/locks.d.ts +16 -0
  31. package/dist/files/locks.js +127 -0
  32. package/dist/files/mutations.d.ts +7 -3
  33. package/dist/files/mutations.js +32 -83
  34. package/dist/files/types.d.ts +19 -5
  35. package/dist/files/utilities.d.ts +4 -4
  36. package/dist/files/utilities.js +24 -7
  37. package/dist/index.d.ts +10 -8
  38. package/dist/index.js +5 -4
  39. package/dist/protocol/index.d.ts +4 -4
  40. package/dist/protocol/index.js +2 -2
  41. package/dist/protocol/types.d.ts +63 -0
  42. package/dist/protocol/types.js +53 -1
  43. package/docs/getting-started.md +4 -4
  44. package/docs/integrations.md +14 -14
  45. package/errors/README.md +6 -4
  46. package/examples/library.mjs +34 -2
  47. package/package.json +4 -3
  48. package/protocol/0.1/README.md +8 -2
package/errors/README.md CHANGED
@@ -10,17 +10,19 @@ Document-format diagnostics are observations. They are separate from the operati
10
10
  | UNSAFE_EDIT | JG_PLANS_UNSAFE_EDIT | The requested edit is unsupported or ambiguous | Unsupported affected YAML/marker structure, selector ambiguity, or invalid spans; nothing is written. |
11
11
  | DESTINATION_EXISTS | JG_PLANS_DESTINATION_EXISTS | The plan destination already exists | Exclusive creation refuses an existing path. |
12
12
  | SOURCE_CHANGED | JG_PLANS_SOURCE_CHANGED | The document changed before replacement | A prior-content comparison observed different bytes; no retry occurs. |
13
- | WRITE_FAILED | JG_PLANS_WRITE_FAILED | The plan document could not be written | Creation or replacement failed; inspect any cleanupFailedPaths. |
13
+ | WRITE_FAILED | JG_PLANS_WRITE_FAILED | The plan document could not be written | Creation, replacement, or removal failed; inspect any cleanupFailedPaths. |
14
+ | LOCK_BUSY | JG_PLANS_LOCK_BUSY | The plan document is locked | Immediate participating-writer contention, including dead owners; no automatic recovery. |
15
+ | LOCK_FAILED | JG_PLANS_LOCK_FAILED | The plan document lock operation failed | Canonicalization/acquisition/release failed; release can follow durable writes. |
14
16
 
15
- parsePlan, parseMilestones, checkPlan, and inspectPlan can throw INVALID_INPUT for incompatible operation arguments. Inspection returns file failures as diagnostics rather than throwing away another readable document. createPlan can throw INVALID_INPUT, UNSUPPORTED_ENCODING, DESTINATION_EXISTS, and WRITE_FAILED. updatePlan can throw INVALID_INPUT, READ_FAILED, UNSUPPORTED_ENCODING, UNSAFE_EDIT, SOURCE_CHANGED, and WRITE_FAILED. Mutation failures exit 2 in the CLI.
17
+ parsePlan, parseMilestones, checkPlan, and inspectPlan can throw INVALID_INPUT for incompatible operation arguments. Inspection returns file failures as diagnostics rather than throwing away another readable document. Pure preparation can throw INVALID_INPUT, UNSUPPORTED_ENCODING, UNSAFE_EDIT, and SOURCE_CHANGED. createPlan adds DESTINATION_EXISTS/WRITE_FAILED and lock errors. updatePlan/writePlanDocument add READ_FAILED/WRITE_FAILED and lock errors. removeMilestones uses INVALID_INPUT, READ_FAILED, UNSUPPORTED_ENCODING, SOURCE_CHANGED, WRITE_FAILED, and lock errors. withPlanDocumentLocks validates arguments and reports lock failures while propagating callback errors after successful release. Mutation failures exit 2 in the CLI.
16
18
 
17
19
  Stable messages exclude user text. Internal causes may retain detailed provider errors and are never emitted by the CLI. Public error.data may contain a safe provider/unsupported-edit reason, an affected core field, or cleanupFailedPaths. For example, unsupported-metadata-value means an affected scalar uses an unsupported form, and noncanonical-id-insertion means a new ID cannot be inserted after a canonical status marker. Reason details refine the stable operational code; they do not quote source. Failed JSON parsing also omits the unsafe syntax-error cause.
18
20
 
19
- Failed creation cleans only still-recognizable owned partial files and its empty plan directory. If user edits or I/O failures prevent that cleanup, paths are reported without deleting intervening content. The selected storage root can remain empty. Updates never recreate missing documents, rewrite bodies, or recover history. The [API](../api/README.md) documents conservative YAML forms and caller coordination requirements.
21
+ Failed creation cleans only still-recognizable owned partial files and its empty plan directory. If user edits or I/O failures prevent that cleanup, paths are reported without deleting intervening content. The selected storage root can remain empty. Existing-target guards never recreate deleted documents. Explicit write operations can replace the selected body/source; they do not recover history. The [API](../api/README.md) documents conservative YAML forms and shared local locks. Acquisition failures report mutationOutcome not-applied. Release failures report operationCompleted and mutationOutcome uncertain if the callback started; inspect durable state before retrying. Internal AggregateError causes retain callback/release failures. Locks are not automatically recovered.
20
22
 
21
23
  ## Document diagnostics
22
24
 
23
- - Plan structure: MISSING_FRONTMATTER, UNTERMINATED_FRONTMATTER, INVALID_YAML, YAML_WARNING, YAML_VALUE_UNAVAILABLE, METADATA_NOT_MAPPING, MISSING_METADATA_FIELD, INVALID_METADATA_FIELD.
25
+ - Plan structure: MISSING_FRONTMATTER, UNTERMINATED_FRONTMATTER, INVALID_YAML, YAML_WARNING, YAML_VALUE_UNAVAILABLE, METADATA_NOT_MAPPING, MISSING_METADATA_FIELD, INVALID_METADATA_FIELD, FINGERPRINT_UNAVAILABLE.
24
26
  - Availability: MISSING_PLAN, MISSING_MILESTONES, ORPHAN_MILESTONES, UNREADABLE_DOCUMENT, FILE_TOO_LARGE, INVALID_ENCODING.
25
27
  - Milestones: NO_MILESTONES, INVALID_ORDINAL, NONSEQUENTIAL_ORDINAL, DUPLICATE_ORDINAL, EMPTY_MILESTONE_TITLE, MISSING_STATUS, EMPTY_STATUS, DUPLICATE_STATUS, MISPLACED_STATUS, DUPLICATE_ID_MARKER, INVALID_MILESTONE_ID, DUPLICATE_ID, MISPLACED_ID, AMBIGUOUS_OVERVIEW, OVERVIEW_MISMATCH.
26
28
 
@@ -1,7 +1,15 @@
1
1
  import { mkdtemp, rm } from 'node:fs/promises';
2
2
  import { tmpdir } from 'node:os';
3
3
  import { join } from 'node:path';
4
- import { checkPlan, createPlan, inspectPlan, updatePlan } from 'jg-plans';
4
+ import {
5
+ checkPlan,
6
+ createPlan,
7
+ inspectPlan,
8
+ updatePlan,
9
+ writePlanDocument,
10
+ removeMilestones,
11
+ preparePlanDocumentWrite,
12
+ } from 'jg-plans';
5
13
 
6
14
  // This example owns a temporary root. Never recursively remove a user's planning root.
7
15
  const root = await mkdtemp(join(tmpdir(), 'jg-plans-example-'));
@@ -12,18 +20,42 @@ try {
12
20
  body: '# A small change\n\nKeep the intent close to the work.\n',
13
21
  milestones: '## Milestone 1: Implement\n**Status:** pending\n',
14
22
  });
15
- // Await the complete operation before starting the next edit of this document.
23
+ // A consumer journal stores exact prepared source/IDs once, then replays those bytes.
24
+ const prepared = preparePlanDocumentWrite(created.milestones.source, {
25
+ document: 'milestones',
26
+ expectedSha256: created.milestones.sha256,
27
+ source: created.milestones.source,
28
+ assignMissingIds: true,
29
+ });
30
+ const written = await writePlanDocument(created.directory, {
31
+ document: 'milestones',
32
+ expectedSha256: created.milestones.sha256,
33
+ source: prepared.source,
34
+ });
16
35
  await updatePlan(created.directory, {
17
36
  document: 'milestones',
37
+ expectedSha256: written.sha256,
18
38
  changes: [{ select: { ordinal: 1 }, set: { status: 'done' } }],
19
39
  });
20
40
  const observed = await inspectPlan(created.directory);
41
+ // Body/core metadata can also be replaced together using the observed digest.
42
+ if (observed.plan.state === 'readable')
43
+ await writePlanDocument(created.directory, {
44
+ document: 'plan',
45
+ expectedSha256: observed.plan.sha256,
46
+ body: observed.plan.value.body,
47
+ set: { revision: 2 },
48
+ });
21
49
  const result = checkPlan({
22
50
  ...(observed.plan.state === 'readable' ? { plan: observed.plan.value.source } : {}),
23
51
  ...(observed.milestones.state === 'readable'
24
52
  ? { milestones: observed.milestones.value.source }
25
53
  : {}),
26
54
  });
55
+ if (observed.milestones.state === 'readable')
56
+ await removeMilestones(created.directory, {
57
+ expectedSha256: observed.milestones.sha256,
58
+ });
27
59
  console.log(JSON.stringify({ conforms: result.conforms, diagnostics: result.diagnostics }));
28
60
  } finally {
29
61
  await rm(root, { recursive: true, force: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jg-plans",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "A compact planning protocol for people and coding agents.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -49,7 +49,6 @@
49
49
  "@eslint/js": "10.0.1",
50
50
  "@types/node": "24.10.1",
51
51
  "eslint": "10.12.0",
52
- "jg-crypto": "0.3.0",
53
52
  "jg-fetch": "0.5.0",
54
53
  "prettier": "3.8.3",
55
54
  "prettier-plugin-astro": "1.1.1",
@@ -71,9 +70,11 @@
71
70
  "tailwindStylesheet": "./website/src/styles/global.css"
72
71
  },
73
72
  "dependencies": {
73
+ "jg-crypto": "0.3.0",
74
74
  "jg-exception": "1.7.0",
75
- "jg-fs": "1.6.0",
75
+ "jg-fs": "1.7.0",
76
76
  "jg-process": "1.6.1",
77
+ "jg-utilities": "1.7.0",
77
78
  "yaml": "2.9.1",
78
79
  "zod": "4.6.7"
79
80
  },
@@ -89,6 +89,12 @@ An optional Overview table with Milestone, Name, and Status columns is derived f
89
89
 
90
90
  Caller-supplied milestone source remains verbatim. A caller generating that source follows writer rules; nonconforming supplied source receives diagnostics rather than automatic normalization. Updating a recognizable misplaced marker may preserve its location with a diagnostic; it does not claim to have repaired conformance.
91
91
 
92
+ ## Source observations
93
+
94
+ Optional milestone frontmatter is a project-owned mapping; it does not require the plan's five preferred fields. Readers preserve it and exclude it from Markdown heading/marker scanning. Both document kinds retain complete original source, including BOM and line endings. The reference library exposes preamble and heading/body ranges, milestone heading ends, and recognized Overview table ranges so consumers can retain requirements outside numbered milestone bodies.
95
+
96
+ Exact-byte document hashes and optional structural fingerprints are library observations, not protocol approval fields. Structural fingerprints cover exact body text and raw metadata after explicitly requested top-level exclusions; the generic default excludes nothing. Unavailable structure is reported without discarding useful text or inferring authority. Consumer profiles choose their own policy.
97
+
92
98
  ## Revisions, history, and deletion
93
99
 
94
100
  For substantive agent revisions, recommend a short inline summary explaining actual scope changes and preserving known progress. Do not silently reset completed work to pending.
@@ -101,13 +107,13 @@ Inspection explicitly distinguishes a missing plan, missing milestone file, orph
101
107
 
102
108
  ## Reference mutation boundary
103
109
 
104
- The first reference library supports creation and targeted edits to core metadata and milestone status/ID markers. It does not rewrite general Markdown, normalize extension fields, reorder milestones, remap progress, maintain a snapshot service, or migrate repositories.
110
+ The reference library supports creation, narrow core-metadata/marker patches, guarded plan-body/core-metadata replacement, complete milestone-source replacement with explicit missing-ID assignment, and guarded milestone removal. Pure preparation supplies exact output for consumer persistence. It never remaps progress, normalizes unrelated extension fields, maintains a snapshot service, or migrates repositories.
105
111
 
106
112
  For existing documents, preserve the original bytes outside the exact requested values or inserted field/marker lines, including unknown data, comments, whitespace, BOM, Unicode, CRLF, and final-newline state. Decode UTF-8 strictly and map character positions to original byte spans correctly. Unsupported or ambiguous affected YAML, unsupported encoding, invalid UTF-8, or unencodable replacement text leaves that file unchanged with a specific failure.
107
113
 
108
114
  A malformed plan must not prevent independent milestone observations or an unambiguous marker edit. Update does not recreate a missing/deleted target. Creation never overwrites an existing destination.
109
115
 
110
- Consumers serialize the whole read/edit/write operation for each document, including concurrent calls in one process and across processes. The standalone CLI provides no cross-process coordination: run its updates to the same document sequentially. Atomic replacement prevents partial-file output; a prior-content check detects observed changes but has a comparison-to-rename race. Do not claim protection against every writer or silently retry over newer contents.
116
+ Library and CLI filesystem mutations share short local document locks, acquired in plan-then-milestones order and released in reverse. The public lock callback allows consumers to prepare and persist under that same namespace. Busy/dead owners fail immediately; recovery is an explicit operator decision. Atomic replacement and byte guards detect observed changes, but nonparticipating editors retain a comparison-to-replacement/deletion race. No cross-document transaction, automatic retry, or completion inference is supplied. See the [API](../../api/README.md#shared-document-locks) for lock names and uncertain release outcomes.
111
117
 
112
118
  ## Consumer-owned policy
113
119