agents-inc 0.165.0 → 0.167.0
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 +23 -0
- package/dist/{chunk-B5UUHBAM.js → chunk-25MPBIK3.js} +3 -3
- package/dist/{chunk-VPJUCVU7.js → chunk-2VUYFTUB.js} +6 -6
- package/dist/{chunk-BGU25XAY.js → chunk-4NDBUJHK.js} +8 -8
- package/dist/{chunk-5M3PQNXI.js → chunk-6L75SQZU.js} +2 -2
- package/dist/{chunk-YNOOZFIB.js → chunk-6LF4CQBY.js} +2 -2
- package/dist/{chunk-UBSSIIWD.js → chunk-7JNJ52CD.js} +4 -4
- package/dist/{chunk-IM45LLQX.js → chunk-A4KDXNOT.js} +47 -137
- package/dist/chunk-A4KDXNOT.js.map +1 -0
- package/dist/{chunk-6SW6SB7H.js → chunk-DAIEQJIF.js} +3 -3
- package/dist/{chunk-AQXKAPCD.js → chunk-ENGYJCTF.js} +1 -3
- package/dist/{chunk-AQXKAPCD.js.map → chunk-ENGYJCTF.js.map} +1 -1
- package/dist/{chunk-6AIZPSEI.js → chunk-G4JK7WVO.js} +15 -16
- package/dist/chunk-G4JK7WVO.js.map +1 -0
- package/dist/{chunk-WTANOSXK.js → chunk-G6UREQ4V.js} +9 -9
- package/dist/chunk-G6UREQ4V.js.map +1 -0
- package/dist/{chunk-V5CWACR5.js → chunk-GE3WKJ6Q.js} +4 -4
- package/dist/{chunk-V5CWACR5.js.map → chunk-GE3WKJ6Q.js.map} +1 -1
- package/dist/{chunk-JV4TKXEN.js → chunk-HHIYT3PI.js} +4 -4
- package/dist/{chunk-WIFIAQZU.js → chunk-HWEKHVLE.js} +6 -6
- package/dist/{chunk-5P26XBZO.js → chunk-JQRJQ4SS.js} +3 -3
- package/dist/{chunk-Y5SNGMB7.js → chunk-LFWLEDUG.js} +6 -6
- package/dist/{chunk-TRTVOVHR.js → chunk-MAWNVT2C.js} +4 -4
- package/dist/{chunk-57KU6SPH.js → chunk-MPTNC32T.js} +3 -3
- package/dist/{chunk-MBUGQI2M.js → chunk-NBXXFIIW.js} +3 -3
- package/dist/{chunk-42TNV2TK.js → chunk-PMJWD27C.js} +3 -3
- package/dist/{chunk-X2KUI7V3.js → chunk-PNB3524H.js} +5 -5
- package/dist/{chunk-IVNKU4DM.js → chunk-PXWG7KFO.js} +2 -2
- package/dist/chunk-PXWG7KFO.js.map +1 -0
- package/dist/{chunk-LXXGZAD3.js → chunk-QHDPLLK6.js} +3 -3
- package/dist/{chunk-TV5Y53R2.js → chunk-RAHSOJQ2.js} +2 -2
- package/dist/{chunk-CTUJO23Z.js → chunk-RZDXDMT6.js} +2 -2
- package/dist/{chunk-PSX7CT6V.js → chunk-SAYZWCH6.js} +2 -2
- package/dist/{chunk-MWDY76MT.js → chunk-SCOQ34YM.js} +2 -2
- package/dist/{chunk-4C7GL4F7.js → chunk-SXVHSOTH.js} +4 -4
- package/dist/{chunk-E6CHHXGY.js → chunk-T6UWJAB3.js} +2 -2
- package/dist/{chunk-F2ZWFWTP.js → chunk-TODCQFRB.js} +2 -2
- package/dist/{chunk-CEBDGZID.js → chunk-TTY6DPJN.js} +3 -3
- package/dist/{chunk-CBMAO6OP.js → chunk-TZ2YJJKK.js} +5 -5
- package/dist/{chunk-WSGX4IWC.js → chunk-V3I7VQ7N.js} +4 -4
- package/dist/{chunk-GKPW33FP.js → chunk-V5WXIM2F.js} +2 -2
- package/dist/{chunk-6CY6PW5X.js → chunk-VAPTVR3J.js} +3 -3
- package/dist/{chunk-CK5RM3DJ.js → chunk-WVUDLKIO.js} +2 -2
- package/dist/{chunk-HR4YDSJK.js → chunk-WWIFNPJG.js} +12 -12
- package/dist/{chunk-P3KJCYSR.js → chunk-XZEVWPX6.js} +7 -7
- package/dist/{chunk-AAWZED5M.js → chunk-Y3VIRVVE.js} +10 -58
- package/dist/chunk-Y3VIRVVE.js.map +1 -0
- package/dist/{chunk-XATIKM3P.js → chunk-Y47EV74W.js} +7 -7
- package/dist/{chunk-UR3RRTPO.js → chunk-ZR4YPKXQ.js} +4 -4
- package/dist/{chunk-UCORXS4D.js → chunk-ZXKBERQU.js} +2 -2
- package/dist/commands/build/marketplace.js +6 -6
- package/dist/commands/build/plugins.js +8 -8
- package/dist/commands/compile.js +14 -15
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/doctor.js +59 -156
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +40 -41
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +12 -13
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/init.js +39 -39
- package/dist/commands/list.js +9 -9
- package/dist/commands/new/marketplace.js +6 -6
- package/dist/commands/search.js +11 -11
- package/dist/commands/share.js +11 -12
- package/dist/commands/share.js.map +1 -1
- package/dist/commands/uninstall.js +39 -69
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +8 -9
- package/dist/commands/update.js.map +1 -1
- package/dist/components/common/removal-plan-confirm.js +2 -2
- package/dist/components/common/select-list.js +2 -2
- package/dist/components/wizard/category-grid.js +4 -4
- package/dist/components/wizard/checkbox-grid.js +4 -4
- package/dist/components/wizard/domain-selection.js +9 -9
- package/dist/components/wizard/run-wizard-session.js +26 -26
- package/dist/components/wizard/scroll-affordance.js +2 -2
- package/dist/components/wizard/skill-agent-summary.js +5 -5
- package/dist/components/wizard/source-grid.js +5 -5
- package/dist/components/wizard/stack-selection.js +7 -7
- package/dist/components/wizard/step-agents.js +8 -8
- package/dist/components/wizard/step-build.js +7 -7
- package/dist/components/wizard/step-confirm.js +9 -9
- package/dist/components/wizard/step-sources.js +8 -8
- package/dist/components/wizard/step-stack.js +8 -8
- package/dist/components/wizard/summary-panel.js +8 -8
- package/dist/components/wizard/toast.js +2 -2
- package/dist/components/wizard/wizard-layout.js +12 -12
- package/dist/components/wizard/wizard-tabs.js +2 -2
- package/dist/components/wizard/wizard.js +25 -25
- package/dist/hooks/init.js +50 -40
- package/dist/hooks/init.js.map +1 -1
- package/dist/load-agent-defs-3C27ENC7.js +14 -0
- package/dist/recompile-project-agents-DGNBCU3N.js +18 -0
- package/dist/{source-loader-RWZAYJ7E.js → source-loader-7KZ3MD5O.js} +4 -4
- package/dist/stores/wizard-store.js +4 -4
- package/package.json +1 -1
- package/src/schemas/project-config.schema.json +1 -1
- package/src/schemas/project-source-config.schema.json +1 -1
- package/dist/chunk-6AIZPSEI.js.map +0 -1
- package/dist/chunk-AAWZED5M.js.map +0 -1
- package/dist/chunk-IM45LLQX.js.map +0 -1
- package/dist/chunk-IVNKU4DM.js.map +0 -1
- package/dist/chunk-WTANOSXK.js.map +0 -1
- package/dist/load-agent-defs-JHLE6MAE.js +0 -14
- package/dist/recompile-project-agents-ZPP5NOLZ.js +0 -18
- /package/dist/{chunk-B5UUHBAM.js.map → chunk-25MPBIK3.js.map} +0 -0
- /package/dist/{chunk-VPJUCVU7.js.map → chunk-2VUYFTUB.js.map} +0 -0
- /package/dist/{chunk-BGU25XAY.js.map → chunk-4NDBUJHK.js.map} +0 -0
- /package/dist/{chunk-5M3PQNXI.js.map → chunk-6L75SQZU.js.map} +0 -0
- /package/dist/{chunk-YNOOZFIB.js.map → chunk-6LF4CQBY.js.map} +0 -0
- /package/dist/{chunk-UBSSIIWD.js.map → chunk-7JNJ52CD.js.map} +0 -0
- /package/dist/{chunk-6SW6SB7H.js.map → chunk-DAIEQJIF.js.map} +0 -0
- /package/dist/{chunk-JV4TKXEN.js.map → chunk-HHIYT3PI.js.map} +0 -0
- /package/dist/{chunk-WIFIAQZU.js.map → chunk-HWEKHVLE.js.map} +0 -0
- /package/dist/{chunk-5P26XBZO.js.map → chunk-JQRJQ4SS.js.map} +0 -0
- /package/dist/{chunk-Y5SNGMB7.js.map → chunk-LFWLEDUG.js.map} +0 -0
- /package/dist/{chunk-TRTVOVHR.js.map → chunk-MAWNVT2C.js.map} +0 -0
- /package/dist/{chunk-57KU6SPH.js.map → chunk-MPTNC32T.js.map} +0 -0
- /package/dist/{chunk-MBUGQI2M.js.map → chunk-NBXXFIIW.js.map} +0 -0
- /package/dist/{chunk-42TNV2TK.js.map → chunk-PMJWD27C.js.map} +0 -0
- /package/dist/{chunk-X2KUI7V3.js.map → chunk-PNB3524H.js.map} +0 -0
- /package/dist/{chunk-LXXGZAD3.js.map → chunk-QHDPLLK6.js.map} +0 -0
- /package/dist/{chunk-TV5Y53R2.js.map → chunk-RAHSOJQ2.js.map} +0 -0
- /package/dist/{chunk-CTUJO23Z.js.map → chunk-RZDXDMT6.js.map} +0 -0
- /package/dist/{chunk-PSX7CT6V.js.map → chunk-SAYZWCH6.js.map} +0 -0
- /package/dist/{chunk-MWDY76MT.js.map → chunk-SCOQ34YM.js.map} +0 -0
- /package/dist/{chunk-4C7GL4F7.js.map → chunk-SXVHSOTH.js.map} +0 -0
- /package/dist/{chunk-E6CHHXGY.js.map → chunk-T6UWJAB3.js.map} +0 -0
- /package/dist/{chunk-F2ZWFWTP.js.map → chunk-TODCQFRB.js.map} +0 -0
- /package/dist/{chunk-CEBDGZID.js.map → chunk-TTY6DPJN.js.map} +0 -0
- /package/dist/{chunk-CBMAO6OP.js.map → chunk-TZ2YJJKK.js.map} +0 -0
- /package/dist/{chunk-WSGX4IWC.js.map → chunk-V3I7VQ7N.js.map} +0 -0
- /package/dist/{chunk-GKPW33FP.js.map → chunk-V5WXIM2F.js.map} +0 -0
- /package/dist/{chunk-6CY6PW5X.js.map → chunk-VAPTVR3J.js.map} +0 -0
- /package/dist/{chunk-CK5RM3DJ.js.map → chunk-WVUDLKIO.js.map} +0 -0
- /package/dist/{chunk-HR4YDSJK.js.map → chunk-WWIFNPJG.js.map} +0 -0
- /package/dist/{chunk-P3KJCYSR.js.map → chunk-XZEVWPX6.js.map} +0 -0
- /package/dist/{chunk-XATIKM3P.js.map → chunk-Y47EV74W.js.map} +0 -0
- /package/dist/{chunk-UR3RRTPO.js.map → chunk-ZR4YPKXQ.js.map} +0 -0
- /package/dist/{chunk-UCORXS4D.js.map → chunk-ZXKBERQU.js.map} +0 -0
- /package/dist/{load-agent-defs-JHLE6MAE.js.map → load-agent-defs-3C27ENC7.js.map} +0 -0
- /package/dist/{recompile-project-agents-ZPP5NOLZ.js.map → recompile-project-agents-DGNBCU3N.js.map} +0 -0
- /package/dist/{source-loader-RWZAYJ7E.js.map → source-loader-7KZ3MD5O.js.map} +0 -0
package/dist/commands/eject.js
CHANGED
|
@@ -5,22 +5,22 @@ import {
|
|
|
5
5
|
loadSource,
|
|
6
6
|
mutateGlobal,
|
|
7
7
|
writeProjectPartial
|
|
8
|
-
} from "../chunk-
|
|
9
|
-
import "../chunk-
|
|
10
|
-
import "../chunk-
|
|
11
|
-
import "../chunk-
|
|
12
|
-
import "../chunk-
|
|
8
|
+
} from "../chunk-G6UREQ4V.js";
|
|
9
|
+
import "../chunk-HWEKHVLE.js";
|
|
10
|
+
import "../chunk-PMJWD27C.js";
|
|
11
|
+
import "../chunk-ZR4YPKXQ.js";
|
|
12
|
+
import "../chunk-GE3WKJ6Q.js";
|
|
13
13
|
import {
|
|
14
14
|
providerFlag,
|
|
15
15
|
providerNamedBy,
|
|
16
16
|
refuseAnAmbiguousInstallation
|
|
17
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-NBXXFIIW.js";
|
|
18
18
|
import {
|
|
19
19
|
BaseCommand,
|
|
20
20
|
EXIT_CODES
|
|
21
|
-
} from "../chunk-
|
|
22
|
-
import "../chunk-
|
|
23
|
-
import "../chunk-
|
|
21
|
+
} from "../chunk-Y3VIRVVE.js";
|
|
22
|
+
import "../chunk-VAPTVR3J.js";
|
|
23
|
+
import "../chunk-RZDXDMT6.js";
|
|
24
24
|
import {
|
|
25
25
|
INCOMPLETE_WORK_RECOVERY,
|
|
26
26
|
INFO_MESSAGES,
|
|
@@ -39,15 +39,15 @@ import {
|
|
|
39
39
|
relativeConfigPath,
|
|
40
40
|
resolveSource,
|
|
41
41
|
sourceFolderInUse
|
|
42
|
-
} from "../chunk-
|
|
42
|
+
} from "../chunk-A4KDXNOT.js";
|
|
43
43
|
import {
|
|
44
44
|
matrix
|
|
45
|
-
} from "../chunk-
|
|
45
|
+
} from "../chunk-V5WXIM2F.js";
|
|
46
46
|
import {
|
|
47
47
|
DIRS,
|
|
48
48
|
LOCAL_SKILLS_PATH,
|
|
49
49
|
PROJECT_ROOT
|
|
50
|
-
} from "../chunk-
|
|
50
|
+
} from "../chunk-ENGYJCTF.js";
|
|
51
51
|
import "../chunk-OI2H6M5I.js";
|
|
52
52
|
|
|
53
53
|
// src/cli/commands/eject.ts
|
|
@@ -116,7 +116,6 @@ var Eject = class _Eject extends BaseCommand {
|
|
|
116
116
|
(message) => this.error(message, { exit: EXIT_CODES.INVALID_ARGS })
|
|
117
117
|
);
|
|
118
118
|
await this.ensureConfigReadable(projectDir);
|
|
119
|
-
await this.settleSourceLayoutBeforeWriting(projectDir);
|
|
120
119
|
const ejectType = this.validateEjectType(args.type);
|
|
121
120
|
const outputBase = await this.resolveOutputBase(flags, projectDir);
|
|
122
121
|
this.printHeader(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/commands/eject.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport os from \"os\";\nimport { BaseCommand } from \"../base-command.js\";\nimport { copy, ensureDir, directoryExists, fileExists, listDirectories } from \"../utils/fs.js\";\nimport { DIRS, LOCAL_SKILLS_PATH, PROJECT_ROOT } from \"../consts.js\";\nimport {\n providerInUse,\n relativeConfigPath,\n sourceFolderInUse,\n} from \"../lib/installation/install-layout.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { type SourceLoadResult } from \"../lib/loading/index.js\";\nimport { loadSource } from \"../lib/operations/index.js\";\nimport { matrix } from \"../lib/matrix/matrix-provider\";\nimport {\n resolveSource,\n loadProjectSourceConfig,\n getProjectConfigPath,\n} from \"../lib/configuration/index.js\";\nimport {\n ensureBlankPair,\n lazyGateDeps,\n mutateGlobal,\n writeProjectPartial,\n} from \"../lib/config-gate/index.js\";\nimport { isHomeDirectory } from \"../lib/installation/index.js\";\nimport {\n providerFlag,\n providerNamedBy,\n refuseAnAmbiguousInstallation,\n} from \"../lib/installation/provider-flag.js\";\nimport { copySkillsToLocalFlattened, type CopiedSkill } from \"../lib/skills/index.js\";\nimport { INCOMPLETE_WORK_RECOVERY, INFO_MESSAGES } from \"../utils/messages.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\nimport { plural } from \"../utils/string.js\";\nimport type { MergedSkillsMatrix } from \"../types/index.js\";\n\nconst EJECT_TYPES = [\"agent-partials\", \"templates\", \"skills\", \"all\"] as const;\ntype EjectType = (typeof EJECT_TYPES)[number];\n\nfunction isEjectType(value: string): value is EjectType {\n return (EJECT_TYPES as readonly string[]).includes(value);\n}\n\nexport default class Eject extends BaseCommand {\n static summary = \"Eject skills, agent partials, or templates for local customization\";\n static description =\n \"Copy agent partials, templates, or skills to your project for customization. \" +\n \"Agent partials and templates are always copied from the CLI. \" +\n \"Skills are copied from the marketplace this installation is configured to read \" +\n \"(the public one by default).\";\n\n static examples = [\n {\n description: \"Eject agent partials for customization\",\n command: \"<%= config.bin %> <%= command.id %> agent-partials\",\n },\n {\n description: \"Eject only agent templates\",\n command: \"<%= config.bin %> <%= command.id %> templates\",\n },\n {\n description: \"Eject skills to local directory\",\n command: \"<%= config.bin %> <%= command.id %> skills\",\n },\n {\n description: \"Eject everything with force overwrite\",\n command: \"<%= config.bin %> <%= command.id %> all --force\",\n },\n {\n description: \"Eject to a custom output directory\",\n command: \"<%= config.bin %> <%= command.id %> skills -o ./custom-dir\",\n },\n ];\n\n static args = {\n type: Args.string({\n description: \"What to eject: agent-partials, templates, skills, all\",\n required: false,\n options: [...EJECT_TYPES],\n }),\n };\n\n static flags = {\n provider: providerFlag(),\n force: Flags.boolean({\n char: \"f\",\n description: \"Overwrite existing files\",\n default: false,\n }),\n output: Flags.string({\n char: \"o\",\n // No `default:`, and no default named here either: each eject type has its own\n // destination and this flag replaces all three at once. The reference page carries\n // the table; a one-line description that picked one of the three would be wrong\n // about the other two, which is what it was.\n description:\n \"Write everything into this directory instead of each eject type's own destination\",\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(Eject);\n const projectDir = process.cwd();\n\n // Above the layout settle, because that refusal is about two FOLDER NAMES of one installation\n // and this one is about two installations. Both have to be answered before anything is\n // written, and this one decides which installation the other is even asking about.\n await refuseAnAmbiguousInstallation(\n projectDir,\n \"eject\",\n providerNamedBy(flags.provider),\n (message) => this.error(message, { exit: EXIT_CODES.INVALID_ARGS }),\n );\n\n // Before anything is copied: a config nobody can read is recreated, not ejected over, and a\n // refusal past this point would follow files already written.\n await this.ensureConfigReadable(projectDir);\n await this.settleSourceLayoutBeforeWriting(projectDir);\n const ejectType = this.validateEjectType(args.type);\n const outputBase = await this.resolveOutputBase(flags, projectDir);\n\n this.printHeader(\n await this.resolveBrandingName(projectDir),\n flags.output ? outputBase : undefined,\n );\n\n const sourceResult = await this.loadSourceIfNeeded(ejectType, projectDir);\n await this.executeEject(ejectType, outputBase, flags, projectDir, sourceResult);\n await this.ensureConfig(projectDir, sourceResult);\n\n this.reportEnding();\n }\n\n /**\n * The command's last word.\n *\n * `Eject complete!` claims the whole eject landed, so it is withheld whenever part of it did\n * not — the account {@link BaseCommand.exitIfWorkIncomplete} prints replaces that tick rather\n * than sitting under it, and carries the non-zero exit with it.\n */\n private reportEnding(): void {\n this.log(\"\");\n if (!this.hasIncompleteWork) this.logSuccess(\"Eject complete!\");\n this.log(\"\");\n\n this.exitIfWorkIncomplete();\n }\n\n private validateEjectType(typeArg: string | undefined): EjectType {\n if (!typeArg) {\n this.error(\"Please specify what to eject: agent-partials, templates, skills, or all\", {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n if (!isEjectType(typeArg)) {\n this.error(`Unknown eject type: ${typeArg}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n return typeArg;\n }\n\n private async resolveOutputBase(\n flags: { output: string | undefined },\n projectDir: string,\n ): Promise<string> {\n if (flags.output) {\n const expandedPath = flags.output.startsWith(\"~\")\n ? path.join(os.homedir(), flags.output.slice(1))\n : flags.output;\n const outputBase = path.resolve(projectDir, expandedPath);\n\n if (await fileExists(outputBase)) {\n this.error(`Output path exists as a file: ${outputBase}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n return outputBase;\n }\n\n return sourceFolderInUse(projectDir, providerInUse(projectDir)).dir;\n }\n\n private printHeader(brandingName: string, outputBase?: string): void {\n this.log(\"\");\n this.log(`${brandingName} Eject`);\n this.log(\"\");\n\n if (outputBase) {\n this.log(`Output directory: ${outputBase}`);\n }\n }\n\n private async loadSourceIfNeeded(\n ejectType: EjectType,\n projectDir: string,\n ): Promise<SourceLoadResult | undefined> {\n if (ejectType === \"skills\" || ejectType === \"all\") {\n const loaded = await loadSource({ projectDir });\n return loaded.sourceResult;\n }\n return undefined;\n }\n\n private async executeEject(\n ejectType: EjectType,\n outputBase: string,\n flags: { force: boolean; output: string | undefined },\n projectDir: string,\n sourceResult: SourceLoadResult | undefined,\n ): Promise<void> {\n const directOutput = !!flags.output;\n\n switch (ejectType) {\n case \"agent-partials\":\n await this.handleAgentPartials(outputBase, flags.force, directOutput, false);\n break;\n case \"templates\":\n await this.handleAgentPartials(outputBase, flags.force, directOutput, true);\n break;\n case \"skills\":\n if (!sourceResult) {\n throw new Error(\"The marketplace must be loaded for skills eject\");\n }\n await this.handleSkills(projectDir, flags.force, sourceResult, directOutput, outputBase);\n break;\n case \"all\":\n if (!sourceResult) {\n throw new Error(\"The marketplace must be loaded for full eject\");\n }\n await this.handleAgentPartials(outputBase, flags.force, directOutput, false);\n await this.handleAgentPartials(outputBase, true, directOutput, true);\n await this.handleSkills(projectDir, flags.force, sourceResult, directOutput, outputBase);\n break;\n default: {\n const _exhaustive: never = ejectType;\n return _exhaustive;\n }\n }\n }\n\n /**\n * The convenience step after the eject: a minimal `config.ts` so a later `compile` has\n * something to read.\n *\n * It can refuse, and by the time it does the ejection has already landed — the templates,\n * partials or skills are on disk and stay there. So the throw is caught rather than left to\n * become the process's exit code: an `ERROR` tells the caller nothing landed and the run can\n * be repeated, which is the wrong instruction for a tree that now holds an ejection. What is\n * owed is the account and `EXIT_CODES.COMPLETED_WITH_FAILURES`.\n *\n * The refusal itself is right and is not weakened here: `ensureMinimalConfig` will not invent\n * a config recording a marketplace it read out of a file it could not evaluate.\n */\n private async ensureConfig(\n projectDir: string,\n sourceResult: SourceLoadResult | undefined,\n ): Promise<void> {\n // Named once, before the write, so the success line and the failure line cannot name\n // different files: the provider is read off the disk and the write may create the folder.\n const configTsRel = relativeConfigPath(projectDir, providerInUse(projectDir));\n\n try {\n const configResult = await ensureMinimalConfig({\n projectDir,\n ...(sourceResult !== undefined && { sourceResult }),\n });\n if (configResult.created) {\n this.logSuccess(`Created ${configTsRel}`);\n }\n } catch (error) {\n this.reportIncompleteWork(\n `Could not create ${configTsRel}: ${getErrorMessage(error)}`,\n INCOMPLETE_WORK_RECOVERY.INSPECT_INSTALLATION,\n );\n }\n }\n\n private async handleAgentPartials(\n outputBase: string,\n force: boolean,\n directOutput: boolean,\n templatesOnly: boolean,\n ): Promise<void> {\n const result = await ejectAgentPartials({\n outputBase,\n force,\n directOutput,\n templatesOnly,\n });\n\n if (result.skipped) {\n this.warn(result.skipReason);\n return;\n }\n\n if (result.templatesSkipped) {\n this.warn(\n \"Agent templates already exist — skipping templates, only ejecting agent partials.\",\n );\n }\n\n this.logSuccess(\n `${templatesOnly ? \"Agent templates\" : \"Agent partials\"} ejected to ${result.destDir}`,\n );\n this.log(\n templatesOnly\n ? \"You can now customize agent templates locally.\"\n : INFO_MESSAGES.AGENT_PARTIALS_CUSTOMIZABLE,\n );\n }\n\n private async handleSkills(\n projectDir: string,\n force: boolean,\n sourceResult: SourceLoadResult,\n directOutput: boolean,\n outputBase: string,\n ): Promise<void> {\n const result = await ejectSkills({\n projectDir,\n force,\n sourceResult,\n matrix,\n directOutput,\n ...(directOutput && { customOutputBase: outputBase }),\n });\n\n if (result.skipped) {\n this.warn(result.skipReason);\n return;\n }\n\n this.logSuccess(\n `${plural(result.copiedSkills.length, \"skill\")} ejected to ${result.destDir} from ${result.sourceLabel}`,\n );\n this.log(\"You can now customize skill content locally.\");\n }\n}\n\ntype EjectAgentPartialsOptions = {\n outputBase: string;\n force: boolean;\n /** When true, outputBase is used directly as the destination (no subdirectory nesting). */\n directOutput?: boolean;\n /** When true, ejects only the _templates directory instead of the full agents directory. */\n templatesOnly?: boolean;\n};\n\ntype EjectAgentPartialsResult =\n | {\n skipped: true;\n skipReason: string;\n templatesSkipped: false;\n }\n | {\n skipped: false;\n /** Destination directory that was written to. */\n destDir: string;\n /** Whether templates were skipped during a full agent-partials eject (existing templates preserved). */\n templatesSkipped: boolean;\n };\n\n/** Direct output writes to the base itself; otherwise agents/ (plus templates/ in templates-only mode). */\nfunction resolveEjectDestDir(\n outputBase: string,\n directOutput: boolean,\n templatesOnly: boolean,\n): string {\n if (directOutput) return outputBase;\n const agentsDir = path.join(outputBase, path.basename(DIRS.agents));\n return templatesOnly ? path.join(agentsDir, path.basename(DIRS.templates)) : agentsDir;\n}\n\n/**\n * Copies agent partials or templates from the CLI source to a target directory.\n *\n * When `templatesOnly` is true, copies only the _templates subdirectory.\n * When false, copies the full agents directory (optionally skipping existing templates).\n *\n * Returns structured data — the command decides what to log.\n */\nasync function ejectAgentPartials(\n options: EjectAgentPartialsOptions,\n): Promise<EjectAgentPartialsResult> {\n const { outputBase, force, directOutput = false, templatesOnly = false } = options;\n\n const sourceDir = templatesOnly\n ? path.join(PROJECT_ROOT, DIRS.templates)\n : path.join(PROJECT_ROOT, DIRS.agents);\n\n if (!(await directoryExists(sourceDir))) {\n return {\n skipped: true,\n skipReason: templatesOnly\n ? \"No agent templates found in CLI.\"\n : \"No agent partials found in CLI.\",\n templatesSkipped: false,\n };\n }\n\n const destDir = resolveEjectDestDir(outputBase, directOutput, templatesOnly);\n\n const templatesBasename = path.basename(DIRS.templates);\n\n if ((await directoryExists(destDir)) && !force) {\n if (templatesOnly) {\n return {\n skipped: true,\n skipReason: `Agent templates already exist at ${destDir}. Use --force to overwrite.`,\n templatesSkipped: false,\n };\n }\n\n const hasTemplates = await directoryExists(path.join(destDir, templatesBasename));\n if ((await hasAgentPartialDirs(destDir)) && !hasTemplates) {\n return {\n skipped: true,\n skipReason: `Agent partials already exist at ${destDir}. Use --force to overwrite.`,\n templatesSkipped: false,\n };\n }\n }\n\n await ensureDir(destDir);\n\n const skipTemplates =\n !templatesOnly && !force && (await directoryExists(path.join(destDir, templatesBasename)));\n\n if (skipTemplates) {\n const sourceEntries = await listDirectories(sourceDir);\n const nonTemplateEntries = sourceEntries.filter((entry) => entry !== templatesBasename);\n for (const entry of nonTemplateEntries) {\n await copy(path.join(sourceDir, entry), path.join(destDir, entry));\n }\n } else {\n await copy(sourceDir, destDir);\n }\n\n return {\n skipped: false,\n destDir,\n templatesSkipped: skipTemplates,\n };\n}\n\ntype EjectSkillsOptions = {\n projectDir: string;\n force: boolean;\n sourceResult: SourceLoadResult;\n matrix: MergedSkillsMatrix;\n /** When true, uses customOutputBase as destination instead of LOCAL_SKILLS_PATH. */\n directOutput?: boolean;\n customOutputBase?: string;\n};\n\ntype EjectSkillsResult =\n | {\n skipped: true;\n skipReason: string;\n copiedSkills: [];\n }\n | {\n skipped: false;\n /** Array of skills that were copied. */\n copiedSkills: CopiedSkill[];\n /** Destination directory that was written to. */\n destDir: string;\n /** Label describing the source that skills were copied from. */\n sourceLabel: string;\n };\n\n/**\n * Copies the marketplace's own skills from source to a target directory.\n *\n * Only the skills the loaded marketplace carries, because those are the only ones its folder\n * holds: a global installation's skill seated from another marketplace is in the matrix and not\n * on disk here. Skills already marked as local are filtered out too, then the remaining skills\n * are copied using copySkillsToLocalFlattened.\n *\n * Returns structured data — the command decides what to log.\n */\nasync function ejectSkills(options: EjectSkillsOptions): Promise<EjectSkillsResult> {\n const {\n projectDir,\n force,\n sourceResult,\n matrix,\n directOutput = false,\n customOutputBase,\n } = options;\n\n const destDir =\n directOutput && customOutputBase ? customOutputBase : path.join(projectDir, LOCAL_SKILLS_PATH);\n\n if ((await directoryExists(destDir)) && !force) {\n return {\n skipped: true,\n skipReason: `Skills already exist at ${destDir}. Use --force to overwrite.`,\n copiedSkills: [],\n };\n }\n\n const skillIds = [...sourceResult.marketplaceSkillIds].filter(\n (skillId) => !matrix.skills[skillId]?.local,\n );\n\n if (skillIds.length === 0) {\n return {\n skipped: true,\n skipReason: \"No skills found in the marketplace to eject.\",\n copiedSkills: [],\n };\n }\n\n await ensureDir(destDir);\n\n const copiedSkills = await copySkillsToLocalFlattened(skillIds, destDir, sourceResult);\n\n const sourceLabel = sourceResult.isLocal\n ? sourceResult.sourcePath\n : sourceResult.marketplace || sourceResult.sourceConfig.source;\n\n return {\n skipped: false,\n copiedSkills,\n destDir,\n sourceLabel,\n };\n}\n\ntype EnsureMinimalConfigOptions = {\n projectDir: string;\n sourceResult?: SourceLoadResult;\n};\n\ntype EnsureMinimalConfigResult = {\n /** Path to the config file. */\n configPath: string;\n /** Whether a new config was created. */\n created: boolean;\n};\n\n/**\n * Ensures a minimal config.ts exists so `npx agents-inc compile` works after eject.\n *\n * If the config already exists, returns immediately with `created: false`.\n * Otherwise generates a minimal config from the resolved source and project metadata.\n *\n * Returns structured data — the command decides what to log.\n */\nasync function ensureMinimalConfig(\n options: EnsureMinimalConfigOptions,\n): Promise<EnsureMinimalConfigResult> {\n const { projectDir, sourceResult } = options;\n\n // One read for the whole function: the config it may invent, and the blank global pair it may\n // create beside it, belong to the same installation.\n const provider = providerInUse(projectDir);\n const tsConfigPath = getProjectConfigPath(projectDir, provider);\n\n if (await fileExists(tsConfigPath)) {\n return { configPath: tsConfigPath, created: false };\n }\n\n // ABORT on an unreadable config. The project has none — the guard above returned for that — so\n // what these two can meet is an unreadable GLOBAL config, and the file about to be invented\n // would record a marketplace read from nowhere. The second call is unreachable for the same\n // reason the guard exists: this project's own config is not there to be unreadable.\n const resolvedConfig =\n sourceResult?.sourceConfig ?? (await resolveSource({ caller: \"stored\", projectDir }));\n const existingProjectConfig = await loadProjectSourceConfig(projectDir);\n const source = resolvedConfig.source || undefined;\n\n // At the home directory the invented config IS the global manifest, and the\n // file it opens with `import type { ProjectConfig } from \"./config-types\"`\n // cannot resolve its own types without the sibling. The gate writes the pair.\n if (isHomeDirectory(projectDir)) {\n await ensureBlankPair(provider);\n if (source) await recordSource(projectDir, source);\n return { configPath: tsConfigPath, created: true };\n }\n\n await writeProjectPartial(\n projectDir,\n {\n skills: [],\n agents: [],\n ...(source ? { marketplace: source } : {}),\n ...(resolvedConfig.marketplace ? { marketplaceName: resolvedConfig.marketplace } : {}),\n ...(existingProjectConfig?.author ? { author: existingProjectConfig.author } : {}),\n ...(existingProjectConfig?.agentsSource\n ? { agentsSource: existingProjectConfig.agentsSource }\n : {}),\n },\n { fallbackName: path.basename(projectDir) },\n );\n\n return { configPath: tsConfigPath, created: true };\n}\n\n/**\n * Records the marketplace ref in whichever scope's config `projectDir` names. At the home\n * directory that config is the global manifest every project's generated types\n * import from, so the write goes through the gate: registered projects inline\n * the scalar and follow it.\n */\nasync function recordSource(projectDir: string, source: string): Promise<void> {\n if (isHomeDirectory(projectDir)) {\n await mutateGlobal(\n { kind: \"set-source\", source, fallbackName: path.basename(projectDir) },\n lazyGateDeps(projectDir),\n );\n return;\n }\n\n // ABORT on an unreadable config. The `?? {}` is a fallback for a config that is not THERE; on\n // one that is there and unreadable it would hand the writer an empty partial, and this scalar\n // write would replace the user's whole file with a two-field one under an invented name.\n const existing = (await loadProjectSourceConfig(projectDir)) ?? {};\n await writeProjectPartial(\n projectDir,\n { ...existing, marketplace: source },\n { fallbackName: path.basename(projectDir) },\n );\n}\n\n/** Checks whether the agents directory contains any agent subdirectories (not just _templates). */\nasync function hasAgentPartialDirs(agentsDir: string): Promise<boolean> {\n const subdirs = await listDirectories(agentsDir);\n const templatesBasename = path.basename(DIRS.templates);\n return subdirs.some((dir) => dir !== templatesBasename);\n}\n"],"mappings":"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","names":["matrix"]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/commands/eject.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport os from \"os\";\nimport { BaseCommand } from \"../base-command.js\";\nimport { copy, ensureDir, directoryExists, fileExists, listDirectories } from \"../utils/fs.js\";\nimport { DIRS, LOCAL_SKILLS_PATH, PROJECT_ROOT } from \"../consts.js\";\nimport {\n providerInUse,\n relativeConfigPath,\n sourceFolderInUse,\n} from \"../lib/installation/install-layout.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { type SourceLoadResult } from \"../lib/loading/index.js\";\nimport { loadSource } from \"../lib/operations/index.js\";\nimport { matrix } from \"../lib/matrix/matrix-provider\";\nimport {\n resolveSource,\n loadProjectSourceConfig,\n getProjectConfigPath,\n} from \"../lib/configuration/index.js\";\nimport {\n ensureBlankPair,\n lazyGateDeps,\n mutateGlobal,\n writeProjectPartial,\n} from \"../lib/config-gate/index.js\";\nimport { isHomeDirectory } from \"../lib/installation/index.js\";\nimport {\n providerFlag,\n providerNamedBy,\n refuseAnAmbiguousInstallation,\n} from \"../lib/installation/provider-flag.js\";\nimport { copySkillsToLocalFlattened, type CopiedSkill } from \"../lib/skills/index.js\";\nimport { INCOMPLETE_WORK_RECOVERY, INFO_MESSAGES } from \"../utils/messages.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\nimport { plural } from \"../utils/string.js\";\nimport type { MergedSkillsMatrix } from \"../types/index.js\";\n\nconst EJECT_TYPES = [\"agent-partials\", \"templates\", \"skills\", \"all\"] as const;\ntype EjectType = (typeof EJECT_TYPES)[number];\n\nfunction isEjectType(value: string): value is EjectType {\n return (EJECT_TYPES as readonly string[]).includes(value);\n}\n\nexport default class Eject extends BaseCommand {\n static summary = \"Eject skills, agent partials, or templates for local customization\";\n static description =\n \"Copy agent partials, templates, or skills to your project for customization. \" +\n \"Agent partials and templates are always copied from the CLI. \" +\n \"Skills are copied from the marketplace this installation is configured to read \" +\n \"(the public one by default).\";\n\n static examples = [\n {\n description: \"Eject agent partials for customization\",\n command: \"<%= config.bin %> <%= command.id %> agent-partials\",\n },\n {\n description: \"Eject only agent templates\",\n command: \"<%= config.bin %> <%= command.id %> templates\",\n },\n {\n description: \"Eject skills to local directory\",\n command: \"<%= config.bin %> <%= command.id %> skills\",\n },\n {\n description: \"Eject everything with force overwrite\",\n command: \"<%= config.bin %> <%= command.id %> all --force\",\n },\n {\n description: \"Eject to a custom output directory\",\n command: \"<%= config.bin %> <%= command.id %> skills -o ./custom-dir\",\n },\n ];\n\n static args = {\n type: Args.string({\n description: \"What to eject: agent-partials, templates, skills, all\",\n required: false,\n options: [...EJECT_TYPES],\n }),\n };\n\n static flags = {\n provider: providerFlag(),\n force: Flags.boolean({\n char: \"f\",\n description: \"Overwrite existing files\",\n default: false,\n }),\n output: Flags.string({\n char: \"o\",\n // No `default:`, and no default named here either: each eject type has its own\n // destination and this flag replaces all three at once. The reference page carries\n // the table; a one-line description that picked one of the three would be wrong\n // about the other two, which is what it was.\n description:\n \"Write everything into this directory instead of each eject type's own destination\",\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(Eject);\n const projectDir = process.cwd();\n\n // Above the layout settle, because that refusal is about two FOLDER NAMES of one installation\n // and this one is about two installations. Both have to be answered before anything is\n // written, and this one decides which installation the other is even asking about.\n await refuseAnAmbiguousInstallation(\n projectDir,\n \"eject\",\n providerNamedBy(flags.provider),\n (message) => this.error(message, { exit: EXIT_CODES.INVALID_ARGS }),\n );\n\n // Before anything is copied: a config nobody can read is recreated, not ejected over, and a\n // refusal past this point would follow files already written.\n await this.ensureConfigReadable(projectDir);\n const ejectType = this.validateEjectType(args.type);\n const outputBase = await this.resolveOutputBase(flags, projectDir);\n\n this.printHeader(\n await this.resolveBrandingName(projectDir),\n flags.output ? outputBase : undefined,\n );\n\n const sourceResult = await this.loadSourceIfNeeded(ejectType, projectDir);\n await this.executeEject(ejectType, outputBase, flags, projectDir, sourceResult);\n await this.ensureConfig(projectDir, sourceResult);\n\n this.reportEnding();\n }\n\n /**\n * The command's last word.\n *\n * `Eject complete!` claims the whole eject landed, so it is withheld whenever part of it did\n * not — the account {@link BaseCommand.exitIfWorkIncomplete} prints replaces that tick rather\n * than sitting under it, and carries the non-zero exit with it.\n */\n private reportEnding(): void {\n this.log(\"\");\n if (!this.hasIncompleteWork) this.logSuccess(\"Eject complete!\");\n this.log(\"\");\n\n this.exitIfWorkIncomplete();\n }\n\n private validateEjectType(typeArg: string | undefined): EjectType {\n if (!typeArg) {\n this.error(\"Please specify what to eject: agent-partials, templates, skills, or all\", {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n if (!isEjectType(typeArg)) {\n this.error(`Unknown eject type: ${typeArg}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n return typeArg;\n }\n\n private async resolveOutputBase(\n flags: { output: string | undefined },\n projectDir: string,\n ): Promise<string> {\n if (flags.output) {\n const expandedPath = flags.output.startsWith(\"~\")\n ? path.join(os.homedir(), flags.output.slice(1))\n : flags.output;\n const outputBase = path.resolve(projectDir, expandedPath);\n\n if (await fileExists(outputBase)) {\n this.error(`Output path exists as a file: ${outputBase}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n return outputBase;\n }\n\n return sourceFolderInUse(projectDir, providerInUse(projectDir)).dir;\n }\n\n private printHeader(brandingName: string, outputBase?: string): void {\n this.log(\"\");\n this.log(`${brandingName} Eject`);\n this.log(\"\");\n\n if (outputBase) {\n this.log(`Output directory: ${outputBase}`);\n }\n }\n\n private async loadSourceIfNeeded(\n ejectType: EjectType,\n projectDir: string,\n ): Promise<SourceLoadResult | undefined> {\n if (ejectType === \"skills\" || ejectType === \"all\") {\n const loaded = await loadSource({ projectDir });\n return loaded.sourceResult;\n }\n return undefined;\n }\n\n private async executeEject(\n ejectType: EjectType,\n outputBase: string,\n flags: { force: boolean; output: string | undefined },\n projectDir: string,\n sourceResult: SourceLoadResult | undefined,\n ): Promise<void> {\n const directOutput = !!flags.output;\n\n switch (ejectType) {\n case \"agent-partials\":\n await this.handleAgentPartials(outputBase, flags.force, directOutput, false);\n break;\n case \"templates\":\n await this.handleAgentPartials(outputBase, flags.force, directOutput, true);\n break;\n case \"skills\":\n if (!sourceResult) {\n throw new Error(\"The marketplace must be loaded for skills eject\");\n }\n await this.handleSkills(projectDir, flags.force, sourceResult, directOutput, outputBase);\n break;\n case \"all\":\n if (!sourceResult) {\n throw new Error(\"The marketplace must be loaded for full eject\");\n }\n await this.handleAgentPartials(outputBase, flags.force, directOutput, false);\n await this.handleAgentPartials(outputBase, true, directOutput, true);\n await this.handleSkills(projectDir, flags.force, sourceResult, directOutput, outputBase);\n break;\n default: {\n const _exhaustive: never = ejectType;\n return _exhaustive;\n }\n }\n }\n\n /**\n * The convenience step after the eject: a minimal `config.ts` so a later `compile` has\n * something to read.\n *\n * It can refuse, and by the time it does the ejection has already landed — the templates,\n * partials or skills are on disk and stay there. So the throw is caught rather than left to\n * become the process's exit code: an `ERROR` tells the caller nothing landed and the run can\n * be repeated, which is the wrong instruction for a tree that now holds an ejection. What is\n * owed is the account and `EXIT_CODES.COMPLETED_WITH_FAILURES`.\n *\n * The refusal itself is right and is not weakened here: `ensureMinimalConfig` will not invent\n * a config recording a marketplace it read out of a file it could not evaluate.\n */\n private async ensureConfig(\n projectDir: string,\n sourceResult: SourceLoadResult | undefined,\n ): Promise<void> {\n // Named once, before the write, so the success line and the failure line cannot name\n // different files: the provider is read off the disk and the write may create the folder.\n const configTsRel = relativeConfigPath(projectDir, providerInUse(projectDir));\n\n try {\n const configResult = await ensureMinimalConfig({\n projectDir,\n ...(sourceResult !== undefined && { sourceResult }),\n });\n if (configResult.created) {\n this.logSuccess(`Created ${configTsRel}`);\n }\n } catch (error) {\n this.reportIncompleteWork(\n `Could not create ${configTsRel}: ${getErrorMessage(error)}`,\n INCOMPLETE_WORK_RECOVERY.INSPECT_INSTALLATION,\n );\n }\n }\n\n private async handleAgentPartials(\n outputBase: string,\n force: boolean,\n directOutput: boolean,\n templatesOnly: boolean,\n ): Promise<void> {\n const result = await ejectAgentPartials({\n outputBase,\n force,\n directOutput,\n templatesOnly,\n });\n\n if (result.skipped) {\n this.warn(result.skipReason);\n return;\n }\n\n if (result.templatesSkipped) {\n this.warn(\n \"Agent templates already exist — skipping templates, only ejecting agent partials.\",\n );\n }\n\n this.logSuccess(\n `${templatesOnly ? \"Agent templates\" : \"Agent partials\"} ejected to ${result.destDir}`,\n );\n this.log(\n templatesOnly\n ? \"You can now customize agent templates locally.\"\n : INFO_MESSAGES.AGENT_PARTIALS_CUSTOMIZABLE,\n );\n }\n\n private async handleSkills(\n projectDir: string,\n force: boolean,\n sourceResult: SourceLoadResult,\n directOutput: boolean,\n outputBase: string,\n ): Promise<void> {\n const result = await ejectSkills({\n projectDir,\n force,\n sourceResult,\n matrix,\n directOutput,\n ...(directOutput && { customOutputBase: outputBase }),\n });\n\n if (result.skipped) {\n this.warn(result.skipReason);\n return;\n }\n\n this.logSuccess(\n `${plural(result.copiedSkills.length, \"skill\")} ejected to ${result.destDir} from ${result.sourceLabel}`,\n );\n this.log(\"You can now customize skill content locally.\");\n }\n}\n\ntype EjectAgentPartialsOptions = {\n outputBase: string;\n force: boolean;\n /** When true, outputBase is used directly as the destination (no subdirectory nesting). */\n directOutput?: boolean;\n /** When true, ejects only the _templates directory instead of the full agents directory. */\n templatesOnly?: boolean;\n};\n\ntype EjectAgentPartialsResult =\n | {\n skipped: true;\n skipReason: string;\n templatesSkipped: false;\n }\n | {\n skipped: false;\n /** Destination directory that was written to. */\n destDir: string;\n /** Whether templates were skipped during a full agent-partials eject (existing templates preserved). */\n templatesSkipped: boolean;\n };\n\n/** Direct output writes to the base itself; otherwise agents/ (plus templates/ in templates-only mode). */\nfunction resolveEjectDestDir(\n outputBase: string,\n directOutput: boolean,\n templatesOnly: boolean,\n): string {\n if (directOutput) return outputBase;\n const agentsDir = path.join(outputBase, path.basename(DIRS.agents));\n return templatesOnly ? path.join(agentsDir, path.basename(DIRS.templates)) : agentsDir;\n}\n\n/**\n * Copies agent partials or templates from the CLI source to a target directory.\n *\n * When `templatesOnly` is true, copies only the _templates subdirectory.\n * When false, copies the full agents directory (optionally skipping existing templates).\n *\n * Returns structured data — the command decides what to log.\n */\nasync function ejectAgentPartials(\n options: EjectAgentPartialsOptions,\n): Promise<EjectAgentPartialsResult> {\n const { outputBase, force, directOutput = false, templatesOnly = false } = options;\n\n const sourceDir = templatesOnly\n ? path.join(PROJECT_ROOT, DIRS.templates)\n : path.join(PROJECT_ROOT, DIRS.agents);\n\n if (!(await directoryExists(sourceDir))) {\n return {\n skipped: true,\n skipReason: templatesOnly\n ? \"No agent templates found in CLI.\"\n : \"No agent partials found in CLI.\",\n templatesSkipped: false,\n };\n }\n\n const destDir = resolveEjectDestDir(outputBase, directOutput, templatesOnly);\n\n const templatesBasename = path.basename(DIRS.templates);\n\n if ((await directoryExists(destDir)) && !force) {\n if (templatesOnly) {\n return {\n skipped: true,\n skipReason: `Agent templates already exist at ${destDir}. Use --force to overwrite.`,\n templatesSkipped: false,\n };\n }\n\n const hasTemplates = await directoryExists(path.join(destDir, templatesBasename));\n if ((await hasAgentPartialDirs(destDir)) && !hasTemplates) {\n return {\n skipped: true,\n skipReason: `Agent partials already exist at ${destDir}. Use --force to overwrite.`,\n templatesSkipped: false,\n };\n }\n }\n\n await ensureDir(destDir);\n\n const skipTemplates =\n !templatesOnly && !force && (await directoryExists(path.join(destDir, templatesBasename)));\n\n if (skipTemplates) {\n const sourceEntries = await listDirectories(sourceDir);\n const nonTemplateEntries = sourceEntries.filter((entry) => entry !== templatesBasename);\n for (const entry of nonTemplateEntries) {\n await copy(path.join(sourceDir, entry), path.join(destDir, entry));\n }\n } else {\n await copy(sourceDir, destDir);\n }\n\n return {\n skipped: false,\n destDir,\n templatesSkipped: skipTemplates,\n };\n}\n\ntype EjectSkillsOptions = {\n projectDir: string;\n force: boolean;\n sourceResult: SourceLoadResult;\n matrix: MergedSkillsMatrix;\n /** When true, uses customOutputBase as destination instead of LOCAL_SKILLS_PATH. */\n directOutput?: boolean;\n customOutputBase?: string;\n};\n\ntype EjectSkillsResult =\n | {\n skipped: true;\n skipReason: string;\n copiedSkills: [];\n }\n | {\n skipped: false;\n /** Array of skills that were copied. */\n copiedSkills: CopiedSkill[];\n /** Destination directory that was written to. */\n destDir: string;\n /** Label describing the source that skills were copied from. */\n sourceLabel: string;\n };\n\n/**\n * Copies the marketplace's own skills from source to a target directory.\n *\n * Only the skills the loaded marketplace carries, because those are the only ones its folder\n * holds: a global installation's skill seated from another marketplace is in the matrix and not\n * on disk here. Skills already marked as local are filtered out too, then the remaining skills\n * are copied using copySkillsToLocalFlattened.\n *\n * Returns structured data — the command decides what to log.\n */\nasync function ejectSkills(options: EjectSkillsOptions): Promise<EjectSkillsResult> {\n const {\n projectDir,\n force,\n sourceResult,\n matrix,\n directOutput = false,\n customOutputBase,\n } = options;\n\n const destDir =\n directOutput && customOutputBase ? customOutputBase : path.join(projectDir, LOCAL_SKILLS_PATH);\n\n if ((await directoryExists(destDir)) && !force) {\n return {\n skipped: true,\n skipReason: `Skills already exist at ${destDir}. Use --force to overwrite.`,\n copiedSkills: [],\n };\n }\n\n const skillIds = [...sourceResult.marketplaceSkillIds].filter(\n (skillId) => !matrix.skills[skillId]?.local,\n );\n\n if (skillIds.length === 0) {\n return {\n skipped: true,\n skipReason: \"No skills found in the marketplace to eject.\",\n copiedSkills: [],\n };\n }\n\n await ensureDir(destDir);\n\n const copiedSkills = await copySkillsToLocalFlattened(skillIds, destDir, sourceResult);\n\n const sourceLabel = sourceResult.isLocal\n ? sourceResult.sourcePath\n : sourceResult.marketplace || sourceResult.sourceConfig.source;\n\n return {\n skipped: false,\n copiedSkills,\n destDir,\n sourceLabel,\n };\n}\n\ntype EnsureMinimalConfigOptions = {\n projectDir: string;\n sourceResult?: SourceLoadResult;\n};\n\ntype EnsureMinimalConfigResult = {\n /** Path to the config file. */\n configPath: string;\n /** Whether a new config was created. */\n created: boolean;\n};\n\n/**\n * Ensures a minimal config.ts exists so `npx agents-inc compile` works after eject.\n *\n * If the config already exists, returns immediately with `created: false`.\n * Otherwise generates a minimal config from the resolved source and project metadata.\n *\n * Returns structured data — the command decides what to log.\n */\nasync function ensureMinimalConfig(\n options: EnsureMinimalConfigOptions,\n): Promise<EnsureMinimalConfigResult> {\n const { projectDir, sourceResult } = options;\n\n // One read for the whole function: the config it may invent, and the blank global pair it may\n // create beside it, belong to the same installation.\n const provider = providerInUse(projectDir);\n const tsConfigPath = getProjectConfigPath(projectDir, provider);\n\n if (await fileExists(tsConfigPath)) {\n return { configPath: tsConfigPath, created: false };\n }\n\n // ABORT on an unreadable config. The project has none — the guard above returned for that — so\n // what these two can meet is an unreadable GLOBAL config, and the file about to be invented\n // would record a marketplace read from nowhere. The second call is unreachable for the same\n // reason the guard exists: this project's own config is not there to be unreadable.\n const resolvedConfig =\n sourceResult?.sourceConfig ?? (await resolveSource({ caller: \"stored\", projectDir }));\n const existingProjectConfig = await loadProjectSourceConfig(projectDir);\n const source = resolvedConfig.source || undefined;\n\n // At the home directory the invented config IS the global manifest, and the\n // file it opens with `import type { ProjectConfig } from \"./config-types\"`\n // cannot resolve its own types without the sibling. The gate writes the pair.\n if (isHomeDirectory(projectDir)) {\n await ensureBlankPair(provider);\n if (source) await recordSource(projectDir, source);\n return { configPath: tsConfigPath, created: true };\n }\n\n await writeProjectPartial(\n projectDir,\n {\n skills: [],\n agents: [],\n ...(source ? { marketplace: source } : {}),\n ...(resolvedConfig.marketplace ? { marketplaceName: resolvedConfig.marketplace } : {}),\n ...(existingProjectConfig?.author ? { author: existingProjectConfig.author } : {}),\n ...(existingProjectConfig?.agentsSource\n ? { agentsSource: existingProjectConfig.agentsSource }\n : {}),\n },\n { fallbackName: path.basename(projectDir) },\n );\n\n return { configPath: tsConfigPath, created: true };\n}\n\n/**\n * Records the marketplace ref in whichever scope's config `projectDir` names. At the home\n * directory that config is the global manifest every project's generated types\n * import from, so the write goes through the gate: registered projects inline\n * the scalar and follow it.\n */\nasync function recordSource(projectDir: string, source: string): Promise<void> {\n if (isHomeDirectory(projectDir)) {\n await mutateGlobal(\n { kind: \"set-source\", source, fallbackName: path.basename(projectDir) },\n lazyGateDeps(projectDir),\n );\n return;\n }\n\n // ABORT on an unreadable config. The `?? {}` is a fallback for a config that is not THERE; on\n // one that is there and unreadable it would hand the writer an empty partial, and this scalar\n // write would replace the user's whole file with a two-field one under an invented name.\n const existing = (await loadProjectSourceConfig(projectDir)) ?? {};\n await writeProjectPartial(\n projectDir,\n { ...existing, marketplace: source },\n { fallbackName: path.basename(projectDir) },\n );\n}\n\n/** Checks whether the agents directory contains any agent subdirectories (not just _templates). */\nasync function hasAgentPartialDirs(agentsDir: string): Promise<boolean> {\n const subdirs = await listDirectories(agentsDir);\n const templatesBasename = path.basename(DIRS.templates);\n return subdirs.some((dir) => dir !== templatesBasename);\n}\n"],"mappings":"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","names":["matrix"]}
|
package/dist/commands/init.js
CHANGED
|
@@ -7,53 +7,53 @@ import {
|
|
|
7
7
|
getDashboardData,
|
|
8
8
|
runDashboardFlow,
|
|
9
9
|
showDashboard
|
|
10
|
-
} from "../chunk-
|
|
11
|
-
import "../chunk-
|
|
12
|
-
import "../chunk-
|
|
13
|
-
import "../chunk-
|
|
14
|
-
import "../chunk-
|
|
15
|
-
import "../chunk-
|
|
16
|
-
import "../chunk-
|
|
17
|
-
import "../chunk-
|
|
18
|
-
import "../chunk-
|
|
19
|
-
import "../chunk-
|
|
20
|
-
import "../chunk-
|
|
21
|
-
import "../chunk-
|
|
22
|
-
import "../chunk-
|
|
23
|
-
import "../chunk-
|
|
24
|
-
import "../chunk-
|
|
25
|
-
import "../chunk-
|
|
26
|
-
import "../chunk-
|
|
27
|
-
import "../chunk-
|
|
28
|
-
import "../chunk-
|
|
10
|
+
} from "../chunk-G4JK7WVO.js";
|
|
11
|
+
import "../chunk-6LF4CQBY.js";
|
|
12
|
+
import "../chunk-V3I7VQ7N.js";
|
|
13
|
+
import "../chunk-HHIYT3PI.js";
|
|
14
|
+
import "../chunk-WWIFNPJG.js";
|
|
15
|
+
import "../chunk-RAHSOJQ2.js";
|
|
16
|
+
import "../chunk-DAIEQJIF.js";
|
|
17
|
+
import "../chunk-SCOQ34YM.js";
|
|
18
|
+
import "../chunk-4NDBUJHK.js";
|
|
19
|
+
import "../chunk-2VUYFTUB.js";
|
|
20
|
+
import "../chunk-T6UWJAB3.js";
|
|
21
|
+
import "../chunk-6L75SQZU.js";
|
|
22
|
+
import "../chunk-LFWLEDUG.js";
|
|
23
|
+
import "../chunk-TZ2YJJKK.js";
|
|
24
|
+
import "../chunk-SAYZWCH6.js";
|
|
25
|
+
import "../chunk-PNB3524H.js";
|
|
26
|
+
import "../chunk-XZEVWPX6.js";
|
|
27
|
+
import "../chunk-QHDPLLK6.js";
|
|
28
|
+
import "../chunk-MPTNC32T.js";
|
|
29
29
|
import "../chunk-TSIU7DME.js";
|
|
30
30
|
import "../chunk-JOEA52NR.js";
|
|
31
31
|
import "../chunk-VRXX4D6K.js";
|
|
32
|
-
import "../chunk-
|
|
32
|
+
import "../chunk-SXVHSOTH.js";
|
|
33
33
|
import "../chunk-XQHZPINL.js";
|
|
34
|
-
import "../chunk-
|
|
35
|
-
import "../chunk-
|
|
34
|
+
import "../chunk-JQRJQ4SS.js";
|
|
35
|
+
import "../chunk-TTY6DPJN.js";
|
|
36
36
|
import "../chunk-WTJ3AY33.js";
|
|
37
|
-
import "../chunk-
|
|
38
|
-
import "../chunk-
|
|
37
|
+
import "../chunk-WVUDLKIO.js";
|
|
38
|
+
import "../chunk-25MPBIK3.js";
|
|
39
39
|
import "../chunk-4AAOOAIN.js";
|
|
40
40
|
import "../chunk-OZXAJNLA.js";
|
|
41
|
-
import "../chunk-
|
|
42
|
-
import "../chunk-
|
|
43
|
-
import "../chunk-
|
|
44
|
-
import "../chunk-
|
|
45
|
-
import "../chunk-
|
|
46
|
-
import "../chunk-
|
|
47
|
-
import "../chunk-
|
|
41
|
+
import "../chunk-ZXKBERQU.js";
|
|
42
|
+
import "../chunk-G6UREQ4V.js";
|
|
43
|
+
import "../chunk-HWEKHVLE.js";
|
|
44
|
+
import "../chunk-PMJWD27C.js";
|
|
45
|
+
import "../chunk-ZR4YPKXQ.js";
|
|
46
|
+
import "../chunk-GE3WKJ6Q.js";
|
|
47
|
+
import "../chunk-MAWNVT2C.js";
|
|
48
48
|
import "../chunk-JFLVEFFP.js";
|
|
49
|
-
import "../chunk-
|
|
50
|
-
import "../chunk-
|
|
51
|
-
import "../chunk-
|
|
52
|
-
import "../chunk-
|
|
53
|
-
import "../chunk-
|
|
54
|
-
import "../chunk-
|
|
55
|
-
import "../chunk-
|
|
56
|
-
import "../chunk-
|
|
49
|
+
import "../chunk-7JNJ52CD.js";
|
|
50
|
+
import "../chunk-NBXXFIIW.js";
|
|
51
|
+
import "../chunk-Y3VIRVVE.js";
|
|
52
|
+
import "../chunk-VAPTVR3J.js";
|
|
53
|
+
import "../chunk-RZDXDMT6.js";
|
|
54
|
+
import "../chunk-A4KDXNOT.js";
|
|
55
|
+
import "../chunk-V5WXIM2F.js";
|
|
56
|
+
import "../chunk-ENGYJCTF.js";
|
|
57
57
|
import "../chunk-OI2H6M5I.js";
|
|
58
58
|
export {
|
|
59
59
|
Dashboard,
|
package/dist/commands/list.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
SkillAgentSummary
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-MAWNVT2C.js";
|
|
5
5
|
import {
|
|
6
6
|
render
|
|
7
7
|
} from "../chunk-JFLVEFFP.js";
|
|
8
8
|
import {
|
|
9
9
|
hydrateWizardStore
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-7JNJ52CD.js";
|
|
11
11
|
import {
|
|
12
12
|
otherInstallationsInThisScope,
|
|
13
13
|
providerFlag,
|
|
14
14
|
providerNamedBy
|
|
15
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-NBXXFIIW.js";
|
|
16
16
|
import {
|
|
17
17
|
BaseCommand
|
|
18
|
-
} from "../chunk-
|
|
19
|
-
import "../chunk-
|
|
20
|
-
import "../chunk-
|
|
18
|
+
} from "../chunk-Y3VIRVVE.js";
|
|
19
|
+
import "../chunk-VAPTVR3J.js";
|
|
20
|
+
import "../chunk-RZDXDMT6.js";
|
|
21
21
|
import {
|
|
22
22
|
INSTALL_MODE_LABELS,
|
|
23
23
|
chooseProviderForThisRun,
|
|
@@ -26,13 +26,13 @@ import {
|
|
|
26
26
|
getInstallationInfo,
|
|
27
27
|
loadProjectConfig,
|
|
28
28
|
providerInUse
|
|
29
|
-
} from "../chunk-
|
|
30
|
-
import "../chunk-
|
|
29
|
+
} from "../chunk-A4KDXNOT.js";
|
|
30
|
+
import "../chunk-V5WXIM2F.js";
|
|
31
31
|
import {
|
|
32
32
|
CLI_COLORS,
|
|
33
33
|
CLI_INVOKE_COMMAND,
|
|
34
34
|
DEFAULT_BRANDING
|
|
35
|
-
} from "../chunk-
|
|
35
|
+
} from "../chunk-ENGYJCTF.js";
|
|
36
36
|
import "../chunk-OI2H6M5I.js";
|
|
37
37
|
|
|
38
38
|
// src/cli/commands/list.tsx
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
import {
|
|
3
3
|
BaseCommand,
|
|
4
4
|
EXIT_CODES
|
|
5
|
-
} from "../../chunk-
|
|
6
|
-
import "../../chunk-
|
|
7
|
-
import "../../chunk-
|
|
5
|
+
} from "../../chunk-Y3VIRVVE.js";
|
|
6
|
+
import "../../chunk-VAPTVR3J.js";
|
|
7
|
+
import "../../chunk-RZDXDMT6.js";
|
|
8
8
|
import {
|
|
9
9
|
isDirectoryEmpty,
|
|
10
10
|
validateKebabCaseName,
|
|
11
11
|
validateMarketplaceName,
|
|
12
12
|
writeFile
|
|
13
|
-
} from "../../chunk-
|
|
14
|
-
import "../../chunk-
|
|
13
|
+
} from "../../chunk-A4KDXNOT.js";
|
|
14
|
+
import "../../chunk-V5WXIM2F.js";
|
|
15
15
|
import {
|
|
16
16
|
CLI_INVOKE_COMMAND,
|
|
17
17
|
DEFAULT_VERSION,
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
SKILL_RULES_PATH,
|
|
21
21
|
STACKS_FILE_PATH,
|
|
22
22
|
STANDARD_FILES
|
|
23
|
-
} from "../../chunk-
|
|
23
|
+
} from "../../chunk-ENGYJCTF.js";
|
|
24
24
|
import "../../chunk-OI2H6M5I.js";
|
|
25
25
|
|
|
26
26
|
// src/cli/commands/new/marketplace.ts
|
package/dist/commands/search.js
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
loadSource
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
6
|
-
import "../chunk-
|
|
7
|
-
import "../chunk-
|
|
8
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-G6UREQ4V.js";
|
|
5
|
+
import "../chunk-HWEKHVLE.js";
|
|
6
|
+
import "../chunk-PMJWD27C.js";
|
|
7
|
+
import "../chunk-ZR4YPKXQ.js";
|
|
8
|
+
import "../chunk-GE3WKJ6Q.js";
|
|
9
9
|
import {
|
|
10
10
|
BaseCommand
|
|
11
|
-
} from "../chunk-
|
|
12
|
-
import "../chunk-
|
|
13
|
-
import "../chunk-
|
|
11
|
+
} from "../chunk-Y3VIRVVE.js";
|
|
12
|
+
import "../chunk-VAPTVR3J.js";
|
|
13
|
+
import "../chunk-RZDXDMT6.js";
|
|
14
14
|
import {
|
|
15
15
|
STATUS_MESSAGES,
|
|
16
16
|
stripTerminalControls,
|
|
17
17
|
truncateText
|
|
18
|
-
} from "../chunk-
|
|
18
|
+
} from "../chunk-A4KDXNOT.js";
|
|
19
19
|
import {
|
|
20
20
|
typedValues
|
|
21
|
-
} from "../chunk-
|
|
22
|
-
import "../chunk-
|
|
21
|
+
} from "../chunk-V5WXIM2F.js";
|
|
22
|
+
import "../chunk-ENGYJCTF.js";
|
|
23
23
|
import "../chunk-OI2H6M5I.js";
|
|
24
24
|
|
|
25
25
|
// src/cli/commands/search.ts
|
package/dist/commands/share.js
CHANGED
|
@@ -2,23 +2,23 @@
|
|
|
2
2
|
import {
|
|
3
3
|
publishSeedConfig,
|
|
4
4
|
seedPayloadForInstallation
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-Y47EV74W.js";
|
|
6
6
|
import {
|
|
7
7
|
unofferablePlacementsFound
|
|
8
|
-
} from "../chunk-
|
|
9
|
-
import "../chunk-
|
|
10
|
-
import "../chunk-
|
|
8
|
+
} from "../chunk-PXWG7KFO.js";
|
|
9
|
+
import "../chunk-25MPBIK3.js";
|
|
10
|
+
import "../chunk-GE3WKJ6Q.js";
|
|
11
11
|
import {
|
|
12
12
|
providerFlag,
|
|
13
13
|
providerNamedBy,
|
|
14
14
|
refuseAnAmbiguousInstallation
|
|
15
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-NBXXFIIW.js";
|
|
16
16
|
import {
|
|
17
17
|
BaseCommand,
|
|
18
18
|
EXIT_CODES
|
|
19
|
-
} from "../chunk-
|
|
20
|
-
import "../chunk-
|
|
21
|
-
import "../chunk-
|
|
19
|
+
} from "../chunk-Y3VIRVVE.js";
|
|
20
|
+
import "../chunk-VAPTVR3J.js";
|
|
21
|
+
import "../chunk-RZDXDMT6.js";
|
|
22
22
|
import {
|
|
23
23
|
formatZodErrors,
|
|
24
24
|
getErrorMessage,
|
|
@@ -30,13 +30,13 @@ import {
|
|
|
30
30
|
stripTerminalControls,
|
|
31
31
|
truncateText,
|
|
32
32
|
warn
|
|
33
|
-
} from "../chunk-
|
|
33
|
+
} from "../chunk-A4KDXNOT.js";
|
|
34
34
|
import {
|
|
35
35
|
typedEntries
|
|
36
|
-
} from "../chunk-
|
|
36
|
+
} from "../chunk-V5WXIM2F.js";
|
|
37
37
|
import {
|
|
38
38
|
installableSeedPayloadSchema
|
|
39
|
-
} from "../chunk-
|
|
39
|
+
} from "../chunk-ENGYJCTF.js";
|
|
40
40
|
import "../chunk-OI2H6M5I.js";
|
|
41
41
|
|
|
42
42
|
// src/cli/commands/share.ts
|
|
@@ -138,7 +138,6 @@ var Share = class _Share extends BaseCommand {
|
|
|
138
138
|
);
|
|
139
139
|
await this.ensureConfigReadable(process.cwd());
|
|
140
140
|
await this.refuseUnofferablePlacements(process.cwd());
|
|
141
|
-
await this.settleSourceLayoutBeforeWriting(process.cwd());
|
|
142
141
|
}
|
|
143
142
|
const { payload, caveats } = flags.stdin ? await this.payloadFromPipe() : await this.payloadFromInstallation();
|
|
144
143
|
const published = await publishSeedConfig(payload);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/commands/share.ts","../../src/cli/lib/seed/read-piped-payload.ts","../../src/cli/utils/read-stream.ts"],"sourcesContent":["import { Flags } from \"@oclif/core\";\n\nimport { BaseCommand } from \"../base-command.js\";\nimport { isLocalSource } from \"../lib/configuration/config.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { unofferablePlacementsFound } from \"../lib/hosts/configured-placements.js\";\nimport { seedPayloadForInstallation } from \"../lib/seed/installation-payload.js\";\nimport { publishSeedConfig } from \"../lib/seed/publish-seed.js\";\nimport {\n readPipedPayload,\n STDIN_IS_A_TERMINAL,\n type PipedPayload,\n} from \"../lib/seed/read-piped-payload.js\";\nimport {\n providerFlag,\n providerNamedBy,\n refuseAnAmbiguousInstallation,\n} from \"../lib/installation/provider-flag.js\";\nimport { warn } from \"../utils/logger.js\";\nimport { readAllOf } from \"../utils/read-stream.js\";\nimport {\n sharedConfigDestinations,\n sharedIdNamesAFolder,\n sharedSkillsLeftBehind,\n shareRefusesEjectedSkills,\n} from \"../utils/messages.js\";\nimport { typedEntries } from \"../utils/typed-object.js\";\nimport type { SkillId } from \"../types/index.js\";\nimport type { SeedPayload } from \"@workspace/matrix/seed\";\n\n/** A payload to publish, and what is owed about it once it has an id. */\ntype ShareablePayload = { payload: SeedPayload; caveats: string[] };\n\n/**\n * What an id minted from this installation will not do everywhere, said after the id rather than\n * refused: it still installs everything else.\n *\n * A payload names one marketplace, by the ref `--marketplace` took. A folder is a ref only this\n * machine can follow, and a plugin from any other marketplace is skipped wherever the id is\n * installed.\n */\nfunction caveatsAbout(payload: SeedPayload, leftBehind: readonly SkillId[]): string[] {\n const { marketplace } = payload;\n return [\n ...(isAFolder(marketplace) ? [sharedIdNamesAFolder(marketplace)] : []),\n ...(leftBehind.length > 0 ? [sharedSkillsLeftBehind(leftBehind)] : []),\n ];\n}\n\n/** Whether a payload's marketplace ref is a folder on this machine rather than a repository. */\nfunction isAFolder(marketplace: string | undefined): marketplace is string {\n return marketplace !== undefined && isLocalSource(marketplace);\n}\n\n/** The skills a payload asks the receiver to eject — local copies, editor-added ones included. */\nfunction ejectedSkillsIn(payload: SeedPayload): string[] {\n return typedEntries(payload.skills)\n .filter(([, skill]) => skill.install === \"eject\")\n .map(([id]) => id);\n}\n\nexport default class Share extends BaseCommand {\n static summary = \"Share this installation as an id anyone can install\";\n\n static description =\n \"Turns the skills, sub-agents and per-agent curation installed here into a configuration the agentsinc.sh store holds, and prints the id it was given. Install it elsewhere with 'init --from <id>', or open it in the editor. The id is the configuration's own hash, so sharing an unchanged installation returns the id it already had.\";\n\n static flags = {\n stdin: Flags.boolean({\n description:\n \"Share a configuration piped in on standard input instead of the one installed here\",\n default: false,\n }),\n provider: providerFlag(),\n };\n\n static examples = [\n \"<%= config.bin %> <%= command.id %>\",\n \"cat proposal.json | <%= config.bin %> <%= command.id %> --stdin\",\n ];\n\n /**\n * Read, map, refuse, publish, then say what the id will not do everywhere.\n *\n * Everything that can fail locally fails before the POST. The store's free tier allows a\n * thousand writes a day and reads a hundred times that, so a write is the scarce half — and one\n * spent on a configuration that cannot be installed buys a dead link.\n *\n * The first three steps are `seedPayloadForInstallation`, shared with `edit --ui`: the two\n * commands mint the same id from the same directory and differ only in what they do with it.\n * The one refusal `edit --ui` does not share is of ejected skills — a share carries plugins\n * only, and the editor is where a user goes to turn ejected skills into plugins.\n */\n async run(): Promise<void> {\n const { flags } = await this.parse(Share);\n\n // Only the installation path reads a directory. A piped payload is the CALLER's configuration\n // and no folder on this machine decides anything about it, so neither a scope holding two\n // installations nor a placement this host cannot fill is this run's problem — asking anyway\n // would refuse a `--stdin` share for the state of a directory it never opens.\n if (!flags.stdin) {\n await refuseAnAmbiguousInstallation(\n process.cwd(),\n \"share\",\n providerNamedBy(flags.provider),\n (message) => this.error(message, { exit: EXIT_CODES.INVALID_ARGS }),\n );\n await this.ensureConfigReadable(process.cwd());\n await this.refuseUnofferablePlacements(process.cwd());\n // With two source folders on disk the resolver reads whichever holds a `config.ts`, which\n // can be the stale one — and an id minted from it describes an installation nobody chose.\n await this.settleSourceLayoutBeforeWriting(process.cwd());\n }\n\n const { payload, caveats } = flags.stdin\n ? await this.payloadFromPipe()\n : await this.payloadFromInstallation();\n\n const published = await publishSeedConfig(payload);\n if (!published.ok) {\n this.error(published.error, { exit: EXIT_CODES.ERROR });\n }\n\n this.reportShared(published.id);\n // Through `warn()` from `utils/logger.ts` rather than `this.warn`: oclif hard-wraps at the\n // terminal width, and a caveat names a folder path that does not survive being broken.\n for (const caveat of caveats) warn(caveat);\n }\n\n /**\n * Refuses a configuration asking for a mode/scope cell its own host does not offer, before the\n * payload is built and long before the POST.\n *\n * **`share` is a read path, and the roster that names them missed it.** The list this refusal\n * was built against reads \"`compile`, `edit`, `update` and `doctor`\" and claims to be every\n * command that acts on a configuration it did not just write — while `share` sits beside them\n * reading the same file through `seedPayloadForInstallation`. What it publishes is described as\n * \"the skills, sub-agents and per-agent curation installed HERE\", and a row the host could not\n * place was never installed here at all, so the id would describe an installation that does not\n * exist. `refuseAnAmbiguousInstallation` above is this finding's sibling and was already asked;\n * the two are the pair `doctor`'s Placements row reports together.\n *\n * A refusal rather than a row, like the other three writers, and for a reason of its own: the\n * store's write is the scarce half, and one spent on an installation nothing on this machine\n * will act on buys a link to a misdescription.\n *\n * `uninstall` reads the same file and is deliberately NOT on this roster: a refusal there would\n * make an unofferable installation unremovable, which is a guard that has swallowed its domain.\n */\n private async refuseUnofferablePlacements(cwd: string): Promise<void> {\n const [finding] = await unofferablePlacementsFound(cwd);\n if (finding !== undefined) this.error(finding, { exit: EXIT_CODES.ERROR });\n }\n\n /** The installation in this directory: mapped, refused if it holds ejected skills, announced. */\n private async payloadFromInstallation(): Promise<ShareablePayload> {\n const prepared = await seedPayloadForInstallation(process.cwd());\n if (!prepared.ok) {\n this.error(prepared.error, { exit: EXIT_CODES.ERROR });\n }\n\n this.refuseEjectedSkills(prepared.payload);\n this.log(`Sharing ${prepared.skills} skill(s) across ${prepared.agents} sub-agent(s)...`);\n\n return {\n payload: prepared.payload,\n caveats: caveatsAbout(prepared.payload, prepared.leftBehind),\n };\n }\n\n /**\n * Refuses a share while anything it would send is an ejected (Local) skill.\n *\n * An ejected skill is a copy on this machine, which the user may have edited and an\n * editor-added skill always is, so a share carries plugins only — from a project, that covers\n * the ejected skills it inherits from the global installation as well as its own. A skill the\n * user wrote by hand is never in the payload, so it neither travels nor refuses.\n */\n private refuseEjectedSkills(payload: SeedPayload): void {\n const ejected = ejectedSkillsIn(payload);\n if (ejected.length > 0) {\n this.error(shareRefusesEjectedSkills(ejected), { exit: EXIT_CODES.ERROR });\n }\n }\n\n /**\n * A configuration the CALLER holds, which is why nothing here reads an installation.\n *\n * That is the whole distinction the flag draws, and it is not cosmetic: a bare `share` resolves\n * an installation the way every other command does — this project, then the global one — so\n * without this branch, sharing a piped payload from a directory with nothing in it would\n * publish whatever the machine happens to have installed globally.\n *\n * The producer this exists for is not this CLI. `meta-config-stack-detect` walks a repository\n * and emits a `SeedPayload` it is forbidden to write or apply, and an id is the only door into\n * the editor, which reads `?fromId=` and nothing else. Publishing from here rather than from\n * the producer keeps `SEED_VERSION`, the `AGENTS_INC_API_URL` override and the caller's\n * user-agent in the one place that owns them.\n *\n * It owes no caveats: those describe an installation, and none was read.\n */\n private async payloadFromPipe(): Promise<ShareablePayload> {\n if (process.stdin.isTTY) {\n this.error(STDIN_IS_A_TERMINAL, { exit: EXIT_CODES.ERROR });\n }\n\n const read: PipedPayload = readPipedPayload(await readAllOf(process.stdin));\n if (!read.ok) {\n this.error(read.error, { exit: EXIT_CODES.ERROR });\n }\n\n return { payload: read.payload, caveats: [] };\n }\n\n /**\n * Both destinations, because an id nobody can act on is not a share and there are exactly two\n * things that read one: this CLI, and the editor the configuration can be reopened in. The\n * lines themselves are `sharedConfigDestinations`, shared with `edit --ui` for the same reason\n * the mint above is.\n */\n private reportShared(id: string): void {\n this.logSuccess(`Shared as ${id}`);\n for (const destination of sharedConfigDestinations(id)) {\n this.log(destination);\n }\n }\n}\n","import { installableSeedPayloadSchema, type SeedPayload } from \"@workspace/matrix/seed\";\n\nimport { formatZodErrors } from \"../schema-validator.js\";\nimport { getErrorMessage } from \"../../utils/errors.js\";\nimport { stripTerminalControls, truncateText } from \"../../utils/string.js\";\n\n/** A payload read from a pipe, or the reason it could not be. */\nexport type PipedPayload =\n | { readonly ok: true; readonly payload: SeedPayload }\n | { readonly ok: false; readonly error: string };\n\nexport const NOTHING_PIPED =\n \"--stdin expects a configuration on standard input and none arrived. Pipe one in, as 'cat proposal.json | agents-inc share --stdin'.\";\n\nexport const STDIN_IS_A_TERMINAL =\n \"--stdin expects a configuration on standard input, but standard input is a terminal. Pipe one in rather than typing it.\";\n\n/**\n * How much of a body to quote back when it is not JSON, so a refusal names what it read.\n *\n * A CHARACTER bound, because what it clips is arbitrary bytes a producer piped by mistake: any\n * cut is as good as any other, and the point is only that the caller recognises what they sent.\n */\nconst EXCERPT = 80;\n\n/**\n * How many problems to name before the rest are counted instead.\n *\n * The scope rule raises one issue per (skill, sub-agent) PAIR rather than one per payload, and\n * each renders at roughly 150 characters — the same sentence every time, with two names changed.\n * A repository scan is 20-40 skills across 3-6 sub-agents, so an unbounded list is 60-240 of them\n * and hundreds of lines: the refusal becomes the wall of text it is complaining about.\n *\n * Four, so the whole message lands near twice the 300-character `EXPLANATION_BUDGET` in\n * `publish-seed.ts`, which bounds the store's account of this same refusal arriving over the\n * wire. Twice, because that one quotes back a remote explanation of a payload already sent, where\n * these are the caller's own pairs and each name is somewhere they have to go and edit — and four\n * of them is enough to show the mistake is a pattern rather than a one-off.\n *\n * A COUNT rather than a `truncateText` over the joined list, which is the one place this file's\n * two bounds differ. A character cut lands mid-sentence, and mid-sentence here means a half-named\n * skill or sub-agent — worse than one left out and counted, because it reads as a name.\n */\nconst PROBLEMS_NAMED = 4;\n\n/**\n * Everything that can fail locally, failing before the caller spends a write.\n *\n * The store's free tier allows a thousand writes a day against a hundred times that in reads, so\n * a write is the scarce half — and one spent on a payload the decoder cannot read buys a dead\n * link. Each of the three refusals below is a different mistake and says which: nothing arrived,\n * what arrived is not JSON, or it is JSON the contract does not accept.\n *\n * `installableSeedPayloadSchema` rather than a shape written here, and that is the point of\n * publishing from the CLI at all. `SEED_VERSION` is a `z.literal`, so a producer that hardcodes\n * the wire format emits payloads the store refuses the day it moves; the schema travels with the\n * code that posts.\n *\n * THE *INSTALLABLE* SCHEMA, AND THE DIFFERENCE IS THE WHOLE BUG THIS CLOSED. The worker validates\n * a POST with `installableSeedPayloadSchema` and a GET with the base `seedPayloadSchema` — write\n * strict, read lenient, deliberately, so links already in the wild stay repairable in the editor.\n * This gate read the BASE schema, so the one rule the two differ by — a project-scoped skill\n * assigned to a sub-agent resting at global, which has nowhere to be written — was the single\n * payload that passed locally and failed at the edge. It arrived as a bare `HTTP 400`.\n *\n * That was not an exotic shape. `agents` is sparse and an absent entry rests on the shared default\n * of `global`, so \"assign a skill and say nothing else\" is already the unwritable pair;\n * `meta-config-stack-detect` emitted it on every run. Reading the same schema the store writes\n * with is what makes this file's promise — everything that can fail locally, failing before the\n * caller spends a write — true rather than nearly true.\n */\nexport function readPipedPayload(body: string): PipedPayload {\n if (body.trim() === \"\") return { ok: false, error: NOTHING_PIPED };\n\n const read = readJson(body);\n if (!read.parsed) return { ok: false, error: notJsonMessage(body, read.reason) };\n\n const result = installableSeedPayloadSchema.safeParse(read.value);\n if (!result.success) {\n return { ok: false, error: refusedByContract(formatZodErrors(result.error)) };\n }\n\n return { ok: true, payload: result.data };\n}\n\n/** Whether a body is JSON at all, separated from whether it is a payload. */\ntype JsonRead =\n | { readonly parsed: true; readonly value: unknown }\n | { readonly parsed: false; readonly reason: string };\n\n/**\n * `JSON.parse` behind a verdict, so the caller reads as three guards rather than as a `let`\n * assigned inside a `try`. The same shape `readYaml` takes in `lib/skills/skill-metadata.ts`,\n * for the same reason: the failure is one of several a reader has to tell apart, and a thrown\n * exception is the one form that cannot sit beside the others.\n */\nfunction readJson(body: string): JsonRead {\n try {\n return { parsed: true, value: JSON.parse(body) };\n } catch (error) {\n return { parsed: false, reason: getErrorMessage(error) };\n }\n}\n\n/**\n * Two quotes of the same untrusted body, and both have to be made inert.\n *\n * The excerpt is the obvious one. The REASON is not, and it is the one that got through: V8 writes\n * `Unexpected token 'h', \"here is...\" is not valid JSON`, quoting the offending input verbatim, so\n * a parser's own account of a failure carries whatever caused it. `truncateText` covers the\n * excerpt; nothing covered the reason, because nothing looked like it came from outside.\n */\nfunction notJsonMessage(body: string, reason: string): string {\n const opening = truncateText(body.trim(), EXCERPT);\n const said = stripTerminalControls(reason);\n return `What arrived on standard input is not JSON: ${said}. It began: ${opening}`;\n}\n\nfunction refusedByContract(problems: string[]): string {\n return `The configuration on standard input is not one this store accepts: ${namedProblems(problems)}`;\n}\n\n/**\n * The first few problems in full, and a count of however many were left out.\n *\n * The count is what keeps a clipped list honest. Without it a caller who fixed the pairs named\n * here and ran again would have no way to tell this from a complete list — so the second refusal\n * would read as a new fault rather than as the rest of the one they were already fixing.\n */\nfunction namedProblems(problems: string[]): string {\n const named = problems.slice(0, PROBLEMS_NAMED).join(\"; \");\n const elided = problems.length - PROBLEMS_NAMED;\n return elided > 0 ? `${named} (and ${elided} more)` : named;\n}\n","import type { Readable } from \"node:stream\";\n\n/**\n * Every chunk of a readable, as text.\n *\n * A stream rather than `readFileSync(\"/dev/stdin\")`: that path does not exist on every platform\n * this CLI runs on, and it reads a pipe the operating system may still be filling. Async\n * iteration is the one form that is correct on all of them.\n */\nexport async function readAllOf(stream: Readable): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));\n }\n\n return Buffer.concat(chunks).toString(\"utf-8\");\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/commands/share.ts","../../src/cli/lib/seed/read-piped-payload.ts","../../src/cli/utils/read-stream.ts"],"sourcesContent":["import { Flags } from \"@oclif/core\";\n\nimport { BaseCommand } from \"../base-command.js\";\nimport { isLocalSource } from \"../lib/configuration/config.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { unofferablePlacementsFound } from \"../lib/hosts/configured-placements.js\";\nimport { seedPayloadForInstallation } from \"../lib/seed/installation-payload.js\";\nimport { publishSeedConfig } from \"../lib/seed/publish-seed.js\";\nimport {\n readPipedPayload,\n STDIN_IS_A_TERMINAL,\n type PipedPayload,\n} from \"../lib/seed/read-piped-payload.js\";\nimport {\n providerFlag,\n providerNamedBy,\n refuseAnAmbiguousInstallation,\n} from \"../lib/installation/provider-flag.js\";\nimport { warn } from \"../utils/logger.js\";\nimport { readAllOf } from \"../utils/read-stream.js\";\nimport {\n sharedConfigDestinations,\n sharedIdNamesAFolder,\n sharedSkillsLeftBehind,\n shareRefusesEjectedSkills,\n} from \"../utils/messages.js\";\nimport { typedEntries } from \"../utils/typed-object.js\";\nimport type { SkillId } from \"../types/index.js\";\nimport type { SeedPayload } from \"@workspace/matrix/seed\";\n\n/** A payload to publish, and what is owed about it once it has an id. */\ntype ShareablePayload = { payload: SeedPayload; caveats: string[] };\n\n/**\n * What an id minted from this installation will not do everywhere, said after the id rather than\n * refused: it still installs everything else.\n *\n * A payload names one marketplace, by the ref `--marketplace` took. A folder is a ref only this\n * machine can follow, and a plugin from any other marketplace is skipped wherever the id is\n * installed.\n */\nfunction caveatsAbout(payload: SeedPayload, leftBehind: readonly SkillId[]): string[] {\n const { marketplace } = payload;\n return [\n ...(isAFolder(marketplace) ? [sharedIdNamesAFolder(marketplace)] : []),\n ...(leftBehind.length > 0 ? [sharedSkillsLeftBehind(leftBehind)] : []),\n ];\n}\n\n/** Whether a payload's marketplace ref is a folder on this machine rather than a repository. */\nfunction isAFolder(marketplace: string | undefined): marketplace is string {\n return marketplace !== undefined && isLocalSource(marketplace);\n}\n\n/** The skills a payload asks the receiver to eject — local copies, editor-added ones included. */\nfunction ejectedSkillsIn(payload: SeedPayload): string[] {\n return typedEntries(payload.skills)\n .filter(([, skill]) => skill.install === \"eject\")\n .map(([id]) => id);\n}\n\nexport default class Share extends BaseCommand {\n static summary = \"Share this installation as an id anyone can install\";\n\n static description =\n \"Turns the skills, sub-agents and per-agent curation installed here into a configuration the agentsinc.sh store holds, and prints the id it was given. Install it elsewhere with 'init --from <id>', or open it in the editor. The id is the configuration's own hash, so sharing an unchanged installation returns the id it already had.\";\n\n static flags = {\n stdin: Flags.boolean({\n description:\n \"Share a configuration piped in on standard input instead of the one installed here\",\n default: false,\n }),\n provider: providerFlag(),\n };\n\n static examples = [\n \"<%= config.bin %> <%= command.id %>\",\n \"cat proposal.json | <%= config.bin %> <%= command.id %> --stdin\",\n ];\n\n /**\n * Read, map, refuse, publish, then say what the id will not do everywhere.\n *\n * Everything that can fail locally fails before the POST. The store's free tier allows a\n * thousand writes a day and reads a hundred times that, so a write is the scarce half — and one\n * spent on a configuration that cannot be installed buys a dead link.\n *\n * The first three steps are `seedPayloadForInstallation`, shared with `edit --ui`: the two\n * commands mint the same id from the same directory and differ only in what they do with it.\n * The one refusal `edit --ui` does not share is of ejected skills — a share carries plugins\n * only, and the editor is where a user goes to turn ejected skills into plugins.\n */\n async run(): Promise<void> {\n const { flags } = await this.parse(Share);\n\n // Only the installation path reads a directory. A piped payload is the CALLER's configuration\n // and no folder on this machine decides anything about it, so neither a scope holding two\n // installations nor a placement this host cannot fill is this run's problem — asking anyway\n // would refuse a `--stdin` share for the state of a directory it never opens.\n if (!flags.stdin) {\n await refuseAnAmbiguousInstallation(\n process.cwd(),\n \"share\",\n providerNamedBy(flags.provider),\n (message) => this.error(message, { exit: EXIT_CODES.INVALID_ARGS }),\n );\n await this.ensureConfigReadable(process.cwd());\n await this.refuseUnofferablePlacements(process.cwd());\n }\n\n const { payload, caveats } = flags.stdin\n ? await this.payloadFromPipe()\n : await this.payloadFromInstallation();\n\n const published = await publishSeedConfig(payload);\n if (!published.ok) {\n this.error(published.error, { exit: EXIT_CODES.ERROR });\n }\n\n this.reportShared(published.id);\n // Through `warn()` from `utils/logger.ts` rather than `this.warn`: oclif hard-wraps at the\n // terminal width, and a caveat names a folder path that does not survive being broken.\n for (const caveat of caveats) warn(caveat);\n }\n\n /**\n * Refuses a configuration asking for a mode/scope cell its own host does not offer, before the\n * payload is built and long before the POST.\n *\n * **`share` is a read path, and the roster that names them missed it.** The list this refusal\n * was built against reads \"`compile`, `edit`, `update` and `doctor`\" and claims to be every\n * command that acts on a configuration it did not just write — while `share` sits beside them\n * reading the same file through `seedPayloadForInstallation`. What it publishes is described as\n * \"the skills, sub-agents and per-agent curation installed HERE\", and a row the host could not\n * place was never installed here at all, so the id would describe an installation that does not\n * exist. `refuseAnAmbiguousInstallation` above is this finding's sibling and was already asked;\n * the two are the pair `doctor`'s Placements row reports together.\n *\n * A refusal rather than a row, like the other three writers, and for a reason of its own: the\n * store's write is the scarce half, and one spent on an installation nothing on this machine\n * will act on buys a link to a misdescription.\n *\n * `uninstall` reads the same file and is deliberately NOT on this roster: a refusal there would\n * make an unofferable installation unremovable, which is a guard that has swallowed its domain.\n */\n private async refuseUnofferablePlacements(cwd: string): Promise<void> {\n const [finding] = await unofferablePlacementsFound(cwd);\n if (finding !== undefined) this.error(finding, { exit: EXIT_CODES.ERROR });\n }\n\n /** The installation in this directory: mapped, refused if it holds ejected skills, announced. */\n private async payloadFromInstallation(): Promise<ShareablePayload> {\n const prepared = await seedPayloadForInstallation(process.cwd());\n if (!prepared.ok) {\n this.error(prepared.error, { exit: EXIT_CODES.ERROR });\n }\n\n this.refuseEjectedSkills(prepared.payload);\n this.log(`Sharing ${prepared.skills} skill(s) across ${prepared.agents} sub-agent(s)...`);\n\n return {\n payload: prepared.payload,\n caveats: caveatsAbout(prepared.payload, prepared.leftBehind),\n };\n }\n\n /**\n * Refuses a share while anything it would send is an ejected (Local) skill.\n *\n * An ejected skill is a copy on this machine, which the user may have edited and an\n * editor-added skill always is, so a share carries plugins only — from a project, that covers\n * the ejected skills it inherits from the global installation as well as its own. A skill the\n * user wrote by hand is never in the payload, so it neither travels nor refuses.\n */\n private refuseEjectedSkills(payload: SeedPayload): void {\n const ejected = ejectedSkillsIn(payload);\n if (ejected.length > 0) {\n this.error(shareRefusesEjectedSkills(ejected), { exit: EXIT_CODES.ERROR });\n }\n }\n\n /**\n * A configuration the CALLER holds, which is why nothing here reads an installation.\n *\n * That is the whole distinction the flag draws, and it is not cosmetic: a bare `share` resolves\n * an installation the way every other command does — this project, then the global one — so\n * without this branch, sharing a piped payload from a directory with nothing in it would\n * publish whatever the machine happens to have installed globally.\n *\n * The producer this exists for is not this CLI. `meta-config-stack-detect` walks a repository\n * and emits a `SeedPayload` it is forbidden to write or apply, and an id is the only door into\n * the editor, which reads `?fromId=` and nothing else. Publishing from here rather than from\n * the producer keeps `SEED_VERSION`, the `AGENTS_INC_API_URL` override and the caller's\n * user-agent in the one place that owns them.\n *\n * It owes no caveats: those describe an installation, and none was read.\n */\n private async payloadFromPipe(): Promise<ShareablePayload> {\n if (process.stdin.isTTY) {\n this.error(STDIN_IS_A_TERMINAL, { exit: EXIT_CODES.ERROR });\n }\n\n const read: PipedPayload = readPipedPayload(await readAllOf(process.stdin));\n if (!read.ok) {\n this.error(read.error, { exit: EXIT_CODES.ERROR });\n }\n\n return { payload: read.payload, caveats: [] };\n }\n\n /**\n * Both destinations, because an id nobody can act on is not a share and there are exactly two\n * things that read one: this CLI, and the editor the configuration can be reopened in. The\n * lines themselves are `sharedConfigDestinations`, shared with `edit --ui` for the same reason\n * the mint above is.\n */\n private reportShared(id: string): void {\n this.logSuccess(`Shared as ${id}`);\n for (const destination of sharedConfigDestinations(id)) {\n this.log(destination);\n }\n }\n}\n","import { installableSeedPayloadSchema, type SeedPayload } from \"@workspace/matrix/seed\";\n\nimport { formatZodErrors } from \"../schema-validator.js\";\nimport { getErrorMessage } from \"../../utils/errors.js\";\nimport { stripTerminalControls, truncateText } from \"../../utils/string.js\";\n\n/** A payload read from a pipe, or the reason it could not be. */\nexport type PipedPayload =\n | { readonly ok: true; readonly payload: SeedPayload }\n | { readonly ok: false; readonly error: string };\n\nexport const NOTHING_PIPED =\n \"--stdin expects a configuration on standard input and none arrived. Pipe one in, as 'cat proposal.json | agents-inc share --stdin'.\";\n\nexport const STDIN_IS_A_TERMINAL =\n \"--stdin expects a configuration on standard input, but standard input is a terminal. Pipe one in rather than typing it.\";\n\n/**\n * How much of a body to quote back when it is not JSON, so a refusal names what it read.\n *\n * A CHARACTER bound, because what it clips is arbitrary bytes a producer piped by mistake: any\n * cut is as good as any other, and the point is only that the caller recognises what they sent.\n */\nconst EXCERPT = 80;\n\n/**\n * How many problems to name before the rest are counted instead.\n *\n * The scope rule raises one issue per (skill, sub-agent) PAIR rather than one per payload, and\n * each renders at roughly 150 characters — the same sentence every time, with two names changed.\n * A repository scan is 20-40 skills across 3-6 sub-agents, so an unbounded list is 60-240 of them\n * and hundreds of lines: the refusal becomes the wall of text it is complaining about.\n *\n * Four, so the whole message lands near twice the 300-character `EXPLANATION_BUDGET` in\n * `publish-seed.ts`, which bounds the store's account of this same refusal arriving over the\n * wire. Twice, because that one quotes back a remote explanation of a payload already sent, where\n * these are the caller's own pairs and each name is somewhere they have to go and edit — and four\n * of them is enough to show the mistake is a pattern rather than a one-off.\n *\n * A COUNT rather than a `truncateText` over the joined list, which is the one place this file's\n * two bounds differ. A character cut lands mid-sentence, and mid-sentence here means a half-named\n * skill or sub-agent — worse than one left out and counted, because it reads as a name.\n */\nconst PROBLEMS_NAMED = 4;\n\n/**\n * Everything that can fail locally, failing before the caller spends a write.\n *\n * The store's free tier allows a thousand writes a day against a hundred times that in reads, so\n * a write is the scarce half — and one spent on a payload the decoder cannot read buys a dead\n * link. Each of the three refusals below is a different mistake and says which: nothing arrived,\n * what arrived is not JSON, or it is JSON the contract does not accept.\n *\n * `installableSeedPayloadSchema` rather than a shape written here, and that is the point of\n * publishing from the CLI at all. `SEED_VERSION` is a `z.literal`, so a producer that hardcodes\n * the wire format emits payloads the store refuses the day it moves; the schema travels with the\n * code that posts.\n *\n * THE *INSTALLABLE* SCHEMA, AND THE DIFFERENCE IS THE WHOLE BUG THIS CLOSED. The worker validates\n * a POST with `installableSeedPayloadSchema` and a GET with the base `seedPayloadSchema` — write\n * strict, read lenient, deliberately, so links already in the wild stay repairable in the editor.\n * This gate read the BASE schema, so the one rule the two differ by — a project-scoped skill\n * assigned to a sub-agent resting at global, which has nowhere to be written — was the single\n * payload that passed locally and failed at the edge. It arrived as a bare `HTTP 400`.\n *\n * That was not an exotic shape. `agents` is sparse and an absent entry rests on the shared default\n * of `global`, so \"assign a skill and say nothing else\" is already the unwritable pair;\n * `meta-config-stack-detect` emitted it on every run. Reading the same schema the store writes\n * with is what makes this file's promise — everything that can fail locally, failing before the\n * caller spends a write — true rather than nearly true.\n */\nexport function readPipedPayload(body: string): PipedPayload {\n if (body.trim() === \"\") return { ok: false, error: NOTHING_PIPED };\n\n const read = readJson(body);\n if (!read.parsed) return { ok: false, error: notJsonMessage(body, read.reason) };\n\n const result = installableSeedPayloadSchema.safeParse(read.value);\n if (!result.success) {\n return { ok: false, error: refusedByContract(formatZodErrors(result.error)) };\n }\n\n return { ok: true, payload: result.data };\n}\n\n/** Whether a body is JSON at all, separated from whether it is a payload. */\ntype JsonRead =\n | { readonly parsed: true; readonly value: unknown }\n | { readonly parsed: false; readonly reason: string };\n\n/**\n * `JSON.parse` behind a verdict, so the caller reads as three guards rather than as a `let`\n * assigned inside a `try`. The same shape `readYaml` takes in `lib/skills/skill-metadata.ts`,\n * for the same reason: the failure is one of several a reader has to tell apart, and a thrown\n * exception is the one form that cannot sit beside the others.\n */\nfunction readJson(body: string): JsonRead {\n try {\n return { parsed: true, value: JSON.parse(body) };\n } catch (error) {\n return { parsed: false, reason: getErrorMessage(error) };\n }\n}\n\n/**\n * Two quotes of the same untrusted body, and both have to be made inert.\n *\n * The excerpt is the obvious one. The REASON is not, and it is the one that got through: V8 writes\n * `Unexpected token 'h', \"here is...\" is not valid JSON`, quoting the offending input verbatim, so\n * a parser's own account of a failure carries whatever caused it. `truncateText` covers the\n * excerpt; nothing covered the reason, because nothing looked like it came from outside.\n */\nfunction notJsonMessage(body: string, reason: string): string {\n const opening = truncateText(body.trim(), EXCERPT);\n const said = stripTerminalControls(reason);\n return `What arrived on standard input is not JSON: ${said}. It began: ${opening}`;\n}\n\nfunction refusedByContract(problems: string[]): string {\n return `The configuration on standard input is not one this store accepts: ${namedProblems(problems)}`;\n}\n\n/**\n * The first few problems in full, and a count of however many were left out.\n *\n * The count is what keeps a clipped list honest. Without it a caller who fixed the pairs named\n * here and ran again would have no way to tell this from a complete list — so the second refusal\n * would read as a new fault rather than as the rest of the one they were already fixing.\n */\nfunction namedProblems(problems: string[]): string {\n const named = problems.slice(0, PROBLEMS_NAMED).join(\"; \");\n const elided = problems.length - PROBLEMS_NAMED;\n return elided > 0 ? `${named} (and ${elided} more)` : named;\n}\n","import type { Readable } from \"node:stream\";\n\n/**\n * Every chunk of a readable, as text.\n *\n * A stream rather than `readFileSync(\"/dev/stdin\")`: that path does not exist on every platform\n * this CLI runs on, and it reads a pipe the operating system may still be filling. Async\n * iteration is the one form that is correct on all of them.\n */\nexport async function readAllOf(stream: Readable): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));\n }\n\n return Buffer.concat(chunks).toString(\"utf-8\");\n}\n"],"mappings":"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","names":[]}
|