@ekanos/cli 0.18.0 → 0.20.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/dist/commands/add.js +1 -1
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/audiences.d.ts +5 -3
- package/dist/commands/audiences.js +6 -4
- package/dist/commands/audiences.js.map +1 -1
- package/dist/commands/scope-notice.d.ts +5 -4
- package/dist/commands/scope-notice.js +22 -11
- package/dist/commands/scope-notice.js.map +1 -1
- package/dist/commands/sync.js +2 -2
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/teams-audience.d.ts +11 -2
- package/dist/commands/teams-audience.js +22 -7
- package/dist/commands/teams-audience.js.map +1 -1
- package/dist/commands/teams-lifecycle.js +8 -2
- package/dist/commands/teams-lifecycle.js.map +1 -1
- 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.js +4 -1
- package/dist/experience/definition-checks.js.map +1 -1
- package/dist/experience/definition-shape.d.ts +2 -0
- 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/index.js +13 -9
- package/dist/index.js.map +1 -1
- package/dist/team-lifecycle-api.d.ts +30 -0
- package/dist/team-lifecycle-api.js +2 -0
- package/dist/team-lifecycle-api.js.map +1 -1
- package/dist/teams-api.js +29 -24
- package/dist/teams-api.js.map +1 -1
- package/package.json +2 -2
- package/templates/experience/package.json.tmpl +4 -4
- package/templates/package.json.tmpl +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/experience/project.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type EkanosJson,\n EkanosJsonSchema,\n type IntegrationEntry,\n type Lockfile,\n LockfileSchema,\n canonicalOperationId,\n experienceIntegrations,\n shortOperation,\n} from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport { notFoundError, validationError } from '../errors';\n\nexport const EKANOS_JSON = 'ekanos.json';\nexport const LOCK_FILE = 'ekanos.lock.json';\nexport const LOCAL_OVERRIDES_FILE = 'ekanos.local.json';\nexport const DEFAULT_CONTRACTS_DIR = 'contracts';\nexport const INTEGRATIONS_DTS = 'src/.ekanos/integrations.d.ts';\n/** The previous name of the generated file, kept as a re-export for one version. */\nexport const LEGACY_SLOTS_DTS = 'src/.ekanos/slots.d.ts';\n\nexport interface ExperienceProject {\n /** Absolute project directory. */\n dir: string;\n ekanos: EkanosJson;\n slug: string;\n entry: string;\n /** The integrations it depends on; operations are canonical ids. */\n integrations: IntegrationEntry[];\n /** True when ekanos.json still uses the deprecated `uses` key. */\n deprecatedUses: boolean;\n /** Old `uses` alias -> integration, where they differ (for the sync notice). */\n renames: Record<string, string>;\n /** Absolute directory holding the pinned contract snapshots. */\n contractsDir: string;\n /** The raw ekanos.json, key order preserved, for rewrites. */\n raw: Record<string, unknown>;\n}\n\nfunction readJson(file: string): unknown {\n let text: string;\n try {\n text = fs.readFileSync(file, 'utf8');\n } catch {\n throw notFoundError(\n `No ${path.basename(file)} at ${file}.`,\n 'Run this from an Ekanos project directory, or pass --dir <path>.',\n );\n }\n try {\n return JSON.parse(text);\n } catch (error) {\n throw validationError(\n `${file} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,\n 'Fix the syntax error and re-run.',\n );\n }\n}\n\n/** `integration` when ekanos.json is absent or says so; used to route commands. */\nexport function readProjectKind(dir: string): 'integration' | 'experience' {\n try {\n const raw = JSON.parse(\n fs.readFileSync(path.join(dir, EKANOS_JSON), 'utf8'),\n ) as { kind?: unknown };\n\n return raw.kind === 'experience' ? 'experience' : 'integration';\n } catch {\n return 'integration';\n }\n}\n\n/**\n * Read and validate an experience's ekanos.json with the shared schema.\n *\n * A fresh scaffold has no integrations yet (you add them with `ekanos add`),\n * which the shared schema rejects (\"declares at least one integration\"). That\n * one rule is suspended here so `add` can bootstrap a project; `check` and\n * `build` report the empty state themselves.\n *\n * The deprecated `uses` shape is read too: its entries come back as\n * `integrations` (alias dropped) with `deprecatedUses` set and `renames`\n * mapping each old alias to its integration, so `ekanos sync` can rewrite the\n * file and say what code to update.\n */\nexport function readExperienceProject(dir: string): ExperienceProject {\n const absolute = path.resolve(dir);\n const raw = readJson(path.join(absolute, EKANOS_JSON));\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n throw validationError(`${EKANOS_JSON} must be a JSON object.`, 'Fix it.');\n }\n const record = raw as Record<string, unknown>;\n\n if (record.kind !== 'experience') {\n throw validationError(\n `${EKANOS_JSON} is not an experience (\"kind\": \"experience\").`,\n 'Run experience commands in an experience project; scaffold one with \"ekanos init --kind experience --slug <slug>\".',\n );\n }\n\n const declaredNone =\n !(Array.isArray(record.integrations) && record.integrations.length > 0) &&\n !(Array.isArray(record.uses) && record.uses.length > 0);\n const probe = declaredNone\n ? { ...record, integrations: [PLACEHOLDER_INTEGRATION], uses: undefined }\n : record;\n const parsed = EkanosJsonSchema.safeParse(probe);\n if (!parsed.success) {\n throw validationError(\n `${EKANOS_JSON}: ${parsed.error.issues\n .map((i) => `${i.path.join('.') || '(root)'}: ${i.message}`)\n .join('; ')}`,\n 'Fix ekanos.json; the experience fields are slug, entry, integrations, contractsDir, allowImports, ignore.',\n );\n }\n\n const ekanos = parsed.data;\n const declared = declaredNone\n ? { entries: [], deprecatedUses: false, renames: {} }\n : experienceIntegrations(ekanos);\n\n return {\n dir: absolute,\n ekanos,\n slug: ekanos.slug as string,\n entry: ekanos.entry as string,\n integrations: declared.entries.map(withCanonicalOperations),\n deprecatedUses: declared.deprecatedUses,\n renames: declared.renames,\n contractsDir: path.resolve(\n absolute,\n ekanos.contractsDir ?? DEFAULT_CONTRACTS_DIR,\n ),\n raw: record,\n };\n}\n\n/** Operations as canonical `<integration>@<version>/<kind>/<name>` ids, for lookups against a contract. */\nfunction withCanonicalOperations(entry: IntegrationEntry): IntegrationEntry {\n return {\n ...entry,\n operations: entry.operations.map((id) => canonicalOperationId(entry, id)),\n };\n}\n\n/** 2-space JSON with a trailing newline: the format every written file uses. */\nexport function formatJson(value: unknown): string {\n return `${JSON.stringify(value, null, 2)}\\n`;\n}\n\n/** Write only when the bytes differ. Returns whether the file changed. */\nexport function writeIfChanged(file: string, content: string): boolean {\n try {\n if (fs.readFileSync(file, 'utf8') === content) return false;\n } catch {\n // missing: write below\n }\n fs.mkdirSync(path.dirname(file), { recursive: true });\n fs.writeFileSync(file, content);\n\n return true;\n}\n\nexport function readLockfile(project: ExperienceProject): Lockfile {\n const file = path.join(project.dir, LOCK_FILE);\n if (!fs.existsSync(file)) return { lockfileVersion: 1, integrations: {} };\n const parsed = LockfileSchema.safeParse(readJson(file));\n if (!parsed.success) {\n throw validationError(\n `${LOCK_FILE}: ${parsed.error.issues.map((i) => `${i.path.join('.')}: ${i.message}`).join('; ')}`,\n 'Regenerate it with \"ekanos sync\".',\n );\n }\n\n return parsed.data;\n}\n\nexport function writeLockfile(\n project: ExperienceProject,\n lock: Lockfile,\n): boolean {\n const integrations = Object.fromEntries(\n Object.entries(lock.integrations).sort(([a], [b]) => (a < b ? -1 : 1)),\n );\n\n return writeIfChanged(\n path.join(project.dir, LOCK_FILE),\n formatJson({ lockfileVersion: 1, integrations }),\n );\n}\n\nconst PLACEHOLDER_INTEGRATION = {\n name: 'pending',\n version: '0',\n operations: ['tool/pending'],\n} as const;\n\n/**\n * Rewrite `integrations` in ekanos.json (short operation form), leaving every\n * other key where it was and dropping the deprecated `uses`.\n */\nexport function writeIntegrations(\n project: ExperienceProject,\n integrations: IntegrationEntry[],\n): boolean {\n const { uses: _uses, ...rest } = project.raw;\n const next = {\n ...rest,\n integrations: integrations.map((entry) => ({\n name: entry.name,\n version: entry.version,\n operations: entry.operations.map(shortOperation),\n ...(entry.required === 'required' ? {} : { required: entry.required }),\n ...(entry.modes.length === 1 && entry.modes[0] === 'team'\n ? {}\n : { modes: entry.modes }),\n })),\n };\n\n return writeIfChanged(path.join(project.dir, EKANOS_JSON), formatJson(next));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/experience/project.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type EkanosJson,\n EkanosJsonSchema,\n type IntegrationEntry,\n type Lockfile,\n LockfileSchema,\n canonicalOperationId,\n experienceIntegrations,\n shortOperation,\n} from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport { notFoundError, validationError } from '../errors';\n\nexport const EKANOS_JSON = 'ekanos.json';\nexport const LOCK_FILE = 'ekanos.lock.json';\nexport const LOCAL_OVERRIDES_FILE = 'ekanos.local.json';\nexport const DEFAULT_CONTRACTS_DIR = 'contracts';\nexport const INTEGRATIONS_DTS = 'src/.ekanos/integrations.d.ts';\n/** The previous name of the generated file, kept as a re-export for one version. */\nexport const LEGACY_SLOTS_DTS = 'src/.ekanos/slots.d.ts';\n\nexport interface ExperienceProject {\n /** Absolute project directory. */\n dir: string;\n ekanos: EkanosJson;\n slug: string;\n entry: string;\n /** The integrations it depends on; operations are canonical ids. */\n integrations: IntegrationEntry[];\n /** True when ekanos.json still uses the deprecated `uses` key. */\n deprecatedUses: boolean;\n /** Old `uses` alias -> integration, where they differ (for the sync notice). */\n renames: Record<string, string>;\n /** Absolute directory holding the pinned contract snapshots. */\n contractsDir: string;\n /** The raw ekanos.json, key order preserved, for rewrites. */\n raw: Record<string, unknown>;\n}\n\nfunction readJson(file: string): unknown {\n let text: string;\n try {\n text = fs.readFileSync(file, 'utf8');\n } catch {\n throw notFoundError(\n `No ${path.basename(file)} at ${file}.`,\n 'Run this from an Ekanos project directory, or pass --dir <path>.',\n );\n }\n try {\n return JSON.parse(text);\n } catch (error) {\n throw validationError(\n `${file} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,\n 'Fix the syntax error and re-run.',\n );\n }\n}\n\n/** `integration` when ekanos.json is absent or says so; used to route commands. */\nexport function readProjectKind(dir: string): 'integration' | 'experience' {\n try {\n const raw = JSON.parse(\n fs.readFileSync(path.join(dir, EKANOS_JSON), 'utf8'),\n ) as { kind?: unknown };\n\n return raw.kind === 'experience' ? 'experience' : 'integration';\n } catch {\n return 'integration';\n }\n}\n\n/**\n * Read and validate an experience's ekanos.json with the shared schema.\n *\n * A fresh scaffold has no integrations yet (you add them with `ekanos add`),\n * which the shared schema rejects (\"declares at least one integration\"). That\n * one rule is suspended here so `add` can bootstrap a project; `check` and\n * `build` report the empty state themselves.\n *\n * The deprecated `uses` shape is read too: its entries come back as\n * `integrations` (alias dropped) with `deprecatedUses` set and `renames`\n * mapping each old alias to its integration, so `ekanos sync` can rewrite the\n * file and say what code to update.\n */\nexport function readExperienceProject(dir: string): ExperienceProject {\n const absolute = path.resolve(dir);\n const raw = readJson(path.join(absolute, EKANOS_JSON));\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n throw validationError(`${EKANOS_JSON} must be a JSON object.`, 'Fix it.');\n }\n const record = raw as Record<string, unknown>;\n\n if (record.kind !== 'experience') {\n throw validationError(\n `${EKANOS_JSON} is not an experience (\"kind\": \"experience\").`,\n 'Run experience commands in an experience project; scaffold one with \"ekanos init --kind experience --slug <slug>\".',\n );\n }\n\n const declaredNone =\n !(Array.isArray(record.integrations) && record.integrations.length > 0) &&\n !(Array.isArray(record.uses) && record.uses.length > 0);\n const probe = declaredNone\n ? { ...record, integrations: [PLACEHOLDER_INTEGRATION], uses: undefined }\n : record;\n const parsed = EkanosJsonSchema.safeParse(probe);\n if (!parsed.success) {\n throw validationError(\n `${EKANOS_JSON}: ${parsed.error.issues\n .map((i) => `${i.path.join('.') || '(root)'}: ${i.message}`)\n .join('; ')}`,\n 'Fix ekanos.json; the experience fields are slug, entry, integrations, contractsDir, allowImports, ignore.',\n );\n }\n\n const ekanos = parsed.data;\n const declared = declaredNone\n ? { entries: [], deprecatedUses: false, renames: {} }\n : experienceIntegrations(ekanos);\n\n return {\n dir: absolute,\n ekanos,\n slug: ekanos.slug as string,\n entry: ekanos.entry as string,\n integrations: declared.entries.map(withCanonicalOperations),\n deprecatedUses: declared.deprecatedUses,\n renames: declared.renames,\n contractsDir: path.resolve(\n absolute,\n ekanos.contractsDir ?? DEFAULT_CONTRACTS_DIR,\n ),\n raw: record,\n };\n}\n\n/**\n * Operations as canonical `<slug>@<version>/<kind>/<name>` ids, for lookups\n * against a contract. A contract's ids carry the bare slug even when the\n * package is named under a namespace, so a `vastly/news` entry canonicalises to\n * `news@0.1/...`.\n */\nfunction withCanonicalOperations(entry: IntegrationEntry): IntegrationEntry {\n const slug = entry.name.slice(entry.name.indexOf('/') + 1);\n\n return {\n ...entry,\n operations: entry.operations.map((id) =>\n canonicalOperationId({ name: slug, version: entry.version }, id),\n ),\n };\n}\n\n/** 2-space JSON with a trailing newline: the format every written file uses. */\nexport function formatJson(value: unknown): string {\n return `${JSON.stringify(value, null, 2)}\\n`;\n}\n\n/** Write only when the bytes differ. Returns whether the file changed. */\nexport function writeIfChanged(file: string, content: string): boolean {\n try {\n if (fs.readFileSync(file, 'utf8') === content) return false;\n } catch {\n // missing: write below\n }\n fs.mkdirSync(path.dirname(file), { recursive: true });\n fs.writeFileSync(file, content);\n\n return true;\n}\n\nexport function readLockfile(project: ExperienceProject): Lockfile {\n const file = path.join(project.dir, LOCK_FILE);\n if (!fs.existsSync(file)) return { lockfileVersion: 1, integrations: {} };\n const parsed = LockfileSchema.safeParse(readJson(file));\n if (!parsed.success) {\n throw validationError(\n `${LOCK_FILE}: ${parsed.error.issues.map((i) => `${i.path.join('.')}: ${i.message}`).join('; ')}`,\n 'Regenerate it with \"ekanos sync\".',\n );\n }\n\n return parsed.data;\n}\n\nexport function writeLockfile(\n project: ExperienceProject,\n lock: Lockfile,\n): boolean {\n const integrations = Object.fromEntries(\n Object.entries(lock.integrations).sort(([a], [b]) => (a < b ? -1 : 1)),\n );\n\n return writeIfChanged(\n path.join(project.dir, LOCK_FILE),\n formatJson({ lockfileVersion: 1, integrations }),\n );\n}\n\nconst PLACEHOLDER_INTEGRATION = {\n name: 'pending',\n version: '0',\n operations: ['tool/pending'],\n} as const;\n\n/**\n * Rewrite `integrations` in ekanos.json (short operation form), leaving every\n * other key where it was and dropping the deprecated `uses`.\n */\nexport function writeIntegrations(\n project: ExperienceProject,\n integrations: IntegrationEntry[],\n): boolean {\n const { uses: _uses, ...rest } = project.raw;\n const next = {\n ...rest,\n integrations: integrations.map((entry) => ({\n name: entry.name,\n version: entry.version,\n operations: entry.operations.map(shortOperation),\n ...(entry.required === 'required' ? {} : { required: entry.required }),\n ...(entry.modes.length === 1 && entry.modes[0] === 'team'\n ? {}\n : { modes: entry.modes }),\n })),\n };\n\n return writeIfChanged(path.join(project.dir, EKANOS_JSON), formatJson(next));\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -317,10 +317,10 @@ const COMMAND_SPECS = {
|
|
|
317
317
|
// `teams audience`.
|
|
318
318
|
member: {
|
|
319
319
|
type: 'string',
|
|
320
|
-
description: "audience: one member's
|
|
320
|
+
description: "audience: one member's audience, by email (setting it is deprecated)",
|
|
321
321
|
}, inherit: {
|
|
322
322
|
type: 'boolean',
|
|
323
|
-
description: "audience --member: clear their own audience so the team's applies",
|
|
323
|
+
description: "audience --member: clear their own audience so the team's applies (deprecated)",
|
|
324
324
|
} }, SECRET_INPUT), { clear: {
|
|
325
325
|
type: 'string',
|
|
326
326
|
repeatable: true,
|
|
@@ -869,8 +869,9 @@ const USAGE = [
|
|
|
869
869
|
' <product>=<id>,…]… [--tools <product>=<name>,…]… | set <audience>',
|
|
870
870
|
' [--name] [--description] [--default] [--all-entitled] [--products',
|
|
871
871
|
' a,b|none] [--widgets …]… [--tools …]… [--yes] (--products replaces;',
|
|
872
|
-
' dropping a product needs --yes). A team
|
|
873
|
-
' with "teams audience <team> [<audience>]
|
|
872
|
+
' dropping a product needs --yes). A team is put on one (its',
|
|
873
|
+
' business type) with "teams audience <team> [<audience>]"; its',
|
|
874
|
+
' groups narrow it per person ("teams groups")',
|
|
874
875
|
' catalog What a source can already use, and how to set it up:',
|
|
875
876
|
' Experiences, then Integrations; one product shows its tools',
|
|
876
877
|
' with their inputs and whose connection agent runs use',
|
|
@@ -898,7 +899,9 @@ const USAGE = [
|
|
|
898
899
|
' invitation is resent, an expired one renewed) |',
|
|
899
900
|
" roles list <team> (each role's permissions) |",
|
|
900
901
|
' leave <team> [--yes] (you leave it; never the primary owner) |',
|
|
901
|
-
|
|
902
|
+
" groups list <team> (the team's own groups, the predefined groups of",
|
|
903
|
+
" its business type and Everyone, each picking within the team's",
|
|
904
|
+
' audience) | groups create <team> <name> [--description',
|
|
902
905
|
' <text>] [--products <slug,slug>] | groups update <team> <group>',
|
|
903
906
|
' [--name <name>] [--description <text>] [--products <slug,…>|none]',
|
|
904
907
|
' | groups delete <team> <group> [--yes] | groups members',
|
|
@@ -944,10 +947,11 @@ const USAGE = [
|
|
|
944
947
|
' events <team> [<product>] [--product <slug>] [--since 24h|7d|<date>]',
|
|
945
948
|
' [--limit <n>] (the integration events recorded for the team, each',
|
|
946
949
|
' with its status, last error and the runs it started, or why none did)',
|
|
947
|
-
' | audience <team> [<audience>] [--member <email>
|
|
948
|
-
" (the
|
|
949
|
-
|
|
950
|
-
|
|
950
|
+
' | audience <team> [<audience>] [--member <email>] [--yes]',
|
|
951
|
+
" (the team's audience, its business type, which every member is on;",
|
|
952
|
+
' their groups narrow it; moving people to an audience that shows',
|
|
953
|
+
" less needs --yes; --member reads one person's, and setting it",
|
|
954
|
+
' (or --inherit) is deprecated: hosts on audiences refuse it)',
|
|
951
955
|
' | scope show <team> (DEPRECATED, use audience: the product scopes it holds and the products',
|
|
952
956
|
' it sees in the app) | scope set <team> <scope> [<scope>…] [--yes]',
|
|
953
957
|
' (replaces them; dropping one needs --yes)',
|