toolroll 0.9.53 → 0.9.55
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/CHANGELOG.md +17 -0
- package/README.md +5 -4
- package/dist/agent-onboard.js +4 -1
- package/dist/approval-rules-ui.d.ts +3 -2
- package/dist/approval-rules-ui.js +15 -20
- package/dist/assignment-ui.d.ts +3 -2
- package/dist/assignment-ui.js +4 -11
- package/dist/backup-ui.d.ts +2 -1
- package/dist/backup-ui.js +16 -27
- package/dist/brand-mark.d.ts +3 -2
- package/dist/brand-mark.js +4 -4
- package/dist/browser/workspace.css +1 -1
- package/dist/browser/workspace.js +25 -25
- package/dist/browser-shell.d.ts +2 -1
- package/dist/browser-shell.js +9 -9
- package/dist/browser-workspace.d.ts +2 -3
- package/dist/browser-workspace.js +0 -3
- package/dist/chat-ask.js +8 -8
- package/dist/chat-core.d.ts +171 -0
- package/dist/chat-core.js +288 -0
- package/dist/chat-decide.d.ts +10 -8
- package/dist/chat-decide.js +26 -21
- package/dist/chat-delivery-state.d.ts +51 -75
- package/dist/chat-delivery-state.js +140 -170
- package/dist/chat-delivery.d.ts +21 -2
- package/dist/chat-delivery.js +313 -194
- package/dist/chat-flow.d.ts +29 -1
- package/dist/chat-flow.js +24 -50
- package/dist/chat-messages.d.ts +319 -0
- package/dist/chat-messages.js +841 -0
- package/dist/chat-migration.d.ts +30 -0
- package/dist/chat-migration.js +802 -0
- package/dist/chat-polish.d.ts +5 -4
- package/dist/chat-polish.js +9 -10
- package/dist/chat-quiet.d.ts +3 -0
- package/dist/chat-quiet.js +5 -0
- package/dist/check-levels-ui.d.ts +2 -1
- package/dist/check-levels-ui.js +26 -53
- package/dist/cli.d.ts +3 -1
- package/dist/cli.js +9 -3
- package/dist/coding-shipping-ui.d.ts +2 -1
- package/dist/coding-shipping-ui.js +6 -6
- package/dist/coding-ui.d.ts +3 -1
- package/dist/coding-ui.js +30 -29
- package/dist/contracts/chat-content.d.ts +71 -2
- package/dist/contracts/chat-content.js +22 -3
- package/dist/contracts/chat-tables.d.ts +11 -4
- package/dist/contracts/chat-tables.js +165 -87
- package/dist/contracts/cli.d.ts +1 -3
- package/dist/contracts/console-api.d.ts +1 -1
- package/dist/contracts/console-api.js +6 -5
- package/dist/contracts/discord-callback.js +2 -1
- package/dist/contracts/health.d.ts +1 -3
- package/dist/contracts/slack-callback.js +3 -2
- package/dist/contracts/store-json.d.ts +1 -5
- package/dist/contracts/store-json.js +1 -4
- package/dist/contracts/teams-callback.js +2 -1
- package/dist/control-ui.d.ts +5 -4
- package/dist/control-ui.js +9 -34
- package/dist/credentials-ui.d.ts +5 -4
- package/dist/credentials-ui.js +23 -24
- package/dist/demo-chat.d.ts +3 -3
- package/dist/demo-chat.js +29 -76
- package/dist/discord-chat.js +19 -38
- package/dist/discord-settings.d.ts +3 -2
- package/dist/discord-settings.js +21 -55
- package/dist/discord.js +4 -14
- package/dist/envelope.js +10 -0
- package/dist/evidence-pack.d.ts +2 -1
- package/dist/evidence-pack.js +45 -49
- package/dist/export-ui.d.ts +7 -2
- package/dist/export-ui.js +4 -10
- package/dist/export.js +4 -4
- package/dist/flow-gallery-ui.d.ts +4 -3
- package/dist/flow-gallery-ui.js +28 -43
- package/dist/flow-starters-ui.d.ts +2 -1
- package/dist/flow-starters-ui.js +12 -15
- package/dist/flow-triggers.d.ts +1 -0
- package/dist/flow-triggers.js +16 -14
- package/dist/flows-ui.d.ts +4 -3
- package/dist/flows-ui.js +19 -30
- package/dist/flows.js +2 -1
- package/dist/guides.js +108 -3
- package/dist/html.d.ts +76 -0
- package/dist/html.js +173 -0
- package/dist/integrations-ui.d.ts +2 -1
- package/dist/integrations-ui.js +19 -23
- package/dist/kits-ui.d.ts +5 -4
- package/dist/kits-ui.js +18 -20
- package/dist/knowledge-ui.d.ts +6 -5
- package/dist/knowledge-ui.js +26 -25
- package/dist/lead-context.d.ts +11 -1
- package/dist/lead-context.js +6 -8
- package/dist/ledger-view.d.ts +2 -1
- package/dist/ledger-view.js +27 -29
- package/dist/limits-ui.d.ts +2 -1
- package/dist/limits-ui.js +7 -7
- package/dist/live-bus.d.ts +50 -8
- package/dist/live-bus.js +133 -50
- package/dist/mate-tools.js +3 -2
- package/dist/mcp-oauth.js +35 -36
- package/dist/models-ui.d.ts +2 -1
- package/dist/models-ui.js +25 -35
- package/dist/modes.d.ts +13 -1
- package/dist/modes.js +17 -1
- package/dist/monitoring-ui.d.ts +4 -3
- package/dist/monitoring-ui.js +13 -26
- package/dist/notification-rows.d.ts +30 -0
- package/dist/notification-rows.js +102 -0
- package/dist/openrouter-models.d.ts +2 -1
- package/dist/openrouter-models.js +5 -9
- package/dist/operate.js +16 -9
- package/dist/people-audit-ui.d.ts +2 -1
- package/dist/people-audit-ui.js +13 -13
- package/dist/plane-review.js +5 -11
- package/dist/policy-ui.d.ts +3 -2
- package/dist/policy-ui.js +17 -23
- package/dist/project-delete-ui.d.ts +4 -3
- package/dist/project-delete-ui.js +15 -27
- package/dist/project-delete.js +21 -26
- package/dist/pull-request-ui.d.ts +2 -1
- package/dist/pull-request-ui.js +17 -32
- package/dist/recipe-ui.d.ts +8 -7
- package/dist/recipe-ui.js +39 -32
- package/dist/release-adapters.d.ts +60 -0
- package/dist/release-adapters.js +435 -0
- package/dist/release-cli.d.ts +24 -0
- package/dist/release-cli.js +181 -0
- package/dist/release-gate.d.ts +80 -0
- package/dist/release-gate.js +150 -0
- package/dist/release-links.d.ts +29 -0
- package/dist/release-links.js +102 -0
- package/dist/release.d.ts +331 -0
- package/dist/release.js +550 -0
- package/dist/reply-shape.d.ts +2 -1
- package/dist/reply-shape.js +5 -5
- package/dist/repository-context-ui.d.ts +2 -1
- package/dist/repository-context-ui.js +2 -7
- package/dist/request-budget-ui.d.ts +2 -1
- package/dist/request-budget-ui.js +16 -16
- package/dist/result-review.d.ts +2 -3
- package/dist/result-review.js +3 -9
- package/dist/result-shots.js +2 -2
- package/dist/retention-ui.d.ts +7 -1
- package/dist/retention-ui.js +7 -11
- package/dist/retention.js +1 -1
- package/dist/serve.d.ts +11 -2
- package/dist/serve.js +69 -58
- package/dist/server/chat.d.ts +3 -6
- package/dist/server/chat.js +969 -1006
- package/dist/server/chrome.d.ts +291 -0
- package/dist/server/chrome.js +747 -0
- package/dist/server/console.css +2819 -0
- package/dist/server/flows.d.ts +2 -6
- package/dist/server/flows.js +840 -766
- package/dist/server/guards.d.ts +1 -1
- package/dist/server/guards.js +5 -2
- package/dist/server/handler-context.d.ts +1 -1
- package/dist/server/handler-context.js +1 -1
- package/dist/server/handler-registry.d.ts +8 -6
- package/dist/server/handler-registry.js +14 -2
- package/dist/server/http.d.ts +274 -0
- package/dist/server/http.js +239 -0
- package/dist/server/live.d.ts +34 -0
- package/dist/server/live.js +309 -0
- package/dist/server/pages.d.ts +2 -6
- package/dist/server/pages.js +808 -789
- package/dist/server/people-tokens.d.ts +1 -6
- package/dist/server/people-tokens.js +580 -572
- package/dist/server/remote.d.ts +4 -7
- package/dist/server/remote.js +37 -70
- package/dist/server/render-chat.d.ts +402 -0
- package/dist/server/render-chat.js +927 -0
- package/dist/server/render-pages.d.ts +535 -0
- package/dist/server/render-pages.js +1277 -0
- package/dist/server/render-people.d.ts +32 -0
- package/dist/server/render-people.js +121 -0
- package/dist/server/render-results.d.ts +744 -0
- package/dist/server/render-results.js +2237 -0
- package/dist/server/render-settings.d.ts +147 -0
- package/dist/server/render-settings.js +577 -0
- package/dist/server/render-tasks.d.ts +632 -0
- package/dist/server/render-tasks.js +2345 -0
- package/dist/server/request-context.d.ts +46 -0
- package/dist/server/request-context.js +17 -0
- package/dist/server/route-table.d.ts +25 -3
- package/dist/server/route-table.js +163 -75
- package/dist/server/runtime.d.ts +15 -7
- package/dist/server/runtime.js +7 -1
- package/dist/server/session.d.ts +138 -0
- package/dist/server/session.js +94 -0
- package/dist/server/settings.d.ts +1 -5
- package/dist/server/settings.js +2182 -2117
- package/dist/server/task-views.d.ts +11 -4
- package/dist/server/task-views.js +26 -22
- package/dist/server/tasks.d.ts +9 -9
- package/dist/server/tasks.js +1486 -1418
- package/dist/server-telemetry.d.ts +4 -3
- package/dist/server-telemetry.js +4 -8
- package/dist/skills-ui.d.ts +4 -3
- package/dist/skills-ui.js +14 -17
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +2 -1
- package/dist/slack-api.d.ts +5 -1
- package/dist/slack-api.js +2 -2
- package/dist/slack-chat.d.ts +9 -4
- package/dist/slack-chat.js +29 -52
- package/dist/slack-settings.d.ts +3 -2
- package/dist/slack-settings.js +23 -57
- package/dist/slack.js +6 -16
- package/dist/spend-ui.d.ts +2 -1
- package/dist/spend-ui.js +9 -32
- package/dist/sso-ui.d.ts +3 -2
- package/dist/sso-ui.js +26 -27
- package/dist/storage-ui.d.ts +2 -1
- package/dist/storage-ui.js +14 -33
- package/dist/store.d.ts +97 -364
- package/dist/store.js +207 -1531
- package/dist/surface.js +14 -3
- package/dist/task-composer.d.ts +2 -1
- package/dist/task-composer.js +7 -7
- package/dist/task-status.d.ts +4 -3
- package/dist/task-status.js +15 -16
- package/dist/team-http.d.ts +5 -9
- package/dist/team-http.js +5 -63
- package/dist/team-ui.d.ts +2 -1
- package/dist/team-ui.js +2 -5
- package/dist/teammate-question.js +12 -12
- package/dist/teammates-ui.d.ts +5 -4
- package/dist/teammates-ui.js +61 -90
- package/dist/teams-chat.js +12 -9
- package/dist/teams-settings.d.ts +3 -2
- package/dist/teams-settings.js +22 -33
- package/dist/teams.js +4 -5
- package/dist/telegram-flow.js +5 -5
- package/dist/telegram-settings.d.ts +3 -2
- package/dist/telegram-settings.js +14 -25
- package/dist/telegram.js +4 -4
- package/dist/toolroll-update-ui.d.ts +3 -2
- package/dist/toolroll-update-ui.js +35 -39
- package/dist/toolroll-update.d.ts +10 -0
- package/dist/toolroll-update.js +50 -3
- package/dist/tools-ui.d.ts +5 -2
- package/dist/tools-ui.js +31 -31
- package/dist/when-html.d.ts +11 -3
- package/dist/when-html.js +5 -6
- package/dist/workspace-revision.js +3 -1
- package/dist/workspace-ui.d.ts +4 -2
- package/dist/workspace-ui.js +10 -10
- package/package.json +1 -1
- package/dist/server/shared.d.ts +0 -3151
- package/dist/server/shared.js +0 -12001
- package/dist/slack-state.d.ts +0 -13
- package/dist/slack-state.js +0 -10
package/dist/recipe-ui.d.ts
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { type Recipe, type RecipeDocument, type WorkflowPreview } from "./recipes.js";
|
|
2
|
+
import { type Html } from "./html.js";
|
|
2
3
|
export declare function recipeFromForm(body: URLSearchParams): RecipeDocument;
|
|
3
|
-
export declare function recipeLibraryHtml(starters: Recipe[], saved: Recipe[], project: string | null,
|
|
4
|
+
export declare function recipeLibraryHtml(starters: Recipe[], saved: Recipe[], project: string | null, revision: number, recent: {
|
|
4
5
|
name: string;
|
|
5
6
|
href: string;
|
|
6
7
|
state: string;
|
|
7
|
-
}[]):
|
|
8
|
-
export declare function recipeEditorHtml(recipe: Recipe, repo: string,
|
|
9
|
-
export declare function workflowPreviewHtml(preview: WorkflowPreview,
|
|
8
|
+
}[]): Html;
|
|
9
|
+
export declare function recipeEditorHtml(recipe: Recipe, repo: string, revision: number, problem?: string | null, values?: URLSearchParams, creator?: boolean): Html;
|
|
10
|
+
export declare function workflowPreviewHtml(preview: WorkflowPreview, revision: number, now: Date, readiness: {
|
|
10
11
|
title: string;
|
|
11
12
|
detail: string;
|
|
12
13
|
href?: string;
|
|
13
|
-
}[], auto: boolean):
|
|
14
|
-
export declare function recipeDefinitionPreviewHtml(preview: WorkflowPreview,
|
|
15
|
-
export declare function recipeRunHtml(recipe: Recipe, repo: string,
|
|
14
|
+
}[], auto: boolean): Html;
|
|
15
|
+
export declare function recipeDefinitionPreviewHtml(preview: WorkflowPreview, revision: number): Html;
|
|
16
|
+
export declare function recipeRunHtml(recipe: Recipe, repo: string, revision: number, problem?: string | null, values?: URLSearchParams, saved?: boolean): Html;
|
|
16
17
|
export declare function recipeAnswersFromForm(body: URLSearchParams): Map<string, string>;
|
|
17
18
|
export declare function recipeScript(): string;
|
|
18
19
|
export declare const RECIPE_CSS = "\n.recipe-heading { margin: .5rem 0 1.75rem; max-width: 46rem; }\n.recipe-heading h1 { font-size: clamp(1.65rem,3vw,2.5rem); letter-spacing:-.035em; margin:.35rem 0 .6rem; }\n.recipe-kicker { font-size:.7rem; text-transform:uppercase; letter-spacing:.12em; color:var(--muted-foreground); }\n.recipe-grid { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:.8rem; margin:1rem 0 2rem; }\n.recipe-card { border:1px solid var(--border); border-radius:var(--radius); padding:1.1rem; background:var(--card); display:flex; flex-direction:column; gap:.5rem; }\n.recipe-card h3 { font-size:1.05rem; margin:0; letter-spacing:-.015em; }\n.recipe-card p { color:var(--muted-foreground); margin:.2rem 0; font-size:.85rem; line-height:1.5; }\n.recipe-card-link { margin-top:auto; padding-top:.75rem; display:flex; justify-content:space-between; }\n.recipe-editor { max-width:52rem; }.recipe-editor h2 { margin-top:0; }\n.recipe-criterion { border:1px solid var(--border); border-radius:calc(var(--radius) - 3px); padding:.8rem; margin:.8rem 0; }\n.recipe-evidence { display:flex; flex-wrap:wrap; gap:.5rem 1rem; }.recipe-evidence label { display:flex; align-items:center; gap:.4rem; font-size:.8rem; }.recipe-evidence input { width:auto; margin:0; }\n.recipe-options { display:grid; grid-template-columns:1fr 1fr; gap:1rem; }\n.recipe-preview-grid { display:grid; grid-template-columns:minmax(0,1.7fr) minmax(16rem,1fr); gap:1rem; }\n.recipe-steps { padding-left:1.4rem; }.recipe-steps li { padding:.4rem 0 .6rem .3rem; }.recipe-steps p { margin:.3rem 0 0; font-size:.85rem; color:var(--muted-foreground); }\n.recipe-launch { display:grid; grid-template-columns:1fr 1fr; gap:1rem; }.recipe-launch form { margin:0 0 .6rem; }\n.recipe-history a { display:flex; justify-content:space-between; gap:1rem; padding:.6rem 0; border-bottom:1px solid var(--border); }.recipe-history span { color:var(--muted-foreground); }\n.recipe-error { border-color:var(--destructive); }\n.recipe-card[hidden] { display:none; }.recipe-search { max-width:28rem; }.recipe-question { border:1px solid var(--border); border-radius:calc(var(--radius) - 3px); margin:1rem 0; padding:.8rem; min-width:0; }.recipe-run { max-width:42rem; }.recipe-run button { margin-top:1rem; }\n@media(max-width:1000px){.recipe-grid { grid-template-columns:repeat(2,minmax(0,1fr)); }}\n@media(max-width:760px){.recipe-grid,.recipe-options,.recipe-preview-grid,.recipe-launch { grid-template-columns:1fr; }.recipe-heading { margin-bottom:1rem; }.recipe-history a { flex-direction:column; gap:.2rem; }}\n";
|
package/dist/recipe-ui.js
CHANGED
|
@@ -2,8 +2,8 @@ import { TASK_TEXT_LIMITS } from "./task-text.js";
|
|
|
2
2
|
import { composerSchedule, scheduleEditorHtml, scheduleEditorScript } from "./task-composer.js";
|
|
3
3
|
import { parseRecipe, workflowSteps, recipeScheduleWords, RecipeError, RECIPE_INPUT_LIMIT } from "./recipes.js";
|
|
4
4
|
import { ACCEPTANCE_LIMITS } from "./scope.js";
|
|
5
|
-
|
|
6
|
-
const hidden = (name, value) => `<input type="hidden" name="${
|
|
5
|
+
import { html, joinHtml, postForm, replaceMarkup } from "./html.js";
|
|
6
|
+
const hidden = (name, value) => html `<input type="hidden" name="${name}" value="${value}">`;
|
|
7
7
|
const evidence = [["check", "Passing tests or commands"], ["changed-path", "Changed files"], ["screenshot", "Screenshot"], ["manual-review", "Reviewer assessment"]];
|
|
8
8
|
export function recipeFromForm(body) {
|
|
9
9
|
for (const name of ["name", "description", "goal", "not", "touches", "planning", "deliverable", "cadence", "repeat", "time", "timezone", "weekday", "interval", "interval-unit", "ceiling", "source", "sourceRevision", "projectRevision", "repo", "preview", "purpose", "sourceFormat"]) {
|
|
@@ -53,63 +53,70 @@ export function recipeFromForm(body) {
|
|
|
53
53
|
return parseRecipe({ format: "standing-orders-recipe", version: inputs.length ? 2 : 1, ...(inputs.length ? { inputs } : {}), name: body.get("name") ?? "", description: body.get("description") ?? "", goal: body.get("goal") ?? "", outOfScope: body.get("not") || null,
|
|
54
54
|
touches: (body.get("touches") ?? "").split(/[\n,]/).map(one => one.trim()).filter(Boolean), acceptance, planning: body.get("planning") ?? "auto", deliverable: body.get("deliverable") ?? "branch", schedule: schedule.schedule, costCeilingUsd: ceiling === "" ? null : Number(ceiling) });
|
|
55
55
|
}
|
|
56
|
-
export function recipeLibraryHtml(starters, saved, project,
|
|
57
|
-
const cards = (recipes, reusable = false) => `<div class="recipe-grid"${reusable
|
|
58
|
-
const savedSection = `<h2>Your project’s recipes</h2>${saved.length >= 100
|
|
59
|
-
return `<div class="recipe-heading"><p class="recipe-kicker">Workflows</p><h1>Good work, on repeat.</h1><p class="hint">Save the work you do often. Answer what changes this time. Kick it off.</p><p><a href="/recipes/new" class="new-task">Create a recipe</a> <a href="/flows">Manage scheduled work →</a></p></div>`
|
|
60
|
-
(project === null ? `<div class="card"><strong>Choose a project to get started.</strong><p>Browse recipes now; <a href="/projects">open a project</a> to customize, save, or run one.</p></div>` : "") +
|
|
61
|
-
(saved.length ? savedSection : "") + `<h2>Start here</h2>${cards(starters)}` + (saved.length ? "" : savedSection) +
|
|
62
|
-
(recent.length ? `<h2>Recent workflows</h2><div class="card recipe-history">${recent.map(one => `<a href="${e(one.href)}"><strong>${e(one.name)}</strong><span>${e(one.state)} →</span></a>`).join("")}</div>` : "") +
|
|
63
|
-
(project === null ? "" : `<details class="card"><summary>Import a shared recipe</summary><p class="hint">Paste exported recipe JSON. You’ll review it in this project before creating any work.</p><form method="post" action="/recipes/import">${hidden("csrf", csrf)}${hidden("repo", project)}${hidden("projectRevision", String(revision))}<label>Recipe JSON<textarea name="document" rows="7" required maxlength="32768" spellcheck="false"></textarea></label><button type="submit">Review imported recipe</button></form></details>`);
|
|
56
|
+
export function recipeLibraryHtml(starters, saved, project, revision, recent) {
|
|
57
|
+
const cards = (recipes, reusable = false) => html `<div class="recipe-grid"${reusable && html ` data-saved-recipes`}>${recipes.map(recipe => html `<article class="recipe-card" data-recipe-card data-recipe-search="${recipe.document.name + " " + recipe.document.description}"><p class="recipe-kicker">${recipe.document.deliverable === "report" ? "Report" : recipe.document.schedule === null ? "One-time work" : "Recurring care"}${recipe.document.version === 2 ? ` · ${recipe.document.inputs.length} question${recipe.document.inputs.length === 1 ? "" : "s"}` : ""}</p><h3>${recipe.document.name}</h3><p>${recipe.document.description}</p><a class="recipe-card-link" href="/recipes/${reusable ? "run" : "start"}?recipe=${recipe.id}&revision=${recipe.revision}">${reusable ? "Use recipe" : "Customize recipe"} <span aria-hidden="true">→</span></a>${reusable && html `<a class="meta" href="/recipes/start?recipe=${recipe.id}&revision=${recipe.revision}">Edit a copy</a>`}</article>`)}</div>`;
|
|
58
|
+
const savedSection = html `<h2>Your project’s recipes</h2>${saved.length >= 100 && html `<p class="meta">Showing 100 recipes, with recently used recipes first.</p>`}${saved.length ? html `<p class="hint">Your usual work, ready to go. Recently used recipes come first.</p><label class="recipe-search">Find a recipe<input type="search" data-recipe-search-input placeholder="Search your recipes…"></label>${cards(saved, true)}<p data-recipe-empty hidden>No recipes match. Try another search.</p>` : html `<p class="hint">Save work you do often. Teammates with project access can use the same recipe.</p>`}`;
|
|
59
|
+
return html `<div class="recipe-heading"><p class="recipe-kicker">Workflows</p><h1>Good work, on repeat.</h1><p class="hint">Save the work you do often. Answer what changes this time. Kick it off.</p><p><a href="/recipes/new" class="new-task">Create a recipe</a> <a href="/flows">Manage scheduled work →</a></p></div>${project === null && html `<div class="card"><strong>Choose a project to get started.</strong><p>Browse recipes now; <a href="/projects">open a project</a> to customize, save, or run one.</p></div>`}${saved.length > 0 && savedSection}<h2>Start here</h2>${cards(starters)}${saved.length === 0 && savedSection}${recent.length > 0 && html `<h2>Recent workflows</h2><div class="card recipe-history">${recent.map(one => html `<a href="${one.href}"><strong>${one.name}</strong><span>${one.state} →</span></a>`)}</div>`}${project !== null && html `<details class="card"><summary>Import a shared recipe</summary><p class="hint">Paste exported recipe JSON. You’ll review it in this project before creating any work.</p>${postForm("/recipes/import", html `<label>Recipe JSON<textarea name="document" rows="7" required maxlength="32768" spellcheck="false"></textarea></label><button type="submit">Review imported recipe</button>`, { projectRevision: String(revision), hidden: { repo: project } })}</details>`}`;
|
|
64
60
|
}
|
|
65
61
|
function criterionHtml(index, criterion, values) {
|
|
66
62
|
const prefix = `criterion-${index}-`;
|
|
67
63
|
const value = (name, fallback) => values?.get(prefix + name) ?? fallback;
|
|
68
64
|
const selected = values ? values.getAll(prefix + "evidence") : criterion?.evidence ?? ["check"];
|
|
69
|
-
return `<fieldset class="recipe-criterion"><legend>${criterion || index === 0 ? `Success check ${index + 1}` : "Additional success check (optional)"}</legend>${hidden(prefix + "id", value("id", criterion?.id ?? `c${index + 1}`))}<label>What should be true?<textarea name="${prefix}statement" rows="2" maxlength="300">${
|
|
65
|
+
return html `<fieldset class="recipe-criterion"><legend>${criterion || index === 0 ? `Success check ${index + 1}` : "Additional success check (optional)"}</legend>${hidden(prefix + "id", value("id", criterion?.id ?? `c${index + 1}`))}<label>What should be true?<textarea name="${prefix}statement" rows="2" maxlength="300">${value("statement", criterion?.statement ?? "")}</textarea></label><div class="recipe-evidence">${evidence.map(([id, label]) => html `<label><input type="checkbox" name="${prefix}evidence" value="${id}"${selected.includes(id) && html ` checked`}>${label}</label>`)}</div><label>How to check it <span class="meta">optional; command or review instructions</span><input type="text" name="${prefix}how" value="${value("how", criterion?.how ?? "")}" maxlength="500"></label></fieldset>`;
|
|
70
66
|
}
|
|
71
|
-
|
|
67
|
+
/** The blank success check the page's script copies, its numbers left for the script to fill in. */
|
|
68
|
+
const criterionTemplate = () => replaceMarkup(criterionHtml(11), /criterion-11-|value="c12"/g, match => match === "criterion-11-" ? html `criterion-INDEX-` : html `value="cNEXT"`);
|
|
69
|
+
export function recipeEditorHtml(recipe, repo, revision, problem = null, values, creator = false) {
|
|
72
70
|
const d = recipe.document;
|
|
73
71
|
const value = (name, fallback) => values?.get(name) ?? fallback;
|
|
74
72
|
const cadence = value("cadence", d.schedule === null ? "once" : "repeat");
|
|
75
73
|
const planning = value("planning", d.planning), deliverable = value("deliverable", d.deliverable);
|
|
76
74
|
const count = values ? Math.min(ACCEPTANCE_LIMITS.criteria, Math.max(d.acceptance.length + 1, ...[...values.keys()].map(key => Number(/^criterion-(\d+)-statement$/.exec(key)?.[1] ?? -1) + 1))) : Math.min(ACCEPTANCE_LIMITS.criteria, d.acceptance.length + 1);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
`<section class="card"><h2>What does success look like?</h2><p class="hint">Give each outcome the evidence you want to see. The workflow checks these before calling the work done.</p><div data-recipe-criteria>${Array.from({ length: count }, (_, i) => criterionHtml(i, d.acceptance[i], values)).join("")}</div><button type="button" data-add-criterion hidden>Add another success check</button><template data-criterion-template>${criterionHtml(11).replaceAll("criterion-11-", "criterion-INDEX-").replaceAll('value="c12"', 'value="cNEXT"')}</template></section>` +
|
|
83
|
-
`<section class="card"><h2>How it should run</h2><div class="recipe-options"><label>Result<select name="deliverable"><option value="branch"${deliverable === "branch" ? " selected" : ""}>Code change with evidence</option><option value="report"${deliverable === "report" ? " selected" : ""}>Report without code changes</option></select></label><label>Planning<select name="planning">${[["auto", "Plan when helpful"], ["required", "Always plan first"], ["skip", "Use this scope directly"]].map(([id, label]) => `<option value="${id}"${planning === id ? " selected" : ""}>${label}</option>`).join("")}</select></label></div><p class="meta">Report work investigates directly. Repeating work files the same scope each time; plan-first workflows run once.</p><label>Frequency<select name="cadence" data-recipe-cadence><option value="once"${cadence === "once" ? " selected" : ""}>Run once</option><option value="repeat"${cadence === "repeat" ? " selected" : ""}>Repeat on a schedule</option></select></label><div data-recipe-recurring>${scheduleEditorHtml(d.schedule, values)}<label>Weekly spending limit <span class="meta">optional, USD</span><input type="number" name="ceiling" min="0.01" step="0.01" value="${e(value("ceiling", d.costCeilingUsd === null ? "" : String(d.costCeilingUsd)))}"></label><p class="meta">One at a time. A spending limit needs an agent that reports dollar costs.</p></div></section>` +
|
|
84
|
-
`<div class="sticky-actions"><button type="submit" name="purpose" value="${creator ? "recipe" : "workflow"}">${creator ? "Preview recipe →" : "Preview workflow →"}</button>${creator ? "" : `<button type="submit" name="purpose" value="recipe" class="quiet">Preview recipe to save</button>`}<p class="meta">${creator ? "Save the instructions once. You can use the recipe whenever this work comes up." : "Previewing runs no agents. You’ll see the approval and scheduling steps next."}</p></div></form>`;
|
|
75
|
+
const outcome = html `<section class="card"><h2>The outcome</h2><label>${creator ? "Recipe name" : "Workflow name"}<input type="text" name="name" value="${value("name", d.name)}" maxlength="200" required></label><label>Short description<input type="text" name="description" value="${value("description", d.description)}" maxlength="400"></label><label>What should the agent do?<textarea name="goal" rows="5" maxlength="${TASK_TEXT_LIMITS.text}" required>${value("goal", d.goal)}</textarea></label><label>What should it leave alone?<textarea name="not" rows="3" maxlength="${TASK_TEXT_LIMITS.text}">${value("not", d.outOfScope ?? "")}</textarea></label><label>Allowed files or folders <span class="meta">optional; one per line</span><textarea name="touches" rows="2" placeholder="src/ tests/">${value("touches", d.touches.join("\n"))}</textarea></label><p class="meta">Blank allows work across this project. Add paths to keep the workflow focused.</p></section>`;
|
|
76
|
+
const success = html `<section class="card"><h2>What does success look like?</h2><p class="hint">Give each outcome the evidence you want to see. The workflow checks these before calling the work done.</p><div data-recipe-criteria>${Array.from({ length: count }, (_, i) => criterionHtml(i, d.acceptance[i], values))}</div><button type="button" data-add-criterion hidden>Add another success check</button><template data-criterion-template>${criterionTemplate()}</template></section>`;
|
|
77
|
+
const running = html `<section class="card"><h2>How it should run</h2><div class="recipe-options"><label>Result<select name="deliverable"><option value="branch"${deliverable === "branch" && html ` selected`}>Code change with evidence</option><option value="report"${deliverable === "report" && html ` selected`}>Report without code changes</option></select></label><label>Planning<select name="planning">${[["auto", "Plan when helpful"], ["required", "Always plan first"], ["skip", "Use this scope directly"]].map(([id, label]) => html `<option value="${id}"${planning === id && html ` selected`}>${label}</option>`)}</select></label></div><p class="meta">Report work investigates directly. Repeating work files the same scope each time; plan-first workflows run once.</p><label>Frequency<select name="cadence" data-recipe-cadence><option value="once"${cadence === "once" && html ` selected`}>Run once</option><option value="repeat"${cadence === "repeat" && html ` selected`}>Repeat on a schedule</option></select></label><div data-recipe-recurring>${scheduleEditorHtml(d.schedule, values)}<label>Weekly spending limit <span class="meta">optional, USD</span><input type="number" name="ceiling" min="0.01" step="0.01" value="${value("ceiling", d.costCeilingUsd === null ? "" : String(d.costCeilingUsd))}"></label><p class="meta">One instance at a time. A spending limit requires an agent that reports dollar costs; approval checks this.</p></div></section>`;
|
|
78
|
+
const actions = html `<div class="sticky-actions"><button type="submit" name="purpose" value="${creator ? "recipe" : "workflow"}">${creator ? "Preview recipe →" : "Preview workflow →"}</button>${!creator && html `<button type="submit" name="purpose" value="recipe" class="quiet">Preview recipe to save</button>`}<p class="meta">${creator ? "Save the instructions once. You can use the recipe whenever this work comes up." : "Previewing runs no agents. You’ll see the approval and scheduling steps next."}</p></div>`;
|
|
79
|
+
return html `<a href="/recipes" class="meta">← All recipes</a><div class="recipe-heading"><p class="recipe-kicker">${creator ? "1 · Describe → 2 · Preview → 3 · Save" : "1 · Choose → 2 · Customize → 3 · Preview"}</p><h1>${creator ? "Create a reusable recipe" : "Make this workflow yours"}</h1><p class="hint">${repo.split(/[\\/]/).pop() || repo} · Choose the outcome, boundaries, and proof you want back.</p></div>${problem !== null && html `<p role="alert" class="card recipe-error">${problem}</p>`}${postForm("/recipes/preview", html `${outcome}${recipeQuestionsHtml(d, values)}${success}${running}${actions}`, { attrs: { class: "recipe-editor" }, projectRevision: String(revision), hidden: { repo, source: recipe.id, sourceRevision: String(recipe.revision), sourceFormat: value("sourceFormat", String(d.version)) } })}`;
|
|
85
80
|
}
|
|
86
|
-
|
|
81
|
+
/** What a success check's evidence is called, for a reader. */
|
|
82
|
+
const evidenceWords = (kinds) => joinHtml(kinds.map(kind => evidence.find(([id]) => id === kind)?.[1] ?? kind), " · ");
|
|
83
|
+
export function workflowPreviewHtml(preview, revision, now, readiness, auto) {
|
|
87
84
|
const d = preview.document;
|
|
88
|
-
const common =
|
|
85
|
+
const common = { projectRevision: String(revision), hidden: { repo: preview.repo, preview: preview.token } };
|
|
89
86
|
const target = preview.taskId === null ? preview.flowId === null ? null : `/flows/${preview.flowId}` : `/t/${encodeURIComponent(preview.taskId)}`;
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
87
|
+
const agreed = html `<section class="card"><h2>The agreed work</h2><p class="recap">${d.goal}</p><h3>Leave alone</h3><p class="recap">${d.outOfScope ?? "No additional exclusions."}</p><h3>Allowed paths</h3><p>${d.touches.length ? joinHtml(d.touches, ", ") : "This project"}</p><h3>Success checks</h3><ul>${d.acceptance.map(c => html `<li><strong>${c.statement}</strong><p class="meta">${evidenceWords(c.evidence)}${c.how ? ` · ${c.how}` : ""}</p></li>`)}</ul></section>`;
|
|
88
|
+
const before = html `<aside><section class="card"><h2>Before it starts</h2>${readiness.map(one => html `<p><strong>${one.title}</strong><br><span class="meta">${one.detail}${one.href && html ` <a href="${one.href}">Open settings →</a>`}</span></p>`)}<p class="meta">These checks describe current setup. Agent availability and approval are checked again when work starts.</p></section><section class="card"><h2>Schedule & control</h2><p>${recipeScheduleWords(d, now)}</p><p>${d.costCeilingUsd === null ? "Uses existing project and agent budget controls." : `Up to $${d.costCeilingUsd.toFixed(2)} per rolling seven days.`}</p><p>${d.schedule !== null ? "Approve the routine once on the next screen. Pause it any time from scheduled work." : auto ? "Your signed project policy will be evaluated when you create this workflow." : "Review and approve on the task page. You can stop or resume there."}</p></section></aside>`;
|
|
89
|
+
const launch = html `<div class="card recipe-launch"><div>${target ? html `<a class="new-task" href="${target}">Open created workflow →</a>` : postForm("/recipes/launch", html `<button type="submit">${d.schedule !== null ? "Create scheduled workflow" : auto ? "Create workflow" : "Create task for approval"}</button>`, common)}<p class="meta">${d.schedule !== null ? "Nothing repeats until you turn the schedule on." : "A matching signed policy may start work automatically."} Creating this workflow twice returns the same work.</p></div><div>${preview.savedId ? html `<a href="/recipes/start?recipe=${preview.savedId}&revision=${preview.savedRevision}">Recipe saved · reuse it →</a>` : postForm("/recipes/save", html `<button type="submit" class="quiet">Save as a project recipe</button>`, common)}<a href="/recipes/export?preview=${preview.token}">Export recipe JSON</a><p class="meta">Save or export without running anything. Sharing includes the work definition, never project access or approvals.</p></div></div>`;
|
|
90
|
+
return html `<a href="/recipes/edit?preview=${preview.token}" class="meta">← Edit this workflow</a><div class="recipe-heading"><p class="recipe-kicker">3 · Preview</p><h1>${d.name}</h1><p class="hint">${d.description}</p></div><div class="recipe-preview-grid"><div><section class="card"><h2>What will happen</h2><ol class="recipe-steps">${workflowSteps(d).map(step => html `<li><strong>${step.title}</strong><p>${step.detail}</p></li>`)}</ol></section>${agreed}</div>${before}</div>${launch}`;
|
|
94
91
|
}
|
|
95
92
|
function inputHtml(index, input, values) {
|
|
96
93
|
const value = (field, fallback) => values?.get(`input-${index}-${field}`) ?? fallback;
|
|
97
|
-
return `<fieldset class="recipe-question"><legend>Question ${index + 1}</legend><div class="recipe-options"><label>Short key<input type="text" name="input-${index}-key" value="${
|
|
94
|
+
return html `<fieldset class="recipe-question"><legend>Question ${index + 1}</legend><div class="recipe-options"><label>Short key<input type="text" name="input-${index}-key" value="${value("key", input?.key ?? "")}" maxlength="32" placeholder="module" pattern="[a-z][a-z0-9_]{0,31}"></label><label>What should we ask?<input type="text" name="input-${index}-label" value="${value("label", input?.label ?? "")}" maxlength="80" placeholder="Which module should we work on?"></label></div><label>Default answer <span class="meta">optional</span><input type="text" name="input-${index}-default" value="${value("default", input?.defaultValue ?? "")}" maxlength="500"></label><p class="meta">Use <code data-question-token>{{${value("key", input?.key ?? "module") || "module"}}}</code> in your instructions or a success check. Clear this row and its placeholders to remove the question.</p><button type="button" data-insert-question hidden>Insert into instructions</button></fieldset>`;
|
|
98
95
|
}
|
|
96
|
+
/** The blank question the page's script copies, its numbers left for the script to fill in (the first "Question 8" only, as before). */
|
|
97
|
+
const questionTemplate = () => {
|
|
98
|
+
let numbered = false;
|
|
99
|
+
return replaceMarkup(inputHtml(7), /input-7-|Question 8/g, match => match === "input-7-" ? html `input-INDEX-` : numbered ? null : (numbered = true, html `Question NEXT`));
|
|
100
|
+
};
|
|
99
101
|
function recipeQuestionsHtml(document, values) {
|
|
100
102
|
const inputs = document.version === 2 ? document.inputs : [];
|
|
101
103
|
const submitted = values ? [...values.keys()].filter(key => /^input-[0-7]-/.test(key)).map(key => Number(key.split("-")[1]) + 1) : [];
|
|
102
104
|
const count = Math.min(RECIPE_INPUT_LIMIT, Math.max(1, inputs.length, ...submitted));
|
|
103
|
-
return `<details class="card"${inputs.length || submitted.some(i => values?.get(`input-${i - 1}-key`))
|
|
105
|
+
return html `<details class="card"${(inputs.length > 0 || submitted.some(i => values?.get(`input-${i - 1}-key`))) && html ` open`}><summary>Ask something each time <span class="meta">optional</span></summary><p class="hint">For example: “Test {{module}} and cover {{scenario}}.” Add a question for each placeholder. People answer these when they use the recipe; the saved instructions stay the same.</p><p class="meta">Use answers in the name, instructions, exclusions, or success checks. Keep allowed paths and check commands fixed. Don’t ask for passwords or keys.</p><div data-recipe-questions>${Array.from({ length: count }, (_, i) => inputHtml(i, inputs[i], values))}</div><button type="button" data-add-question hidden>Add a question</button><template data-question-template>${questionTemplate()}</template></details>`;
|
|
104
106
|
}
|
|
105
|
-
export function recipeDefinitionPreviewHtml(preview,
|
|
107
|
+
export function recipeDefinitionPreviewHtml(preview, revision) {
|
|
106
108
|
const d = preview.document;
|
|
107
109
|
const inputs = d.version === 2 ? d.inputs : [];
|
|
108
|
-
|
|
110
|
+
const uses = html `<section class="card"><h2>When someone uses this recipe</h2>${inputs.length ? html `<ol>${inputs.map(input => html `<li><strong>${input.label}</strong><p class="meta">{{${input.key}}}${input.defaultValue ? ` · Default: ${input.defaultValue}` : " · Answer required each time"}</p></li>`)}</ol>` : html `<p>No questions to answer. The saved scope is ready to preview and use.</p>`}<p>Each use previews the exact work before creating it. The project’s approval and recovery settings still apply.</p></section>`;
|
|
111
|
+
const instructions = html `<section class="card"><h2>Saved instructions</h2><p class="recap">${d.goal}</p><h3>Leave alone</h3><p class="recap">${d.outOfScope ?? "No additional exclusions."}</p><h3>Allowed paths</h3><p>${d.touches.length ? joinHtml(d.touches, ", ") : "This project"}</p><h3>Success checks</h3><ul>${d.acceptance.map(one => html `<li>${one.statement}<p class="meta">${evidenceWords(one.evidence)}${one.how ? ` · ${one.how}` : ""}</p></li>`)}</ul><p class="meta">${d.deliverable === "report" ? "Report" : "Code change"} · ${d.schedule === null ? "Run once" : d.schedule} · ${d.planning === "required" ? "Plan first" : d.planning === "auto" ? "Plan when helpful" : "Use the approved scope directly"}${d.costCeilingUsd === null ? "" : ` · $${d.costCeilingUsd} weekly limit`}</p></section>`;
|
|
112
|
+
const save = preview.savedId ? html `<a class="new-task" href="/recipes/run?recipe=${preview.savedId}&revision=${preview.savedRevision}">Use recipe →</a>`
|
|
113
|
+
: postForm("/recipes/save", html `<button type="submit">Save recipe</button>`, { projectRevision: String(revision), hidden: { repo: preview.repo, preview: preview.token, next: "use" } });
|
|
114
|
+
return html `<a class="meta" href="/recipes/edit?preview=${preview.token}&purpose=recipe">← Edit recipe</a><div class="recipe-heading"><p class="recipe-kicker">2 · Preview your recipe</p><h1>${d.name}</h1><p class="hint">${d.description || "A reusable starting point for work you do often."}</p></div>${uses}${instructions}<section class="card recipe-launch"><div>${save}<p class="meta">Saving creates no work. Everyone with project access can reuse this copy.</p></div><a href="/recipes/export?preview=${preview.token}">Export recipe JSON</a></section>`;
|
|
109
115
|
}
|
|
110
|
-
export function recipeRunHtml(recipe, repo,
|
|
116
|
+
export function recipeRunHtml(recipe, repo, revision, problem = null, values, saved = false) {
|
|
111
117
|
const d = recipe.document, inputs = d.version === 2 ? d.inputs : [];
|
|
112
|
-
|
|
118
|
+
const run = postForm("/recipes/prepare", html `<h2>${inputs.length ? "What changes this time?" : "Ready to go"}</h2>${inputs.map(input => html `<label>${input.label}<textarea name="answer-${input.key}" rows="2" maxlength="500" required>${values?.get(`answer-${input.key}`) ?? input.defaultValue ?? ""}</textarea></label>`)}${inputs.length === 0 && html `<p>No setup to repeat. Preview the saved scope and create the work.</p>`}<p class="meta">${d.schedule === null ? "Creates one task each time you use this recipe." : "Creates a new schedule with these answers fixed for every firing. Manage an existing schedule from Routines."}</p><button type="submit">Preview this run →</button><p class="meta">Previewing starts no agents. Existing project approvals apply when you create work.</p>`, { attrs: { class: "recipe-run card" }, projectRevision: String(revision), hidden: { repo, recipe: recipe.id, recipeRevision: String(recipe.revision) } });
|
|
119
|
+
return html `<a class="meta" href="/recipes">← Your recipes</a><div class="recipe-heading"><p class="recipe-kicker">${saved ? "Recipe saved · ready when you are" : "Use a recipe"}</p><h1>${d.name}</h1><p class="hint">${d.description || "Your saved instructions, ready to use again."}</p></div>${problem && html `<p role="alert" class="card recipe-error">${problem}</p>`}${run}<details class="card"><summary>Saved instructions and boundaries</summary><p class="recap">${d.goal}</p><p class="recap">Leave alone: ${d.outOfScope ?? "No additional exclusions."}</p><p>Allowed paths: ${d.touches.length ? joinHtml(d.touches, ", ") : "This project"}</p><ul>${d.acceptance.map(one => html `<li>${one.statement}</li>`)}</ul><a href="/recipes/start?recipe=${recipe.id}&revision=${recipe.revision}">Edit a copy of this recipe →</a></details>`;
|
|
113
120
|
}
|
|
114
121
|
export function recipeAnswersFromForm(body) {
|
|
115
122
|
const answers = new Map();
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The world `toolroll release` acts on (release.ts): the gate checkout through git, GitHub through the signed-in `gh`,
|
|
3
|
+
* the npm registry over HTTPS, the installed Toolroll through its own CLI (`--json`) and launchd definitions, and the
|
|
4
|
+
* Homebrew tap through `gh`. Each call is bounded; none asks for or stores a credential — `gh`, npm and Toolroll use
|
|
5
|
+
* the sign-ins this machine already has.
|
|
6
|
+
*/
|
|
7
|
+
import type { GateState, Installed, ReleaseAdapters } from "./release.js";
|
|
8
|
+
export type Exec = (command: string, args: readonly string[], options?: {
|
|
9
|
+
cwd?: string;
|
|
10
|
+
timeoutMs?: number;
|
|
11
|
+
env?: NodeJS.ProcessEnv;
|
|
12
|
+
}) => Promise<{
|
|
13
|
+
code: number;
|
|
14
|
+
stdout: string;
|
|
15
|
+
stderr: string;
|
|
16
|
+
}>;
|
|
17
|
+
/** A child process, its output kept whole; a missing program or a time limit is exit 127 or 124, never a throw. */
|
|
18
|
+
export declare const exec: Exec;
|
|
19
|
+
/** owner/name from an https or ssh GitHub remote. */
|
|
20
|
+
export declare function githubSlug(url: string): string | null;
|
|
21
|
+
/** The runtime (a `dist` folder, resolved) each launchd service of Toolroll runs: its definition names `<dist>/cli.js`. */
|
|
22
|
+
export declare function serviceRuntimes(agents?: string): string[];
|
|
23
|
+
/** The runtime each CLI name resolves to on PATH: the `dist` folder its `bin.js` sits in, or null when not linked there. */
|
|
24
|
+
export declare function cliRuntimes(path?: string, names?: string[]): Installed["clis"];
|
|
25
|
+
type Json = Record<string, unknown>;
|
|
26
|
+
/** `task show --json`, read as the release needs it. */
|
|
27
|
+
export declare function gateStateOf(answer: Json, accounts?: readonly unknown[]): GateState;
|
|
28
|
+
/** Every process on this machine (`ps`): pid and full command line. */
|
|
29
|
+
export declare function processes(): {
|
|
30
|
+
pid: number;
|
|
31
|
+
command: string;
|
|
32
|
+
}[];
|
|
33
|
+
/** The final line of deploy-browser's output that is a JSON object: its `runtime` (a dist folder), when it has one. */
|
|
34
|
+
export declare function deployedRuntime(stdout: string): string | null;
|
|
35
|
+
/** What a deployment's stage says about the update pause: its id and phase when the journal is before the swap and the
|
|
36
|
+
* live database's pause is that deployment's. `owner` reads the live pause's owner. */
|
|
37
|
+
export declare function stageGate(stage: string, owner: () => string | null): {
|
|
38
|
+
id: string;
|
|
39
|
+
phase: string;
|
|
40
|
+
} | null;
|
|
41
|
+
export type AdapterOptions = {
|
|
42
|
+
checkout: string;
|
|
43
|
+
/** The live database (default: this installation's). */
|
|
44
|
+
database?: string;
|
|
45
|
+
processes?: typeof processes;
|
|
46
|
+
/** owner/name of the Homebrew tap and its formula's path there. */
|
|
47
|
+
tap?: string;
|
|
48
|
+
formula?: string;
|
|
49
|
+
/** How long the deployment itself may run, in minutes. */
|
|
50
|
+
deployMinutes?: number;
|
|
51
|
+
run?: Exec;
|
|
52
|
+
fetch?: typeof fetch;
|
|
53
|
+
say?: (line: string) => void;
|
|
54
|
+
now?: () => Date;
|
|
55
|
+
sleep?: (ms: number) => Promise<void>;
|
|
56
|
+
};
|
|
57
|
+
export declare function releaseAdapters(options: AdapterOptions): ReleaseAdapters;
|
|
58
|
+
/** The formula with its first `url` and `sha256` replaced; anything else is left exactly as it was. */
|
|
59
|
+
export declare function bumpFormula(text: string, url: string, sha256: string): string;
|
|
60
|
+
export {};
|