@open-agent-toolkit/cli 0.3.19 → 0.3.20
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/README.md +2 -1
- package/assets/agents/oat-phase-implementer.md +26 -3
- package/assets/agents/oat-reviewer.md +8 -3
- package/assets/bundle-metadata.json +1 -1
- package/assets/docs/reference/cli-reference.md +12 -7
- package/assets/docs/reference/oat-directory-structure.md +1 -0
- package/assets/docs/reference/project-artifacts.md +56 -1
- package/assets/docs/reference/project-state-machine.md +41 -7
- package/assets/docs/skills/brainstorm.md +3 -2
- package/assets/docs/skills/index.md +13 -10
- package/assets/docs/workflows/advanced/autonomy.md +3 -1
- package/assets/docs/workflows/advanced/dispatch-ceiling.md +2 -2
- package/assets/docs/workflows/advanced/workflow-gates.md +17 -4
- package/assets/docs/workflows/approvals-and-automation.md +21 -10
- package/assets/docs/workflows/choose-workflow.md +17 -9
- package/assets/docs/workflows/ideas/index.md +1 -1
- package/assets/docs/workflows/ideas/lifecycle.md +3 -2
- package/assets/docs/workflows/projects/closeout/closeout-skills.md +80 -7
- package/assets/docs/workflows/projects/closeout/pr-flow.md +7 -1
- package/assets/docs/workflows/projects/execution/execution-skills.md +16 -3
- package/assets/docs/workflows/projects/execution/implementation-execution.md +1 -1
- package/assets/docs/workflows/projects/execution/picking-up-projects.md +11 -1
- package/assets/docs/workflows/projects/lifecycle.md +108 -9
- package/assets/docs/workflows/projects/planning/hill-checkpoints.md +6 -6
- package/assets/docs/workflows/projects/planning/planning-skills.md +9 -7
- package/assets/docs/workflows/projects/planning/starting-projects.md +57 -11
- package/assets/docs/workflows/projects/reviews/index.md +22 -1
- package/assets/docs/workflows/projects/reviews/review-flavors.md +5 -3
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-brainstorm/SKILL.md +34 -9
- package/assets/skills/oat-brainstorm/references/destinations.md +6 -3
- package/assets/skills/oat-docs/SKILL.md +7 -3
- package/assets/skills/oat-pjm-review-backlog/SKILL.md +2 -2
- package/assets/skills/oat-project-autonomous/SKILL.md +9 -3
- package/assets/skills/oat-project-autonomous/references/gate-inventory.md +151 -132
- package/assets/skills/oat-project-brief/SKILL.md +1 -1
- package/assets/skills/oat-project-brief/references/brief-contract.md +458 -9
- package/assets/skills/oat-project-brief/references/docs/autonomy-contract.md +151 -132
- package/assets/skills/oat-project-brief/references/docs/gate-approval-record.md +9 -0
- package/assets/skills/oat-project-capture/SKILL.md +2 -2
- package/assets/skills/oat-project-complete/SKILL.md +14 -5
- package/assets/skills/oat-project-discover/SKILL.md +3 -2
- package/assets/skills/oat-project-document/SKILL.md +12 -6
- package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +151 -132
- package/assets/skills/oat-project-goal/SKILL.md +697 -0
- package/assets/skills/oat-project-goal/references/docs/autonomy-contract.md +412 -0
- package/assets/skills/oat-project-goal/references/docs/gate-approval-record.md +93 -0
- package/assets/skills/oat-project-implement/SKILL.md +1 -1
- package/assets/skills/oat-project-implement/references/completion-and-closeout.md +67 -0
- package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +151 -132
- package/assets/skills/oat-project-implement/references/docs/gate-approval-record.md +9 -0
- package/assets/skills/oat-project-implement/references/phase-execution.md +10 -3
- package/assets/skills/oat-project-implement/references/plan-and-resume.md +28 -1
- package/assets/skills/oat-project-lite/SKILL.md +1 -1
- package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +151 -132
- package/assets/skills/oat-project-new/SKILL.md +3 -3
- package/assets/skills/oat-project-next/SKILL.md +45 -15
- package/assets/skills/oat-project-next/references/docs/gate-approval-record.md +9 -0
- package/assets/skills/oat-project-plan/SKILL.md +14 -3
- package/assets/skills/oat-project-plan-writing/SKILL.md +6 -4
- package/assets/skills/oat-project-pr-final/SKILL.md +51 -1
- package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +151 -132
- package/assets/skills/oat-project-pr-progress/SKILL.md +97 -3
- package/assets/skills/oat-project-progress/SKILL.md +38 -5
- package/assets/skills/oat-project-progress/references/docs/gate-approval-record.md +9 -0
- package/assets/skills/oat-project-quick-start/SKILL.md +14 -9
- package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +151 -132
- package/assets/skills/oat-project-quick-start/references/docs/gate-approval-record.md +9 -0
- package/assets/skills/oat-project-reconcile/SKILL.md +31 -2
- package/assets/skills/oat-project-review-provide/SKILL.md +79 -13
- package/assets/skills/oat-project-review-receive/SKILL.md +70 -1
- package/assets/skills/oat-project-revise/SKILL.md +25 -1
- package/assets/skills/oat-project-summary/SKILL.md +60 -5
- package/assets/skills/oat-wave-execute/SKILL.md +2 -2
- package/assets/templates/state.md +1 -1
- package/dist/commands/project/closeout-check/closeout-invariant.d.ts +119 -3
- package/dist/commands/project/closeout-check/closeout-invariant.d.ts.map +1 -1
- package/dist/commands/project/closeout-check/closeout-invariant.js +454 -2
- package/dist/commands/project/closeout-check/index.d.ts +21 -3
- package/dist/commands/project/closeout-check/index.d.ts.map +1 -1
- package/dist/commands/project/closeout-check/index.js +190 -4
- package/dist/commands/project/complete-state/index.d.ts +2 -1
- package/dist/commands/project/complete-state/index.d.ts.map +1 -1
- package/dist/commands/project/complete-state/index.js +7 -1
- package/dist/commands/project/delivery/check.d.ts +66 -0
- package/dist/commands/project/delivery/check.d.ts.map +1 -0
- package/dist/commands/project/delivery/check.js +232 -0
- package/dist/commands/project/delivery/evidence.d.ts +171 -0
- package/dist/commands/project/delivery/evidence.d.ts.map +1 -0
- package/dist/commands/project/delivery/evidence.js +902 -0
- package/dist/commands/project/delivery/index.d.ts +7 -0
- package/dist/commands/project/delivery/index.d.ts.map +1 -0
- package/dist/commands/project/delivery/index.js +13 -0
- package/dist/commands/project/delivery/refresh.d.ts +110 -0
- package/dist/commands/project/delivery/refresh.d.ts.map +1 -0
- package/dist/commands/project/delivery/refresh.js +441 -0
- package/dist/commands/project/index.d.ts.map +1 -1
- package/dist/commands/project/index.js +2 -0
- package/dist/commands/project/log/append.d.ts +6 -0
- package/dist/commands/project/log/append.d.ts.map +1 -1
- package/dist/commands/project/log/append.js +6 -1
- package/dist/commands/project/new/scaffold.d.ts.map +1 -1
- package/dist/commands/project/new/scaffold.js +47 -1
- package/dist/commands/project/promote/promote.d.ts +15 -1
- package/dist/commands/project/promote/promote.d.ts.map +1 -1
- package/dist/commands/project/promote/promote.js +99 -15
- package/dist/commands/project/validate-plan/index.d.ts.map +1 -1
- package/dist/commands/project/validate-plan/index.js +10 -0
- package/dist/commands/project/validate-plan/profiles.d.ts +19 -4
- package/dist/commands/project/validate-plan/profiles.d.ts.map +1 -1
- package/dist/commands/project/validate-plan/profiles.js +153 -2
- package/dist/commands/shared/frontmatter.d.ts +1 -1
- package/dist/commands/shared/frontmatter.d.ts.map +1 -1
- package/dist/commands/shared/frontmatter.js +1 -0
- package/dist/commands/state/generate.d.ts.map +1 -1
- package/dist/commands/state/generate.js +35 -4
- package/dist/commands/tools/shared/pack-manifest.d.ts.map +1 -1
- package/dist/commands/tools/shared/pack-manifest.js +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
export { createProjectDeliveryCheckCommand, deliveryEffectiveScope, evaluateSubjectEvidence, loadGoalDeliveryProject, } from './check.js';
|
|
3
|
+
export { applyObservationWrites, createProjectDeliveryRefreshCommand, endpointSatisfied, planDeliveryRefresh, } from './refresh.js';
|
|
4
|
+
export { classifyPath, evaluateDeliveryReview, evaluateGateCarrier, evaluateSuccessor, type CarrierEvaluation, type CarrierExpectation, type EvidenceScope, type ReviewEvaluation, type SuccessorResult, } from './evidence.js';
|
|
5
|
+
/** `oat project delivery`: the goal delivery registry's observation surface. */
|
|
6
|
+
export declare function createProjectDeliveryCommand(): Command;
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/delivery/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,OAAO,EACL,iCAAiC,EACjC,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,sBAAsB,EACtB,mCAAmC,EACnC,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,YAAY,EACZ,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACrB,MAAM,YAAY,CAAC;AAEpB,gFAAgF;AAChF,wBAAgB,4BAA4B,IAAI,OAAO,CAOtD"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { createProjectDeliveryCheckCommand } from './check.js';
|
|
3
|
+
import { createProjectDeliveryRefreshCommand } from './refresh.js';
|
|
4
|
+
export { createProjectDeliveryCheckCommand, deliveryEffectiveScope, evaluateSubjectEvidence, loadGoalDeliveryProject, } from './check.js';
|
|
5
|
+
export { applyObservationWrites, createProjectDeliveryRefreshCommand, endpointSatisfied, planDeliveryRefresh, } from './refresh.js';
|
|
6
|
+
export { classifyPath, evaluateDeliveryReview, evaluateGateCarrier, evaluateSuccessor, } from './evidence.js';
|
|
7
|
+
/** `oat project delivery`: the goal delivery registry's observation surface. */
|
|
8
|
+
export function createProjectDeliveryCommand() {
|
|
9
|
+
return new Command('delivery')
|
|
10
|
+
.description('Observe goal delivery registry members and check delivery evidence freshness')
|
|
11
|
+
.addCommand(createProjectDeliveryRefreshCommand())
|
|
12
|
+
.addCommand(createProjectDeliveryCheckCommand());
|
|
13
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { type CommandContext, type GlobalOptions } from '../../../app/command-context.js';
|
|
2
|
+
import { type GhRunner } from '../../project/links/refresh.js';
|
|
3
|
+
import { type GitRunner } from '../../project/sync/git.js';
|
|
4
|
+
import { type DeliveryMember, type DeliveryMemberStatus, type GoalDelivery } from '@open-agent-toolkit/control-plane';
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import { type DeliveryProjectDependencies, type GoalDeliveryProject } from './check.js';
|
|
7
|
+
import { type CarrierEvaluation, type ReviewEvaluation } from './evidence.js';
|
|
8
|
+
/**
|
|
9
|
+
* `oat project delivery refresh` (design "Endpoint observation and
|
|
10
|
+
* refresh"). It observes every registered delivery member through `gh pr
|
|
11
|
+
* view <url> --json state,headRefOid,baseRefOid` and persists observations
|
|
12
|
+
* and derived freshness only:
|
|
13
|
+
*
|
|
14
|
+
* - member `observed_head`, `observed_base` and `status`;
|
|
15
|
+
* - delivery `status: at_endpoint` once the agreed endpoint is observed, and
|
|
16
|
+
* the first observed attainment in `endpoint_attainment`;
|
|
17
|
+
* - `integrated_review.disposition: stale` and the milestone exit carrier's
|
|
18
|
+
* `freshness: stale` with `freshness_reason` when the shared evaluator
|
|
19
|
+
* finds the evidence no longer covers the observation.
|
|
20
|
+
*
|
|
21
|
+
* It never writes `oat_milestone_status` or `oat_goal_recovery`, never
|
|
22
|
+
* rewrites a reviewed revision, a member base or the first endpoint
|
|
23
|
+
* attainment, and never manufactures a passed review or a fresh carrier.
|
|
24
|
+
* Observation is atomic: if any member cannot be observed nothing is written.
|
|
25
|
+
*/
|
|
26
|
+
export interface MemberObservation {
|
|
27
|
+
head: string;
|
|
28
|
+
base: string;
|
|
29
|
+
status: DeliveryMemberStatus;
|
|
30
|
+
}
|
|
31
|
+
export type ObservationWriteMode = 'observe' | 'once';
|
|
32
|
+
/**
|
|
33
|
+
* A path segment: a literal key or index, or a symbolic delivery/milestone
|
|
34
|
+
* reference resolved against the raw YAML when the write is applied.
|
|
35
|
+
*/
|
|
36
|
+
export type ObservationPathSegment = string | number | {
|
|
37
|
+
deliveryId: string;
|
|
38
|
+
} | {
|
|
39
|
+
milestone: string;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* One state write. `observe` writes may replace a stored observation; `once`
|
|
43
|
+
* writes apply only while the stored value is unset. The never-overwrite rule
|
|
44
|
+
* in `mayReplaceStoredValue` decides which stored values a write may replace.
|
|
45
|
+
*/
|
|
46
|
+
export interface ObservationWrite {
|
|
47
|
+
path: ObservationPathSegment[];
|
|
48
|
+
value: unknown;
|
|
49
|
+
mode: ObservationWriteMode;
|
|
50
|
+
}
|
|
51
|
+
export interface DeliveryRefreshResult {
|
|
52
|
+
deliveryId: string;
|
|
53
|
+
milestone: string | null;
|
|
54
|
+
status: GoalDelivery['status'];
|
|
55
|
+
endpointSatisfied: boolean;
|
|
56
|
+
members: {
|
|
57
|
+
url: string | null;
|
|
58
|
+
observed_head: string | null;
|
|
59
|
+
observed_base: string | null;
|
|
60
|
+
status: DeliveryMemberStatus | null;
|
|
61
|
+
}[];
|
|
62
|
+
review: ReviewEvaluation;
|
|
63
|
+
}
|
|
64
|
+
export interface RefreshReport {
|
|
65
|
+
deliveries: DeliveryRefreshResult[];
|
|
66
|
+
exitCarriers: {
|
|
67
|
+
milestone: string;
|
|
68
|
+
delivery: string;
|
|
69
|
+
evaluation: CarrierEvaluation;
|
|
70
|
+
}[];
|
|
71
|
+
writes: ObservationWrite[];
|
|
72
|
+
changed: boolean;
|
|
73
|
+
}
|
|
74
|
+
export declare function observeMember(gh: GhRunner, url: string): Promise<MemberObservation | string>;
|
|
75
|
+
/** Endpoint satisfaction on observed member state (design "Endpoint satisfaction"). */
|
|
76
|
+
export declare function endpointSatisfied(endpoint: GoalDelivery['endpoint'], members: readonly Pick<DeliveryMember, 'status'>[]): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Compute the refresh for a loaded goal project: observe members, derive
|
|
79
|
+
* endpoint and freshness, and return the state writes. Pure apart from the
|
|
80
|
+
* injected `gh` and `git` runners.
|
|
81
|
+
*/
|
|
82
|
+
export declare function planDeliveryRefresh(project: GoalDeliveryProject, runners: {
|
|
83
|
+
gh: GhRunner;
|
|
84
|
+
git: GitRunner;
|
|
85
|
+
now: () => Date;
|
|
86
|
+
}): Promise<RefreshReport | {
|
|
87
|
+
failures: string[];
|
|
88
|
+
}>;
|
|
89
|
+
/**
|
|
90
|
+
* Apply refresh writes to `state.md` under the never-overwrite rule
|
|
91
|
+
* (`mayReplaceStoredValue`). Returns the new content, or the original when
|
|
92
|
+
* nothing changed.
|
|
93
|
+
*/
|
|
94
|
+
export declare function applyObservationWrites(stateContent: string, writes: readonly ObservationWrite[]): {
|
|
95
|
+
content: string;
|
|
96
|
+
changed: boolean;
|
|
97
|
+
applied: ObservationWrite[];
|
|
98
|
+
};
|
|
99
|
+
export interface DeliveryRefreshDependencies extends DeliveryProjectDependencies {
|
|
100
|
+
buildCommandContext: (options: GlobalOptions) => CommandContext;
|
|
101
|
+
gh: GhRunner;
|
|
102
|
+
git: GitRunner;
|
|
103
|
+
writeFile: (path: string, content: string) => Promise<void>;
|
|
104
|
+
now: () => Date;
|
|
105
|
+
}
|
|
106
|
+
export declare function refreshDeliveries(projectArgument: string, cwd: string, dependencies: DeliveryRefreshDependencies): Promise<RefreshReport | {
|
|
107
|
+
failures: string[];
|
|
108
|
+
}>;
|
|
109
|
+
export declare function createProjectDeliveryRefreshCommand(overrides?: Partial<DeliveryRefreshDependencies>): Command;
|
|
110
|
+
//# sourceMappingURL=refresh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/delivery/refresh.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
import { writeFile } from 'node:fs/promises';
|
|
2
|
+
import { buildCommandContext, } from '../../../app/command-context.js';
|
|
3
|
+
import { defaultGhRunner, } from '../../project/links/refresh.js';
|
|
4
|
+
import { defaultGitRunner } from '../../project/sync/git.js';
|
|
5
|
+
import { getFrontmatterBlock } from '../../shared/frontmatter.js';
|
|
6
|
+
import { replaceFrontmatter } from '../../shared/frontmatter-write.js';
|
|
7
|
+
import { readGlobalOptions } from '../../shared/shared.utils.js';
|
|
8
|
+
import { CliError } from '../../../errors/cli-error.js';
|
|
9
|
+
import { normalizeMilestoneId, } from '@open-agent-toolkit/control-plane';
|
|
10
|
+
import { Command } from 'commander';
|
|
11
|
+
import YAML, { isMap, isScalar, isSeq } from 'yaml';
|
|
12
|
+
import { DEFAULT_DELIVERY_PROJECT_DEPENDENCIES, deliveryEffectiveScope, loadGoalDeliveryProject, } from './check.js';
|
|
13
|
+
import { deliveryEvidenceScope, evaluateDeliveryReview, evaluateGateCarrier, } from './evidence.js';
|
|
14
|
+
/** The only frontmatter keys a refresh writes under. */
|
|
15
|
+
const REFRESH_WRITE_ROOTS = new Set(['oat_deliveries', 'oat_milestone_gates']);
|
|
16
|
+
const MEMBER_OBSERVATION_LEAVES = new Set([
|
|
17
|
+
'observed_head',
|
|
18
|
+
'observed_base',
|
|
19
|
+
'status',
|
|
20
|
+
]);
|
|
21
|
+
const CARRIER_FRESHNESS_LEAVES = new Set(['freshness', 'freshness_reason']);
|
|
22
|
+
/**
|
|
23
|
+
* The never-overwrite rule (A4), structural rather than by leaf name: a
|
|
24
|
+
* stored value may be replaced only by an `observe` write at one of the
|
|
25
|
+
* observation paths —
|
|
26
|
+
*
|
|
27
|
+
* - `oat_deliveries[d].members[i].{observed_head, observed_base, status}`;
|
|
28
|
+
* - `oat_deliveries[d].status`, only while the stored value is `open`;
|
|
29
|
+
* - `oat_deliveries[d].integrated_review.disposition`;
|
|
30
|
+
* - `oat_milestone_gates[m].{plan, exit}.{freshness, freshness_reason}`.
|
|
31
|
+
*
|
|
32
|
+
* Every other path — reviewed revisions, member bases, frozen scopes, review
|
|
33
|
+
* identities, carrier outcomes and the first endpoint attainment — is
|
|
34
|
+
* historical evidence and is written only while unset.
|
|
35
|
+
*/
|
|
36
|
+
function mayReplaceStoredValue(write, stored) {
|
|
37
|
+
if (write.mode !== 'observe')
|
|
38
|
+
return false;
|
|
39
|
+
const [root, , ...rest] = write.path;
|
|
40
|
+
if (root === 'oat_deliveries') {
|
|
41
|
+
if (rest.length === 3 &&
|
|
42
|
+
rest[0] === 'members' &&
|
|
43
|
+
typeof rest[1] === 'number' &&
|
|
44
|
+
typeof rest[2] === 'string' &&
|
|
45
|
+
MEMBER_OBSERVATION_LEAVES.has(rest[2])) {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
if (rest.length === 1 && rest[0] === 'status') {
|
|
49
|
+
return stored === 'open';
|
|
50
|
+
}
|
|
51
|
+
return (rest.length === 2 &&
|
|
52
|
+
rest[0] === 'integrated_review' &&
|
|
53
|
+
rest[1] === 'disposition');
|
|
54
|
+
}
|
|
55
|
+
if (root === 'oat_milestone_gates') {
|
|
56
|
+
return (rest.length === 2 &&
|
|
57
|
+
(rest[0] === 'exit' || rest[0] === 'plan') &&
|
|
58
|
+
typeof rest[1] === 'string' &&
|
|
59
|
+
CARRIER_FRESHNESS_LEAVES.has(rest[1]));
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
const PR_STATES = {
|
|
64
|
+
OPEN: 'open',
|
|
65
|
+
MERGED: 'merged',
|
|
66
|
+
CLOSED: 'closed',
|
|
67
|
+
};
|
|
68
|
+
const SHA_PATTERN = /^[0-9a-f]{40}$/;
|
|
69
|
+
export async function observeMember(gh, url) {
|
|
70
|
+
const viewed = await gh.run([
|
|
71
|
+
'pr',
|
|
72
|
+
'view',
|
|
73
|
+
url,
|
|
74
|
+
'--json',
|
|
75
|
+
'state,headRefOid,baseRefOid',
|
|
76
|
+
]);
|
|
77
|
+
if (viewed.code !== 0) {
|
|
78
|
+
return viewed.missing
|
|
79
|
+
? 'the GitHub CLI is unavailable'
|
|
80
|
+
: `gh pr view failed: ${viewed.stderr || viewed.stdout || `exit ${viewed.code}`}`;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const parsed = JSON.parse(viewed.stdout);
|
|
84
|
+
const status = PR_STATES[String(parsed['state'] ?? '')];
|
|
85
|
+
const head = parsed['headRefOid'];
|
|
86
|
+
const base = parsed['baseRefOid'];
|
|
87
|
+
if (status === undefined ||
|
|
88
|
+
typeof head !== 'string' ||
|
|
89
|
+
typeof base !== 'string' ||
|
|
90
|
+
!SHA_PATTERN.test(head) ||
|
|
91
|
+
!SHA_PATTERN.test(base)) {
|
|
92
|
+
return 'gh returned an incomplete observation';
|
|
93
|
+
}
|
|
94
|
+
return { head, base, status };
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return 'gh returned output that is not JSON';
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/** Endpoint satisfaction on observed member state (design "Endpoint satisfaction"). */
|
|
101
|
+
export function endpointSatisfied(endpoint, members) {
|
|
102
|
+
if (members.length === 0 || endpoint === null)
|
|
103
|
+
return false;
|
|
104
|
+
return endpoint === 'merged'
|
|
105
|
+
? members.every((member) => member.status === 'merged')
|
|
106
|
+
: members.every((member) => member.status === 'open' || member.status === 'merged');
|
|
107
|
+
}
|
|
108
|
+
/** Deliveries a refresh observes: registered and not replaced. */
|
|
109
|
+
function isObservable(delivery) {
|
|
110
|
+
return delivery.status === 'open' || delivery.status === 'at_endpoint';
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Compute the refresh for a loaded goal project: observe members, derive
|
|
114
|
+
* endpoint and freshness, and return the state writes. Pure apart from the
|
|
115
|
+
* injected `gh` and `git` runners.
|
|
116
|
+
*/
|
|
117
|
+
export async function planDeliveryRefresh(project, runners) {
|
|
118
|
+
const deliveries = project.state.deliveries ?? [];
|
|
119
|
+
const observations = new Map();
|
|
120
|
+
const failures = [];
|
|
121
|
+
for (const delivery of deliveries.filter(isObservable)) {
|
|
122
|
+
const observed = [];
|
|
123
|
+
for (const member of delivery.members) {
|
|
124
|
+
if (member.url === null) {
|
|
125
|
+
failures.push(`${delivery.delivery_id}: a member has no URL to observe`);
|
|
126
|
+
observed.push(null);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const result = await observeMember(runners.gh, member.url);
|
|
130
|
+
if (typeof result === 'string') {
|
|
131
|
+
failures.push(`${delivery.delivery_id} ${member.url}: ${result}`);
|
|
132
|
+
observed.push(null);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
observed.push(result);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
observations.set(delivery.delivery_id, observed);
|
|
139
|
+
}
|
|
140
|
+
if (failures.length > 0) {
|
|
141
|
+
// Failure to observe a required member is never endpoint success, and a
|
|
142
|
+
// partial refresh would mix observations from different moments.
|
|
143
|
+
return { failures };
|
|
144
|
+
}
|
|
145
|
+
const writes = [];
|
|
146
|
+
const results = [];
|
|
147
|
+
const observedById = new Map();
|
|
148
|
+
const deliveryPath = (delivery) => [
|
|
149
|
+
'oat_deliveries',
|
|
150
|
+
{ deliveryId: delivery.delivery_id },
|
|
151
|
+
];
|
|
152
|
+
for (const delivery of deliveries.filter(isObservable)) {
|
|
153
|
+
const observed = observations.get(delivery.delivery_id) ?? [];
|
|
154
|
+
const members = delivery.members.map((member, index) => {
|
|
155
|
+
const observation = observed[index];
|
|
156
|
+
return observation
|
|
157
|
+
? {
|
|
158
|
+
...member,
|
|
159
|
+
observed_head: observation.head,
|
|
160
|
+
observed_base: observation.base,
|
|
161
|
+
status: observation.status,
|
|
162
|
+
}
|
|
163
|
+
: member;
|
|
164
|
+
});
|
|
165
|
+
for (const [index, observation] of observed.entries()) {
|
|
166
|
+
if (!observation)
|
|
167
|
+
continue;
|
|
168
|
+
const memberPath = [...deliveryPath(delivery), 'members', index];
|
|
169
|
+
writes.push({
|
|
170
|
+
path: [...memberPath, 'observed_head'],
|
|
171
|
+
value: observation.head,
|
|
172
|
+
mode: 'observe',
|
|
173
|
+
}, {
|
|
174
|
+
path: [...memberPath, 'observed_base'],
|
|
175
|
+
value: observation.base,
|
|
176
|
+
mode: 'observe',
|
|
177
|
+
}, {
|
|
178
|
+
path: [...memberPath, 'status'],
|
|
179
|
+
value: observation.status,
|
|
180
|
+
mode: 'observe',
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
const satisfied = endpointSatisfied(delivery.endpoint, members);
|
|
184
|
+
let status = delivery.status;
|
|
185
|
+
if (satisfied) {
|
|
186
|
+
if (status === 'open') {
|
|
187
|
+
status = 'at_endpoint';
|
|
188
|
+
writes.push({
|
|
189
|
+
path: [...deliveryPath(delivery), 'status'],
|
|
190
|
+
value: 'at_endpoint',
|
|
191
|
+
mode: 'observe',
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
writes.push({
|
|
195
|
+
path: [...deliveryPath(delivery), 'endpoint_attainment'],
|
|
196
|
+
value: {
|
|
197
|
+
observed_at: runners.now().toISOString(),
|
|
198
|
+
members: members.map((member) => ({
|
|
199
|
+
url: member.url,
|
|
200
|
+
head: member.observed_head,
|
|
201
|
+
base: member.observed_base,
|
|
202
|
+
status: member.status,
|
|
203
|
+
})),
|
|
204
|
+
},
|
|
205
|
+
mode: 'once',
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
const observedDelivery = { ...delivery, members, status };
|
|
209
|
+
observedById.set(delivery.delivery_id, observedDelivery);
|
|
210
|
+
const review = await evaluateDeliveryReview(runners.git, evidenceScope(project, observedDelivery), observedDelivery, deliveryEffectiveScope(deliveries, observedDelivery));
|
|
211
|
+
if (delivery.integrated_review !== null &&
|
|
212
|
+
!review.fresh &&
|
|
213
|
+
delivery.integrated_review.disposition === 'passed') {
|
|
214
|
+
writes.push({
|
|
215
|
+
path: [...deliveryPath(delivery), 'integrated_review', 'disposition'],
|
|
216
|
+
value: 'stale',
|
|
217
|
+
mode: 'observe',
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
results.push({
|
|
221
|
+
deliveryId: delivery.delivery_id,
|
|
222
|
+
milestone: delivery.milestone,
|
|
223
|
+
status,
|
|
224
|
+
endpointSatisfied: satisfied,
|
|
225
|
+
members: members.map((member) => ({
|
|
226
|
+
url: member.url,
|
|
227
|
+
observed_head: member.observed_head,
|
|
228
|
+
observed_base: member.observed_base,
|
|
229
|
+
status: member.status,
|
|
230
|
+
})),
|
|
231
|
+
review,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
// The milestone exit carrier is judged for each milestone's latest
|
|
235
|
+
// registered delivery. Refresh records only staleness: it never upgrades a
|
|
236
|
+
// carrier to fresh, which only implement's scoped closeout writes.
|
|
237
|
+
const exitCarriers = [];
|
|
238
|
+
const latestByMilestone = new Map();
|
|
239
|
+
for (const delivery of deliveries) {
|
|
240
|
+
const observed = observedById.get(delivery.delivery_id);
|
|
241
|
+
if (observed && observed.milestone !== null) {
|
|
242
|
+
latestByMilestone.set(observed.milestone, observed);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
for (const [milestone, delivery] of latestByMilestone) {
|
|
246
|
+
const carrier = project.state.milestoneGates?.[milestone]?.exit ?? null;
|
|
247
|
+
if (carrier === null)
|
|
248
|
+
continue;
|
|
249
|
+
const scope = evidenceScope(project, delivery);
|
|
250
|
+
const evaluation = await evaluateGateCarrier(carrier, {
|
|
251
|
+
kind: 'code',
|
|
252
|
+
scope: deliveryEffectiveScope(deliveries, delivery),
|
|
253
|
+
match: 'covers',
|
|
254
|
+
overrideDisabled: project.exitGateDisabled,
|
|
255
|
+
}, {
|
|
256
|
+
git: runners.git,
|
|
257
|
+
scope,
|
|
258
|
+
publishedHeads: delivery.members.map((member) => member.observed_head),
|
|
259
|
+
});
|
|
260
|
+
exitCarriers.push({
|
|
261
|
+
milestone,
|
|
262
|
+
delivery: delivery.delivery_id,
|
|
263
|
+
evaluation,
|
|
264
|
+
});
|
|
265
|
+
if (evaluation.freshness === 'stale') {
|
|
266
|
+
const carrierPath = [
|
|
267
|
+
'oat_milestone_gates',
|
|
268
|
+
{ milestone },
|
|
269
|
+
'exit',
|
|
270
|
+
];
|
|
271
|
+
writes.push({
|
|
272
|
+
path: [...carrierPath, 'freshness'],
|
|
273
|
+
value: 'stale',
|
|
274
|
+
mode: 'observe',
|
|
275
|
+
}, {
|
|
276
|
+
path: [...carrierPath, 'freshness_reason'],
|
|
277
|
+
value: `delivery refresh (${delivery.delivery_id}): ${evaluation.reason ?? 'stale'}`,
|
|
278
|
+
mode: 'observe',
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return { deliveries: results, exitCarriers, writes, changed: false };
|
|
283
|
+
}
|
|
284
|
+
function evidenceScope(project, delivery) {
|
|
285
|
+
return deliveryEvidenceScope(project, project.state.deliveries ?? [], delivery);
|
|
286
|
+
}
|
|
287
|
+
// ---------------------------------------------------------------------------
|
|
288
|
+
// Applying writes to state.md frontmatter
|
|
289
|
+
// ---------------------------------------------------------------------------
|
|
290
|
+
function isUnsetNode(value) {
|
|
291
|
+
return (value === undefined ||
|
|
292
|
+
value === null ||
|
|
293
|
+
(isScalar(value) && (value.value === null || value.value === '')));
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Resolve the symbolic path segments (`{ deliveryId }`, `{ milestone }`) to
|
|
297
|
+
* the raw YAML indices and keys, so a write lands on the entry the reader
|
|
298
|
+
* parsed even when the raw list holds unparseable entries or `m1` spelling.
|
|
299
|
+
*/
|
|
300
|
+
function resolvePath(document, path) {
|
|
301
|
+
const resolved = [];
|
|
302
|
+
for (const segment of path) {
|
|
303
|
+
if (typeof segment !== 'object') {
|
|
304
|
+
resolved.push(segment);
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
const parent = document.getIn(resolved, true);
|
|
308
|
+
if ('deliveryId' in segment) {
|
|
309
|
+
if (!isSeq(parent))
|
|
310
|
+
return null;
|
|
311
|
+
const index = parent.items.findIndex((item) => isMap(item) && String(item.get('delivery_id')) === segment.deliveryId);
|
|
312
|
+
if (index < 0)
|
|
313
|
+
return null;
|
|
314
|
+
resolved.push(index);
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
if (!isMap(parent))
|
|
318
|
+
return null;
|
|
319
|
+
const key = parent.items
|
|
320
|
+
.map((pair) => (isScalar(pair.key) ? String(pair.key.value) : null))
|
|
321
|
+
.find((raw) => raw !== null && normalizeMilestoneId(raw) === segment.milestone);
|
|
322
|
+
if (key === undefined || key === null)
|
|
323
|
+
return null;
|
|
324
|
+
resolved.push(key);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return resolved;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Apply refresh writes to `state.md` under the never-overwrite rule
|
|
331
|
+
* (`mayReplaceStoredValue`). Returns the new content, or the original when
|
|
332
|
+
* nothing changed.
|
|
333
|
+
*/
|
|
334
|
+
export function applyObservationWrites(stateContent, writes) {
|
|
335
|
+
const block = getFrontmatterBlock(stateContent);
|
|
336
|
+
if (block === null) {
|
|
337
|
+
throw new CliError('state.md has no frontmatter to refresh', 1);
|
|
338
|
+
}
|
|
339
|
+
const document = YAML.parseDocument(block, { uniqueKeys: true });
|
|
340
|
+
if (document.errors.length > 0) {
|
|
341
|
+
throw new CliError(`state.md frontmatter is malformed: ${document.errors[0]?.message ?? 'YAML error'}`, 1);
|
|
342
|
+
}
|
|
343
|
+
const applied = [];
|
|
344
|
+
for (const write of writes) {
|
|
345
|
+
const [root] = write.path;
|
|
346
|
+
if (typeof root !== 'string' || !REFRESH_WRITE_ROOTS.has(root)) {
|
|
347
|
+
// Refresh never writes milestone status, recovery or any other key.
|
|
348
|
+
throw new CliError(`delivery refresh may not write ${String(root)}; it records delivery observations and derived freshness only`, 2);
|
|
349
|
+
}
|
|
350
|
+
const path = resolvePath(document, write.path);
|
|
351
|
+
if (path === null)
|
|
352
|
+
continue;
|
|
353
|
+
const current = document.getIn(path, true);
|
|
354
|
+
if (!isUnsetNode(current) &&
|
|
355
|
+
!mayReplaceStoredValue(write, isScalar(current) ? current.value : document.getIn(path))) {
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
const previous = document.getIn(path);
|
|
359
|
+
if (JSON.stringify(previous) === JSON.stringify(write.value))
|
|
360
|
+
continue;
|
|
361
|
+
document.setIn(path, document.createNode(write.value, { flow: false }));
|
|
362
|
+
applied.push({ ...write, path });
|
|
363
|
+
}
|
|
364
|
+
if (applied.length === 0) {
|
|
365
|
+
return { content: stateContent, changed: false, applied };
|
|
366
|
+
}
|
|
367
|
+
const nextBlock = document.toString({ lineWidth: 0 }).replace(/\n$/, '');
|
|
368
|
+
return {
|
|
369
|
+
content: replaceFrontmatter(stateContent, nextBlock),
|
|
370
|
+
changed: true,
|
|
371
|
+
applied,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
const DEFAULT_REFRESH_DEPENDENCIES = {
|
|
375
|
+
...DEFAULT_DELIVERY_PROJECT_DEPENDENCIES,
|
|
376
|
+
buildCommandContext,
|
|
377
|
+
gh: defaultGhRunner,
|
|
378
|
+
git: defaultGitRunner,
|
|
379
|
+
writeFile: (path, content) => writeFile(path, content, 'utf8'),
|
|
380
|
+
now: () => new Date(),
|
|
381
|
+
};
|
|
382
|
+
export async function refreshDeliveries(projectArgument, cwd, dependencies) {
|
|
383
|
+
const project = await loadGoalDeliveryProject(projectArgument, cwd, dependencies);
|
|
384
|
+
const planned = await planDeliveryRefresh(project, dependencies);
|
|
385
|
+
if ('failures' in planned) {
|
|
386
|
+
return planned;
|
|
387
|
+
}
|
|
388
|
+
const result = applyObservationWrites(project.stateContent, planned.writes);
|
|
389
|
+
if (result.changed) {
|
|
390
|
+
await dependencies.writeFile(project.statePath, result.content);
|
|
391
|
+
}
|
|
392
|
+
return { ...planned, writes: result.applied, changed: result.changed };
|
|
393
|
+
}
|
|
394
|
+
export function createProjectDeliveryRefreshCommand(overrides = {}) {
|
|
395
|
+
const dependencies = { ...DEFAULT_REFRESH_DEPENDENCIES, ...overrides };
|
|
396
|
+
return new Command('refresh')
|
|
397
|
+
.description('Observe registered goal delivery members with gh and persist observations, endpoint attainment and derived staleness in state.md')
|
|
398
|
+
.requiredOption('--project <path>', 'Goal project path')
|
|
399
|
+
.action(async (options, command) => {
|
|
400
|
+
const context = dependencies.buildCommandContext(readGlobalOptions(command));
|
|
401
|
+
try {
|
|
402
|
+
const report = await refreshDeliveries(options.project, context.cwd, dependencies);
|
|
403
|
+
if ('failures' in report) {
|
|
404
|
+
const message = `Delivery refresh observed nothing: ${report.failures.join('; ')}`;
|
|
405
|
+
if (context.json) {
|
|
406
|
+
context.logger.json({
|
|
407
|
+
status: 'failed',
|
|
408
|
+
failures: report.failures,
|
|
409
|
+
message,
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
context.logger.error(message);
|
|
414
|
+
}
|
|
415
|
+
process.exitCode = 1;
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
if (context.json) {
|
|
419
|
+
context.logger.json({ status: 'ok', ...report });
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
context.logger.info([
|
|
423
|
+
`Refreshed ${report.deliveries.length} delivery(ies)${report.changed ? '' : '; state.md unchanged'}.`,
|
|
424
|
+
...report.deliveries.map((delivery) => ` ${delivery.deliveryId}: ${delivery.status ?? 'unknown'}${delivery.endpointSatisfied ? ' (endpoint observed)' : ''}; review ${delivery.review.fresh ? 'fresh' : `stale: ${delivery.review.reason ?? 'unknown'}`}`),
|
|
425
|
+
...report.exitCarriers.map((carrier) => ` ${carrier.milestone} exit carrier: ${carrier.evaluation.freshness}${carrier.evaluation.reason ? ` (${carrier.evaluation.reason})` : ''}`),
|
|
426
|
+
].join('\n'));
|
|
427
|
+
}
|
|
428
|
+
process.exitCode = 0;
|
|
429
|
+
}
|
|
430
|
+
catch (error) {
|
|
431
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
432
|
+
if (context.json) {
|
|
433
|
+
context.logger.json({ status: 'error', message });
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
context.logger.error(message);
|
|
437
|
+
}
|
|
438
|
+
process.exitCode = error instanceof CliError ? error.exitCode : 1;
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/project/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/project/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0BpC,wBAAgB,oBAAoB,IAAI,OAAO,CA0B9C"}
|
|
@@ -3,6 +3,7 @@ import { createProjectArchiveCommand } from './archive/index.js';
|
|
|
3
3
|
import { createProjectCloseoutCheckCommand } from './closeout-check/index.js';
|
|
4
4
|
import { createProjectCompleteDiscoveryCommand } from './complete-discovery/index.js';
|
|
5
5
|
import { createProjectCompleteStateCommand } from './complete-state/index.js';
|
|
6
|
+
import { createProjectDeliveryCommand } from './delivery/index.js';
|
|
6
7
|
import { createProjectDispatchCommand } from './dispatch/index.js';
|
|
7
8
|
import { createProjectDispatchCeilingCommand } from './dispatch-ceiling/index.js';
|
|
8
9
|
import { createProjectLinksCommand } from './links/index.js';
|
|
@@ -28,6 +29,7 @@ export function createProjectCommand() {
|
|
|
28
29
|
.addCommand(createProjectCloseoutCheckCommand())
|
|
29
30
|
.addCommand(createProjectCompleteDiscoveryCommand())
|
|
30
31
|
.addCommand(createProjectCompleteStateCommand())
|
|
32
|
+
.addCommand(createProjectDeliveryCommand())
|
|
31
33
|
.addCommand(createProjectDispatchCommand())
|
|
32
34
|
.addCommand(createProjectDispatchCeilingCommand())
|
|
33
35
|
.addCommand(createProjectListCommand())
|
|
@@ -4,6 +4,12 @@ import { type ResolvedConfig } from '../../../config/resolve.js';
|
|
|
4
4
|
import { Command } from 'commander';
|
|
5
5
|
import { type ProjectLogSeal } from './check.js';
|
|
6
6
|
export declare const PROJECT_LOG_FILENAME = "project-log.md";
|
|
7
|
+
/**
|
|
8
|
+
* Where `appendEntry` inserts: entries go before the end-of-run synthesis
|
|
9
|
+
* section, so an append is not a byte-suffix of the previous log. The
|
|
10
|
+
* delivery-evidence evaluator reads the same marker to recognize an append.
|
|
11
|
+
*/
|
|
12
|
+
export declare const SYNTHESIS_HEADING_PREFIX = "\n## End-of-run synthesis";
|
|
7
13
|
/**
|
|
8
14
|
* Directory, relative to a project, that holds gate partial-finalization
|
|
9
15
|
* receipts. Ignored by the repository so a receipt never dirties the tree.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"append.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/log/append.ts"],"names":[],"mappings":"AA8BA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAA0B,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAI9E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,SAAS,CAAC;AAqBjB,eAAO,MAAM,oBAAoB,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"append.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/log/append.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,7 +16,12 @@ import { Command } from 'commander';
|
|
|
16
16
|
import { findProjectLogAmbiguity, findProjectLogSeal, unreachableProjectLogSealError, } from './check.js';
|
|
17
17
|
import { composeJudgmentHeading, composeStructuralHeading, containsAmbiguousProjectLogMarker, isProjectLogEntryMarker, findProjectLogSealHeadingLine, isProjectLogSealHeading, isProjectLogSectionMarker, PROJECT_LOG_AREA_MAX_LENGTH, PROJECT_LOG_HEADING_DELIMITER, PROJECT_LOG_LINE_TERMINATOR_RE, PROJECT_LOG_LONE_TERMINATOR_RE, PROJECT_LOG_SCOPES, PROJECT_LOG_TYPES, normalizeProjectLogLineEndings, splitProjectLogLines, } from './grammar.js';
|
|
18
18
|
export const PROJECT_LOG_FILENAME = 'project-log.md';
|
|
19
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Where `appendEntry` inserts: entries go before the end-of-run synthesis
|
|
21
|
+
* section, so an append is not a byte-suffix of the previous log. The
|
|
22
|
+
* delivery-evidence evaluator reads the same marker to recognize an append.
|
|
23
|
+
*/
|
|
24
|
+
export const SYNTHESIS_HEADING_PREFIX = '\n## End-of-run synthesis';
|
|
20
25
|
/**
|
|
21
26
|
* Directory, relative to a project, that holds gate partial-finalization
|
|
22
27
|
* receipts. Ignored by the repository so a receipt never dirties the tree.
|