@zalosai/zalos-cli 0.2.14 → 0.2.15

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/PUBLISHING.md CHANGED
@@ -39,8 +39,8 @@ Zalos product access.
39
39
  pnpm --filter @zalosai/zalos-cli exec npm pack --dry-run
40
40
  ```
41
41
 
42
- Only `package.json`, `README.md`, `PUBLISHING.md`, and runtime JavaScript under `dist/`
43
- should be included.
42
+ Only `package.json`, `README.md`, `PUBLISHING.md`, the bundled `skills/` Markdown, and runtime
43
+ JavaScript under `dist/` should be included.
44
44
 
45
45
  4. In GitHub, open **Actions → Publish Zalos CLI → Run workflow**.
46
46
  Select `develop` and enter the exact version from `package.json`. The workflow rejects
@@ -59,6 +59,8 @@ Do not publish with uncommitted package changes or reuse an existing version.
59
59
 
60
60
  ## Central developer access release
61
61
 
62
+ Version 0.2.15 bundles the `zl-ops` production-operations skill and adds offline `zl skills`
63
+ commands to list, read, and install it into Codex or Claude skill roots.
62
64
  Version 0.2.14 moves publishing to npm Trusted Publishing through the
63
65
  `publish-zalos-cli.yml` GitHub Actions workflow, so releases no longer rely on a stored npm token.
64
66
  Version 0.2.13 adds revision-safe Markdown import and export for team Pages. It converts common
package/README.md CHANGED
@@ -11,11 +11,31 @@ Requires Node.js 22 or newer. The product CLI is public on npm and does not
11
11
  require GitHub CLI or GitHub Packages access.
12
12
 
13
13
  ```bash
14
- npm install --global @zalosai/zalos-cli@0.2.14
14
+ npm install --global @zalosai/zalos-cli@0.2.15
15
15
  ```
16
16
 
17
17
  Installing the CLI does not grant access.
18
18
 
19
+ ## Agent skills
20
+
21
+ The package includes a production-operations skill for Codex and Claude. It describes
22
+ region selection, browser login, team switching, preview-first changes, workflow
23
+ publishing, Team Files, Pages, and Motion work without embedding credentials.
24
+
25
+ ```bash
26
+ zl skills list
27
+ zl skills read zl-ops
28
+ zl skills install zl-ops --target codex
29
+ # Or:
30
+ zl skills install zl-ops --target claude
31
+ ```
32
+
33
+ Codex installs to `$CODEX_HOME/skills` when `CODEX_HOME` is set, otherwise `~/.codex/skills`;
34
+ Claude installs to `~/.claude/skills`. Use `--directory <path>` to install beneath a custom skills
35
+ root. Installation leaves an identical existing skill unchanged and refuses to replace local edits unless `--force` is
36
+ explicitly supplied. These commands work locally and do not need authentication or an
37
+ environment selection.
38
+
19
39
  ## First run
20
40
 
21
41
  ```bash
