@open-agent-toolkit/cli 0.2.65 → 0.2.66

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 (142) hide show
  1. package/assets/bundle-metadata.json +1 -1
  2. package/assets/docs/cli-utilities/configuration.md +19 -1
  3. package/assets/docs/cli-utilities/index.md +3 -0
  4. package/assets/docs/cli-utilities/remote-project-management.md +191 -0
  5. package/assets/docs/reference/cli-reference.md +12 -1
  6. package/assets/docs/reference/file-locations.md +22 -0
  7. package/assets/docs/reference/oat-directory-structure.md +30 -17
  8. package/assets/docs/reference/troubleshooting.md +44 -0
  9. package/assets/docs/workflows/skills/index.md +33 -0
  10. package/assets/public-package-versions.json +4 -4
  11. package/assets/skills/oat-doctor/SKILL.md +4 -4
  12. package/assets/skills/oat-pjm-remote/SKILL.md +101 -0
  13. package/assets/skills/oat-pjm-remote/references/external-action-protocol.md +43 -0
  14. package/dist/commands/backlog/new.d.ts +1 -0
  15. package/dist/commands/backlog/new.d.ts.map +1 -1
  16. package/dist/commands/backlog/new.js +3 -1
  17. package/dist/commands/config/index.d.ts +1 -0
  18. package/dist/commands/config/index.d.ts.map +1 -1
  19. package/dist/commands/config/index.js +232 -1
  20. package/dist/commands/pjm/doctor.d.ts +2 -0
  21. package/dist/commands/pjm/doctor.d.ts.map +1 -1
  22. package/dist/commands/pjm/doctor.js +71 -1
  23. package/dist/commands/pjm/index.d.ts +2 -0
  24. package/dist/commands/pjm/index.d.ts.map +1 -1
  25. package/dist/commands/pjm/index.js +3 -0
  26. package/dist/commands/pjm/remote/__integration__/lifecycle-harness.d.ts +60 -0
  27. package/dist/commands/pjm/remote/__integration__/lifecycle-harness.d.ts.map +1 -0
  28. package/dist/commands/pjm/remote/__integration__/lifecycle-harness.js +151 -0
  29. package/dist/commands/pjm/remote/association.d.ts +27 -0
  30. package/dist/commands/pjm/remote/association.d.ts.map +1 -0
  31. package/dist/commands/pjm/remote/association.js +68 -0
  32. package/dist/commands/pjm/remote/authority.d.ts +210 -0
  33. package/dist/commands/pjm/remote/authority.d.ts.map +1 -0
  34. package/dist/commands/pjm/remote/authority.js +341 -0
  35. package/dist/commands/pjm/remote/batch.d.ts +15 -0
  36. package/dist/commands/pjm/remote/batch.d.ts.map +1 -0
  37. package/dist/commands/pjm/remote/batch.js +126 -0
  38. package/dist/commands/pjm/remote/closeout.d.ts +69 -0
  39. package/dist/commands/pjm/remote/closeout.d.ts.map +1 -0
  40. package/dist/commands/pjm/remote/closeout.js +208 -0
  41. package/dist/commands/pjm/remote/create-binding.d.ts +62 -0
  42. package/dist/commands/pjm/remote/create-binding.d.ts.map +1 -0
  43. package/dist/commands/pjm/remote/create-binding.js +126 -0
  44. package/dist/commands/pjm/remote/credential-safety.d.ts +7 -0
  45. package/dist/commands/pjm/remote/credential-safety.d.ts.map +1 -0
  46. package/dist/commands/pjm/remote/credential-safety.js +21 -0
  47. package/dist/commands/pjm/remote/discussion.d.ts +49 -0
  48. package/dist/commands/pjm/remote/discussion.d.ts.map +1 -0
  49. package/dist/commands/pjm/remote/discussion.js +124 -0
  50. package/dist/commands/pjm/remote/doctor.d.ts +22 -0
  51. package/dist/commands/pjm/remote/doctor.d.ts.map +1 -0
  52. package/dist/commands/pjm/remote/doctor.js +380 -0
  53. package/dist/commands/pjm/remote/external-action.d.ts +208 -0
  54. package/dist/commands/pjm/remote/external-action.d.ts.map +1 -0
  55. package/dist/commands/pjm/remote/external-action.js +367 -0
  56. package/dist/commands/pjm/remote/host-execution.d.ts +28 -0
  57. package/dist/commands/pjm/remote/host-execution.d.ts.map +1 -0
  58. package/dist/commands/pjm/remote/host-execution.js +63 -0
  59. package/dist/commands/pjm/remote/index.d.ts +41 -0
  60. package/dist/commands/pjm/remote/index.d.ts.map +1 -0
  61. package/dist/commands/pjm/remote/index.js +280 -0
  62. package/dist/commands/pjm/remote/jira-adf.d.ts +35 -0
  63. package/dist/commands/pjm/remote/jira-adf.d.ts.map +1 -0
  64. package/dist/commands/pjm/remote/jira-adf.js +169 -0
  65. package/dist/commands/pjm/remote/lifecycle.d.ts +163 -0
  66. package/dist/commands/pjm/remote/lifecycle.d.ts.map +1 -0
  67. package/dist/commands/pjm/remote/lifecycle.js +224 -0
  68. package/dist/commands/pjm/remote/local-projection.d.ts +30 -0
  69. package/dist/commands/pjm/remote/local-projection.d.ts.map +1 -0
  70. package/dist/commands/pjm/remote/local-projection.js +95 -0
  71. package/dist/commands/pjm/remote/managed-markdown.d.ts +30 -0
  72. package/dist/commands/pjm/remote/managed-markdown.d.ts.map +1 -0
  73. package/dist/commands/pjm/remote/managed-markdown.js +128 -0
  74. package/dist/commands/pjm/remote/migrate.d.ts +14 -0
  75. package/dist/commands/pjm/remote/migrate.d.ts.map +1 -0
  76. package/dist/commands/pjm/remote/migrate.js +32 -0
  77. package/dist/commands/pjm/remote/operation-state.d.ts +15 -0
  78. package/dist/commands/pjm/remote/operation-state.d.ts.map +1 -0
  79. package/dist/commands/pjm/remote/operation-state.js +143 -0
  80. package/dist/commands/pjm/remote/outbound-projection-safety.d.ts +25 -0
  81. package/dist/commands/pjm/remote/outbound-projection-safety.d.ts.map +1 -0
  82. package/dist/commands/pjm/remote/outbound-projection-safety.js +99 -0
  83. package/dist/commands/pjm/remote/output.d.ts +60 -0
  84. package/dist/commands/pjm/remote/output.d.ts.map +1 -0
  85. package/dist/commands/pjm/remote/output.js +48 -0
  86. package/dist/commands/pjm/remote/preview.d.ts +88 -0
  87. package/dist/commands/pjm/remote/preview.d.ts.map +1 -0
  88. package/dist/commands/pjm/remote/preview.js +154 -0
  89. package/dist/commands/pjm/remote/provider-conformance.d.ts +13 -0
  90. package/dist/commands/pjm/remote/provider-conformance.d.ts.map +1 -0
  91. package/dist/commands/pjm/remote/provider-conformance.js +37 -0
  92. package/dist/commands/pjm/remote/provider.d.ts +57 -0
  93. package/dist/commands/pjm/remote/provider.d.ts.map +1 -0
  94. package/dist/commands/pjm/remote/provider.js +28 -0
  95. package/dist/commands/pjm/remote/providers/github-publication-safety.d.ts +46 -0
  96. package/dist/commands/pjm/remote/providers/github-publication-safety.d.ts.map +1 -0
  97. package/dist/commands/pjm/remote/providers/github-publication-safety.js +126 -0
  98. package/dist/commands/pjm/remote/providers/github.d.ts +207 -0
  99. package/dist/commands/pjm/remote/providers/github.d.ts.map +1 -0
  100. package/dist/commands/pjm/remote/providers/github.js +1456 -0
  101. package/dist/commands/pjm/remote/providers/jira.d.ts +245 -0
  102. package/dist/commands/pjm/remote/providers/jira.d.ts.map +1 -0
  103. package/dist/commands/pjm/remote/providers/jira.js +1650 -0
  104. package/dist/commands/pjm/remote/providers/linear.d.ts +182 -0
  105. package/dist/commands/pjm/remote/providers/linear.d.ts.map +1 -0
  106. package/dist/commands/pjm/remote/providers/linear.js +1289 -0
  107. package/dist/commands/pjm/remote/purpose-policy.d.ts +29 -0
  108. package/dist/commands/pjm/remote/purpose-policy.d.ts.map +1 -0
  109. package/dist/commands/pjm/remote/purpose-policy.js +118 -0
  110. package/dist/commands/pjm/remote/reconcile.d.ts +42 -0
  111. package/dist/commands/pjm/remote/reconcile.d.ts.map +1 -0
  112. package/dist/commands/pjm/remote/reconcile.js +101 -0
  113. package/dist/commands/pjm/remote/resolution.d.ts +122 -0
  114. package/dist/commands/pjm/remote/resolution.d.ts.map +1 -0
  115. package/dist/commands/pjm/remote/resolution.js +243 -0
  116. package/dist/commands/pjm/remote/schema.d.ts +9309 -0
  117. package/dist/commands/pjm/remote/schema.d.ts.map +1 -0
  118. package/dist/commands/pjm/remote/schema.js +1503 -0
  119. package/dist/commands/pjm/remote/service.d.ts +20 -0
  120. package/dist/commands/pjm/remote/service.d.ts.map +1 -0
  121. package/dist/commands/pjm/remote/service.js +5121 -0
  122. package/dist/commands/pjm/remote/shared-storage.d.ts +36 -0
  123. package/dist/commands/pjm/remote/shared-storage.d.ts.map +1 -0
  124. package/dist/commands/pjm/remote/shared-storage.js +110 -0
  125. package/dist/commands/pjm/remote/snapshot.d.ts +32 -0
  126. package/dist/commands/pjm/remote/snapshot.d.ts.map +1 -0
  127. package/dist/commands/pjm/remote/snapshot.js +140 -0
  128. package/dist/commands/pjm/remote/storage-locator.d.ts +29 -0
  129. package/dist/commands/pjm/remote/storage-locator.d.ts.map +1 -0
  130. package/dist/commands/pjm/remote/storage-locator.js +62 -0
  131. package/dist/commands/pjm/remote/store.d.ts +85 -0
  132. package/dist/commands/pjm/remote/store.d.ts.map +1 -0
  133. package/dist/commands/pjm/remote/store.js +553 -0
  134. package/dist/commands/pjm/remote/verification.d.ts +40 -0
  135. package/dist/commands/pjm/remote/verification.d.ts.map +1 -0
  136. package/dist/commands/pjm/remote/verification.js +100 -0
  137. package/dist/commands/tools/shared/pack-manifest.d.ts.map +1 -1
  138. package/dist/commands/tools/shared/pack-manifest.js +1 -0
  139. package/dist/config/oat-config.d.ts +26 -0
  140. package/dist/config/oat-config.d.ts.map +1 -1
  141. package/dist/config/oat-config.js +186 -2
  142. package/package.json +2 -2
