@axinom/mosaic-agent-skills 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axinom/mosaic-agent-skills",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "MCP server bundled with Mosaic development skills and tools for AI agents",
5
5
  "bin": "./dist/index.js",
6
6
  "files": [
@@ -36,5 +36,5 @@
36
36
  "publishConfig": {
37
37
  "access": "public"
38
38
  },
39
- "gitHead": "7f614a26d23fbd7e917653b42f234f9ba51f6580"
39
+ "gitHead": "8e28563eaafe8791244c3eebdb9da64b8e400c0c"
40
40
  }
@@ -0,0 +1,103 @@
1
+ ---
2
+ name: deploy-service
3
+ description: |
4
+ Deploys a custom service from a Mosaic monorepo to the Axinom Mosaic
5
+ Hosting Service. Covers the full lifecycle: authenticating, discovering
6
+ deployable services, verifying one-time prerequisites (container registry,
7
+ service definition), building and pushing a Docker image, optionally
8
+ building and registering a microfrontend pilet, uploading a deployment
9
+ manifest, initiating a rolling deployment, and monitoring status with
10
+ log-based error diagnosis.
11
+
12
+ Use this skill whenever the user wants to deploy, redeploy, or release a
13
+ service to the Mosaic Hosting Service — including first-time deployments,
14
+ updating a running service, or recovering from a failed deployment.
15
+ allowed-tools:
16
+ - list_skills
17
+ - get_skill
18
+ - get_skill_references
19
+ - execute_skill
20
+ ---
21
+
22
+ # Deploy Service to Mosaic Hosting
23
+
24
+ ## Input
25
+
26
+ Service name or ID (e.g. "media", "media-service"). If omitted, discover
27
+ and ask.
28
+
29
+ ## Overview
30
+
31
+ Each deployment is a tuple of: container image + deployment manifest +
32
+ optional pilet (only for services with a `workflows/` folder). Deployments
33
+ are additive — each supersedes the previous; reusing an existing image,
34
+ pilet, or manifest in a new deployment is always valid.
35
+
36
+ ### API vs CLI
37
+
38
+ | Action | Use |
39
+ |--------|-----|
40
+ | Auth token, registry/service-definition check & create | API |
41
+ | Docker build & push | shell |
42
+ | Pilet build, pack & register | CLI (file upload) |
43
+ | Manifest upload | CLI — preserves `${__ax_hosted__.dynamic.%}` secret injection |
44
+ | Deployment initiation | CLI — name-based, no UUID lookups |
45
+ | Status polling, log fetching, DNS endpoints | API |
46
+
47
+ Retrieve all reference files with `get_skill_references` before starting.
48
+ For API calls, use Node.js with `--input-type=commonjs` to avoid ESM/CJS
49
+ conflicts. Pattern:
50
+
51
+ ```bash
52
+ node --input-type=commonjs <<'EOF'
53
+ const https = require('https');
54
+ const fs = require('fs');
55
+ // ... make request, write result to file
56
+ EOF
57
+ ```
58
+
59
+ Save the token to `.jwt` and reuse it.
60
+
61
+ ## Steps
62
+
63
+ ### 0. Authenticate → `refs/credentials-and-setup.md`
64
+
65
+ Read credentials from root `.env`, obtain a token, save to `.jwt`.
66
+
67
+ ### 1. Discover & Select Service
68
+
69
+ Scan `services/*/service/mosaic-hosting-deployment-manifest.yaml`. For each,
70
+ read `serviceId` from the YAML and note whether a sibling `workflows/` folder
71
+ exists (`hasWorkflows`).
72
+
73
+ Ask the user to choose if not already specified.
74
+
75
+ ### 2. Prerequisites → `refs/credentials-and-setup.md`
76
+
77
+ Check (and create if missing) the container registry connection and service
78
+ definition via API. Both are one-time per environment/service.
79
+
80
+ ### 3. Backend Image → `refs/build-and-push-image.md`
81
+
82
+ *Does the backend need updating?* Yes → build & push, get `imageTag`.
83
+ No → ask for the existing tag to reuse.
84
+
85
+ ### 4. Pilet (skip if `hasWorkflows` is false) → `refs/build-and-register-pilet.md`
86
+
87
+ *Does the frontend need updating?* Yes → build, pack & register via CLI.
88
+ No → confirm the existing `piletRef` to reuse.
89
+
90
+ ### 5. Manifest → `refs/manifest-review-and-upload.md`
91
+
92
+ Ask if any manifest changes are needed. If changes are required, review and
93
+ upload a new named manifest. If the manifest is unchanged, the user may select
94
+ an existing one and skip the upload — each deployment just needs a valid
95
+ `manifestName`, whether new or reused.
96
+
97
+ ### 6. Deploy & Monitor → `refs/deploy-and-monitor.md`
98
+
99
+ Initiate via CLI, parse `serviceDeploymentId` from the output, poll status
100
+ via API. On `READY` show DNS endpoints. On `CREATE_ERROR` fetch logs,
101
+ diagnose, and either fix the manifest and redeploy, or hand off to the user.
102
+
103
+ Once the deployment resolves (success or terminal error), delete `.jwt`.
@@ -0,0 +1,55 @@
1
+ ---
2
+ name: build-and-push-image
3
+ input:
4
+ - registryHost, repositoryName (from service definition)
5
+ - servicePath (e.g. services/media/service)
6
+ - buildScript (e.g. build:media-service:prod)
7
+ output:
8
+ - imageTag (YYYYMMDD.N — passed as -t to the deploy command)
9
+ ---
10
+
11
+ # Build & Push Container Image
12
+
13
+ ## Existing Images
14
+
15
+ `repositoryTags` on the service definition lists all pushed images, sorted
16
+ newest first (tags are `YYYYMMDD.N`, so alpha order = chronological):
17
+
18
+ ```graphql
19
+ # POST {HOSTING_SERVICE_BASE_URL}/graphql
20
+ query {
21
+ serviceDefinitions(condition: { serviceId: "{serviceId}" }) {
22
+ nodes {
23
+ repositoryTags { fullyQualifiedImageName containerImageVersion }
24
+ }
25
+ }
26
+ }
27
+ ```
28
+
29
+ Present as a numbered list (newest first) with `[0] Build & push a new image` as the last option. Wait for the user to pick by number — never ask them to type a tag manually.
30
+
31
+ ## Build & Push
32
+
33
+ Check Docker login: `docker info` (look for `Username:`). If not logged in:
34
+ ```bash
35
+ docker login {registryHost}
36
+ ```
37
+ Fallback: check `~/.docker/config.json` or `~/snap/docker/current/.docker/config.json`.
38
+
39
+ Dockerfile is typically at the repo root. If not, search and confirm with the user.
40
+
41
+ Tag pattern: `YYYYMMDD.N` (e.g. `20260423.1`, increment `.N` for same-day builds).
42
+ The Hosting Service appends this to `{registryHost}/{repositoryName}:` — pass only
43
+ the date+index as `-t` to the deploy command, not the full reference.
44
+
45
+ Run from **repo root**:
46
+ ```bash
47
+ docker build \
48
+ -t {registryHost}/{repositoryName}:{imageTag} \
49
+ --build-arg PACKAGE_ROOT={servicePath} \
50
+ --build-arg PACKAGE_BUILD_COMMAND={buildScript} \
51
+ --platform linux/amd64 \
52
+ .
53
+
54
+ docker push {registryHost}/{repositoryName}:{imageTag}
55
+ ```
@@ -0,0 +1,54 @@
1
+ ---
2
+ name: build-and-register-pilet
3
+ input:
4
+ - serviceId
5
+ - workflowsPath (e.g. services/media/workflows)
6
+ output:
7
+ - piletRef = {piletName}@{piletVersion} (passed as -p to the deploy command)
8
+ ---
9
+
10
+ # Build & Register Pilet
11
+
12
+ ## Existing Pilets
13
+
14
+ ```graphql
15
+ # POST {HOSTING_SERVICE_BASE_URL}/graphql
16
+ query {
17
+ servicePiletArtifacts(
18
+ filter: { serviceId: { equalTo: "{serviceId}" } }
19
+ orderBy: CREATED_DATE_DESC
20
+ first: 5
21
+ ) {
22
+ nodes { name packageVersion createdDate }
23
+ }
24
+ }
25
+ ```
26
+
27
+ Present results as a numbered list (`{name}@{packageVersion}`, newest first) with `[0] Build & register a new pilet` as the last option. Wait for the user to pick by number. The chosen value is passed as `-p` to the deploy command.
28
+
29
+ ## Build & Register
30
+
31
+ Read `name` and `version` from `{workflowsPath}/package.json` — these form
32
+ the pilet reference `{piletName}@{piletVersion}` used in the deploy command.
33
+
34
+ ```bash
35
+ cd {workflowsPath} && yarn build && yarn pilet pack
36
+ ```
37
+
38
+ Locate the produced `.tgz`:
39
+ ```bash
40
+ find {workflowsPath} -maxdepth 1 -name "*.tgz"
41
+ ```
42
+
43
+ Use the path returned by `find` directly as `{tgzPath}`.
44
+
45
+ If `{piletName}@{piletVersion}` already appears in the existing pilets list,
46
+ warn the user that it will be overwritten and ask for confirmation before proceeding.
47
+
48
+ Register (requires `MICRO_FRONTEND_SERVICE_BASE_URL` in root `.env`):
49
+ ```bash
50
+ yarn util:load-vars mosaic hosting pilet register \
51
+ -i {serviceId} \
52
+ -p {tgzPath} \
53
+ --overrideRegistration
54
+ ```
@@ -0,0 +1,88 @@
1
+ ---
2
+ name: credentials-and-setup
3
+ input:
4
+ - serviceId
5
+ - root .env (MOSAIC_HOSTING_CLIENT_ID, MOSAIC_HOSTING_CLIENT_SECRET, ID_SERVICE_AUTH_BASE_URL, HOSTING_SERVICE_BASE_URL)
6
+ output:
7
+ - access token in .jwt
8
+ - registryHost, registryUsername confirmed
9
+ - serviceDefinitionId, repositoryName confirmed
10
+ ---
11
+
12
+ # Credentials & Prerequisites
13
+
14
+ ## Token
15
+
16
+ If `MOSAIC_HOSTING_CLIENT_ID` or `MOSAIC_HOSTING_CLIENT_SECRET` are missing
17
+ from root `.env`, check whether a setup script exists:
18
+
19
+ ```bash
20
+ # Check for a hosting setup script (name may vary per repo)
21
+ grep -r "setup.*hosting\|hosting.*setup" package.json scripts/ 2>/dev/null | head -5
22
+ ```
23
+
24
+ If a setup script is found (e.g. `yarn setup:hosting`), run it. It typically
25
+ requires `DEV_SERVICE_ACCOUNT_CLIENT_ID` and `DEV_SERVICE_ACCOUNT_CLIENT_SECRET`
26
+ to already be in `.env` — if those are also missing, stop and ask the user.
27
+
28
+ If no setup script exists, ask the user to provide `MOSAIC_HOSTING_CLIENT_ID`
29
+ and `MOSAIC_HOSTING_CLIENT_SECRET` directly and add them to `.env`.
30
+
31
+ ```graphql
32
+ # POST {ID_SERVICE_AUTH_BASE_URL}/graphql (no auth required)
33
+ mutation {
34
+ authenticateServiceAccount(input: {
35
+ clientId: "{MOSAIC_HOSTING_CLIENT_ID}"
36
+ clientSecret: "{MOSAIC_HOSTING_CLIENT_SECRET}"
37
+ }) { accessToken }
38
+ }
39
+ ```
40
+
41
+ Save `accessToken` to `.jwt`. All subsequent calls use
42
+ `Authorization: Bearer {token}`. On 401, re-fetch and overwrite.
43
+
44
+ ## Container Registry
45
+
46
+ The Hosting Service constructs image references as
47
+ `{registryHost}/{repositoryName}:{imageTag}`.
48
+
49
+ ```graphql
50
+ # POST {HOSTING_SERVICE_BASE_URL}/graphql
51
+ { containerRegistryConnections { nodes { id host username } } }
52
+ ```
53
+
54
+ If connections exist, confirm which one with the user. If none, ask for
55
+ host/username/password then:
56
+
57
+ ```graphql
58
+ mutation {
59
+ createContainerRegistryConnection(input: {
60
+ containerRegistryConnection: { host: "...", username: "...", password: "..." }
61
+ }) { containerRegistryConnection { id host username } }
62
+ }
63
+ ```
64
+
65
+ ## Service Definition
66
+
67
+ ```graphql
68
+ { serviceDefinitions(condition: { serviceId: "{serviceId}" }) {
69
+ nodes { id serviceId repositoryName activeDeploymentStatus }
70
+ } }
71
+ ```
72
+
73
+ If found, proceed. If not, suggest `{registryUsername}/{serviceId}` as
74
+ `repositoryName`, confirm with user, then:
75
+
76
+ ```graphql
77
+ mutation {
78
+ createServiceDefinition(input: {
79
+ serviceDefinition: {
80
+ serviceId: "{serviceId}"
81
+ name: "{serviceId}"
82
+ repositoryName: "{registryUsername}/{serviceId}"
83
+ }
84
+ }) { serviceDefinition { id repositoryName } }
85
+ }
86
+ ```
87
+
88
+ > Avoid `ax-` or `axinom-` prefixes in serviceId — reserved for Axinom Owned services.
@@ -0,0 +1,76 @@
1
+ ---
2
+ name: deploy-and-monitor
3
+ input:
4
+ - serviceId, imageTag, manifestName, piletRef = {piletName}@{piletVersion} (optional)
5
+ - HOSTING_SERVICE_BASE_URL + token from .jwt
6
+ output:
7
+ - serviceDeploymentId, status, DNS endpoints
8
+ ---
9
+
10
+ # Deploy & Monitor
11
+
12
+ ## Initiate via CLI
13
+
14
+ ```bash
15
+ # with pilet
16
+ yarn util:load-vars mosaic hosting service deploy \
17
+ -i {serviceId} -t {imageTag} -p {piletRef} \
18
+ -m {manifestName} -n {serviceId}-deployment-{YYYYMMDD}.N
19
+
20
+ # without pilet
21
+ yarn util:load-vars mosaic hosting service deploy \
22
+ -i {serviceId} -t {imageTag} \
23
+ -m {manifestName} -n {serviceId}-deployment-{YYYYMMDD}.N
24
+ ```
25
+
26
+ Use today's date for the deployment name. Increment `.N` if multiple deployments are made on the same day.
27
+
28
+ The CLI prints human-readable status lines followed by a JSON object. Extract the
29
+ JSON by finding the line that starts with `{` and parse `serviceDeploymentId` from it:
30
+ ```json
31
+ {"serviceDeploymentId":"<uuid>","name":"...","status":"CREATE_PENDING"}
32
+ ```
33
+
34
+ Use this ID for all subsequent queries. Do not query by `last: 1` ordering —
35
+ stale failed deployments from prior runs can appear ahead of the new one.
36
+
37
+ ## Poll Status
38
+
39
+ Poll every ~15s until status is no longer `CREATE_PENDING`:
40
+
41
+ ```graphql
42
+ # POST {HOSTING_SERVICE_BASE_URL}/graphql
43
+ query($id: UUID!) {
44
+ serviceDeployment(id: $id) {
45
+ status
46
+ errorMessage
47
+ dnsRecords { nodes { configRefName fqdn } }
48
+ }
49
+ }
50
+ # variables: {"id": "{serviceDeploymentId}"}
51
+ ```
52
+
53
+ **`READY`** — show DNS endpoints (each `configRefName` maps to a port in
54
+ `dnsMappedPorts` in the manifest):
55
+ ```
56
+ API: https://{fqdn} (configRefName = "api")
57
+ ```
58
+
59
+ **`CREATE_ERROR`** — fetch logs (`SERVICE_DEPLOYMENTS_VIEW` permission required):
60
+
61
+ ```graphql
62
+ # POST {HOSTING_SERVICE_BASE_URL}/graphql
63
+ query($c: ServiceDeploymentLogCondition) {
64
+ serviceDeploymentLogs(condition: $c, orderBy: TIMESTAMP_ASC) {
65
+ nodes { messageType message timestamp }
66
+ }
67
+ }
68
+ # variables: {"c": {"serviceDeploymentId": "{serviceDeploymentId}"}}
69
+ ```
70
+
71
+ - **Config/manifest error** → fix the YAML, re-upload with an incremented
72
+ tag (e.g. `20260423.2`), re-deploy reusing the same `imageTag` and `piletRef`
73
+ - **Code/runtime error** → tell the user; do not retry until they push a fix,
74
+ then restart from the image build step
75
+
76
+ Always use a new deployment name — never modify an existing deployment.
@@ -0,0 +1,63 @@
1
+ ---
2
+ name: manifest-review-and-upload
3
+ input:
4
+ - serviceId
5
+ - manifestPath (absolute path to mosaic-hosting-deployment-manifest.yaml)
6
+ - servicePath (for .env.template comparison)
7
+ - imageTag (used as uniqueTag for the manifest name)
8
+ output:
9
+ - manifestName (e.g. media-service-manifest-20260423.1 — passed as -m to
10
+ deploy)
11
+ ---
12
+
13
+ # Manifest Review & Upload
14
+
15
+ ## Existing Manifests
16
+
17
+ ```graphql
18
+ # POST {HOSTING_SERVICE_BASE_URL}/graphql
19
+ query {
20
+ serviceDeploymentManifests(
21
+ filter: { serviceId: { equalTo: "{serviceId}" } }
22
+ orderBy: CREATED_DATE_DESC
23
+ first: 5
24
+ ) {
25
+ nodes {
26
+ name
27
+ createdDate
28
+ }
29
+ }
30
+ }
31
+ ```
32
+
33
+ Present as a numbered list (newest first) with `[0] Upload a new manifest` as the last option. Wait for the user to pick by number — never ask them to type a name manually. If the user picks an existing manifest, skip the upload step and use that name directly.
34
+
35
+ ## Review
36
+
37
+ **Unresolved placeholders:** search for `REPLACE_WITH_VALID_` — stop and ask the
38
+ user to fill these in before uploading.
39
+
40
+ **Missing variables:** compare variable names in `{servicePath}/.env.template`
41
+ against `regularVariables` + `secureVariables` in the manifest. Surface any gaps
42
+ to the user (skip obviously dev-only vars like `GRAPHQL_GUI_ENABLED`).
43
+
44
+ **Secrets:** sensitive values can be injected at upload time without being
45
+ hardcoded in the YAML:
46
+
47
+ ```yaml
48
+ secureVariables:
49
+ MY_SECRET: ${__ax_hosted__.dynamic.MY_SECRET}
50
+ ```
51
+
52
+ `yarn util:load-vars` feeds root `.env` into the environment before the CLI
53
+ runs, making those values available for substitution. This is why manifest
54
+ upload must use the CLI and not the API directly.
55
+
56
+ ## Upload
57
+
58
+ ```bash
59
+ yarn util:load-vars mosaic hosting manifest upload \
60
+ -i {serviceId} \
61
+ -p {manifestPath} \
62
+ -n {serviceId}-manifest-{imageTag}
63
+ ```