@autohq/cli 0.1.91 → 0.1.93
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/dist/agent-bridge.js +8 -8
- package/dist/index.js +40 -300
- package/package.json +2 -1
package/dist/agent-bridge.js
CHANGED
|
@@ -19524,12 +19524,12 @@ var AgentBridgeMcpServerConfigSchema = external_exports.object({
|
|
|
19524
19524
|
type: external_exports.literal("http"),
|
|
19525
19525
|
url: external_exports.string().trim().min(1),
|
|
19526
19526
|
headers: external_exports.record(external_exports.string().trim().min(1), external_exports.string()).optional()
|
|
19527
|
-
})
|
|
19527
|
+
});
|
|
19528
19528
|
var AgentBridgeClaudeConfigSchema = external_exports.object({
|
|
19529
19529
|
cwd: external_exports.string().trim().min(1).optional(),
|
|
19530
19530
|
env: external_exports.record(external_exports.string().trim().min(1), external_exports.string()),
|
|
19531
19531
|
mcpServers: external_exports.record(external_exports.string().trim().min(1), AgentBridgeMcpServerConfigSchema).optional()
|
|
19532
|
-
})
|
|
19532
|
+
});
|
|
19533
19533
|
var RuntimeBridgeBootstrapPlaintextSchema = external_exports.object({
|
|
19534
19534
|
version: external_exports.literal(1),
|
|
19535
19535
|
outputSeqStart: external_exports.number().int().nonnegative(),
|
|
@@ -19540,31 +19540,31 @@ var RuntimeBridgeBootstrapPlaintextSchema = external_exports.object({
|
|
|
19540
19540
|
gitCredentials: external_exports.object({
|
|
19541
19541
|
url: external_exports.string().trim().min(1),
|
|
19542
19542
|
accessToken: external_exports.string().trim().min(1)
|
|
19543
|
-
}).
|
|
19544
|
-
})
|
|
19543
|
+
}).optional()
|
|
19544
|
+
});
|
|
19545
19545
|
var RuntimeBridgeEncryptedBootstrapSchema = external_exports.object({
|
|
19546
19546
|
version: external_exports.literal(1),
|
|
19547
19547
|
ciphertext: external_exports.string().trim().min(1),
|
|
19548
19548
|
iv: external_exports.string().trim().min(1),
|
|
19549
19549
|
authTag: external_exports.string().trim().min(1),
|
|
19550
19550
|
salt: external_exports.string().trim().min(1)
|
|
19551
|
-
})
|
|
19551
|
+
});
|
|
19552
19552
|
var RuntimeBridgeBootstrapEnvelopeSchema = external_exports.object({
|
|
19553
19553
|
runId: SessionRunIdSchema,
|
|
19554
19554
|
runtimeId: RuntimeIdSchema,
|
|
19555
19555
|
bridgeLeaseId: RuntimeBridgeLeaseIdSchema,
|
|
19556
19556
|
bootstrap: RuntimeBridgeEncryptedBootstrapSchema
|
|
19557
|
-
})
|
|
19557
|
+
});
|
|
19558
19558
|
var RuntimeBridgeBootstrapAckSchema = external_exports.object({
|
|
19559
19559
|
status: external_exports.enum(["ready", "failed"]),
|
|
19560
19560
|
error: external_exports.string().trim().min(1).optional(),
|
|
19561
19561
|
at: external_exports.string().datetime()
|
|
19562
|
-
})
|
|
19562
|
+
});
|
|
19563
19563
|
var RuntimeBridgeConnectedPayloadSchema = external_exports.object({
|
|
19564
19564
|
runId: SessionRunIdSchema,
|
|
19565
19565
|
runtimeId: RuntimeIdSchema,
|
|
19566
19566
|
bridgeLeaseId: RuntimeBridgeLeaseIdSchema
|
|
19567
|
-
})
|
|
19567
|
+
});
|
|
19568
19568
|
var RuntimeBridgeCommandDeliverySchema = external_exports.object({
|
|
19569
19569
|
type: external_exports.literal("command.delivery"),
|
|
19570
19570
|
deliveryId: external_exports.string().trim().min(1),
|
package/dist/index.js
CHANGED
|
@@ -20276,22 +20276,26 @@ async function createOAuthLoopbackCallback(input) {
|
|
|
20276
20276
|
const error51 = url2.searchParams.get("error");
|
|
20277
20277
|
if (error51) {
|
|
20278
20278
|
response.writeHead(400, { "content-type": "text/html; charset=utf-8" });
|
|
20279
|
-
|
|
20280
|
-
|
|
20279
|
+
endThenSettle(
|
|
20280
|
+
response,
|
|
20281
|
+
resolveHtml(failureHtml, { code: "" }),
|
|
20282
|
+
() => rejectResult(new Error(error51))
|
|
20283
|
+
);
|
|
20281
20284
|
return;
|
|
20282
20285
|
}
|
|
20283
20286
|
const code = url2.searchParams.get("code");
|
|
20284
20287
|
if (!code) {
|
|
20285
20288
|
response.writeHead(400, { "content-type": "text/html; charset=utf-8" });
|
|
20286
|
-
|
|
20289
|
+
endThenSettle(
|
|
20290
|
+
response,
|
|
20287
20291
|
renderOAuthLoopbackPage({
|
|
20288
20292
|
status: "failure",
|
|
20289
20293
|
eyebrow: "Auto",
|
|
20290
20294
|
title: "Missing authorization code",
|
|
20291
20295
|
message: "Return to your terminal to retry the authorization flow."
|
|
20292
|
-
})
|
|
20296
|
+
}),
|
|
20297
|
+
() => rejectResult(new Error("Missing authorization code"))
|
|
20293
20298
|
);
|
|
20294
|
-
rejectResult(new Error("Missing authorization code"));
|
|
20295
20299
|
return;
|
|
20296
20300
|
}
|
|
20297
20301
|
const result2 = {
|
|
@@ -20301,8 +20305,11 @@ async function createOAuthLoopbackCallback(input) {
|
|
|
20301
20305
|
state: url2.searchParams.get("state") ?? void 0
|
|
20302
20306
|
};
|
|
20303
20307
|
response.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
20304
|
-
|
|
20305
|
-
|
|
20308
|
+
endThenSettle(
|
|
20309
|
+
response,
|
|
20310
|
+
resolveHtml(successHtml, result2),
|
|
20311
|
+
() => resolveResult(result2)
|
|
20312
|
+
);
|
|
20306
20313
|
});
|
|
20307
20314
|
await listenOnPreferredPort(
|
|
20308
20315
|
server,
|
|
@@ -20310,7 +20317,10 @@ async function createOAuthLoopbackCallback(input) {
|
|
|
20310
20317
|
);
|
|
20311
20318
|
const address = server.address();
|
|
20312
20319
|
return {
|
|
20313
|
-
close: () =>
|
|
20320
|
+
close: () => {
|
|
20321
|
+
server.close();
|
|
20322
|
+
server.closeAllConnections();
|
|
20323
|
+
},
|
|
20314
20324
|
redirectUri: `http://127.0.0.1:${address.port}${path2}`,
|
|
20315
20325
|
result
|
|
20316
20326
|
};
|
|
@@ -20480,6 +20490,11 @@ function renderOAuthLoopbackPage(input) {
|
|
|
20480
20490
|
function resolveHtml(html, result) {
|
|
20481
20491
|
return typeof html === "function" ? html(result) : html;
|
|
20482
20492
|
}
|
|
20493
|
+
function endThenSettle(response, html, settle) {
|
|
20494
|
+
response.once("finish", settle);
|
|
20495
|
+
response.once("close", settle);
|
|
20496
|
+
response.end(html);
|
|
20497
|
+
}
|
|
20483
20498
|
function escapeHtml(value) {
|
|
20484
20499
|
return value.replace(/[&<>"']/g, (character) => {
|
|
20485
20500
|
switch (character) {
|
|
@@ -21598,7 +21613,7 @@ var init_package = __esm({
|
|
|
21598
21613
|
"package.json"() {
|
|
21599
21614
|
package_default = {
|
|
21600
21615
|
name: "@autohq/cli",
|
|
21601
|
-
version: "0.1.
|
|
21616
|
+
version: "0.1.93",
|
|
21602
21617
|
license: "SEE LICENSE IN README.md",
|
|
21603
21618
|
publishConfig: {
|
|
21604
21619
|
access: "public"
|
|
@@ -21621,6 +21636,7 @@ var init_package = __esm({
|
|
|
21621
21636
|
build: "tsup",
|
|
21622
21637
|
dev: "tsx src/main.ts",
|
|
21623
21638
|
"dev:tui": "node ../../scripts/cli-tui-dev-watch.mjs",
|
|
21639
|
+
"skill:generate": "tsx scripts/generate-skill-content.ts",
|
|
21624
21640
|
test: "npm run test:unit",
|
|
21625
21641
|
"test:unit": 'tsx --test "test/**/*.unit.test.ts"',
|
|
21626
21642
|
typecheck: "tsc --noEmit"
|
|
@@ -26973,12 +26989,12 @@ var AgentBridgeMcpServerConfigSchema = external_exports.object({
|
|
|
26973
26989
|
type: external_exports.literal("http"),
|
|
26974
26990
|
url: external_exports.string().trim().min(1),
|
|
26975
26991
|
headers: external_exports.record(external_exports.string().trim().min(1), external_exports.string()).optional()
|
|
26976
|
-
})
|
|
26992
|
+
});
|
|
26977
26993
|
var AgentBridgeClaudeConfigSchema = external_exports.object({
|
|
26978
26994
|
cwd: external_exports.string().trim().min(1).optional(),
|
|
26979
26995
|
env: external_exports.record(external_exports.string().trim().min(1), external_exports.string()),
|
|
26980
26996
|
mcpServers: external_exports.record(external_exports.string().trim().min(1), AgentBridgeMcpServerConfigSchema).optional()
|
|
26981
|
-
})
|
|
26997
|
+
});
|
|
26982
26998
|
var RuntimeBridgeBootstrapPlaintextSchema = external_exports.object({
|
|
26983
26999
|
version: external_exports.literal(1),
|
|
26984
27000
|
outputSeqStart: external_exports.number().int().nonnegative(),
|
|
@@ -26989,31 +27005,31 @@ var RuntimeBridgeBootstrapPlaintextSchema = external_exports.object({
|
|
|
26989
27005
|
gitCredentials: external_exports.object({
|
|
26990
27006
|
url: external_exports.string().trim().min(1),
|
|
26991
27007
|
accessToken: external_exports.string().trim().min(1)
|
|
26992
|
-
}).
|
|
26993
|
-
})
|
|
27008
|
+
}).optional()
|
|
27009
|
+
});
|
|
26994
27010
|
var RuntimeBridgeEncryptedBootstrapSchema = external_exports.object({
|
|
26995
27011
|
version: external_exports.literal(1),
|
|
26996
27012
|
ciphertext: external_exports.string().trim().min(1),
|
|
26997
27013
|
iv: external_exports.string().trim().min(1),
|
|
26998
27014
|
authTag: external_exports.string().trim().min(1),
|
|
26999
27015
|
salt: external_exports.string().trim().min(1)
|
|
27000
|
-
})
|
|
27016
|
+
});
|
|
27001
27017
|
var RuntimeBridgeBootstrapEnvelopeSchema = external_exports.object({
|
|
27002
27018
|
runId: SessionRunIdSchema,
|
|
27003
27019
|
runtimeId: RuntimeIdSchema,
|
|
27004
27020
|
bridgeLeaseId: RuntimeBridgeLeaseIdSchema,
|
|
27005
27021
|
bootstrap: RuntimeBridgeEncryptedBootstrapSchema
|
|
27006
|
-
})
|
|
27022
|
+
});
|
|
27007
27023
|
var RuntimeBridgeBootstrapAckSchema = external_exports.object({
|
|
27008
27024
|
status: external_exports.enum(["ready", "failed"]),
|
|
27009
27025
|
error: external_exports.string().trim().min(1).optional(),
|
|
27010
27026
|
at: external_exports.string().datetime()
|
|
27011
|
-
})
|
|
27027
|
+
});
|
|
27012
27028
|
var RuntimeBridgeConnectedPayloadSchema = external_exports.object({
|
|
27013
27029
|
runId: SessionRunIdSchema,
|
|
27014
27030
|
runtimeId: RuntimeIdSchema,
|
|
27015
27031
|
bridgeLeaseId: RuntimeBridgeLeaseIdSchema
|
|
27016
|
-
})
|
|
27032
|
+
});
|
|
27017
27033
|
var RuntimeBridgeCommandDeliverySchema = external_exports.object({
|
|
27018
27034
|
type: external_exports.literal("command.delivery"),
|
|
27019
27035
|
deliveryId: external_exports.string().trim().min(1),
|
|
@@ -28868,8 +28884,8 @@ function registerAuthCommands(program, context) {
|
|
|
28868
28884
|
program.command("whoami").description("Show the authenticated Auto actor.").action(async () => {
|
|
28869
28885
|
await handleWhoami(context);
|
|
28870
28886
|
});
|
|
28871
|
-
const auth = program.command("auth").description("Manage Auto authentication.");
|
|
28872
|
-
auth.command("login").description("Log in as a user.").option("--api-url <url>", "Auto web server URL").option("--device", "Use device authorization flow").option("--code <code>", "Exchange an existing authorization code").option("--verifier <verifier>", "PKCE verifier for --code").action(async (options) => {
|
|
28887
|
+
const auth = program.command("auth").description("Manage Auto authentication. Defaults to login.");
|
|
28888
|
+
auth.command("login", { isDefault: true }).description("Log in as a user.").option("--api-url <url>", "Auto web server URL").option("--device", "Use device authorization flow").option("--code <code>", "Exchange an existing authorization code").option("--verifier <verifier>", "PKCE verifier for --code").action(async (options) => {
|
|
28873
28889
|
const globalOptions = program.opts();
|
|
28874
28890
|
await login({
|
|
28875
28891
|
options: {
|
|
@@ -29879,286 +29895,7 @@ function acceptedInvitationLine(response) {
|
|
|
29879
29895
|
].join(" ");
|
|
29880
29896
|
}
|
|
29881
29897
|
|
|
29882
|
-
// src/commands/onboard/
|
|
29883
|
-
var onboardingSkillMarkdown = `# Onboard your user to auto
|
|
29884
|
-
|
|
29885
|
-
You are a coding agent running inside the user's repository. Your job is to
|
|
29886
|
-
take them from zero to a working auto deployment in one conversation, with
|
|
29887
|
-
the least possible friction. Follow the six beats in order, and run every
|
|
29888
|
-
waiting step in parallel with your own work.
|
|
29889
|
-
|
|
29890
|
-
## Ground rules
|
|
29891
|
-
|
|
29892
|
-
- This document is choreography, not mechanics. Trust \`auto --help\` and live
|
|
29893
|
-
command output over this document whenever they disagree.
|
|
29894
|
-
- Never block on the user. When a step needs a human click (sign-in, Slack
|
|
29895
|
-
install, GitHub App), hand them the link and keep working on the next beat
|
|
29896
|
-
while they click.
|
|
29897
|
-
- Ask before changing anything outside \`.auto/\`. Editing AGENTS.md happens
|
|
29898
|
-
only with the user's explicit opt-in: show the exact block you intend to
|
|
29899
|
-
append and wait for a yes.
|
|
29900
|
-
- Install exactly one workflow, not a menu. Bias hard toward the lowest
|
|
29901
|
-
time-to-first-trigger: a workflow that fires within hours beats one that
|
|
29902
|
-
fires next quarter.
|
|
29903
|
-
- Talk like a collaborator. One question at a time, short messages, no walls
|
|
29904
|
-
of setup output.
|
|
29905
|
-
|
|
29906
|
-
## Beat 1: Pitch
|
|
29907
|
-
|
|
29908
|
-
Explain what auto is in your own words, grounded in this repository. The
|
|
29909
|
-
canonical framing:
|
|
29910
|
-
|
|
29911
|
-
> auto lets you program software factories the same way you program CI/CD.
|
|
29912
|
-
> Compose agents and triggers into workflows using simple YAML files, and
|
|
29913
|
-
> deploy them into the cloud on merge. Anything that can be described in a
|
|
29914
|
-
> standard operating procedure can become a chart of agents and triggers.
|
|
29915
|
-
|
|
29916
|
-
Localize it: name a real procedure you can see in this repo ("your PR review
|
|
29917
|
-
flow could be a chart that reviews every PR against your conventions").
|
|
29918
|
-
Close with why the next beat matters: factory agents work while the user is
|
|
29919
|
-
not looking, so they need a way to reach the user.
|
|
29920
|
-
|
|
29921
|
-
## Beat 2: Channel
|
|
29922
|
-
|
|
29923
|
-
Say something like: "I work best when I can reach you proactively \u2014 let's
|
|
29924
|
-
get me into your Slack." Then, without waiting:
|
|
29925
|
-
|
|
29926
|
-
1. Start sign-in with \`auto auth login --device\` and give the user the
|
|
29927
|
-
verification URL. Account, organization, and project setup happen in the
|
|
29928
|
-
browser.
|
|
29929
|
-
2. Check \`auto connections list --available\` and start the Slack connection
|
|
29930
|
-
(\`auto connect slack\`), giving the user that link too.
|
|
29931
|
-
3. Move straight to Beat 3 while the user clicks. Poll for completion in the
|
|
29932
|
-
background; never sit idle waiting for a click.
|
|
29933
|
-
|
|
29934
|
-
## Beat 3: Study
|
|
29935
|
-
|
|
29936
|
-
Build a repo dossier while the clicks happen. Explore the codebase and git
|
|
29937
|
-
history for:
|
|
29938
|
-
|
|
29939
|
-
- Stack and layout: languages, frameworks, build and test setup, CI and
|
|
29940
|
-
deploy workflows (Beat 6 wires into these).
|
|
29941
|
-
- How the team works: PR conventions, review patterns, branch and release
|
|
29942
|
-
habits, merge frequency.
|
|
29943
|
-
- Tools referenced: issue tracker keys in commits and branches, chat or
|
|
29944
|
-
deploy tooling named in docs and workflow files, existing agent config
|
|
29945
|
-
(CLAUDE.md, AGENTS.md, .cursor).
|
|
29946
|
-
- Live state, using the user's own credentials (git, gh): open PRs, CI
|
|
29947
|
-
status, recent activity.
|
|
29948
|
-
|
|
29949
|
-
Write the dossier as structured markdown. It has two consumers: the
|
|
29950
|
-
concierge agent (Beat 4) and your own interview (Beat 5). End it with 2-3
|
|
29951
|
-
candidate workflows from the playbook below, each tied to a concrete signal
|
|
29952
|
-
you found.
|
|
29953
|
-
|
|
29954
|
-
## Beat 4: First contact
|
|
29955
|
-
|
|
29956
|
-
The concierge is a session you create in this project, not one that ships
|
|
29957
|
-
pre-installed. When sign-in, Slack, and the dossier are all ready:
|
|
29958
|
-
|
|
29959
|
-
1. Draft the concierge into \`.auto/\` from the template below. Adapt names,
|
|
29960
|
-
reuse an existing profile or environment if the project already has one,
|
|
29961
|
-
and verify with \`auto apply --dry-run\` before applying.
|
|
29962
|
-
2. Launch it headlessly with the dossier as the run message:
|
|
29963
|
-
\`auto run concierge --message <dossier>\`. Run messages cap at 20,000
|
|
29964
|
-
characters, so distill the dossier to fit; lead with the live state
|
|
29965
|
-
(open PRs, CI status) since that is what makes first contact specific.
|
|
29966
|
-
|
|
29967
|
-
\`\`\`yaml
|
|
29968
|
-
kind: session
|
|
29969
|
-
metadata:
|
|
29970
|
-
name: concierge
|
|
29971
|
-
spec:
|
|
29972
|
-
profile: concierge
|
|
29973
|
-
identity:
|
|
29974
|
-
displayName: auto concierge
|
|
29975
|
-
username: auto-concierge
|
|
29976
|
-
description: This project's auto agent. Ask it to add or change workflows.
|
|
29977
|
-
tools:
|
|
29978
|
-
chat:
|
|
29979
|
-
ref: slack-chat
|
|
29980
|
-
initialPrompt: |
|
|
29981
|
-
You are this project's auto concierge. If your message contains a repo
|
|
29982
|
-
dossier, this is first contact: send the user exactly one Slack message
|
|
29983
|
-
via chat.send - one concrete, verifiable observation from the dossier
|
|
29984
|
-
plus one offer. Short, specific, never templated. Otherwise the user is
|
|
29985
|
-
consulting you: help them add or adjust workflows by editing .auto/
|
|
29986
|
-
resources and applying them.
|
|
29987
|
-
\`\`\`
|
|
29988
|
-
|
|
29989
|
-
The profile and the slack-chat tool follow the project's existing
|
|
29990
|
-
conventions; if the project has neither, draft minimal ones (see
|
|
29991
|
-
\`auto apply --help\` and the resource examples in the docs).
|
|
29992
|
-
|
|
29993
|
-
The concierge reads the dossier and sends the user one proactive Slack
|
|
29994
|
-
message: a specific observation about this repo plus one offer. Do not
|
|
29995
|
-
attach to the run or take over the terminal; you remain the user's
|
|
29996
|
-
interface.
|
|
29997
|
-
|
|
29998
|
-
Tell the user to check Slack. The buzz is the point: an agent they just met
|
|
29999
|
-
already knows their codebase and can reach them.
|
|
30000
|
-
|
|
30001
|
-
If the apply fails or the Slack identity is not ready yet, skip this beat
|
|
30002
|
-
and let the installed workflow's first firing be first contact instead.
|
|
30003
|
-
|
|
30004
|
-
## Beat 5: Interview, then install
|
|
30005
|
-
|
|
30006
|
-
Back in the terminal, ask 3-5 questions, one at a time, each grounded in
|
|
30007
|
-
the dossier ("I see FRA- refs everywhere \u2014 who triages those?"). Converge on
|
|
30008
|
-
one workflow. Then:
|
|
30009
|
-
|
|
30010
|
-
1. Draft the session YAML into \`.auto/sessions/\`.
|
|
30011
|
-
2. Show a plain-language summary of what will run and when ("on every PR
|
|
30012
|
-
opened, I'll review it against your conventions and report in Slack").
|
|
30013
|
-
3. Get one explicit yes.
|
|
30014
|
-
4. If the workflow needs repository events, connect the GitHub App now
|
|
30015
|
-
(\`auto connect github\`) \u2014 this is the moment the ask is motivated. Other
|
|
30016
|
-
providers (Linear, Notion, ...) connect only when the chosen workflow
|
|
30017
|
-
needs them, never speculatively.
|
|
30018
|
-
5. Apply with \`auto apply\` and confirm the trigger is active. Route the
|
|
30019
|
-
workflow's reports to the Slack channel from Beat 2.
|
|
30020
|
-
|
|
30021
|
-
## Beat 6: Wire CI to apply on merge
|
|
30022
|
-
|
|
30023
|
-
Every apply so far ran from this terminal under the user's own login. Its
|
|
30024
|
-
durable home is CI: a dry-run plan as a check on every PR, and the real
|
|
30025
|
-
apply when changes merge \u2014 \`.auto/\` ships the same way the code does. Do
|
|
30026
|
-
this once the GitHub App is connected and the first apply has succeeded.
|
|
30027
|
-
|
|
30028
|
-
1. CI authenticates as a service account, never as the user. Create two \u2014
|
|
30029
|
-
the \`applier\` token lives only on the merge path, while the \`read-only\`
|
|
30030
|
-
token is exposed to PR-triggered runs: it can produce the dry-run plan
|
|
30031
|
-
but cannot perform a real apply, and it stays revocable on its own. Pipe
|
|
30032
|
-
each token straight into a GitHub secret so it never touches your
|
|
30033
|
-
transcript or disk \u2014 with \`pipefail\` and \`jq -re\` so a failed create
|
|
30034
|
-
cannot silently store an empty secret:
|
|
30035
|
-
|
|
30036
|
-
\`\`\`sh
|
|
30037
|
-
set -o pipefail
|
|
30038
|
-
auto service-account create github-actions-auto-apply \\
|
|
30039
|
-
--preset applier --json \\
|
|
30040
|
-
| jq -re .token | gh secret set AUTO_APPLY_SERVICE_ACCOUNT_TOKEN
|
|
30041
|
-
auto service-account create github-actions-auto-apply-dry-run \\
|
|
30042
|
-
--preset read-only --json \\
|
|
30043
|
-
| jq -re .token | gh secret set AUTO_APPLY_DRY_RUN_SERVICE_ACCOUNT_TOKEN
|
|
30044
|
-
\`\`\`
|
|
30045
|
-
|
|
30046
|
-
Confirm both pipelines exited 0 and \`gh secret list\` shows both names
|
|
30047
|
-
before moving on. If deploys go through a GitHub environment, scope the
|
|
30048
|
-
apply secret to it (\`gh secret set --env\`).
|
|
30049
|
-
2. Fit into the deploy process you mapped in Beat 3. If a workflow already
|
|
30050
|
-
ships merges, splice two steps in after its deploy succeeds \u2014 plan
|
|
30051
|
-
(\`auto apply --dry-run\`), then \`auto apply\` \u2014 reusing its checkout and
|
|
30052
|
-
Node setup. If nothing deploys from CI yet, add the standalone workflow
|
|
30053
|
-
below. Either way, keep the PR dry-run check: it shows reviewers the
|
|
30054
|
-
exact create/update/archive plan their merge will execute.
|
|
30055
|
-
3. Workflow files live outside \`.auto/\`, so show the user the file and get
|
|
30056
|
-
a yes; commit it on the same branch as the \`.auto/\` resources.
|
|
30057
|
-
|
|
30058
|
-
\`\`\`yaml
|
|
30059
|
-
name: Auto Apply
|
|
30060
|
-
|
|
30061
|
-
# Both triggers assume the default branch is main; swap in the repo's
|
|
30062
|
-
# actual default branch before committing.
|
|
30063
|
-
on:
|
|
30064
|
-
pull_request:
|
|
30065
|
-
branches: [main]
|
|
30066
|
-
push:
|
|
30067
|
-
branches: [main]
|
|
30068
|
-
|
|
30069
|
-
permissions:
|
|
30070
|
-
contents: read
|
|
30071
|
-
|
|
30072
|
-
concurrency:
|
|
30073
|
-
group: auto-apply-\${{ github.event.pull_request.number || github.ref }}
|
|
30074
|
-
cancel-in-progress: \${{ github.event_name == 'pull_request' }}
|
|
30075
|
-
|
|
30076
|
-
jobs:
|
|
30077
|
-
plan:
|
|
30078
|
-
runs-on: ubuntu-latest
|
|
30079
|
-
timeout-minutes: 10
|
|
30080
|
-
steps:
|
|
30081
|
-
- uses: actions/checkout@v4
|
|
30082
|
-
- uses: actions/setup-node@v4
|
|
30083
|
-
with:
|
|
30084
|
-
node-version: lts/*
|
|
30085
|
-
- run: npx -y --package=@autohq/cli auto apply --dry-run
|
|
30086
|
-
env:
|
|
30087
|
-
AUTO_API_TOKEN: \${{ secrets.AUTO_APPLY_DRY_RUN_SERVICE_ACCOUNT_TOKEN }}
|
|
30088
|
-
|
|
30089
|
-
apply:
|
|
30090
|
-
if: \${{ github.event_name == 'push' }}
|
|
30091
|
-
needs: plan
|
|
30092
|
-
runs-on: ubuntu-latest
|
|
30093
|
-
timeout-minutes: 10
|
|
30094
|
-
steps:
|
|
30095
|
-
- uses: actions/checkout@v4
|
|
30096
|
-
- uses: actions/setup-node@v4
|
|
30097
|
-
with:
|
|
30098
|
-
node-version: lts/*
|
|
30099
|
-
- run: npx -y --package=@autohq/cli auto apply
|
|
30100
|
-
env:
|
|
30101
|
-
AUTO_API_TOKEN: \${{ secrets.AUTO_APPLY_SERVICE_ACCOUNT_TOKEN }}
|
|
30102
|
-
\`\`\`
|
|
30103
|
-
|
|
30104
|
-
Adapt it to the repo: the default branch name, the team's Node setup or
|
|
30105
|
-
pinned tool versions, and set \`AUTO_API_BASE_URL\` only if the project runs
|
|
30106
|
-
against a non-default Auto host. \`pull_request\` runs from forks do not
|
|
30107
|
-
receive secrets; if fork PRs are routine here, run the dry-run from a
|
|
30108
|
-
\`pull_request_target\` workflow that checks out workflow code from the base
|
|
30109
|
-
branch and only \`.auto/\` from the PR head.
|
|
30110
|
-
|
|
30111
|
-
After the PR merges, watch the first run and confirm its plan reports the
|
|
30112
|
-
resources you already applied as unchanged. From then on, \`.auto/\` on the
|
|
30113
|
-
default branch is the source of truth \u2014 directory apply prunes resources
|
|
30114
|
-
that are no longer declared, so the team changes agents by PR, not by
|
|
30115
|
-
terminal.
|
|
30116
|
-
|
|
30117
|
-
## Workflow playbook
|
|
30118
|
-
|
|
30119
|
-
Candidates, strongest signals, and what confirms fit:
|
|
30120
|
-
|
|
30121
|
-
- PR review: frequent PRs, visible review conventions. Confirm: "what do
|
|
30122
|
-
reviewers always catch by hand?" Fires on the next PR.
|
|
30123
|
-
- CI failure triage: CI config plus red or flaky runs in recent history.
|
|
30124
|
-
Confirm: "who notices when main goes red?" Fires within hours.
|
|
30125
|
-
- Issue triage: tracker refs in commits, an untriaged backlog. Confirm:
|
|
30126
|
-
"who looks at new issues today?" Needs the tracker connected.
|
|
30127
|
-
- Daily digest: busy repo, distributed team. Confirm: "would a morning
|
|
30128
|
-
summary of PRs, CI, and issues be useful?" Fires next morning.
|
|
30129
|
-
- Dependency or flaky-test watch: lockfile churn or retry patterns in CI.
|
|
30130
|
-
Slower to first fire; prefer the options above for the first install.
|
|
30131
|
-
|
|
30132
|
-
Estimate time-to-first-trigger for each candidate you propose, and say it
|
|
30133
|
-
out loud when proposing.
|
|
30134
|
-
|
|
30135
|
-
## If something is blocked
|
|
30136
|
-
|
|
30137
|
-
- Slack needs admin approval: continue without the channel. Finish the
|
|
30138
|
-
interview and install; tell the user their agent will appear in Slack once
|
|
30139
|
-
the install is approved, and have the concierge retry.
|
|
30140
|
-
- Sign-in stalls: the user may not have an invite yet; point them at the
|
|
30141
|
-
auto site and pause gracefully rather than failing.
|
|
30142
|
-
- \`gh secret set\` fails (no repo admin rights, gh not authenticated):
|
|
30143
|
-
leave the CI workflow in the PR anyway and hand the user the two
|
|
30144
|
-
create-and-pipe commands from Beat 6 to run themselves. Tokens are shown
|
|
30145
|
-
once and must never be pasted into the conversation.
|
|
30146
|
-
- A command disagrees with this document: the command is right. Re-read
|
|
30147
|
-
\`auto --help\` and adapt.
|
|
30148
|
-
|
|
30149
|
-
## What you leave behind
|
|
30150
|
-
|
|
30151
|
-
- \`.auto/\` committed on a branch with a PR the user can merge: the
|
|
30152
|
-
concierge and workflow session YAML, the CI apply workflow from Beat 6,
|
|
30153
|
-
plus \`context.md\` (the distilled dossier). Write the PR description for
|
|
30154
|
-
teammates \u2014 it doubles as the announcement that this repo now has an
|
|
30155
|
-
auto agent.
|
|
30156
|
-
- With the user's opt-in, an AGENTS.md section that tells every future
|
|
30157
|
-
coding agent in this repo that auto exists, what is deployed, and how to
|
|
30158
|
-
add workflows.
|
|
30159
|
-
- Tell the user the two ways back: talk to the bot in Slack, or run
|
|
30160
|
-
\`auto onboard --agent\` again any time.
|
|
30161
|
-
`;
|
|
29898
|
+
// src/commands/onboard/quickstart-content.ts
|
|
30162
29899
|
var humanQuickstartText = `Get started with auto:
|
|
30163
29900
|
|
|
30164
29901
|
1. auto auth login sign in (device flow; account setup in browser)
|
|
@@ -30177,6 +29914,9 @@ a first workflow tailored to how your team works.
|
|
|
30177
29914
|
Docs and help: auto --help
|
|
30178
29915
|
`;
|
|
30179
29916
|
|
|
29917
|
+
// src/commands/onboard/skill-content.generated.ts
|
|
29918
|
+
var onboardingSkillMarkdown = "# Onboard your user to auto\n\nYou are a coding agent running inside the user's repository. Your job is to\ntake them from zero to a working auto deployment in one conversation, with\nthe least possible friction. Follow the six beats in order, and run every\nwaiting step in parallel with your own work.\n\n## Ground rules\n\n- This document is choreography, not mechanics. Trust `auto --help` and live\n command output over this document whenever they disagree.\n- Never block on the user. When a step needs a human click (sign-in, Slack\n install, GitHub App), hand them the link and keep working on the next beat\n while they click.\n- Ask before changing anything outside `.auto/`. Editing AGENTS.md happens\n only with the user's explicit opt-in: show the exact block you intend to\n append and wait for a yes.\n- Install exactly one workflow, not a menu. Bias hard toward the lowest\n time-to-first-trigger: a workflow that fires within hours beats one that\n fires next quarter.\n- Talk like a collaborator. One question at a time, short messages, no walls\n of setup output.\n\n## Beat 1: Pitch\n\nExplain what auto is in your own words, grounded in this repository. The\ncanonical framing:\n\n> auto lets you program software factories the same way you program CI/CD.\n> Compose agents and triggers into workflows using simple YAML files, and\n> deploy them into the cloud on merge. Anything that can be described in a\n> standard operating procedure can become a chart of agents and triggers.\n\nLocalize it: name a real procedure you can see in this repo (\"your PR review\nflow could be a chart that reviews every PR against your conventions\").\nClose with why the next beat matters: factory agents work while the user is\nnot looking, so they need a way to reach the user.\n\n## Beat 2: Channel\n\nSay something like: \"I work best when I can reach you proactively \u2014 let's\nget me into your Slack.\" Then, without waiting:\n\n1. Start sign-in with `auto auth login --device` and give the user the\n verification URL. Account, organization, and project setup happen in the\n browser.\n2. Check `auto connections list --available` and start the Slack connection\n (`auto connect slack`), giving the user that link too.\n3. Move straight to Beat 3 while the user clicks. Poll for completion in the\n background; never sit idle waiting for a click.\n\n## Beat 3: Study\n\nBuild a repo dossier while the clicks happen. Explore the codebase and git\nhistory for:\n\n- Stack and layout: languages, frameworks, build and test setup, CI and\n deploy workflows (Beat 6 wires into these).\n- How the team works: PR conventions, review patterns, branch and release\n habits, merge frequency.\n- Tools referenced: issue tracker keys in commits and branches, chat or\n deploy tooling named in docs and workflow files, existing agent config\n (CLAUDE.md, AGENTS.md, .cursor).\n- Live state, using the user's own credentials (git, gh): open PRs, CI\n status, recent activity.\n\nWrite the dossier as structured markdown. It has two consumers: the\nconcierge agent (Beat 4) and your own interview (Beat 5). End it with 2-3\ncandidate workflows from the playbook below, each tied to a concrete signal\nyou found.\n\n## Beat 4: First contact\n\nThe concierge is a session you create in this project, not one that ships\npre-installed. When sign-in, Slack, and the dossier are all ready:\n\n1. Draft the concierge into `.auto/` from the template below. Adapt names,\n reuse an existing profile or environment if the project already has one,\n and verify with `auto apply --dry-run` before applying.\n2. Launch it headlessly with the dossier as the run message:\n `auto run concierge --message <dossier>`. Run messages cap at 20,000\n characters, so distill the dossier to fit; lead with the live state\n (open PRs, CI status) since that is what makes first contact specific.\n\n```yaml\nkind: session\nmetadata:\n name: concierge\nspec:\n profile: concierge\n identity:\n displayName: auto concierge\n username: auto-concierge\n description: This project's auto agent. Ask it to add or change workflows.\n tools:\n chat:\n ref: slack-chat\n initialPrompt: |\n You are this project's auto concierge. If your message contains a repo\n dossier, this is first contact: send the user exactly one Slack message\n via chat.send - one concrete, verifiable observation from the dossier\n plus one offer. Short, specific, never templated. Otherwise the user is\n consulting you: help them add or adjust workflows by editing .auto/\n resources and applying them.\n```\n\nThe profile and the slack-chat tool follow the project's existing\nconventions; if the project has neither, draft minimal ones (see\n`auto apply --help` and the resource examples in the docs).\n\nThe concierge reads the dossier and sends the user one proactive Slack\nmessage: a specific observation about this repo plus one offer. Do not\nattach to the run or take over the terminal; you remain the user's\ninterface.\n\nTell the user to check Slack. The buzz is the point: an agent they just met\nalready knows their codebase and can reach them.\n\nIf the apply fails or the Slack identity is not ready yet, skip this beat\nand let the installed workflow's first firing be first contact instead.\n\n## Beat 5: Interview, then install\n\nBack in the terminal, ask 3-5 questions, one at a time, each grounded in\nthe dossier (\"I see FRA- refs everywhere \u2014 who triages those?\"). Converge on\none workflow. Then:\n\n1. Draft the session YAML into `.auto/sessions/`.\n2. Show a plain-language summary of what will run and when (\"on every PR\n opened, I'll review it against your conventions and report in Slack\").\n3. Get one explicit yes.\n4. If the workflow needs repository events, connect the GitHub App now\n (`auto connect github`) \u2014 this is the moment the ask is motivated. Other\n providers (Linear, Notion, ...) connect only when the chosen workflow\n needs them, never speculatively.\n5. Apply with `auto apply` and confirm the trigger is active. Route the\n workflow's reports to the Slack channel from Beat 2.\n\n## Beat 6: Wire CI to apply on merge\n\nEvery apply so far ran from this terminal under the user's own login. Its\ndurable home is CI: a dry-run plan as a check on every PR, and the real\napply when changes merge \u2014 `.auto/` ships the same way the code does. Do\nthis once the GitHub App is connected and the first apply has succeeded.\n\n1. CI authenticates as a service account, never as the user. Create two \u2014\n the `applier` token lives only on the merge path, while the `read-only`\n token is exposed to PR-triggered runs: it can produce the dry-run plan\n but cannot perform a real apply, and it stays revocable on its own. Pipe\n each token straight into a GitHub secret so it never touches your\n transcript or disk \u2014 with `pipefail` and `jq -re` so a failed create\n cannot silently store an empty secret:\n\n ```sh\n set -o pipefail\n auto service-account create github-actions-auto-apply \\\n --preset applier --json \\\n | jq -re .token | gh secret set AUTO_APPLY_SERVICE_ACCOUNT_TOKEN\n auto service-account create github-actions-auto-apply-dry-run \\\n --preset read-only --json \\\n | jq -re .token | gh secret set AUTO_APPLY_DRY_RUN_SERVICE_ACCOUNT_TOKEN\n ```\n\n Confirm both pipelines exited 0 and `gh secret list` shows both names\n before moving on. If deploys go through a GitHub environment, scope the\n apply secret to it (`gh secret set --env`).\n2. Fit into the deploy process you mapped in Beat 3. If a workflow already\n ships merges, splice two steps in after its deploy succeeds \u2014 plan\n (`auto apply --dry-run`), then `auto apply` \u2014 reusing its checkout and\n Node setup. If nothing deploys from CI yet, add the standalone workflow\n below. Either way, keep the PR dry-run check: it shows reviewers the\n exact create/update/archive plan their merge will execute.\n3. Workflow files live outside `.auto/`, so show the user the file and get\n a yes; commit it on the same branch as the `.auto/` resources.\n\n```yaml\nname: Auto Apply\n\n# Both triggers assume the default branch is main; swap in the repo's\n# actual default branch before committing.\non:\n pull_request:\n branches: [main]\n push:\n branches: [main]\n\npermissions:\n contents: read\n\nconcurrency:\n group: auto-apply-${{ github.event.pull_request.number || github.ref }}\n cancel-in-progress: ${{ github.event_name == 'pull_request' }}\n\njobs:\n plan:\n runs-on: ubuntu-latest\n timeout-minutes: 10\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-node@v4\n with:\n node-version: lts/*\n - run: npx -y --package=@autohq/cli auto apply --dry-run\n env:\n AUTO_API_TOKEN: ${{ secrets.AUTO_APPLY_DRY_RUN_SERVICE_ACCOUNT_TOKEN }}\n\n apply:\n if: ${{ github.event_name == 'push' }}\n needs: plan\n runs-on: ubuntu-latest\n timeout-minutes: 10\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-node@v4\n with:\n node-version: lts/*\n - run: npx -y --package=@autohq/cli auto apply\n env:\n AUTO_API_TOKEN: ${{ secrets.AUTO_APPLY_SERVICE_ACCOUNT_TOKEN }}\n```\n\nAdapt it to the repo: the default branch name, the team's Node setup or\npinned tool versions, and set `AUTO_API_BASE_URL` only if the project runs\nagainst a non-default Auto host. `pull_request` runs from forks do not\nreceive secrets; if fork PRs are routine here, run the dry-run from a\n`pull_request_target` workflow that checks out workflow code from the base\nbranch and only `.auto/` from the PR head.\n\nAfter the PR merges, watch the first run and confirm its plan reports the\nresources you already applied as unchanged. From then on, `.auto/` on the\ndefault branch is the source of truth \u2014 directory apply prunes resources\nthat are no longer declared, so the team changes agents by PR, not by\nterminal.\n\n## Workflow playbook\n\nCandidates, strongest signals, and what confirms fit:\n\n- PR review: frequent PRs, visible review conventions. Confirm: \"what do\n reviewers always catch by hand?\" Fires on the next PR.\n- CI failure triage: CI config plus red or flaky runs in recent history.\n Confirm: \"who notices when main goes red?\" Fires within hours.\n- Issue triage: tracker refs in commits, an untriaged backlog. Confirm:\n \"who looks at new issues today?\" Needs the tracker connected.\n- Daily digest: busy repo, distributed team. Confirm: \"would a morning\n summary of PRs, CI, and issues be useful?\" Fires next morning.\n- Dependency or flaky-test watch: lockfile churn or retry patterns in CI.\n Slower to first fire; prefer the options above for the first install.\n\nEstimate time-to-first-trigger for each candidate you propose, and say it\nout loud when proposing.\n\n## If something is blocked\n\n- Slack needs admin approval: continue without the channel. Finish the\n interview and install; tell the user their agent will appear in Slack once\n the install is approved, and have the concierge retry.\n- Sign-in stalls: the user may not have an invite yet; point them at the\n auto site and pause gracefully rather than failing.\n- `gh secret set` fails (no repo admin rights, gh not authenticated):\n leave the CI workflow in the PR anyway and hand the user the two\n create-and-pipe commands from Beat 6 to run themselves. Tokens are shown\n once and must never be pasted into the conversation.\n- A command disagrees with this document: the command is right. Re-read\n `auto --help` and adapt.\n\n## What you leave behind\n\n- `.auto/` committed on a branch with a PR the user can merge: the\n concierge and workflow session YAML, the CI apply workflow from Beat 6,\n plus `context.md` (the distilled dossier). Write the PR description for\n teammates \u2014 it doubles as the announcement that this repo now has an\n auto agent.\n- With the user's opt-in, an AGENTS.md section that tells every future\n coding agent in this repo that auto exists, what is deployed, and how to\n add workflows.\n- Tell the user the two ways back: talk to the bot in Slack, or run\n `auto onboard --agent` again any time.\n";
|
|
29919
|
+
|
|
30180
29920
|
// src/commands/onboard/commands.ts
|
|
30181
29921
|
function registerOnboardCommands(program, context) {
|
|
30182
29922
|
program.command("onboard").description(
|
|
@@ -30224,7 +29964,7 @@ function registerOrganizationCommands(program, context) {
|
|
|
30224
29964
|
context.writeOutput(organizationLine(organization));
|
|
30225
29965
|
}
|
|
30226
29966
|
});
|
|
30227
|
-
orgs.command("create").description("Create an organization, optionally with an initial project.").requiredOption("--name <name>", "Organization name").option("--project-name <name>", "Initial project name").option("--api-url <url>", "Auto API base URL").option("--server <url>", "Auto web server URL").option("--use", "Set the new organization or project as active").action(async (options) => {
|
|
29967
|
+
orgs.command("create").description("Create an organization, optionally with an initial project.").requiredOption("--name <name>", "Organization name").option("--project-name <name>", "Initial project name").option("--api-url <url>", "Auto API base URL").option("--server <url>", "Auto web server URL").option("--use", "Set the new organization or project as active", true).option("--no-use", "Keep the current active organization and project").action(async (options) => {
|
|
30228
29968
|
const response = await createDirectoryClient(context).createOrganization({
|
|
30229
29969
|
organizationName: options.name,
|
|
30230
29970
|
projectName: options.projectName,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autohq/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.93",
|
|
4
4
|
"license": "SEE LICENSE IN README.md",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"build": "tsup",
|
|
24
24
|
"dev": "tsx src/main.ts",
|
|
25
25
|
"dev:tui": "node ../../scripts/cli-tui-dev-watch.mjs",
|
|
26
|
+
"skill:generate": "tsx scripts/generate-skill-content.ts",
|
|
26
27
|
"test": "npm run test:unit",
|
|
27
28
|
"test:unit": "tsx --test \"test/**/*.unit.test.ts\"",
|
|
28
29
|
"typecheck": "tsc --noEmit"
|