@@ -0,0 +1,90 @@
1
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
+ import { homedir } from 'node:os';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { ValidationError } from '../utils/errors.js';
6
+ import { printJson } from '../utils/output.js';
7
+ import { action } from '../utils/product-api.js';
8
+ const OPS_SKILL_NAME = 'zl-ops';
9
+ const OPS_SKILL_PATH = fileURLToPath(new URL('../../skills/zl-ops/SKILL.md', import.meta.url));
10
+ function isSkillTarget(value) {
11
+ return value === 'claude' || value === 'codex';
12
+ }
13
+ function skillPath(name) {
14
+ if (name !== OPS_SKILL_NAME)
15
+ throw new ValidationError('skill', `Unknown skill: ${name}. Available: ${OPS_SKILL_NAME}`);
16
+ return OPS_SKILL_PATH;
17
+ }
18
+ export function resolveDefaultSkillsDirectory(target, home = homedir()) {
19
+ if (target === 'codex') {
20
+ const codexHome = process.env.CODEX_HOME;
21
+ if (codexHome)
22
+ return join(codexHome, 'skills');
23
+ return join(home, '.codex/skills');
24
+ }
25
+ return join(home, '.claude/skills');
26
+ }
27
+ function resolveInstallDirectory(options) {
28
+ if (options.directory && options.target)
29
+ throw new ValidationError('skills', 'Specify either --target or --directory, not both');
30
+ if (options.directory)
31
+ return resolve(options.directory);
32
+ if (!options.target)
33
+ throw new ValidationError('target', 'Choose --target codex or --target claude, or provide --directory');
34
+ if (!isSkillTarget(options.target))
35
+ throw new ValidationError('target', 'Expected --target codex or --target claude');
36
+ return resolveDefaultSkillsDirectory(options.target);
37
+ }
38
+ export async function readSkill(name) {
39
+ return readFile(skillPath(name), 'utf8');
40
+ }
41
+ async function existingContents(path) {
42
+ try {
43
+ return await readFile(path, 'utf8');
44
+ }
45
+ catch (error) {
46
+ if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT')
47
+ return null;
48
+ throw error;
49
+ }
50
+ }
51
+ export async function installSkill(name, options) {
52
+ const contents = await readSkill(name);
53
+ const directory = resolveInstallDirectory(options);
54
+ const destination = join(directory, name, 'SKILL.md');
55
+ const existing = await existingContents(destination);
56
+ if (existing === contents)
57
+ return { skill: name, status: 'unchanged', path: destination };
58
+ if (existing !== null && !options.force)
59
+ throw new ValidationError('destination', `Skill already exists at ${destination}; use --force to replace local changes`);
60
+ await mkdir(dirname(destination), { recursive: true, mode: 0o755 });
61
+ await writeFile(destination, contents, { mode: 0o644 });
62
+ return {
63
+ skill: name,
64
+ status: existing === null ? 'installed' : 'updated',
65
+ path: destination,
66
+ };
67
+ }
68
+ export function registerSkillsCommand(program) {
69
+ const command = program.command('skills').description('Read and install bundled agent skills');
70
+ command
71
+ .command('list')
72
+ .description('List bundled skills (no network or authentication required)')
73
+ .action(() => printJson({
74
+ skills: [{ name: OPS_SKILL_NAME, description: 'Zalos production operations' }],
75
+ }));
76
+ command
77
+ .command('read <name>')
78
+ .description('Print a bundled SKILL.md (no network or authentication required)')
79
+ .action(async (name) => action(async () => {
80
+ process.stdout.write(await readSkill(name));
81
+ }));
82
+ command
83
+ .command('install <name>')
84
+ .description('Install a bundled skill for Codex or Claude')
85
+ .option('--target <target>', 'Install into the standard codex or claude skill directory')
86
+ .option('--directory <path>', 'Install beneath a custom skills directory')
87
+ .option('--force', 'Replace a locally modified installed skill')
88
+ .action(async (name, options) => action(async () => printJson(await installSkill(name, options))));
89
+ }
90
+ //# sourceMappingURL=skills.js.map
package/dist/main.js CHANGED
@@ -20,6 +20,7 @@ import { registerTaskCommentCommand } from './commands/task-comment.js';
20
20
  import { registerTaskCommand } from './commands/task.js';
21
21
  import { registerTeamCommand } from './commands/team.js';
22
22
  import { registerPageCommand } from './commands/page.js';
23
+ import { registerSkillsCommand } from './commands/skills.js';
23
24
  import { configureApiUrlOverride, currentEnvironment } from './environments.js';
24
25
  import { handleError } from './utils/errors.js';
25
26
  const program = new Command();
@@ -41,8 +42,10 @@ program
41
42
  configureApiUrlOverride(opts.apiUrl);
42
43
  if (actionCommand.name() === 'zl' ||
43
44
  actionCommand.name() === 'schema' ||
45
+ actionCommand.name() === 'skills' ||
44
46
  (actionCommand.name() === 'validate' && actionCommand.parent?.name() === 'workflow') ||
45
- actionCommand.parent?.name() === 'schema')
47
+ actionCommand.parent?.name() === 'schema' ||
48
+ actionCommand.parent?.name() === 'skills')
46
49
  return;
