alignfirst 0.1.0-beta.7 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -89,12 +89,12 @@ AlignFirst stores specifications, plans, and summaries in `.plans/<ticket-id>/`.
|
|
|
89
89
|
|
|
90
90
|
## Catchup output
|
|
91
91
|
|
|
92
|
-
`alignfirst ticket [<id>] --catchup` prints the ticket's Markdown files, plans excluded, each in a `<file>` block carrying its path and modification time. When the history exceeds the output budget, only the entry list is printed
|
|
92
|
+
`alignfirst ticket [<id>] --catchup` prints the ticket's Markdown files, plans excluded, each in a `<file>` block carrying its path and modification time. When the history exceeds the output budget, only the entry list is printed, with a notice telling the agent to read the relevant files and skip the plans.
|
|
93
93
|
|
|
94
94
|
## Updates
|
|
95
95
|
|
|
96
96
|
```sh
|
|
97
|
-
npm
|
|
97
|
+
npm install -g alignfirst@latest
|
|
98
98
|
npx skills update --global --yes
|
|
99
99
|
```
|
|
100
100
|
|
package/dist/commands/ticket.js
CHANGED
|
@@ -11,6 +11,8 @@ const USAGE = `Usage:
|
|
|
11
11
|
{{FORM}} ticket --side [--next [<filename>]] [--new-cycle] [--json] [--dry-run]
|
|
12
12
|
{{FORM}} ticket [<id>] --catchup
|
|
13
13
|
|
|
14
|
+
--next may repeat, each occurrence with a filename: the names are numbered in order.
|
|
15
|
+
|
|
14
16
|
--catchup prints the ticket's Markdown files, plans excluded, summaries included.
|
|
15
17
|
Files over 64 KiB are listed without content. Above 30 KiB of output, only the entry
|
|
16
18
|
list is printed.
|
|
@@ -68,12 +70,10 @@ function parseTicketArgs(ctx, args, usage) {
|
|
|
68
70
|
if (values.catchup &&
|
|
69
71
|
(values.side || values.next !== undefined || values.json || values["dry-run"]))
|
|
70
72
|
throw new CliError(`--catchup cannot be combined with --side, --next, --json, or --dry-run.\n\n${usage}`);
|
|
71
|
-
if (normalized.filename !== undefined)
|
|
72
|
-
validateNextFilename(normalized.filename);
|
|
73
73
|
const resolution = resolveTicketId(ctx, positionals[0], values);
|
|
74
74
|
return {
|
|
75
75
|
...resolution,
|
|
76
|
-
next: values.next === undefined ? undefined : (normalized.
|
|
76
|
+
next: values.next === undefined ? undefined : resolveNextRequest(normalized.requests, usage),
|
|
77
77
|
newCycle: values["new-cycle"],
|
|
78
78
|
json: values.json,
|
|
79
79
|
dryRun: values["dry-run"],
|
|
@@ -82,7 +82,7 @@ function parseTicketArgs(ctx, args, usage) {
|
|
|
82
82
|
};
|
|
83
83
|
}
|
|
84
84
|
function normalizeNextArgs(args) {
|
|
85
|
-
const normalized = { args: [] };
|
|
85
|
+
const normalized = { args: [], requests: [] };
|
|
86
86
|
for (let index = 0; index < args.length; ++index) {
|
|
87
87
|
const arg = args[index];
|
|
88
88
|
if (arg === "--") {
|
|
@@ -90,7 +90,7 @@ function normalizeNextArgs(args) {
|
|
|
90
90
|
break;
|
|
91
91
|
}
|
|
92
92
|
if (arg.startsWith("--next=")) {
|
|
93
|
-
normalized.
|
|
93
|
+
normalized.requests.push(arg.slice("--next=".length));
|
|
94
94
|
normalized.args.push("--next");
|
|
95
95
|
continue;
|
|
96
96
|
}
|
|
@@ -98,14 +98,25 @@ function normalizeNextArgs(args) {
|
|
|
98
98
|
if (arg !== "--next")
|
|
99
99
|
continue;
|
|
100
100
|
const following = args[index + 1];
|
|
101
|
-
delete normalized.filename;
|
|
102
101
|
if (following !== undefined && !following.startsWith("-")) {
|
|
103
|
-
normalized.
|
|
102
|
+
normalized.requests.push(following);
|
|
104
103
|
++index;
|
|
105
104
|
}
|
|
105
|
+
else
|
|
106
|
+
normalized.requests.push(undefined);
|
|
106
107
|
}
|
|
107
108
|
return normalized;
|
|
108
109
|
}
|
|
110
|
+
function resolveNextRequest(requests, usage) {
|
|
111
|
+
if (requests.length === 1 && requests[0] === undefined)
|
|
112
|
+
return true;
|
|
113
|
+
const filenames = requests.filter((request) => request !== undefined);
|
|
114
|
+
if (filenames.length < requests.length)
|
|
115
|
+
throw new CliError(`A repeated --next requires a filename on each occurrence.\n\n${usage}`);
|
|
116
|
+
for (const filename of filenames)
|
|
117
|
+
validateNextFilename(filename);
|
|
118
|
+
return filenames;
|
|
119
|
+
}
|
|
109
120
|
function validateNextFilename(filename) {
|
|
110
121
|
if (filename.length === 0 || filename === "." || filename === ".." || /[\\/]/u.test(filename)) {
|
|
111
122
|
throw new CliError("--next must be a non-empty single path segment.");
|
|
@@ -135,21 +146,26 @@ function resolveTicket(ctx, options) {
|
|
|
135
146
|
};
|
|
136
147
|
return resolveTicketDir(ctx.cwd, options.id, { dryRun: options.dryRun });
|
|
137
148
|
}
|
|
138
|
-
function writeNextReport(ctx, options, result,
|
|
149
|
+
function writeNextReport(ctx, options, result, request) {
|
|
139
150
|
const names = result.entries.map((entry) => entry.name);
|
|
140
151
|
const { cycleLetter, fileNumber } = nextFilePosition(names, options.newCycle);
|
|
141
|
-
const
|
|
152
|
+
const fileName = (filename, offset) => `${cycleLetter}${fileNumber + offset}-${filename}`;
|
|
142
153
|
const report = {
|
|
143
154
|
TICKET_DIR: `${relative(ctx.cwd, result.dir)}/`,
|
|
144
155
|
CYCLE_LETTER: cycleLetter,
|
|
145
|
-
|
|
146
|
-
|
|
156
|
+
...(request === true
|
|
157
|
+
? { FILE_NUMBER: fileNumber, FILE_PREFIX: `${cycleLetter}${fileNumber}` }
|
|
158
|
+
: request.length === 1
|
|
159
|
+
? { FILE_NUMBER: fileNumber, FILE_NAME: fileName(request[0], 0) }
|
|
160
|
+
: { FILE_NAMES: request.map(fileName) }),
|
|
147
161
|
};
|
|
148
162
|
if (options.json) {
|
|
149
163
|
ctx.stdout.write(`${JSON.stringify(report, undefined, 2)}\n`);
|
|
150
164
|
return;
|
|
151
165
|
}
|
|
152
|
-
const lines = Object.entries(report).map(([name, value]) =>
|
|
166
|
+
const lines = Object.entries(report).map(([name, value]) => Array.isArray(value)
|
|
167
|
+
? [`- ${name}:`, ...value.map((item) => ` - \`${item}\``)].join("\n")
|
|
168
|
+
: `- ${name}: \`${value}\``);
|
|
153
169
|
ctx.stdout.write(`${lines.join("\n")}\n`);
|
|
154
170
|
}
|
|
155
171
|
function jsonReport(ctx, options, result) {
|
package/dist/plans/catchup.js
CHANGED
|
@@ -7,7 +7,7 @@ const MAX_FILE_BYTES = 64 * 1024;
|
|
|
7
7
|
const MAX_OUTPUT_BYTES = 30 * 1024;
|
|
8
8
|
const PLAN_FILE = /^[A-Z]\d+-(?:main-plan|plan-.*)\.md$/;
|
|
9
9
|
const OMISSION_NOTICE = `Content omitted: over the ${formatSize(MAX_FILE_BYTES)} limit.`;
|
|
10
|
-
const TOO_LARGE_NOTICE = `History too large to print (over the ${formatSize(MAX_OUTPUT_BYTES)} budget). Read the relevant files among the entries above
|
|
10
|
+
const TOO_LARGE_NOTICE = `History too large to print (over the ${formatSize(MAX_OUTPUT_BYTES)} budget). Read the relevant files among the entries above, skipping the plans (\`*-plan.md\`, \`*-main-plan.md\`, \`*-plan-*.md\`): their \`.summary.md\` files cover them.`;
|
|
11
11
|
export function renderCatchup(cwd, ticket, report) {
|
|
12
12
|
const files = ticket.entries.flatMap((entry) => catchupFile(cwd, ticket.dir, entry));
|
|
13
13
|
if (files.length === 0)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "alignfirst",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"license": "CC0-1.0",
|
|
5
5
|
"author": "Thomas MUR",
|
|
6
6
|
"description": "The AlignFirst CLI: protocols, plans and docs in one command.",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@paleo/docmap": "~0.10.0
|
|
37
|
+
"@paleo/docmap": "~0.10.0",
|
|
38
38
|
"arktype": "^2.2.3",
|
|
39
39
|
"semver": "^7.8.5"
|
|
40
40
|
},
|
package/templates/guide/core.md
CHANGED
|
@@ -18,9 +18,9 @@ Files use `{CYCLE_LETTER}{FILE_NUMBER}-{FILE_TYPE}.md`. FILE_PREFIX combines the
|
|
|
18
18
|
|
|
19
19
|
Immediately before creating each file, run `{{TICKET_CMD}} --next <filename>` with the extension included. It returns TICKET_DIR, CYCLE_LETTER, FILE_NUMBER, and FILE_NAME. Append FILE_NAME to TICKET_DIR to get the file path, preserving the leading dot and existing slash.
|
|
20
20
|
|
|
21
|
-
With no filename, `{{TICKET_CMD}} --next` returns FILE_PREFIX instead of FILE_NAME. Add `--new-cycle` to
|
|
21
|
+
With no filename, `{{TICKET_CMD}} --next` returns FILE_PREFIX instead of FILE_NAME. To name several files at once, repeat `--next <filename>` once per file: the command returns FILE_NAMES, numbered in that order. Add `--new-cycle` to any form when the protocol or user calls for a new cycle.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
No form reserves a number. Write the named file or files before requesting another filename. With `--json`, the same information uses the same field names.
|
|
24
24
|
|
|
25
25
|
Common file types are `spec`, `plan`, `AAD.summary`, `description`, `review`, and `merge.summary`. Use another type when needed.
|
|
26
26
|
|
|
@@ -24,14 +24,18 @@ Run `{{TICKET_CMD}} --next merge.summary.md` to continue the current cycle. Appe
|
|
|
24
24
|
|
|
25
25
|
Resolve the conflicts properly — preserve both intents whenever possible. Do not blindly accept one side.
|
|
26
26
|
|
|
27
|
+
Resolve conflicts one at a time. Avoid batch processing, broad search-and-replace operations, and other brute-force edits.
|
|
28
|
+
|
|
27
29
|
**Special case for lock files:** If a lock file has conflicts:
|
|
28
30
|
|
|
29
31
|
1. Accept all the changes from the incoming branch.
|
|
30
32
|
2. After all other conflicts are resolved, run the proper install command so the package manager re-applies the current branch's dependency changes.
|
|
31
33
|
|
|
32
|
-
## 4.
|
|
34
|
+
## 4. Validate and Commit
|
|
35
|
+
|
|
36
|
+
After resolving all conflicts, run the codebase's usual checks, such as compilation, linting, and unit tests. Commit the merge as soon as the available checks pass, using Git's default message (for example, `git commit --no-edit`).
|
|
33
37
|
|
|
34
|
-
|
|
38
|
+
If you need to execute the project, whether through E2E tests or manual checks, do so after the merge commit. Commit any resulting fixes separately.
|
|
35
39
|
|
|
36
40
|
## 5. Summarize
|
|
37
41
|
|
|
@@ -207,32 +207,22 @@ Note:
|
|
|
207
207
|
|
|
208
208
|
## Phase 5. Writing
|
|
209
209
|
|
|
210
|
-
|
|
210
|
+
Continue the current cycle. Request the file names with `{{TICKET_CMD}} --next`, then write every file it named before requesting anything else. Append each name to TICKET_DIR to get its path. Never overwrite an existing file.
|
|
211
211
|
|
|
212
|
-
|
|
212
|
+
**Single plan**: run `{{TICKET_CMD}} --next plan.md`.
|
|
213
213
|
|
|
214
|
-
|
|
214
|
+
- Plan: `{TICKET_DIR}{CYCLE_LETTER}{FILE_NUMBER}-plan.md`, e.g. `.plans/123/A2-plan.md`
|
|
215
|
+
- Handover: `.plans/123/A2-plan.summary.md`
|
|
215
216
|
|
|
216
|
-
|
|
217
|
-
- Example: `.plans/123/A2-plan.md`
|
|
218
|
-
- Handover: `.plans/123/A2-plan.summary.md`
|
|
219
|
-
- No main plan needed
|
|
217
|
+
**Multiple plans**: run one command with a `--next` per file, the main plan first, then the specialized plans in the order the main plan lists them. The command returns all the names, numbered in that order, so the main plan can reference the specialized plans exactly. Example:
|
|
220
218
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
- Example: `.plans/123/A2-main-plan.md`
|
|
225
|
-
- Handover: `.plans/123/A2-main-plan.summary.md` (written after all specialized plans complete)
|
|
226
|
-
- **Specialized plans**: `{TICKET_DIR}{CYCLE_LETTER}{FILE_NUMBER}-plan-{DESCRIPTOR}.md`
|
|
227
|
-
- Use a descriptive name as `{DESCRIPTOR}` (e.g., work scope, stack area)
|
|
228
|
-
- Example: `.plans/123/A3-plan-api.md`, `.plans/123/A4-plan-ui.md`
|
|
229
|
-
- Handovers: `.plans/123/A3-plan-api.summary.md`, etc.
|
|
230
|
-
|
|
231
|
-
**Important**:
|
|
219
|
+
```
|
|
220
|
+
{{TICKET_CMD}} --next main-plan.md --next plan-api.md --next plan-ui.md
|
|
221
|
+
```
|
|
232
222
|
|
|
233
|
-
-
|
|
234
|
-
-
|
|
235
|
-
-
|
|
223
|
+
- Main plan: `{TICKET_DIR}{CYCLE_LETTER}{FILE_NUMBER}-main-plan.md`, e.g. `.plans/123/A2-main-plan.md`
|
|
224
|
+
- Specialized plans: `{TICKET_DIR}{CYCLE_LETTER}{FILE_NUMBER}-plan-{DESCRIPTOR}.md`, e.g. `.plans/123/A3-plan-api.md`, `.plans/123/A4-plan-ui.md`. The descriptor is lowercase and hyphenated and names the work scope or stack area.
|
|
225
|
+
- Handovers: replace the final `.md` with `.summary.md`, e.g. `.plans/123/A3-plan-api.summary.md`. The main plan handover is written after all specialized plans complete.
|
|
236
226
|
|
|
237
227
|
_Important Note: There will be lint errors in the markdown files you write. Ignore them. NEVER FIX LINT ERRORS (FORMATTING ISSUES) IN THE PLANS._
|
|
238
228
|
|