breakaway 1.2.1-main.27 → 1.2.1-main.29
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 +1 -1
- package/package.json +1 -1
- package/scripts/tasks/cli.js +15 -8
- package/scripts/tasks.mjs +16 -4
- package/src/cli-version.js +2 -2
- package/src/decision.js +1 -1
package/README.md
CHANGED
|
@@ -175,7 +175,7 @@ breakaway publishes releases and never deploys an install. Every install, the ow
|
|
|
175
175
|
- **A stable release** `vX.Y.Z` is the owner's: they run the **Release** workflow with the pre-release to promote. The bundle is that pre-release's, unchanged, and the notes cover everything since the last stable.
|
|
176
176
|
- **The CLI** is on npm as [`breakaway`](https://www.npmjs.com/package/breakaway), staged on npm by the same workflow, with provenance, and live once the owner approves it there with 2FA. npm's trusted publishing can't yet read the OIDC identity of a repository as new as this one ([npm/cli#9969](https://github.com/npm/cli/issues/9969)), so until it can, a token that can stage but never publish by itself stands in, in an environment only `main` can use. Every pre-release goes out under the `next` dist-tag, and a stable release as `latest`. `npx breakaway <command>` is `node scripts/tasks.mjs <command>`.
|
|
177
177
|
- **A major release** is one where an install has to do something by hand: a config or binding change, a Durable Object class or migration, a route or cron. Its notes have a **Manual steps** section and its manifest says `manual: true`, which an install's deploy stops on. A change that needs it sets `manual` and `manualSteps` in `release.json`, and the pull request that ships the steps clears them. When the only step is `wrangler deploy` (a new Durable Object class, a cron, a route), it also sets `wranglerDeploy: true`, and an install whose Deploy may run `wrangler deploy` does it itself (the install template's README says when). Data the Durable Object stores changes forward-only and additively, so an install can always go back one release, except across a new Durable Object class, which Cloudflare doesn't roll back.
|
|
178
|
-
- **The version** is `package.json`'s; the release workflow sets it to the pre-release's before it builds. `GET /api/ping` and `GET /api/health` report it as `release`. An install that deploys a stable passes it as the `BREAKAWAY_VERSION` variable, since the bundle was built as the pre-release.
|
|
178
|
+
- **The version** is `package.json`'s; the release workflow sets it to the pre-release's before it builds. Patches count by themselves; for the next minor or major, **Prepare** on the board's GitHub view starts an agent that opens the pull request setting it. `GET /api/ping` and `GET /api/health` report it as `release`. An install that deploys a stable passes it as the `BREAKAWAY_VERSION` variable, since the bundle was built as the pre-release.
|
|
179
179
|
|
|
180
180
|
</details>
|
|
181
181
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "breakaway",
|
|
3
|
-
"version": "1.2.1-main.
|
|
3
|
+
"version": "1.2.1-main.29",
|
|
4
4
|
"description": "The task board for you and your coding agents: a Cloudflare Worker, its web app, Taskwarrior sync, and the CLI (npx breakaway).",
|
|
5
5
|
"license": "FSL-1.1-Apache-2.0",
|
|
6
6
|
"type": "module",
|
package/scripts/tasks/cli.js
CHANGED
|
@@ -145,16 +145,21 @@ export function forceFields(force, by) {
|
|
|
145
145
|
* `agents new`: the request that makes a task from a prompt and starts an agent on it. It's the checkout's repository
|
|
146
146
|
* unless `--repo` names another. It always says who asks, so the board refuses an agent's name: only the owner starts one.
|
|
147
147
|
* With `decision` (`agents new --decision <ID> ["<note>"]`, BRK-110) the board writes the prompt from that answered
|
|
148
|
-
* decision, in the decision's repository, and the text is the owner's note under it.
|
|
148
|
+
* decision, in the decision's repository, and the text is the owner's note under it. With `next`
|
|
149
|
+
* (`agents new --next minor|major ["<note>"]`, BRK-100) it writes the prompt that sets the repository's next version.
|
|
149
150
|
* @param {string} prompt
|
|
150
|
-
* @param {{ repo?: string | null, force?: boolean, by?: string, decision?: string | null }} [options]
|
|
151
|
+
* @param {{ repo?: string | null, force?: boolean, by?: string, decision?: string | null, next?: string | null }} [options]
|
|
151
152
|
*/
|
|
152
|
-
export function generalAgentRequest(prompt, { repo = null, force = false, by, decision = null } = {}) {
|
|
153
|
+
export function generalAgentRequest(prompt, { repo = null, force = false, by, decision = null, next = null } = {}) {
|
|
153
154
|
const text = String(prompt ?? '').trim();
|
|
154
|
-
if (
|
|
155
|
+
if (decision && next) return { error: 'start one from --decision or --next, not both' };
|
|
156
|
+
if (next && !['minor', 'major'].includes(next))
|
|
157
|
+
return { error: 'patches count by themselves: --next minor or --next major' };
|
|
158
|
+
if (!text && !decision && !next)
|
|
155
159
|
return { error: 'say what the agent should do: npx breakaway agents new "Tidy the docs" [--image <file>]' };
|
|
160
|
+
const board = decision ? { decision } : next ? { next } : null;
|
|
156
161
|
const body = {
|
|
157
|
-
...(
|
|
162
|
+
...(board ? { ...board, ...(text ? { note: text } : {}) } : { prompt: text }),
|
|
158
163
|
...(repo ? { repo } : {}),
|
|
159
164
|
...(force ? { force: true } : {}),
|
|
160
165
|
...(by ? { by } : {}),
|
|
@@ -164,12 +169,14 @@ export function generalAgentRequest(prompt, { repo = null, force = false, by, de
|
|
|
164
169
|
|
|
165
170
|
/**
|
|
166
171
|
* What the CLI says about a general agent's answer: the task and that it started, or why it waits (and whether Force
|
|
167
|
-
* start could skip that), or, from a decision, the open one that already has it.
|
|
172
|
+
* start could skip that), or, from a decision or for the next version (`next`), the open one that already has it.
|
|
168
173
|
* @param {{ task: { wid?: string, short?: string }, run?: { url?: string, agent?: string } | null, waiting?: string | null, forceable?: boolean, already?: string | null }} answer
|
|
174
|
+
* @param {{ next?: string | null }} [options]
|
|
169
175
|
*/
|
|
170
|
-
export function generalAgentSummary({ task, run, waiting, forceable, already }) {
|
|
176
|
+
export function generalAgentSummary({ task, run, waiting, forceable, already }, { next = null } = {}) {
|
|
171
177
|
const id = task.wid ?? task.short;
|
|
172
|
-
if (!run && already)
|
|
178
|
+
if (!run && already)
|
|
179
|
+
return `${id} already ${next ? 'prepares the next version' : 'refines from these answers'}: ${already}.`;
|
|
173
180
|
if (run) return `Started ${run.agent ? `${run.agent} ` : 'an agent '}on ${id}${run.url ? `: ${run.url}` : ''}`;
|
|
174
181
|
return `Saved ${id}, waiting to start: ${waiting ?? 'no room yet'}.${forceable ? ` Start it now past the board's limits: npx breakaway agents start ${id} --force` : ''}`;
|
|
175
182
|
}
|
package/scripts/tasks.mjs
CHANGED
|
@@ -145,6 +145,7 @@ Reading (list, next, claim, and add work in this checkout's repos
|
|
|
145
145
|
agents cloud agents: what's running, what's waiting to start
|
|
146
146
|
agents new "<prompt>" start an agent from a prompt: it makes its own task [--image <file>]… [--repo <slug>] [--force] (owner)
|
|
147
147
|
agents new --decision <ref> ["<note>"] start an agent that brings the work waiting for an answered decision in line with its answers; the board writes its prompt [--force] (owner)
|
|
148
|
+
agents new --next minor|major ["<note>"] start an agent that sets package.json to the next minor or major release; the board writes its prompt [--repo <slug>] [--force] (owner)
|
|
148
149
|
agents start <ref> start a Claude cloud agent on a task [--note <text>] [--force]
|
|
149
150
|
agents refine <ref> start an agent that improves a task, not builds it --note <what to look at or change> [--force]
|
|
150
151
|
agents plan [<plan>] your Claude plan and what it allows; pro, max5, or max20 picks one (owner) and sets the limits to its defaults
|
|
@@ -230,6 +231,8 @@ Working
|
|
|
230
231
|
--pipeline <file.json|none> sets its deploy pipeline ({"workers": {"staging", "production"}, "workflows": {...}, "deployPaths"}) or clears it
|
|
231
232
|
features add <slug> new feature: its tasks join by carrying <slug> as a tag [--title <text>]
|
|
232
233
|
[--brief <text> | --brief-file <path>] [--release <x.y.z>] (agents add one without a release)
|
|
234
|
+
--from <ref> (owner): made from the group <ref> is in on the Dependencies view: its open tasks
|
|
235
|
+
join, and tasks already in another feature stay there
|
|
233
236
|
features modify <slug> change one (owner): --title, --brief, --brief-file, --release <x.y.z|none>, --state open|shipped
|
|
234
237
|
routines add <slug> new routine (owner) --name <text> --prompt <text> | --prompt-file <path> [--done-when <text>] [--horizon now|next|later] [--gap <minutes>] [--daily <n>]
|
|
235
238
|
[--repo <slug>] the repository it runs in (default: the checkout's)
|
|
@@ -780,10 +783,12 @@ const commands = {
|
|
|
780
783
|
}
|
|
781
784
|
if (sub === 'new') {
|
|
782
785
|
const decision = typeof opts.decision === 'string' ? opts.decision : null;
|
|
786
|
+
const next = typeof opts.next === 'string' ? opts.next : null;
|
|
783
787
|
const built = generalAgentRequest(args.slice(1).join(' '), {
|
|
784
788
|
// From a decision, the board runs it in the decision's repository unless --repo says otherwise.
|
|
785
789
|
repo: opts.repo ?? (decision ? null : (await checkoutRepo()).slug),
|
|
786
790
|
decision,
|
|
791
|
+
next,
|
|
787
792
|
force: Boolean(opts.force),
|
|
788
793
|
by: opts.as ?? setting('AGENT'),
|
|
789
794
|
});
|
|
@@ -796,7 +801,7 @@ const commands = {
|
|
|
796
801
|
const image = await upload(ref(answer.task), file);
|
|
797
802
|
if (!opts.json) console.log(`Attached ${image.name} (${Math.ceil(image.size / 1024)} KB).`);
|
|
798
803
|
}
|
|
799
|
-
print(answer, generalAgentSummary);
|
|
804
|
+
print(answer, (d) => generalAgentSummary(d, { next }));
|
|
800
805
|
return;
|
|
801
806
|
}
|
|
802
807
|
if (sub === 'start') {
|
|
@@ -1080,11 +1085,18 @@ const commands = {
|
|
|
1080
1085
|
const by = opts.as ?? setting('AGENT');
|
|
1081
1086
|
if (sub === 'add') {
|
|
1082
1087
|
const slug = need(args[1], 'slug').toLowerCase();
|
|
1083
|
-
const
|
|
1084
|
-
|
|
1088
|
+
const from = opts.from === undefined ? {} : { from: opts.from };
|
|
1089
|
+
const added = await call('POST', 'features', { slug, ...body(), ...from, ...(by ? { by } : {}) });
|
|
1090
|
+
print(added, (d) =>
|
|
1085
1091
|
[
|
|
1086
1092
|
`Added the feature ${d.feature.slug}${d.feature.release ? `, aimed at ${d.feature.release}` : ''}: ${progressLine(d.feature.progress)}.`,
|
|
1087
|
-
|
|
1093
|
+
...(d.joined
|
|
1094
|
+
? [
|
|
1095
|
+
`Joined by its tag: ${d.joined.join(', ')}.`,
|
|
1096
|
+
...d.kept.map((k) => `${k.wid} stays in ${k.feature}: a task is in one feature.`),
|
|
1097
|
+
`Chase it: npx breakaway chase ${d.feature.slug}`,
|
|
1098
|
+
]
|
|
1099
|
+
: [`Tasks join it by the tag: npx breakaway modify <ref> --tag ${d.feature.slug}`]),
|
|
1088
1100
|
].join('\n'),
|
|
1089
1101
|
);
|
|
1090
1102
|
return;
|
package/src/cli-version.js
CHANGED
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* and how to update it. scripts/tasks/version.test.js fails when the copied files change and this doesn't:
|
|
5
5
|
* so it lives in the board's package (CLD-135) and the CLI imports it from here.
|
|
6
6
|
*/
|
|
7
|
-
export const CLI_VERSION =
|
|
8
|
-
export const CLI_FINGERPRINT = '
|
|
7
|
+
export const CLI_VERSION = 60;
|
|
8
|
+
export const CLI_FINGERPRINT = 'faef5017c4405443';
|
package/src/decision.js
CHANGED
|
@@ -241,7 +241,7 @@ export function summarize(questions, answers) {
|
|
|
241
241
|
}
|
|
242
242
|
|
|
243
243
|
/** Tags that aren't a feature's (IDEA-28 section 1): the board's own, horizons, and release tags. */
|
|
244
|
-
const NOT_FEATURES = new Set(['agent', 'owner', 'decide', 'idea', 'general']);
|
|
244
|
+
const NOT_FEATURES = new Set(['agent', 'owner', 'decide', 'idea', 'general', 'version']);
|
|
245
245
|
export const featureTags = (tags) =>
|
|
246
246
|
(tags ?? []).filter((t) => !NOT_FEATURES.has(t) && !t.startsWith('horizon-') && !/^v\d/u.test(t));
|
|
247
247
|
|