@stackbone/cli 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -0
- package/main.js +230 -89
- package/package.json +1 -1
- package/stackbone-cli-0.3.1.tgz +0 -0
- package/stackbone-cli-0.3.0.tgz +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,58 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.3.1] - 2026-08-06
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`stackbone dev` links a project that arrived without a link.** `.stackbone/`
|
|
15
|
+
is gitignored — by the very block `init` and `link` write — so a project
|
|
16
|
+
cloned from someone else's repository has none, and there was no clean way to
|
|
17
|
+
get one: `dev` refused and pointed at `stackbone init`, which registers a
|
|
18
|
+
_new_ agent and scaffolds its own `package.json` over the project you were
|
|
19
|
+
handed, or at `stackbone link`, which registers an already-deployed box and so
|
|
20
|
+
requires its URL, HMAC secret and image tag. Neither describes "I was given
|
|
21
|
+
this project and want to run it".
|
|
22
|
+
|
|
23
|
+
Now `dev` lists the agents your organization owns, lets you pick one or create
|
|
24
|
+
a new one named after the folder, writes the link, gitignores it, and carries
|
|
25
|
+
on booting. Non-interactive runs (`--json`, `--yes`, CI, no terminal) still
|
|
26
|
+
fail rather than guessing, with a message naming the options that apply.
|
|
27
|
+
|
|
28
|
+
## [0.3.0] - 2026-08-06
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- **`stackbone package` turns a project into a folder someone else can run.**
|
|
33
|
+
It compiles the workspace and writes a two-line Dockerfile over the published
|
|
34
|
+
Stackbone runtime base, a `docker-compose.yml` that also brings up a Postgres
|
|
35
|
+
and a Redis, an `.env` carrying a freshly generated `STACKBONE_SECRET_KEY`,
|
|
36
|
+
and a README written for whoever receives it. On the far end it is two
|
|
37
|
+
commands: `docker compose up -d`, then a health check. Building the image is
|
|
38
|
+
one `COPY` over a base that already carries the server and its dependencies,
|
|
39
|
+
so it takes seconds and needs neither the Stackbone monorepo nor an install.
|
|
40
|
+
|
|
41
|
+
The command always compiles rather than packaging whatever is sitting in
|
|
42
|
+
`dist/`: the folder gets run by someone else, days later, and there is nobody
|
|
43
|
+
left to notice it was built from yesterday's code.
|
|
44
|
+
|
|
45
|
+
`--offline` also saves the image into the folder (around 150 MB) for a
|
|
46
|
+
network that cannot reach a registry. That variant emits no build
|
|
47
|
+
instructions, since the image arrives by loading the archive.
|
|
48
|
+
|
|
49
|
+
Two things the generated files say that nothing said before: **the database
|
|
50
|
+
needs the `pgvector` extension** — without it the first boot applies most of
|
|
51
|
+
the schema and then stops, which reads like a bug in the agent rather than a
|
|
52
|
+
missing extension — and the agent serves on **8080** unless `PORT` says
|
|
53
|
+
otherwise, with `/live` as the health check a managed host should use.
|
|
54
|
+
|
|
55
|
+
### Changed
|
|
56
|
+
|
|
57
|
+
- **`stackbone build` no longer has to be followed by hand-written deployment
|
|
58
|
+
files.** It still emits just the workspace bundle, for anyone who already
|
|
59
|
+
owns their image and their deployment; `stackbone package` is now the route
|
|
60
|
+
to take when you do not.
|
|
61
|
+
|
|
10
62
|
## [0.2.10] - 2026-08-02
|
|
11
63
|
|
|
12
64
|
### Added
|
package/main.js
CHANGED
|
@@ -10576,7 +10576,7 @@ var createBoxAuthGate = (options) => {
|
|
|
10576
10576
|
//#endregion
|
|
10577
10577
|
//#region ../../libs/runtime/workspace-runtime/src/lib/server/contract.ts
|
|
10578
10578
|
init_src$13();
|
|
10579
|
-
var STACKBONE_CLI_BUILD_VERSION = "0.3.
|
|
10579
|
+
var STACKBONE_CLI_BUILD_VERSION = "0.3.1";
|
|
10580
10580
|
/**
|
|
10581
10581
|
* Capabilities the local emulator advertises on `GET /api/contract`, derived
|
|
10582
10582
|
* from the route registry above so the advertised set and the mounted routes
|
|
@@ -53652,6 +53652,175 @@ var assertSdkCompatible = async (ctx, opts) => {
|
|
|
53652
53652
|
return result;
|
|
53653
53653
|
};
|
|
53654
53654
|
//#endregion
|
|
53655
|
+
//#region src/services/project.service.ts
|
|
53656
|
+
var GITIGNORE_MARKER_BEGIN$1 = "# >>> stackbone >>>";
|
|
53657
|
+
var GITIGNORE_BLOCK = [
|
|
53658
|
+
GITIGNORE_MARKER_BEGIN$1,
|
|
53659
|
+
".stackbone/",
|
|
53660
|
+
"node_modules/",
|
|
53661
|
+
"dist/",
|
|
53662
|
+
"# <<< stackbone <<<",
|
|
53663
|
+
""
|
|
53664
|
+
].join("\n");
|
|
53665
|
+
var exists = async (path) => {
|
|
53666
|
+
try {
|
|
53667
|
+
await stat(path);
|
|
53668
|
+
return true;
|
|
53669
|
+
} catch (err) {
|
|
53670
|
+
if (isENOENT(err)) return false;
|
|
53671
|
+
throw err;
|
|
53672
|
+
}
|
|
53673
|
+
};
|
|
53674
|
+
var writeProjectConfig = async (ctx, agent, input, extras = {}) => {
|
|
53675
|
+
const config = {
|
|
53676
|
+
schemaVersion: 1,
|
|
53677
|
+
organizationId: agent.organizationId,
|
|
53678
|
+
agentId: agent.id,
|
|
53679
|
+
controlPlaneUrl: ctx.apiUrl,
|
|
53680
|
+
...extras.localDevInstallationId !== void 0 ? { localDevInstallationId: extras.localDevInstallationId } : {},
|
|
53681
|
+
...extras.organizationSlug !== void 0 ? { organizationSlug: extras.organizationSlug } : {},
|
|
53682
|
+
...extras.agentSlug !== void 0 ? { agentSlug: extras.agentSlug } : {},
|
|
53683
|
+
...extras.starter !== void 0 ? { starter: extras.starter } : {}
|
|
53684
|
+
};
|
|
53685
|
+
await mkdir(join(input.root, ".stackbone"), { recursive: true });
|
|
53686
|
+
await writeFile(join(input.root, ".stackbone", "project.json"), JSON.stringify(config, null, 2));
|
|
53687
|
+
return config;
|
|
53688
|
+
};
|
|
53689
|
+
var ensureGitignore = async (root) => {
|
|
53690
|
+
const path = join(root, ".gitignore");
|
|
53691
|
+
let current = "";
|
|
53692
|
+
try {
|
|
53693
|
+
current = await readFile(path, "utf8");
|
|
53694
|
+
} catch (err) {
|
|
53695
|
+
if (!isENOENT(err)) throw err;
|
|
53696
|
+
}
|
|
53697
|
+
if (current.includes(GITIGNORE_MARKER_BEGIN$1)) return;
|
|
53698
|
+
await writeFile(path, current.length > 0 && !current.endsWith("\n") ? `${current}\n${GITIGNORE_BLOCK}` : `${current}${GITIGNORE_BLOCK}`);
|
|
53699
|
+
};
|
|
53700
|
+
var detectExistingProjectFiles = async (root, paths) => {
|
|
53701
|
+
const checks = await Promise.all(paths.map((p) => exists(join(root, p))));
|
|
53702
|
+
return paths.filter((_, i) => checks[i]);
|
|
53703
|
+
};
|
|
53704
|
+
//#endregion
|
|
53705
|
+
//#region src/services/register-agent.ts
|
|
53706
|
+
var registerAgentEager = async (ctx, input) => {
|
|
53707
|
+
const slug = input.slug ?? input.name;
|
|
53708
|
+
let agent;
|
|
53709
|
+
let created = false;
|
|
53710
|
+
try {
|
|
53711
|
+
agent = await getAgentByOwnerAndSlug(ctx, input.organizationSlug, slug);
|
|
53712
|
+
} catch (err) {
|
|
53713
|
+
if (!(isStackboneCliError(err) && err.code === "not_found")) throw err;
|
|
53714
|
+
agent = await createAgent(ctx, {
|
|
53715
|
+
organizationSlug: input.organizationSlug,
|
|
53716
|
+
name: input.name,
|
|
53717
|
+
slug,
|
|
53718
|
+
...input.description !== void 0 ? { description: input.description } : {}
|
|
53719
|
+
});
|
|
53720
|
+
created = true;
|
|
53721
|
+
}
|
|
53722
|
+
const localDev = await upsertLocalDevInstallation(ctx, {
|
|
53723
|
+
creatorOrganizationSlug: input.organizationSlug,
|
|
53724
|
+
agentTemplateSlug: agent.slug
|
|
53725
|
+
});
|
|
53726
|
+
return {
|
|
53727
|
+
agent,
|
|
53728
|
+
localDev,
|
|
53729
|
+
created
|
|
53730
|
+
};
|
|
53731
|
+
};
|
|
53732
|
+
//#endregion
|
|
53733
|
+
//#region src/commands/dev/link-on-demand.ts
|
|
53734
|
+
/** Sentinel for the "none of these" row in the agent picker. */
|
|
53735
|
+
var CREATE_NEW = "\0create-new";
|
|
53736
|
+
/**
|
|
53737
|
+
* A control-plane slug from a folder name: lowercase, non-alphanumerics folded
|
|
53738
|
+
* to single dashes, no leading or trailing dash. A folder called `Astex Email
|
|
53739
|
+
* Agent` should not fail the create call for a reason nobody typed.
|
|
53740
|
+
*/
|
|
53741
|
+
var slugifyProjectName = (name) => name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
53742
|
+
var promptForAgentInteractively = async (agents) => {
|
|
53743
|
+
if (agents.length === 0) return null;
|
|
53744
|
+
const value = await select({
|
|
53745
|
+
message: "This project is not linked to an agent yet. Which one is it?",
|
|
53746
|
+
options: [...agents.map((a) => ({
|
|
53747
|
+
value: a.slug,
|
|
53748
|
+
label: a.name,
|
|
53749
|
+
hint: a.slug
|
|
53750
|
+
})), {
|
|
53751
|
+
value: CREATE_NEW,
|
|
53752
|
+
label: "Create a new agent",
|
|
53753
|
+
hint: "registers one for this project"
|
|
53754
|
+
}]
|
|
53755
|
+
});
|
|
53756
|
+
if (isCancel(value)) throw new StackboneCliError({
|
|
53757
|
+
code: "no_project",
|
|
53758
|
+
message: "No agent selected, so this directory is still unlinked.",
|
|
53759
|
+
suggestion: "Run `stackbone dev` again and pick an agent, or create one in Studio."
|
|
53760
|
+
});
|
|
53761
|
+
return value === CREATE_NEW ? null : String(value);
|
|
53762
|
+
};
|
|
53763
|
+
var promptForNewNameInteractively = async (suggested) => {
|
|
53764
|
+
const value = await text$1({
|
|
53765
|
+
message: "Name for the new agent",
|
|
53766
|
+
initialValue: suggested,
|
|
53767
|
+
validate: (v) => slugifyProjectName(v ?? "").length === 0 ? "Pick a name with letters or numbers in it." : void 0
|
|
53768
|
+
});
|
|
53769
|
+
if (isCancel(value)) throw new StackboneCliError({
|
|
53770
|
+
code: "no_project",
|
|
53771
|
+
message: "No name given, so no agent was created.",
|
|
53772
|
+
suggestion: "Run `stackbone dev` again to pick or create one."
|
|
53773
|
+
});
|
|
53774
|
+
return String(value);
|
|
53775
|
+
};
|
|
53776
|
+
/**
|
|
53777
|
+
* The message a non-interactive run gets. Kept apart from the interactive path
|
|
53778
|
+
* because it is the one a CI log will carry, and the old text sent the reader to
|
|
53779
|
+
* two commands that both do the wrong thing here.
|
|
53780
|
+
*/
|
|
53781
|
+
var unlinkedProjectError = () => new StackboneCliError({
|
|
53782
|
+
code: "no_project",
|
|
53783
|
+
message: "No project linked in this directory, and nothing here can ask which agent it is.",
|
|
53784
|
+
suggestion: "Run `stackbone dev` in a terminal to pick an agent, or write .stackbone/project.json yourself (`stackbone agents get <slug>` prints the id). `stackbone init` scaffolds a NEW project over this one — not what you want for a project you were handed."
|
|
53785
|
+
});
|
|
53786
|
+
/**
|
|
53787
|
+
* Link this directory to an agent, asking which one, and return the config the
|
|
53788
|
+
* boot needs. Throws {@link unlinkedProjectError} when nobody can be asked.
|
|
53789
|
+
*/
|
|
53790
|
+
var linkProjectOnDemand = async (ctx, projectRoot, deps = {}) => {
|
|
53791
|
+
if (!canPromptInteractively(ctx)) throw unlinkedProjectError();
|
|
53792
|
+
const list = deps.listAgents ?? listAgents;
|
|
53793
|
+
const activeOrg = deps.getActiveOrganization ?? getActiveOrganization;
|
|
53794
|
+
const register = deps.registerAgentEager ?? registerAgentEager;
|
|
53795
|
+
const askAgent = deps.promptForAgent ?? promptForAgentInteractively;
|
|
53796
|
+
const askName = deps.promptForNewName ?? promptForNewNameInteractively;
|
|
53797
|
+
const org = await activeOrg(ctx);
|
|
53798
|
+
const name = await askAgent((await list(ctx)).map((a) => ({
|
|
53799
|
+
slug: a.slug,
|
|
53800
|
+
name: a.name ?? a.slug
|
|
53801
|
+
}))) ?? slugifyProjectName(await askName(basename(projectRoot)));
|
|
53802
|
+
if (name.length === 0) throw new StackboneCliError({
|
|
53803
|
+
code: "generic",
|
|
53804
|
+
message: "That name has no letters or numbers in it, so it cannot become an agent slug.",
|
|
53805
|
+
suggestion: "Run `stackbone dev` again and give the agent a name."
|
|
53806
|
+
});
|
|
53807
|
+
const registration = await register(ctx, {
|
|
53808
|
+
organizationSlug: org.slug,
|
|
53809
|
+
name
|
|
53810
|
+
});
|
|
53811
|
+
const config = await writeProjectConfig(ctx, registration.agent, {
|
|
53812
|
+
root: projectRoot,
|
|
53813
|
+
force: false
|
|
53814
|
+
}, {
|
|
53815
|
+
localDevInstallationId: registration.localDev.id,
|
|
53816
|
+
organizationSlug: registration.localDev.organizationSlug,
|
|
53817
|
+
agentSlug: registration.localDev.agentSlug
|
|
53818
|
+
});
|
|
53819
|
+
await ensureGitignore(projectRoot);
|
|
53820
|
+
log.success(registration.created ? `Registered agent "${registration.agent.slug}" and linked this directory to it.` : `Linked this directory to agent "${registration.agent.slug}".`);
|
|
53821
|
+
return config;
|
|
53822
|
+
};
|
|
53823
|
+
//#endregion
|
|
53655
53824
|
//#region src/commands/dev/print-contract.ts
|
|
53656
53825
|
var defaultWriteStdout = (chunk) => {
|
|
53657
53826
|
process.stdout.write(chunk);
|
|
@@ -53766,12 +53935,7 @@ var createReloadRenderer = () => {
|
|
|
53766
53935
|
};
|
|
53767
53936
|
};
|
|
53768
53937
|
var buildHandler$2 = (ctx, flags) => protectedCommand(async (innerCtx) => {
|
|
53769
|
-
const config = await innerCtx.projectConfig.read();
|
|
53770
|
-
if (!config) throw new StackboneCliError({
|
|
53771
|
-
code: "no_project",
|
|
53772
|
-
message: "No project linked in this directory",
|
|
53773
|
-
suggestion: "Run `stackbone init` or `stackbone link` first"
|
|
53774
|
-
});
|
|
53938
|
+
const config = await innerCtx.projectConfig.read() ?? await linkProjectOnDemand(innerCtx, resolve(innerCtx.cwd));
|
|
53775
53939
|
if (!innerCtx.flags.json) intro(formatBrandHeader({
|
|
53776
53940
|
version: STACKBONE_CLI_BUILD_VERSION,
|
|
53777
53941
|
command: "dev",
|
|
@@ -54785,6 +54949,18 @@ it. The emulator API listens on \`http://127.0.0.1:4242\` by default. The tunnel
|
|
|
54785
54949
|
mandatory: it fills the \`local_tunnel_url\` field on the \`installation\` row and
|
|
54786
54950
|
yields the Studio deeplink.
|
|
54787
54951
|
|
|
54952
|
+
**A project that was handed to you links itself here.** \`.stackbone/\` is
|
|
54953
|
+
gitignored, so a project cloned from someone else's repository arrives with no
|
|
54954
|
+
link. \`dev\` lists the agents your organization owns, lets you pick one or create
|
|
54955
|
+
a new one named after the folder, writes \`.stackbone/project.json\` and carries on
|
|
54956
|
+
booting. Neither of the alternatives fits this case: \`stackbone init\` registers a
|
|
54957
|
+
_new_ agent and scaffolds its own \`package.json\` over the project you just
|
|
54958
|
+
received, and \`stackbone link\` is for registering a box you already deployed, so
|
|
54959
|
+
it requires its URL, HMAC secret and image tag.
|
|
54960
|
+
|
|
54961
|
+
Non-interactive runs (\`--json\`, \`--yes\`, CI, no terminal) still fail rather than
|
|
54962
|
+
guessing, and say what to do instead.
|
|
54963
|
+
|
|
54788
54964
|
The project is a **workspace**: every \`deep-agents/<name>/index.ts\`, plus
|
|
54789
54965
|
every \`workflows/<name>.workflow.ts\`, discovered by convention (with an
|
|
54790
54966
|
explicit \`stackbone.config.ts\` override for workflows). Boot:
|
|
@@ -56446,10 +56622,12 @@ them.
|
|
|
56446
56622
|
the CLI must run from WSL2, Docker Desktop with WSL2 integration enabled
|
|
56447
56623
|
(or Docker Engine inside the Ubuntu distro) covers it.
|
|
56448
56624
|
- **A project:** run \`stackbone init\` to scaffold a workspace shell (a
|
|
56449
|
-
\`deep-agents/\` folder, a \`workflows/\` folder and supporting files)
|
|
56450
|
-
|
|
56451
|
-
\`stackbone add
|
|
56452
|
-
|
|
56625
|
+
\`deep-agents/\` folder, a \`workflows/\` folder and supporting files). Add
|
|
56626
|
+
pieces over time with \`stackbone add agent <name>\`,
|
|
56627
|
+
\`stackbone add workflow <name>\` or \`stackbone add workflow-agent <name>\`.
|
|
56628
|
+
A project someone handed you needs none of that: it arrives unlinked, and
|
|
56629
|
+
\`dev\` asks which agent it is. See
|
|
56630
|
+
[A project that arrived without a link](#a-project-that-arrived-without-a-link).
|
|
56453
56631
|
- **At least one agent or workflow:** \`stackbone dev\` discovers your workspace
|
|
56454
56632
|
by convention, any \`deep-agents/<name>/index.ts\` (or a
|
|
56455
56633
|
\`workflows/<name>.workflow.ts\`) is enough to activate the runtime. A
|
|
@@ -56461,6 +56639,27 @@ them.
|
|
|
56461
56639
|
\`STACKBONE_FRPC_BIN\` to point at a system install when your environment
|
|
56462
56640
|
forbids untrusted binaries.
|
|
56463
56641
|
|
|
56642
|
+
## A project that arrived without a link
|
|
56643
|
+
|
|
56644
|
+
A project you cloned from someone else's repository has no link to an agent.
|
|
56645
|
+
\`.stackbone/\` is gitignored, so the link never travels with the code.
|
|
56646
|
+
|
|
56647
|
+
\`stackbone dev\` does not stop for that. It lists the agents your organization
|
|
56648
|
+
owns, lets you pick one or create a new one named after the folder, writes
|
|
56649
|
+
\`.stackbone/project.json\`, adds it to \`.gitignore\` and carries on booting.
|
|
56650
|
+
|
|
56651
|
+
Neither of the other commands fits this case:
|
|
56652
|
+
|
|
56653
|
+
- \`stackbone init\` registers a **new** agent and writes its own \`package.json\`,
|
|
56654
|
+
\`tsconfig.json\` and scaffold over the project you were just handed.
|
|
56655
|
+
- \`stackbone link\` registers a box you have already deployed, so it requires
|
|
56656
|
+
that box's URL, HMAC secret and image tag.
|
|
56657
|
+
|
|
56658
|
+
A run that cannot ask fails instead of guessing, and says what to do instead.
|
|
56659
|
+
That covers any run without a terminal, a \`CI\` environment variable, \`--yes\` or
|
|
56660
|
+
\`--json\`. See
|
|
56661
|
+
[This directory is not linked to an agent](/docs/cli/troubleshooting#this-directory-is-not-linked-to-an-agent).
|
|
56662
|
+
|
|
56464
56663
|
## Synopsis
|
|
56465
56664
|
|
|
56466
56665
|
\`\`\`sh
|
|
@@ -57118,6 +57317,26 @@ Stages you do not use are skipped: no workflows means no \`workflows\` or
|
|
|
57118
57317
|
|
|
57119
57318
|
## \`stackbone dev\` failures
|
|
57120
57319
|
|
|
57320
|
+
### This directory is not linked to an agent
|
|
57321
|
+
|
|
57322
|
+
**Symptom:** \`stackbone dev\` exits before any stage runs with \`no_project\` and
|
|
57323
|
+
"No project linked in this directory, and nothing here can ask which agent it
|
|
57324
|
+
is."
|
|
57325
|
+
|
|
57326
|
+
**Cause:** the project has no \`.stackbone/project.json\` and this run cannot
|
|
57327
|
+
prompt for one. \`.stackbone/\` is gitignored, so a project cloned from someone
|
|
57328
|
+
else's repository always arrives unlinked, and a run without a terminal (or one
|
|
57329
|
+
with a \`CI\` environment variable, \`--yes\` or \`--json\`) has nobody to ask.
|
|
57330
|
+
|
|
57331
|
+
**Fix:** run \`stackbone dev\` once from a terminal and pick the agent. It writes
|
|
57332
|
+
the link, and every later run reuses it, scripted or not. To link without a
|
|
57333
|
+
prompt, write \`.stackbone/project.json\` yourself; \`stackbone agents get <slug>\`
|
|
57334
|
+
prints the agent id it needs.
|
|
57335
|
+
|
|
57336
|
+
Reaching for \`stackbone init\` here is the common mistake: it registers a new
|
|
57337
|
+
agent and scaffolds over the project you were handed. Full contract:
|
|
57338
|
+
[A project that arrived without a link](/docs/cli/local-development#a-project-that-arrived-without-a-link).
|
|
57339
|
+
|
|
57121
57340
|
### Docker not running, or the datastore is unhealthy
|
|
57122
57341
|
|
|
57123
57342
|
**Symptom:** the \`docker\` stage fails, or \`platform-migrations\` /
|
|
@@ -62648,84 +62867,6 @@ var createHitlCommand = defineGroup({
|
|
|
62648
62867
|
}
|
|
62649
62868
|
});
|
|
62650
62869
|
//#endregion
|
|
62651
|
-
//#region src/services/register-agent.ts
|
|
62652
|
-
var registerAgentEager = async (ctx, input) => {
|
|
62653
|
-
const slug = input.slug ?? input.name;
|
|
62654
|
-
let agent;
|
|
62655
|
-
let created = false;
|
|
62656
|
-
try {
|
|
62657
|
-
agent = await getAgentByOwnerAndSlug(ctx, input.organizationSlug, slug);
|
|
62658
|
-
} catch (err) {
|
|
62659
|
-
if (!(isStackboneCliError(err) && err.code === "not_found")) throw err;
|
|
62660
|
-
agent = await createAgent(ctx, {
|
|
62661
|
-
organizationSlug: input.organizationSlug,
|
|
62662
|
-
name: input.name,
|
|
62663
|
-
slug,
|
|
62664
|
-
...input.description !== void 0 ? { description: input.description } : {}
|
|
62665
|
-
});
|
|
62666
|
-
created = true;
|
|
62667
|
-
}
|
|
62668
|
-
const localDev = await upsertLocalDevInstallation(ctx, {
|
|
62669
|
-
creatorOrganizationSlug: input.organizationSlug,
|
|
62670
|
-
agentTemplateSlug: agent.slug
|
|
62671
|
-
});
|
|
62672
|
-
return {
|
|
62673
|
-
agent,
|
|
62674
|
-
localDev,
|
|
62675
|
-
created
|
|
62676
|
-
};
|
|
62677
|
-
};
|
|
62678
|
-
//#endregion
|
|
62679
|
-
//#region src/services/project.service.ts
|
|
62680
|
-
var GITIGNORE_MARKER_BEGIN$1 = "# >>> stackbone >>>";
|
|
62681
|
-
var GITIGNORE_BLOCK = [
|
|
62682
|
-
GITIGNORE_MARKER_BEGIN$1,
|
|
62683
|
-
".stackbone/",
|
|
62684
|
-
"node_modules/",
|
|
62685
|
-
"dist/",
|
|
62686
|
-
"# <<< stackbone <<<",
|
|
62687
|
-
""
|
|
62688
|
-
].join("\n");
|
|
62689
|
-
var exists = async (path) => {
|
|
62690
|
-
try {
|
|
62691
|
-
await stat(path);
|
|
62692
|
-
return true;
|
|
62693
|
-
} catch (err) {
|
|
62694
|
-
if (isENOENT(err)) return false;
|
|
62695
|
-
throw err;
|
|
62696
|
-
}
|
|
62697
|
-
};
|
|
62698
|
-
var writeProjectConfig = async (ctx, agent, input, extras = {}) => {
|
|
62699
|
-
const config = {
|
|
62700
|
-
schemaVersion: 1,
|
|
62701
|
-
organizationId: agent.organizationId,
|
|
62702
|
-
agentId: agent.id,
|
|
62703
|
-
controlPlaneUrl: ctx.apiUrl,
|
|
62704
|
-
...extras.localDevInstallationId !== void 0 ? { localDevInstallationId: extras.localDevInstallationId } : {},
|
|
62705
|
-
...extras.organizationSlug !== void 0 ? { organizationSlug: extras.organizationSlug } : {},
|
|
62706
|
-
...extras.agentSlug !== void 0 ? { agentSlug: extras.agentSlug } : {},
|
|
62707
|
-
...extras.starter !== void 0 ? { starter: extras.starter } : {}
|
|
62708
|
-
};
|
|
62709
|
-
await mkdir(join(input.root, ".stackbone"), { recursive: true });
|
|
62710
|
-
await writeFile(join(input.root, ".stackbone", "project.json"), JSON.stringify(config, null, 2));
|
|
62711
|
-
return config;
|
|
62712
|
-
};
|
|
62713
|
-
var ensureGitignore = async (root) => {
|
|
62714
|
-
const path = join(root, ".gitignore");
|
|
62715
|
-
let current = "";
|
|
62716
|
-
try {
|
|
62717
|
-
current = await readFile(path, "utf8");
|
|
62718
|
-
} catch (err) {
|
|
62719
|
-
if (!isENOENT(err)) throw err;
|
|
62720
|
-
}
|
|
62721
|
-
if (current.includes(GITIGNORE_MARKER_BEGIN$1)) return;
|
|
62722
|
-
await writeFile(path, current.length > 0 && !current.endsWith("\n") ? `${current}\n${GITIGNORE_BLOCK}` : `${current}${GITIGNORE_BLOCK}`);
|
|
62723
|
-
};
|
|
62724
|
-
var detectExistingProjectFiles = async (root, paths) => {
|
|
62725
|
-
const checks = await Promise.all(paths.map((p) => exists(join(root, p))));
|
|
62726
|
-
return paths.filter((_, i) => checks[i]);
|
|
62727
|
-
};
|
|
62728
|
-
//#endregion
|
|
62729
62870
|
//#region src/services/skills.service.ts
|
|
62730
62871
|
var execFileAsync = promisify(execFile);
|
|
62731
62872
|
/**
|
package/package.json
CHANGED
|
Binary file
|
package/stackbone-cli-0.3.0.tgz
DELETED
|
Binary file
|