@ekanos/cli 0.17.1 → 0.19.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/README.md +1 -0
- package/dist/commands/add.js +1 -1
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/catalog.js +11 -7
- package/dist/commands/catalog.js.map +1 -1
- package/dist/commands/names.d.ts +19 -0
- package/dist/commands/names.js +122 -0
- package/dist/commands/names.js.map +1 -0
- package/dist/commands/publish.d.ts +53 -3
- package/dist/commands/publish.js +58 -16
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/sources.js +15 -5
- package/dist/commands/sources.js.map +1 -1
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.js +12 -12
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/sync.js +2 -2
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/teams-connect.js +1 -1
- package/dist/commands/teams-connect.js.map +1 -1
- package/dist/experience/boundary.d.ts +2 -2
- package/dist/experience/boundary.js +2 -11
- package/dist/experience/boundary.js.map +1 -1
- package/dist/experience/build.d.ts +3 -1
- package/dist/experience/build.js +15 -26
- package/dist/experience/build.js.map +1 -1
- package/dist/experience/clean-room.d.ts +40 -0
- package/dist/experience/clean-room.js +150 -0
- package/dist/experience/clean-room.js.map +1 -0
- package/dist/experience/contract-sources.d.ts +7 -2
- package/dist/experience/contract-sources.js +15 -8
- package/dist/experience/contract-sources.js.map +1 -1
- package/dist/experience/definition-checks.d.ts +12 -1
- package/dist/experience/definition-checks.js +34 -11
- package/dist/experience/definition-checks.js.map +1 -1
- package/dist/experience/definition-shape.d.ts +20 -2
- package/dist/experience/definition-shape.js.map +1 -1
- package/dist/experience/project.js +8 -2
- package/dist/experience/project.js.map +1 -1
- package/dist/experience/publish.d.ts +42 -5
- package/dist/experience/publish.js +195 -11
- package/dist/experience/publish.js.map +1 -1
- package/dist/harness-scaffold.js +3 -1
- package/dist/harness-scaffold.js.map +1 -1
- package/dist/index.js +25 -2
- package/dist/index.js.map +1 -1
- package/dist/names-api.d.ts +90 -0
- package/dist/names-api.js +123 -0
- package/dist/names-api.js.map +1 -0
- package/dist/product-kinds.d.ts +13 -0
- package/dist/product-kinds.js +17 -0
- package/dist/product-kinds.js.map +1 -0
- package/dist/publish-api.d.ts +38 -5
- package/dist/publish-api.js +59 -16
- package/dist/publish-api.js.map +1 -1
- package/dist/repo/publish.d.ts +6 -3
- package/dist/repo/publish.js +48 -14
- package/dist/repo/publish.js.map +1 -1
- package/dist/source-products-api.d.ts +3 -2
- package/dist/source-products-api.js +1 -1
- package/dist/source-products-api.js.map +1 -1
- package/dist/team-connect-api.d.ts +4 -0
- package/dist/team-connect-api.js +1 -1
- package/dist/team-connect-api.js.map +1 -1
- package/dist/toolchain-api.d.ts +15 -0
- package/dist/toolchain-api.js +12 -1
- package/dist/toolchain-api.js.map +1 -1
- package/package.json +2 -2
- package/templates/experience/package.json.tmpl +7 -4
- package/templates/harness/app/experience/layout/page.tsx.tmpl +1 -0
- package/templates/harness/app/experience/layout.tsx.tmpl +3 -0
- package/templates/harness/app/experience/pages/[id]/[...path]/page.tsx.tmpl +1 -0
- package/templates/package.json.tmpl +4 -4
package/dist/toolchain-api.d.ts
CHANGED
|
@@ -23,6 +23,11 @@ import { type ToolchainNote, type ToolchainVersions } from './toolchain.js';
|
|
|
23
23
|
* // host
|
|
24
24
|
* // refuses
|
|
25
25
|
* notes?: [{ level: "warn" | "info", message: string }],
|
|
26
|
+
* capabilities?: { experienceSubmissions?: boolean }, // optional
|
|
27
|
+
* // host features; a host
|
|
28
|
+
* // that predates one omits
|
|
29
|
+
* // the key and a caller
|
|
30
|
+
* // reads that as "no"
|
|
26
31
|
* } }
|
|
27
32
|
* → any other status, or a body that fails to parse or match this shape
|
|
28
33
|
*
|
|
@@ -46,10 +51,20 @@ import { type ToolchainNote, type ToolchainVersions } from './toolchain.js';
|
|
|
46
51
|
* outright rather than quietly papered over by the npm fallback.
|
|
47
52
|
* ---------------------------------------------------------------------------
|
|
48
53
|
*/
|
|
54
|
+
/**
|
|
55
|
+
* Optional host features, advertised additively. A key the host does not send
|
|
56
|
+
* reads as `false`, so an older deployment behaves exactly as before.
|
|
57
|
+
*/
|
|
58
|
+
export interface HostCapabilities {
|
|
59
|
+
/** `POST /api/partner/submissions` accepts `kind=experience` and the host admits it. */
|
|
60
|
+
experienceSubmissions: boolean;
|
|
61
|
+
}
|
|
49
62
|
export interface ToolchainReport {
|
|
50
63
|
current: ToolchainVersions;
|
|
51
64
|
minimum: ToolchainVersions;
|
|
52
65
|
notes: ToolchainNote[];
|
|
66
|
+
/** Absent when the host sent none (an older host). */
|
|
67
|
+
capabilities?: HostCapabilities;
|
|
53
68
|
}
|
|
54
69
|
export type FetchToolchainResult = {
|
|
55
70
|
status: 'ok';
|
package/dist/toolchain-api.js
CHANGED
|
@@ -48,7 +48,18 @@ function parseReport(body) {
|
|
|
48
48
|
}
|
|
49
49
|
const rawNotes = data.notes;
|
|
50
50
|
const notes = Array.isArray(rawNotes) ? rawNotes.filter(isNote) : [];
|
|
51
|
-
|
|
51
|
+
const capabilities = parseCapabilities(data.capabilities);
|
|
52
|
+
return Object.assign({ current,
|
|
53
|
+
minimum,
|
|
54
|
+
notes }, (capabilities ? { capabilities } : {}));
|
|
55
|
+
}
|
|
56
|
+
function parseCapabilities(value) {
|
|
57
|
+
if (typeof value !== 'object' || value === null)
|
|
58
|
+
return null;
|
|
59
|
+
return {
|
|
60
|
+
experienceSubmissions: value.experienceSubmissions ===
|
|
61
|
+
true,
|
|
62
|
+
};
|
|
52
63
|
}
|
|
53
64
|
function parseVersions(value) {
|
|
54
65
|
if (typeof value !== 'object' || value === null)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolchain-api.js","sourceRoot":"","sources":["../src/toolchain-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EACL,kBAAkB,EAGlB,mBAAmB,GACpB,MAAM,aAAa,CAAC;AA6DrB,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAAY,EACZ,WAAmB;IAEnB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,IAAI,wBAAwB,EAAE;YAC9D,MAAM,EAAE,KAAK;YACb,OAAO,EAAE;gBACP,MAAM,EAAE,kBAAkB;gBAC1B,aAAa,EAAE,UAAU,WAAW,EAAE;aACvC;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;QAEnD,MAAM,IAAI,GAAY,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC5C,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QAEjC,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;QACtD,IAAI,SAAS,IAAI,MAAM;YACrB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;QACvD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAClC,CAAC;eAAO,CAAC;QACP,uEAAuE;QACvE,qEAAqE;QACrE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IACnC,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAClB,IAAa;IAEb,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC3D,MAAM,IAAI,GAAI,IAA2B,CAAC,IAAI,CAAC;IAC/C,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAE3D,MAAM,OAAO,GAAG,aAAa,CAAE,IAA8B,CAAC,OAAO,CAAC,CAAC;IACvE,MAAM,OAAO,GAAG,aAAa,CAAE,IAA8B,CAAC,OAAO,CAAC,CAAC;IACvE,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAEtC,KAAK,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI;QAC9B,CAAC,SAAS,EAAE,OAAO,CAAC;QACpB,CAAC,SAAS,EAAE,OAAO,CAAC;KACZ,EAAE,CAAC;QACX,MAAM,GAAG,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAC1C,IAAI,GAAG,EAAE,CAAC;YACR,OAAO;gBACL,OAAO,EAAE,cAAc,KAAK,IAAI,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,iCAAiC;aAC7H,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAI,IAA4B,CAAC,KAAK,CAAC;IACrD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAErE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AACrC,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC7D,MAAM,MAAM,GAAG,KAAgC,CAAC;IAChD,MAAM,MAAM,GAA+B,EAAE,CAAC;IAE9C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAC3B,kBAAkB,CACY,EAAE,CAAC;QACjC,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAC7D,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IACpB,CAAC;IAED,OAAO,MAA2B,CAAC;AACrC,CAAC;AAED,SAAS,MAAM,CAAC,KAAc;IAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,IAAI,GAAG,KAA+C,CAAC;IAC7D,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,KAAK,MAAM,IAAI,IAAI,CAAC,KAAK,KAAK,MAAM,CAAC;QAChD,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,CACjC,CAAC;AACJ,CAAC","sourcesContent":["import { request } from './auth/ekanos-api';\nimport {\n TOOLCHAIN_PACKAGES,\n type ToolchainNote,\n type ToolchainVersions,\n firstInexactVersion,\n} from './toolchain';\n\n/**\n * The CLI's client for the Ekanos toolchain-advisory route.\n *\n * ---------------------------------------------------------------------------\n * WIRE CONTRACT — the seam between this package and the Ekanos web app.\n *\n * The server side is the host's `/api/partner/toolchain` route and ships on\n * a DIFFERENT BRANCH from this file, same as every other route in\n * `auth/ekanos-api.ts` and `publish-api.ts`. Nothing here imports host code;\n * the two halves are coupled only by HTTP, and the tests stub `fetch`,\n * never the route.\n *\n * GET /api/partner/toolchain [Authorization: Bearer <access_token>]\n * → 200 { ok: true, data: {\n * current: { cli, sdk, ui, integrationSchema, harness }, // the\n * // coherent\n * // set the\n * // host\n * // recommends\n * minimum: { cli, sdk, ui, integrationSchema, harness }, // below\n * // this the\n * // host\n * // refuses\n * notes?: [{ level: \"warn\" | \"info\", message: string }],\n * } }\n * → any other status, or a body that fails to parse or match this shape\n *\n * This endpoint is treated as ADVISORY, not authoritative in the way the auth\n * and submission routes are: a 404 (an older Ekanos deployment that predates\n * this route) or a 501 (deliberately unimplemented) are both entirely\n * ordinary, and a 4xx/5xx/network failure/malformed body all mean exactly the\n * same thing to every caller — \"the endpoint is unavailable, fall back to the\n * npm registry\" — so this module never throws. There is no not-configured\n * distinction to make here the way `cli-config` has: a caller with no way to\n * reach this route at all (no host, no session) never calls it in the first\n * place; see `toolchain-resolve.ts`.\n *\n * Unknown extra fields in the response are tolerated (only the fields above\n * are read); a missing `notes` defaults to an empty array.\n *\n * The one exception to \"never throws, always falls back\": a version that is\n * present but is not an exact semver (`1.2.3`, `1.2.3-rc.1`) is `invalid`, not\n * `unavailable`. Each version becomes a `pnpm add -E` spec, so a value like\n * `github:owner/repo` is a host trying to install code; that is refused\n * outright rather than quietly papered over by the npm fallback.\n * ---------------------------------------------------------------------------\n */\n\nexport interface ToolchainReport {\n current: ToolchainVersions;\n minimum: ToolchainVersions;\n notes: ToolchainNote[];\n}\n\nexport type FetchToolchainResult =\n | { status: 'ok'; report: ToolchainReport }\n | { status: 'invalid'; detail: string }\n | { status: 'unavailable' };\n\nexport async function fetchToolchainReport(\n host: string,\n accessToken: string,\n): Promise<FetchToolchainResult> {\n try {\n const response = await request(`${host}/api/partner/toolchain`, {\n method: 'GET',\n headers: {\n accept: 'application/json',\n authorization: `Bearer ${accessToken}`,\n },\n });\n\n if (!response.ok) return { status: 'unavailable' };\n\n const body: unknown = await response.json();\n const report = parseReport(body);\n\n if (report === null) return { status: 'unavailable' };\n if ('invalid' in report)\n return { status: 'invalid', detail: report.invalid };\n return { status: 'ok', report };\n } catch {\n // Network failure, timeout, or a body that is not even JSON — all read\n // the same: the endpoint is unavailable this time, fall back to npm.\n return { status: 'unavailable' };\n }\n}\n\nfunction parseReport(\n body: unknown,\n): ToolchainReport | { invalid: string } | null {\n if (typeof body !== 'object' || body === null) return null;\n const data = (body as { data?: unknown }).data;\n if (typeof data !== 'object' || data === null) return null;\n\n const current = parseVersions((data as { current?: unknown }).current);\n const minimum = parseVersions((data as { minimum?: unknown }).minimum);\n if (!current || !minimum) return null;\n\n for (const [label, versions] of [\n ['current', current],\n ['minimum', minimum],\n ] as const) {\n const bad = firstInexactVersion(versions);\n if (bad) {\n return {\n invalid: `the host's ${label} ${TOOLCHAIN_PACKAGES[bad.key]} is ${JSON.stringify(bad.value)}, which is not an exact version`,\n };\n }\n }\n\n const rawNotes = (data as { notes?: unknown }).notes;\n const notes = Array.isArray(rawNotes) ? rawNotes.filter(isNote) : [];\n\n return { current, minimum, notes };\n}\n\nfunction parseVersions(value: unknown): ToolchainVersions | null {\n if (typeof value !== 'object' || value === null) return null;\n const record = value as Record<string, unknown>;\n const result: Partial<ToolchainVersions> = {};\n\n for (const key of Object.keys(\n TOOLCHAIN_PACKAGES,\n ) as (keyof ToolchainVersions)[]) {\n const raw = record[key];\n if (typeof raw !== 'string' || raw.length === 0) return null;\n result[key] = raw;\n }\n\n return result as ToolchainVersions;\n}\n\nfunction isNote(value: unknown): value is ToolchainNote {\n if (typeof value !== 'object' || value === null) return false;\n const note = value as { level?: unknown; message?: unknown };\n return (\n (note.level === 'warn' || note.level === 'info') &&\n typeof note.message === 'string'\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"toolchain-api.js","sourceRoot":"","sources":["../src/toolchain-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EACL,kBAAkB,EAGlB,mBAAmB,GACpB,MAAM,aAAa,CAAC;AA6ErB,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAAY,EACZ,WAAmB;IAEnB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,IAAI,wBAAwB,EAAE;YAC9D,MAAM,EAAE,KAAK;YACb,OAAO,EAAE;gBACP,MAAM,EAAE,kBAAkB;gBAC1B,aAAa,EAAE,UAAU,WAAW,EAAE;aACvC;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;QAEnD,MAAM,IAAI,GAAY,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC5C,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QAEjC,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;QACtD,IAAI,SAAS,IAAI,MAAM;YACrB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;QACvD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAClC,CAAC;eAAO,CAAC;QACP,uEAAuE;QACvE,qEAAqE;QACrE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IACnC,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAClB,IAAa;IAEb,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC3D,MAAM,IAAI,GAAI,IAA2B,CAAC,IAAI,CAAC;IAC/C,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAE3D,MAAM,OAAO,GAAG,aAAa,CAAE,IAA8B,CAAC,OAAO,CAAC,CAAC;IACvE,MAAM,OAAO,GAAG,aAAa,CAAE,IAA8B,CAAC,OAAO,CAAC,CAAC;IACvE,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAEtC,KAAK,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI;QAC9B,CAAC,SAAS,EAAE,OAAO,CAAC;QACpB,CAAC,SAAS,EAAE,OAAO,CAAC;KACZ,EAAE,CAAC;QACX,MAAM,GAAG,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAC1C,IAAI,GAAG,EAAE,CAAC;YACR,OAAO;gBACL,OAAO,EAAE,cAAc,KAAK,IAAI,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,iCAAiC;aAC7H,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAI,IAA4B,CAAC,KAAK,CAAC;IACrD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAErE,MAAM,YAAY,GAAG,iBAAiB,CACnC,IAAmC,CAAC,YAAY,CAClD,CAAC;IAEF,uBACE,OAAO;QACP,OAAO;QACP,KAAK,IACF,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EACzC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAc;IACvC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAE7D,OAAO;QACL,qBAAqB,EAClB,KAA6C,CAAC,qBAAqB;YACpE,IAAI;KACP,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC7D,MAAM,MAAM,GAAG,KAAgC,CAAC;IAChD,MAAM,MAAM,GAA+B,EAAE,CAAC;IAE9C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAC3B,kBAAkB,CACY,EAAE,CAAC;QACjC,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAC7D,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IACpB,CAAC;IAED,OAAO,MAA2B,CAAC;AACrC,CAAC;AAED,SAAS,MAAM,CAAC,KAAc;IAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,IAAI,GAAG,KAA+C,CAAC;IAC7D,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,KAAK,MAAM,IAAI,IAAI,CAAC,KAAK,KAAK,MAAM,CAAC;QAChD,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,CACjC,CAAC;AACJ,CAAC","sourcesContent":["import { request } from './auth/ekanos-api';\nimport {\n TOOLCHAIN_PACKAGES,\n type ToolchainNote,\n type ToolchainVersions,\n firstInexactVersion,\n} from './toolchain';\n\n/**\n * The CLI's client for the Ekanos toolchain-advisory route.\n *\n * ---------------------------------------------------------------------------\n * WIRE CONTRACT — the seam between this package and the Ekanos web app.\n *\n * The server side is the host's `/api/partner/toolchain` route and ships on\n * a DIFFERENT BRANCH from this file, same as every other route in\n * `auth/ekanos-api.ts` and `publish-api.ts`. Nothing here imports host code;\n * the two halves are coupled only by HTTP, and the tests stub `fetch`,\n * never the route.\n *\n * GET /api/partner/toolchain [Authorization: Bearer <access_token>]\n * → 200 { ok: true, data: {\n * current: { cli, sdk, ui, integrationSchema, harness }, // the\n * // coherent\n * // set the\n * // host\n * // recommends\n * minimum: { cli, sdk, ui, integrationSchema, harness }, // below\n * // this the\n * // host\n * // refuses\n * notes?: [{ level: \"warn\" | \"info\", message: string }],\n * capabilities?: { experienceSubmissions?: boolean }, // optional\n * // host features; a host\n * // that predates one omits\n * // the key and a caller\n * // reads that as \"no\"\n * } }\n * → any other status, or a body that fails to parse or match this shape\n *\n * This endpoint is treated as ADVISORY, not authoritative in the way the auth\n * and submission routes are: a 404 (an older Ekanos deployment that predates\n * this route) or a 501 (deliberately unimplemented) are both entirely\n * ordinary, and a 4xx/5xx/network failure/malformed body all mean exactly the\n * same thing to every caller — \"the endpoint is unavailable, fall back to the\n * npm registry\" — so this module never throws. There is no not-configured\n * distinction to make here the way `cli-config` has: a caller with no way to\n * reach this route at all (no host, no session) never calls it in the first\n * place; see `toolchain-resolve.ts`.\n *\n * Unknown extra fields in the response are tolerated (only the fields above\n * are read); a missing `notes` defaults to an empty array.\n *\n * The one exception to \"never throws, always falls back\": a version that is\n * present but is not an exact semver (`1.2.3`, `1.2.3-rc.1`) is `invalid`, not\n * `unavailable`. Each version becomes a `pnpm add -E` spec, so a value like\n * `github:owner/repo` is a host trying to install code; that is refused\n * outright rather than quietly papered over by the npm fallback.\n * ---------------------------------------------------------------------------\n */\n\n/**\n * Optional host features, advertised additively. A key the host does not send\n * reads as `false`, so an older deployment behaves exactly as before.\n */\nexport interface HostCapabilities {\n /** `POST /api/partner/submissions` accepts `kind=experience` and the host admits it. */\n experienceSubmissions: boolean;\n}\n\nexport interface ToolchainReport {\n current: ToolchainVersions;\n minimum: ToolchainVersions;\n notes: ToolchainNote[];\n /** Absent when the host sent none (an older host). */\n capabilities?: HostCapabilities;\n}\n\nexport type FetchToolchainResult =\n | { status: 'ok'; report: ToolchainReport }\n | { status: 'invalid'; detail: string }\n | { status: 'unavailable' };\n\nexport async function fetchToolchainReport(\n host: string,\n accessToken: string,\n): Promise<FetchToolchainResult> {\n try {\n const response = await request(`${host}/api/partner/toolchain`, {\n method: 'GET',\n headers: {\n accept: 'application/json',\n authorization: `Bearer ${accessToken}`,\n },\n });\n\n if (!response.ok) return { status: 'unavailable' };\n\n const body: unknown = await response.json();\n const report = parseReport(body);\n\n if (report === null) return { status: 'unavailable' };\n if ('invalid' in report)\n return { status: 'invalid', detail: report.invalid };\n return { status: 'ok', report };\n } catch {\n // Network failure, timeout, or a body that is not even JSON — all read\n // the same: the endpoint is unavailable this time, fall back to npm.\n return { status: 'unavailable' };\n }\n}\n\nfunction parseReport(\n body: unknown,\n): ToolchainReport | { invalid: string } | null {\n if (typeof body !== 'object' || body === null) return null;\n const data = (body as { data?: unknown }).data;\n if (typeof data !== 'object' || data === null) return null;\n\n const current = parseVersions((data as { current?: unknown }).current);\n const minimum = parseVersions((data as { minimum?: unknown }).minimum);\n if (!current || !minimum) return null;\n\n for (const [label, versions] of [\n ['current', current],\n ['minimum', minimum],\n ] as const) {\n const bad = firstInexactVersion(versions);\n if (bad) {\n return {\n invalid: `the host's ${label} ${TOOLCHAIN_PACKAGES[bad.key]} is ${JSON.stringify(bad.value)}, which is not an exact version`,\n };\n }\n }\n\n const rawNotes = (data as { notes?: unknown }).notes;\n const notes = Array.isArray(rawNotes) ? rawNotes.filter(isNote) : [];\n\n const capabilities = parseCapabilities(\n (data as { capabilities?: unknown }).capabilities,\n );\n\n return {\n current,\n minimum,\n notes,\n ...(capabilities ? { capabilities } : {}),\n };\n}\n\nfunction parseCapabilities(value: unknown): HostCapabilities | null {\n if (typeof value !== 'object' || value === null) return null;\n\n return {\n experienceSubmissions:\n (value as { experienceSubmissions?: unknown }).experienceSubmissions ===\n true,\n };\n}\n\nfunction parseVersions(value: unknown): ToolchainVersions | null {\n if (typeof value !== 'object' || value === null) return null;\n const record = value as Record<string, unknown>;\n const result: Partial<ToolchainVersions> = {};\n\n for (const key of Object.keys(\n TOOLCHAIN_PACKAGES,\n ) as (keyof ToolchainVersions)[]) {\n const raw = record[key];\n if (typeof raw !== 'string' || raw.length === 0) return null;\n result[key] = raw;\n }\n\n return result as ToolchainVersions;\n}\n\nfunction isNote(value: unknown): value is ToolchainNote {\n if (typeof value !== 'object' || value === null) return false;\n const note = value as { level?: unknown; message?: unknown };\n return (\n (note.level === 'warn' || note.level === 'info') &&\n typeof note.message === 'string'\n );\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ekanos/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The Ekanos partner toolchain CLI: scaffold, validate, and test an Ekanos integration against the published @ekanos packages. Agent-native — every verb speaks JSON with a stable exit-code taxonomy.",
|
|
6
6
|
"keywords": [
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@clack/prompts": "1.7.0",
|
|
38
|
-
"@ekanos/integration-schema": "0.
|
|
38
|
+
"@ekanos/integration-schema": "0.21.0",
|
|
39
39
|
"esbuild": "0.28.1",
|
|
40
40
|
"picocolors": "1.1.1"
|
|
41
41
|
},
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "An Ekanos experience built with @ekanos/sdk.",
|
|
7
7
|
"files": [
|
|
8
|
+
"src",
|
|
9
|
+
"tsconfig.json",
|
|
10
|
+
"npm-shrinkwrap.json",
|
|
8
11
|
"dist",
|
|
9
12
|
"manifest.json",
|
|
10
13
|
"ekanos.json",
|
|
@@ -18,16 +21,16 @@
|
|
|
18
21
|
"build": "npx ekanos build"
|
|
19
22
|
},
|
|
20
23
|
"dependencies": {
|
|
21
|
-
"@ekanos/sdk": "^0.
|
|
22
|
-
"@ekanos/ui": "^0.
|
|
24
|
+
"@ekanos/sdk": "^0.21.0",
|
|
25
|
+
"@ekanos/ui": "^0.21.0",
|
|
23
26
|
"@tanstack/react-query": "^5.101.4",
|
|
24
27
|
"react": "^19.2.8",
|
|
25
28
|
"react-dom": "^19.2.8",
|
|
26
29
|
"zod": "^3.25.76"
|
|
27
30
|
},
|
|
28
31
|
"devDependencies": {
|
|
29
|
-
"@ekanos/cli": "^0.
|
|
30
|
-
"@ekanos/harness": "^0.
|
|
32
|
+
"@ekanos/cli": "^0.19.0",
|
|
33
|
+
"@ekanos/harness": "^0.21.0",
|
|
31
34
|
"@tailwindcss/postcss": "^4.3.3",
|
|
32
35
|
"@typescript-eslint/parser": "^8.46.2",
|
|
33
36
|
"@types/react": "^19.2.0",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ExperienceLayoutPage as default } from '@ekanos/harness/routes';
|
|
@@ -10,6 +10,9 @@ export default function ExperienceLayout(props: { children: React.ReactNode }) {
|
|
|
10
10
|
experience={{
|
|
11
11
|
widgets: experience.widgets ?? [],
|
|
12
12
|
pages: experience.pages ?? [],
|
|
13
|
+
...(experience.suggestedLayout
|
|
14
|
+
? { suggestedLayout: experience.suggestedLayout }
|
|
15
|
+
: {}),
|
|
13
16
|
}}
|
|
14
17
|
{...props}
|
|
15
18
|
/>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ExperiencePageHost as default } from '@ekanos/harness/routes';
|
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
"prepare": "node scripts/setup-hooks.mjs"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@ekanos/sdk": "^0.
|
|
16
|
-
"@ekanos/ui": "^0.
|
|
15
|
+
"@ekanos/sdk": "^0.21.0",
|
|
16
|
+
"@ekanos/ui": "^0.21.0"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@ekanos/cli": "^0.
|
|
20
|
-
"@ekanos/harness": "^0.
|
|
19
|
+
"@ekanos/cli": "^0.19.0",
|
|
20
|
+
"@ekanos/harness": "^0.21.0",
|
|
21
21
|
"@hookform/resolvers": "^5.2.2",
|
|
22
22
|
"@tailwindcss/postcss": "^4.3.3",
|
|
23
23
|
"@tanstack/react-query": "^5.101.4",
|