47
50
  try {
48
51
  currentEnvironment();
@@ -65,6 +68,7 @@ registerCredentialCommand(program);
65
68
  registerFileCommand(program);
66
69
  registerTeamCommand(program);
67
70
  registerPageCommand(program);
71
+ registerSkillsCommand(program);
68
72
  registerSchemaCommand(program);
69
73
  registerStateCommand(program);
70
74
  registerLabelCommand(program);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zalosai/zalos-cli",
3
- "version": "0.2.14",
3
+ "version": "0.2.15",
4
4
  "description": "API-only product command-line interface for Zalos",
5
5
  "repository": {
6
6
  "type": "git",
@@ -15,7 +15,8 @@
15
15
  "files": [
16
16
  "dist/**/*.js",
17
17
  "README.md",
18
- "PUBLISHING.md"
18
+ "PUBLISHING.md",
19
+ "skills/**/*.md"
19
20
  ],
20
21
  "engines": {
21
22
  "node": ">=22"
@@ -0,0 +1,116 @@
1
+ ---
2
+ name: zl-ops
3
+ description: Operate Zalos production workflows, executions, Team Files, Pages, and Motion work through the public Zalos CLI.
4
+ ---
5
+
6
+ # Zalos CLI Operations
7
+
8
+ Use this skill when an operator needs to inspect or safely change Zalos data through `zl`.
9
+ The CLI works against one production region at a time. Ask whether the task is in
10
+ `us-prod` or `eu-prod` when it is not already specified; never infer a region.
11
+
12
+ ## Set up and verify access
13
+
14
+ ```bash
15
+ node --version
16
+ npm install --global @zalosai/zalos-cli@latest
17
+ zl --environment <us-prod|eu-prod> auth login
18
+ zl --environment <us-prod|eu-prod> auth status
19
+ zl --environment <us-prod|eu-prod> team list
20
+ ```
21
+
22
+ A current Zalos browser session completes login automatically. Only ask the user to
23
+ interact with the browser if the browser itself requires sign-in or consent. Do not
24
+ print credentials, profile files, or API tokens.
25
+
26
+ Run `zl --version` and the relevant `--help` command before saying that a command or
27
+ option is unavailable. An absent documented command usually means the global CLI needs
28
+ an update.
29
+
30
+ ## Select the correct team
31
+
32
+ `team list` returns the active memberships available to the signed-in user in the
33
+ chosen region. Use its opaque `publicId` value, such as `tm_4ERk9QxW`:
34
+
35
+ ```bash
36
+ zl --environment <us-prod|eu-prod> team switch <team-ref>
37
+ ```
38
+
39
+ Switch the selected team before a change. A switch only works for a team the user can
40
+ access and preserves the session expiry. For permitted read-only file inspection, use
41
+ an explicit `--team-id <team-ref>` where the command supports it. Never treat a `tm_`
42
+ reference as a UUID.
43
+
44
+ ## Inspect before changing
45
+
46
+ Start with a small read and use fields to keep output focused:
47
+
48
+ ```bash
49
+ zl --environment <us-prod|eu-prod> workflow list --fields id,name,active
50
+ zl --environment <us-prod|eu-prod> workflow view <workflow-id>
51
+ zl --environment <us-prod|eu-prod> execution list --limit 20
52
+ zl --environment <us-prod|eu-prod> execution summary <execution-id>
53
+ zl --environment <us-prod|eu-prod> page list --fields id,title,updatedAt
54
+ zl --environment <us-prod|eu-prod> file tree --team-id <team-ref>
55
+ ```
56
+
57
+ Use the IDs from command output. For an execution artifact, inspect the execution first,
58
+ then download the immutable artifact through the authenticated CLI:
59
+
60
+ ```bash
61
+ zl --environment <us-prod|eu-prod> execution artifact download <artifact-id> --output /tmp/artifact
62
+ ```
63
+
64
+ ## Make controlled changes
65
+
66
+ For a supported mutation, preview it first. Review the response, then repeat the same
67
+ command with `--apply` only when the intended team, object, and paths are confirmed.
68
+
69
+ ```bash
70
+ zl --environment <us-prod|eu-prod> workflow update <workflow-id> --input /tmp/workflow.json --dry-run
71
+ zl --environment <us-prod|eu-prod> workflow update <workflow-id> --input /tmp/workflow.json --apply
72
+ zl --environment <us-prod|eu-prod> workflow publish <workflow-id> --apply
73
+ ```
74
+
75
+ A workflow update saves a draft. Publish the workflow after reviewing its draft and
76
+ live-version response; executions continue using the published version until then.
77
+
78
+ For Team Files seeding, preview first, then use exactly the checksum returned by that
79
+ preview:
80
+
81
+ ```bash
82
+ zl --environment <us-prod|eu-prod> file seed --source-team-id <source-team-ref> --source-path /Fixtures --target-path /Rehearsal
83
+ zl --environment <us-prod|eu-prod> file seed --source-team-id <source-team-ref> --source-path /Fixtures --target-path /Rehearsal --apply --expected-checksum <sha256>
84
+ ```
85
+
86
+ ## Pages and Motion work
87
+
88
+ Pages use Markdown files with a revision marker. Export before editing, then preview
89
+ and apply the update using that file:
90
+
91
+ ```bash
92
+ zl --environment <us-prod|eu-prod> page export <page-id> --output /tmp/process.md
93
+ zl --environment <us-prod|eu-prod> page update <page-id> --input /tmp/process.md --dry-run
94
+ zl --environment <us-prod|eu-prod> page update <page-id> --input /tmp/process.md --apply
95
+ ```
96
+
97
+ For Motion work, inspect the project and valid state IDs first. Use `--dry-run` for task
98
+ creation, updates, moves, and comments whenever the command offers it.
99
+
100
+ ```bash
101
+ zl --environment <us-prod|eu-prod> project list --fields id,name
102
+ zl --environment <us-prod|eu-prod> state list --project-id <project-id> --fields id,name,type
103
+ zl --environment <us-prod|eu-prod> task create --project-id <project-id> --json '{"title":"Example"}' --dry-run
104
+ ```
105
+
106
+ ## Get current command help
107
+
108
+ ```bash
109
+ zl --help
110
+ zl <resource> --help
111
+ zl schema <resource>
112
+ ```
113
+
114
+ Successful product commands emit JSON on stdout. Errors emit structured JSON on stderr
115
+ and exit nonzero. Keep operational output focused on the requested object and report
116
+ what was inspected, previewed, applied, and published.