@@ -0,0 +1,224 @@
1
+ import { buildExternalAction, } from './external-action.js';
2
+ import { selectHostExecution, } from './host-execution.js';
3
+ import { requireCurrentOutboundSafety, } from './outbound-projection-safety.js';
4
+ import { validatePreviewApproval } from './preview.js';
5
+ import { semanticDigest, } from './provider.js';
6
+ import { sanitizeRemoteSnapshot, } from './snapshot.js';
7
+ export async function refreshBinding(bindingId, dependencies) {
8
+ const binding = await requireBinding(bindingId, dependencies.store);
9
+ const remote = await dependencies.provider.read({
10
+ provider: binding.provider,
11
+ context: binding.context,
12
+ });
13
+ const snapshot = normalizeSnapshot(binding, remote, dependencies.provider.adapter);
14
+ await dependencies.store.commitRefresh(binding.bindingId, snapshot);
15
+ return { status: 'ok', snapshot };
16
+ }
17
+ export async function intakeRemoteIssue(input, dependencies) {
18
+ const remote = await dependencies.provider.read({
19
+ provider: input.binding.provider,
20
+ context: input.binding.context,
21
+ });
22
+ const binding = {
23
+ ...input.binding,
24
+ snapshot: null,
25
+ baseline: null,
26
+ };
27
+ const snapshot = normalizeSnapshot(binding, remote, dependencies.provider.adapter);
28
+ const issue = dependencies.provider.adapter.normalize(remote.observation);
29
+ const baseline = {
30
+ acceptedAt: dependencies.now(),
31
+ fields: {
32
+ title: issue.title,
33
+ description: issue.description,
34
+ priority: issue.priority,
35
+ },
36
+ localRevision: input.localRevision,
37
+ remoteRevisionDigest: issue.revisionDigest,
38
+ };
39
+ await dependencies.store.commitIntake({
40
+ binding,
41
+ snapshot,
42
+ baseline,
43
+ mode: input.mode,
44
+ });
45
+ return { status: 'ok', snapshot, baseline };
46
+ }
47
+ function normalizeSnapshot(binding, remote, adapter) {
48
+ if (adapter.provider !== binding.provider)
49
+ throw new Error('Lifecycle provider adapter mismatch.');
50
+ const issue = adapter.normalize(remote.observation);
51
+ if (issue.provider !== binding.provider)
52
+ throw new Error('Lifecycle observation provider mismatch.');
53
+ return sanitizeRemoteSnapshot({
54
+ ...remote.snapshot,
55
+ bindingId: binding.bindingId,
56
+ provider: binding.provider,
57
+ issue: {
58
+ title: issue.title,
59
+ description: issue.description ?? '',
60
+ priority: issue.priority,
61
+ status: issue.status,
62
+ },
63
+ }, { allowedExtensionKeys: remote.allowedExtensionKeys });
64
+ }
65
+ async function requireBinding(bindingId, store) {
66
+ const binding = await store.readBinding(bindingId);
67
+ if (!binding)
68
+ throw new Error(`Remote binding '${bindingId}' does not exist.`);
69
+ return binding;
70
+ }
71
+ export function baselineRevisionDigest(baseline) {
72
+ return semanticDigest(baseline);
73
+ }
74
+ export async function publishUnboundBinding(input, dependencies) {
75
+ return dependencies.createAndBind(input);
76
+ }
77
+ export async function publishBinding(input, dependencies) {
78
+ requireCurrentOutboundSafety(input.projection, input.outboundSafety);
79
+ if (input.preview.projectionDigest !== input.outboundSafety.projectionDigest ||
80
+ input.preview.safetyResultDigest !== input.outboundSafety.resultDigest) {
81
+ throw new Error('Publish preview safety evidence is stale or mismatched.');
82
+ }
83
+ const preRead = await dependencies.preRead({ binding: input.binding });
84
+ if (preRead.revisionDigest !== input.preview.observedRevisionDigest) {
85
+ await dependencies.store.markTerminal(input.operationId, 'blocked', semanticDigest(preRead));
86
+ return { status: 'blocked' };
87
+ }
88
+ const [authority, invocation, recomputed] = await Promise.all([
89
+ dependencies.resolveCurrentAuthority({
90
+ binding: input.binding,
91
+ operation: input.operation,
92
+ }),
93
+ dependencies.currentInvocation(),
94
+ dependencies.recomputeAfterPreRead({
95
+ binding: input.binding,
96
+ operation: input.operation,
97
+ revisionDigest: preRead.revisionDigest,
98
+ }),
99
+ ]);
100
+ assertResolvedAuthority(authority, invocation, input, dependencies);
101
+ requireCurrentOutboundSafety(recomputed.projection, recomputed.outboundSafety);
102
+ if (semanticDigest(recomputed.projection) !==
103
+ semanticDigest(input.projection) ||
104
+ recomputed.outboundSafety.projectionDigest !==
105
+ input.preview.projectionDigest ||
106
+ recomputed.outboundSafety.resultDigest !==
107
+ input.preview.safetyResultDigest ||
108
+ recomputed.previewDigest !== input.preview.digest ||
109
+ recomputed.policyDigest !== input.preview.policyDigest) {
110
+ throw new Error('Mutation projection, safety, preview, or policy drifted after pre-read.');
111
+ }
112
+ const selection = selectHostExecution({
113
+ provider: input.binding.provider,
114
+ context: input.binding.context,
115
+ operation: input.operation,
116
+ candidates: recomputed.capabilityCandidates,
117
+ attemptStarted: false,
118
+ });
119
+ if (!selection.selected)
120
+ throw new Error(`No current host capability: ${selection.reason}.`);
121
+ if (selection.evidence.evidenceDigest !== input.preview.capabilityEvidenceDigest) {
122
+ throw new Error('Host capability evidence drifted before mutation attempt.');
123
+ }
124
+ await dependencies.store.persistPlanned({
125
+ operationId: input.operationId,
126
+ bindingId: input.binding.bindingId,
127
+ previewDigest: input.preview.digest,
128
+ projectionDigest: input.preview.projectionDigest,
129
+ safetyResultDigest: input.preview.safetyResultDigest,
130
+ authority,
131
+ });
132
+ const action = buildExternalAction({
133
+ operationId: input.operationId,
134
+ stepId: input.stepId,
135
+ provider: input.binding.provider,
136
+ semanticOperation: input.operation,
137
+ context: input.binding.context,
138
+ intent: {
139
+ stableId: input.binding.snapshot?.identity.stableId ?? null,
140
+ fields: recomputed.projection,
141
+ },
142
+ expectedObservation: {
143
+ fields: Object.keys(input.projection),
144
+ requireIdentity: true,
145
+ stableId: input.binding.snapshot?.identity.stableId ?? null,
146
+ capabilityEvidenceDigest: selection.evidence.evidenceDigest,
147
+ },
148
+ persistedPreview: input.preview,
149
+ projection: recomputed.projection,
150
+ outboundSafety: recomputed.outboundSafety,
151
+ });
152
+ await dependencies.store.markAttemptStarted(input.operationId, action, selection.evidence);
153
+ const attempt = await dependencies.execute(action);
154
+ if (attempt.classification === 'not-committed') {
155
+ await dependencies.store.markTerminal(input.operationId, 'rejected', attempt.evidenceDigest);
156
+ return { status: 'rejected', action };
157
+ }
158
+ if (attempt.classification === 'unknown') {
159
+ await dependencies.store.markTerminal(input.operationId, 'uncertain', attempt.evidenceDigest);
160
+ return { status: 'uncertain', action };
161
+ }
162
+ try {
163
+ const readback = await dependencies.readBack({
164
+ binding: input.binding,
165
+ action,
166
+ });
167
+ const verified = Object.entries(input.projection).every(([field, value]) => readback.fields[field] === value);
168
+ const status = verified ? 'verified' : 'uncertain';
169
+ await dependencies.store.markTerminal(input.operationId, status, semanticDigest(readback));
170
+ return { status, action };
171
+ }
172
+ catch {
173
+ await dependencies.store.markTerminal(input.operationId, 'uncertain', semanticDigest({ code: 'readback-unavailable' }));
174
+ return { status: 'uncertain', action };
175
+ }
176
+ }
177
+ export async function reconcileRemoteBinding(input, dependencies) {
178
+ if (input.conflicts.length > 0)
179
+ return { status: 'blocked' };
180
+ return publishBinding(input, dependencies);
181
+ }
182
+ function assertResolvedAuthority(authority, invocation, input, dependencies) {
183
+ if (authority.effective === 'read-only')
184
+ throw new Error('Remote mutation is read-only.');
185
+ if (authority.effective === 'user-authorized' &&
186
+ (invocation.kind !== 'interactive' ||
187
+ invocation.evidenceDigest !== authority.instructionDigest)) {
188
+ throw new Error('Explicit user instruction does not authorize this mutation.');
189
+ }
190
+ if (authority.effective === 'user-approved' &&
191
+ (!authority.approval ||
192
+ !validatePreviewApproval({
193
+ schemaVersion: 1,
194
+ digest: input.preview.digest,
195
+ bindingId: input.binding.bindingId,
196
+ provider: input.binding.provider,
197
+ operationClass: input.operation === 'create' ? 'create' : 'update-fields',
198
+ fieldMask: Object.keys(input.projection),
199
+ createdAt: input.preview.createdAt,
200
+ componentDigests: {
201
+ target: 'persisted',
202
+ baseline: 'persisted',
203
+ revision: input.preview.observedRevisionDigest,
204
+ capability: input.preview.capabilityEvidenceDigest,
205
+ policy: input.preview.policyDigest,
206
+ projection: input.preview.projectionDigest,
207
+ outboundSafety: input.preview.safetyResultDigest,
208
+ },
209
+ renderedFields: {
210
+ title: { kind: 'hash', digest: 'persisted', bytes: 0 },
211
+ description: { kind: 'hash', digest: 'persisted', bytes: 0 },
212
+ priority: { kind: 'hash', digest: 'persisted', bytes: 0 },
213
+ },
214
+ }, authority.approval, { now: dependencies.now(), maxAgeMs: dependencies.approvalMaxAgeMs }).valid)) {
215
+ throw new Error('Fresh approval does not match the current preview.');
216
+ }
217
+ if (authority.effective === 'autonomous' &&
218
+ (invocation.kind !== 'workflow' ||
219
+ !authority.activeWorkflow ||
220
+ invocation.workflowId !== authority.activeWorkflow.workflowId ||
221
+ invocation.revision !== authority.activeWorkflow.revision)) {
222
+ throw new Error('Autonomous mutation requires current active-workflow authority.');
223
+ }
224
+ }
@@ -0,0 +1,30 @@
1
+ export interface LocalProjection {
2
+ title: string;
3
+ description: string | null;
4
+ priority: string | null;
5
+ source: 'backlog-description' | 'explicit-project-publication';
6
+ sourceRevision: string;
7
+ observedAt: string;
8
+ }
9
+ interface BacklogProjectionTarget {
10
+ kind: 'backlog';
11
+ path: string;
12
+ content: string;
13
+ }
14
+ interface ProjectPublication {
15
+ title: string;
16
+ description: string | null;
17
+ priority: string | null;
18
+ }
19
+ interface ProjectProjectionTarget {
20
+ kind: 'project';
21
+ path: string;
22
+ publication: ProjectPublication;
23
+ }
24
+ export interface ResolveLocalProjectionInput {
25
+ target: BacklogProjectionTarget | ProjectProjectionTarget;
26
+ observedAt: string;
27
+ }
28
+ export declare function resolveLocalProjection(input: ResolveLocalProjectionInput): LocalProjection;
29
+ export {};
30
+ //# sourceMappingURL=local-projection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-projection.d.ts","sourceRoot":"","sources":["../../../../src/commands/pjm/remote/local-projection.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,qBAAqB,GAAG,8BAA8B,CAAC;IAC/D,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,uBAAuB;IAC/B,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,kBAAkB;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,UAAU,uBAAuB;IAC/B,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,kBAAkB,CAAC;CACjC;AAED,MAAM,WAAW,2BAA2B;IAC1C,MAAM,EAAE,uBAAuB,GAAG,uBAAuB,CAAC;IAC1D,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,2BAA2B,GACjC,eAAe,CAcjB"}
@@ -0,0 +1,95 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { getFrontmatterBlock, parseFrontmatterScalarFields, } from '../../shared/frontmatter.js';
3
+ export function resolveLocalProjection(input) {
4
+ assertObservedAt(input.observedAt);
5
+ if (!input.target.path.trim()) {
6
+ throw new Error('Local projection source path must not be empty.');
7
+ }
8
+ if (input.target.kind === 'backlog') {
9
+ return resolveBacklogProjection(input.target, input.observedAt);
10
+ }
11
+ if (input.target.kind === 'project') {
12
+ return resolveProjectProjection(input.target, input.observedAt);
13
+ }
14
+ throw new Error('Unsupported local projection target kind.');
15
+ }
16
+ function resolveBacklogProjection(target, observedAt) {
17
+ const frontmatter = getFrontmatterBlock(target.content);
18
+ if (!frontmatter) {
19
+ throw new Error(`Backlog projection '${target.path}' requires frontmatter.`);
20
+ }
21
+ const parsed = parseFrontmatterScalarFields(frontmatter, [
22
+ 'title',
23
+ 'priority',
24
+ ]);
25
+ if (!parsed.valid || !parsed.values.title) {
26
+ throw new Error(`Backlog projection '${target.path}' requires valid frontmatter with one string title.`);
27
+ }
28
+ const description = extractDescriptionSection(target.content, target.path);
29
+ const selected = {
30
+ targetKind: target.kind,
31
+ sourcePath: target.path,
32
+ title: parsed.values.title,
33
+ description,
34
+ priority: parsed.values.priority ?? null,
35
+ source: 'backlog-description',
36
+ };
37
+ return {
38
+ title: selected.title,
39
+ description: selected.description,
40
+ priority: selected.priority,
41
+ source: selected.source,
42
+ sourceRevision: hashSelectedProjection(selected),
43
+ observedAt,
44
+ };
45
+ }
46
+ function resolveProjectProjection(target, observedAt) {
47
+ const title = target.publication.title.trim();
48
+ if (!title) {
49
+ throw new Error('An explicit project publication requires a title.');
50
+ }
51
+ const selected = {
52
+ targetKind: target.kind,
53
+ sourcePath: target.path,
54
+ title,
55
+ description: normalizeOptionalValue(target.publication.description),
56
+ priority: normalizeOptionalValue(target.publication.priority),
57
+ source: 'explicit-project-publication',
58
+ };
59
+ return {
60
+ title: selected.title,
61
+ description: selected.description,
62
+ priority: selected.priority,
63
+ source: selected.source,
64
+ sourceRevision: hashSelectedProjection(selected),
65
+ observedAt,
66
+ };
67
+ }
68
+ function extractDescriptionSection(content, sourcePath) {
69
+ const headings = [...content.matchAll(/^##[ \t]+Description[ \t]*$/gm)];
70
+ if (headings.length !== 1) {
71
+ throw new Error(`Backlog projection '${sourcePath}' requires exactly one level-two Description section.`);
72
+ }
73
+ const heading = headings[0];
74
+ const sectionStart = heading.index + heading[0].length;
75
+ const remaining = content.slice(sectionStart).replace(/^\r?\n/, '');
76
+ const nextOwnedHeading = /^#{1,2}[ \t]+[^\r\n]+$/m.exec(remaining);
77
+ const section = (nextOwnedHeading ? remaining.slice(0, nextOwnedHeading.index) : remaining).trim();
78
+ return section || null;
79
+ }
80
+ function normalizeOptionalValue(value) {
81
+ if (value === null)
82
+ return null;
83
+ const normalized = value.trim();
84
+ return normalized || null;
85
+ }
86
+ function hashSelectedProjection(value) {
87
+ return `sha256:${createHash('sha256')
88
+ .update(JSON.stringify(value))
89
+ .digest('hex')}`;
90
+ }
91
+ function assertObservedAt(value) {
92
+ if (!Number.isFinite(Date.parse(value))) {
93
+ throw new Error(`Invalid projection observation time '${value}'.`);
94
+ }
95
+ }
@@ -0,0 +1,30 @@
1
+ export type ManagedMarkdownChoiceReason = 'missing-boundary' | 'duplicate-boundary' | 'nested-boundary' | 'malformed-boundary' | 'heading-mismatch';
2
+ export type ManagedMarkdownInspection = {
3
+ status: 'absent';
4
+ content: null;
5
+ } | {
6
+ status: 'managed';
7
+ content: string;
8
+ range: {
9
+ start: number;
10
+ end: number;
11
+ };
12
+ } | {
13
+ status: 'choice-required';
14
+ reason: Exclude<ManagedMarkdownChoiceReason, 'missing-boundary'>;
15
+ body: string;
16
+ };
17
+ export type ManagedMarkdownUpdate = {
18
+ status: 'updated';
19
+ operation: 'insert' | 'replace';
20
+ body: string;
21
+ } | {
22
+ status: 'choice-required';
23
+ reason: ManagedMarkdownChoiceReason;
24
+ body: string;
25
+ };
26
+ export declare function buildManagedMarkdownBlock(bindingId: string, content: string): string;
27
+ export declare function inspectManagedMarkdown(body: string, bindingId: string): ManagedMarkdownInspection;
28
+ export declare function insertManagedMarkdown(body: string, bindingId: string, content: string): ManagedMarkdownUpdate;
29
+ export declare function replaceManagedMarkdown(body: string, bindingId: string, content: string): ManagedMarkdownUpdate;
30
+ //# sourceMappingURL=managed-markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"managed-markdown.d.ts","sourceRoot":"","sources":["../../../../src/commands/pjm/remote/managed-markdown.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,2BAA2B,GACnC,kBAAkB,GAClB,oBAAoB,GACpB,iBAAiB,GACjB,oBAAoB,GACpB,kBAAkB,CAAC;AAEvB,MAAM,MAAM,yBAAyB,GACjC;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,IAAI,CAAA;CAAE,GACnC;IACE,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CACvC,GACD;IACE,MAAM,EAAE,iBAAiB,CAAC;IAC1B,MAAM,EAAE,OAAO,CAAC,2BAA2B,EAAE,kBAAkB,CAAC,CAAC;IACjE,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEN,MAAM,MAAM,qBAAqB,GAC7B;IACE,MAAM,EAAE,SAAS,CAAC;IAClB,SAAS,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;CACd,GACD;IACE,MAAM,EAAE,iBAAiB,CAAC;IAC1B,MAAM,EAAE,2BAA2B,CAAC;IACpC,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAIN,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,MAAM,CAGR;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB,yBAAyB,CA2D3B;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,qBAAqB,CAwBvB;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,qBAAqB,CAkBvB"}
@@ -0,0 +1,128 @@
1
+ const ANY_BOUNDARY = /<!-- OAT-MANAGED:[^>\r\n]+:(?:START|END) -->/g;
2
+ export function buildManagedMarkdownBlock(bindingId, content) {
3
+ assertBindingId(bindingId);
4
+ return `${startBoundary(bindingId)}\n## OAT-managed\n\n${content}\n${endBoundary(bindingId)}`;
5
+ }
6
+ export function inspectManagedMarkdown(body, bindingId) {
7
+ assertBindingId(bindingId);
8
+ const start = startBoundary(bindingId);
9
+ const end = endBoundary(bindingId);
10
+ const starts = findAll(body, start);
11
+ const ends = findAll(body, end);
12
+ if (starts.length === 0 && ends.length === 0) {
13
+ return { status: 'absent', content: null };
14
+ }
15
+ if (starts.length !== 1 || ends.length !== 1) {
16
+ return {
17
+ status: 'choice-required',
18
+ reason: starts.length > 1 || ends.length > 1
19
+ ? 'duplicate-boundary'
20
+ : 'malformed-boundary',
21
+ body,
22
+ };
23
+ }
24
+ const startIndex = starts[0];
25
+ const endIndex = ends[0];
26
+ if (endIndex <= startIndex) {
27
+ return {
28
+ status: 'choice-required',
29
+ reason: 'malformed-boundary',
30
+ body,
31
+ };
32
+ }
33
+ const innerStart = startIndex + start.length;
34
+ const inner = body.slice(innerStart, endIndex);
35
+ if (ANY_BOUNDARY.test(inner)) {
36
+ ANY_BOUNDARY.lastIndex = 0;
37
+ return {
38
+ status: 'choice-required',
39
+ reason: 'nested-boundary',
40
+ body,
41
+ };
42
+ }
43
+ ANY_BOUNDARY.lastIndex = 0;
44
+ const managed = /^\r?\n## OAT-managed[ \t]*\r?\n\r?\n([\s\S]*?)\r?\n$/.exec(inner);
45
+ if (!managed) {
46
+ return {
47
+ status: 'choice-required',
48
+ reason: 'heading-mismatch',
49
+ body,
50
+ };
51
+ }
52
+ return {
53
+ status: 'managed',
54
+ content: managed[1],
55
+ range: { start: startIndex, end: endIndex + end.length },
56
+ };
57
+ }
58
+ export function insertManagedMarkdown(body, bindingId, content) {
59
+ const inspection = inspectManagedMarkdown(body, bindingId);
60
+ if (inspection.status !== 'absent') {
61
+ return {
62
+ status: 'choice-required',
63
+ reason: inspection.status === 'managed'
64
+ ? 'duplicate-boundary'
65
+ : inspection.reason,
66
+ body,
67
+ };
68
+ }
69
+ if (containsBoundary(content)) {
70
+ return { status: 'choice-required', reason: 'nested-boundary', body };
71
+ }
72
+ return {
73
+ status: 'updated',
74
+ operation: 'insert',
75
+ body: `${body}${insertionSeparator(body)}${buildManagedMarkdownBlock(bindingId, content)}`,
76
+ };
77
+ }
78
+ export function replaceManagedMarkdown(body, bindingId, content) {
79
+ const inspection = inspectManagedMarkdown(body, bindingId);
80
+ if (inspection.status === 'absent') {
81
+ return { status: 'choice-required', reason: 'missing-boundary', body };
82
+ }
83
+ if (inspection.status === 'choice-required')
84
+ return inspection;
85
+ if (containsBoundary(content)) {
86
+ return { status: 'choice-required', reason: 'nested-boundary', body };
87
+ }
88
+ return {
89
+ status: 'updated',
90
+ operation: 'replace',
91
+ body: `${body.slice(0, inspection.range.start)}${buildManagedMarkdownBlock(bindingId, content)}${body.slice(inspection.range.end)}`,
92
+ };
93
+ }
94
+ function startBoundary(bindingId) {
95
+ return `<!-- OAT-MANAGED:${bindingId}:START -->`;
96
+ }
97
+ function endBoundary(bindingId) {
98
+ return `<!-- OAT-MANAGED:${bindingId}:END -->`;
99
+ }
100
+ function findAll(body, value) {
101
+ const indices = [];
102
+ let from = 0;
103
+ while (from <= body.length) {
104
+ const index = body.indexOf(value, from);
105
+ if (index === -1)
106
+ break;
107
+ indices.push(index);
108
+ from = index + value.length;
109
+ }
110
+ return indices;
111
+ }
112
+ function insertionSeparator(body) {
113
+ if (body.length === 0 || body.endsWith('\n\n'))
114
+ return '';
115
+ if (body.endsWith('\n'))
116
+ return '\n';
117
+ return '\n\n';
118
+ }
119
+ function containsBoundary(value) {
120
+ const found = ANY_BOUNDARY.test(value);
121
+ ANY_BOUNDARY.lastIndex = 0;
122
+ return found;
123
+ }
124
+ function assertBindingId(bindingId) {
125
+ if (!bindingId || /[\r\n:<>]/.test(bindingId)) {
126
+ throw new Error('Managed Markdown requires a safe binding ID.');
127
+ }
128
+ }
@@ -0,0 +1,14 @@
1
+ export interface RemoteMigrationResult {
2
+ schemaVersion: 1;
3
+ mode: 'check' | 'apply';
4
+ previewDigest: string;
5
+ changed: boolean;
6
+ applied: boolean;
7
+ associatedIssues: unknown[];
8
+ }
9
+ export declare function migrateRemoteAssociations(input: {
10
+ mode: 'check' | 'apply';
11
+ associatedIssues: readonly unknown[];
12
+ approvalDigest?: string;
13
+ }): RemoteMigrationResult;
14
+ //# sourceMappingURL=migrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../../../src/commands/pjm/remote/migrate.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,CAAC,CAAC;IACjB,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,EAAE,OAAO,EAAE,CAAC;CAC7B;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACxB,gBAAgB,EAAE,SAAS,OAAO,EAAE,CAAC;IACrC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,GAAG,qBAAqB,CAoBxB"}
@@ -0,0 +1,32 @@
1
+ import { semanticDigest } from './provider.js';
2
+ export function migrateRemoteAssociations(input) {
3
+ const associatedIssues = input.associatedIssues.map(canonicalizeAssociation);
4
+ const previewDigest = semanticDigest({
5
+ operation: 'local-remote-association-migration',
6
+ before: input.associatedIssues,
7
+ after: associatedIssues,
8
+ });
9
+ const changed = JSON.stringify(input.associatedIssues) !== JSON.stringify(associatedIssues);
10
+ if (input.mode === 'apply' && input.approvalDigest !== previewDigest) {
11
+ throw new Error('Apply requires the exact approved migration preview.');
12
+ }
13
+ return {
14
+ schemaVersion: 1,
15
+ mode: input.mode,
16
+ previewDigest,
17
+ changed,
18
+ applied: input.mode === 'apply',
19
+ associatedIssues,
20
+ };
21
+ }
22
+ function canonicalizeAssociation(value) {
23
+ if (typeof value !== 'string')
24
+ return value;
25
+ const separator = value.indexOf(':');
26
+ if (separator <= 0 || separator === value.length - 1)
27
+ return value;
28
+ const type = value.slice(0, separator);
29
+ if (!['github', 'linear', 'jira'].includes(type))
30
+ return value;
31
+ return { type, ref: value.slice(separator + 1) };
32
+ }
@@ -0,0 +1,15 @@
1
+ export declare const OPERATION_STATES: readonly ['planned', 'pending', 'authorized', 'attempt-started', 'verification-pending', 'blocked', 'verified', 'partial', 'uncertain', 'failed', 'rejected'];
2
+ export type OperationState = (typeof OPERATION_STATES)[number];
3
+ export declare function transitionRemoteOperation(current: OperationState, next: OperationState, subject?: 'parent' | 'substep'): OperationState;
4
+ export interface CompositeSubstepState {
5
+ substepId: string;
6
+ state: OperationState;
7
+ }
8
+ export interface CompositeOperationStateReduction {
9
+ state: OperationState;
10
+ verifiedSubstepIds: string[];
11
+ continuableSubstepId: string | null;
12
+ retryDisposition: 'not-applicable' | 'safe-before-attempt' | 'reconcile-required';
13
+ }
14
+ export declare function reduceCompositeOperationState(substeps: readonly CompositeSubstepState[]): CompositeOperationStateReduction;
15
+ //# sourceMappingURL=operation-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operation-state.d.ts","sourceRoot":"","sources":["../../../../src/commands/pjm/remote/operation-state.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,YAC3B,SAAS,EACT,SAAS,EACT,YAAY,EACZ,iBAAiB,EACjB,sBAAsB,EACtB,SAAS,EACT,UAAU,EACV,SAAS,EACT,WAAW,EACX,QAAQ,EACR,UAAU,CACF,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAuC/D,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,cAAc,EACpB,OAAO,GAAE,QAAQ,GAAG,SAAoB,GACvC,cAAc,CAOhB;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,cAAc,CAAC;CACvB;AAED,MAAM,WAAW,gCAAgC;IAC/C,KAAK,EAAE,cAAc,CAAC;IACtB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,gBAAgB,EACZ,gBAAgB,GAChB,qBAAqB,GACrB,oBAAoB,CAAC;CAC1B;AAED,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,SAAS,qBAAqB,EAAE,GACzC,gCAAgC,CAgFlC"}