@cognite/cli 1.9.0 → 1.10.0-alpha.2

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 CHANGED
@@ -12,10 +12,6 @@ npx @cognite/cli apps create
12
12
 
13
13
  This prompts for your app name, org, project, and cluster, then generates a fully configured React + TypeScript project.
14
14
 
15
- ## Feature Flags
16
-
17
- Set environment variable `COGNITE_ALPHA_ENABLE_SESSION_AUTH` to true in order to enable session authentication enabling auth login and logout commands which will let you skip browser login by securely persisting access tokens on your machine.
18
-
19
15
  ## Authentication
20
16
 
21
17
  New apps created with `npx @cognite/cli apps create` depend on [`@cognite/app-sdk`](https://www.npmjs.com/package/@cognite/app-sdk) — **not `@cognite/cli`** — for auth and host integration. `@cognite/cli` is the CLI used to scaffold, develop, and deploy the app; the generated app itself talks to the Fusion app host via `@cognite/app-sdk`'s Comlink handshake. The template wires this up for you.
@@ -28,6 +24,14 @@ Deploy interactively via browser OAuth:
28
24
  npx @cognite/cli apps deploy --interactive
29
25
  ```
30
26
 
27
+ For local non-interactive deploys, sign in once to persist a refreshable
28
+ session — `apps deploy` picks it up automatically:
29
+
30
+ ```bash
31
+ npx @cognite/cli auth login
32
+ npx @cognite/cli apps deploy
33
+ ```
34
+
31
35
  For CI, set your client secret as an environment variable and run:
32
36
 
33
37
  ```bash
@@ -69,6 +73,7 @@ Browse available skills at [cognitedata/builder-skills](https://github.com/cogni
69
73
  ## Requirements
70
74
 
71
75
  - Node.js ≥ 20
76
+ - npm ≥ 11.10.0 to install/build generated apps — enforced via `engines.npm` + `engine-strict=true` in the generated app's `.npmrc`. Not required for running `@cognite/cli` itself (e.g. via `npx`).
72
77
  - React ≥ 18 (optional peer dependency — only needed for auth components)
73
78
 
74
79
  ## Telemetry
@@ -0,0 +1,182 @@
1
+ # Agent Project — AI Development Guide
2
+
3
+ This file is for **AI coding assistants** (Cursor, Claude Code, etc.) working in this
4
+ repository. Humans should start with `README.md`.
5
+
6
+ ## Project layout
7
+
8
+ | Path | Purpose |
9
+ |------|---------|
10
+ | `<name>.agent.yaml` | Agent definition — read this file for current field values |
11
+ | `eval/eval.yaml` | Eval cases and optional `include:` fragments under `eval/` |
12
+ | `README.md` | Human-oriented quick start and workflow |
13
+
14
+ ## Reference documentation
15
+
16
+ For full field schemas, tool types, scorer details, and CLI flags beyond what this
17
+ file covers, see the Cognite CLI agents documentation:
18
+
19
+ - [Cognite CLI — Agents](https://docs.cognite.com/dev/sdks/cognite-cli/agents)
20
+ - [Eval cases JSON Schema](https://docs.cognite.com/assets/schemas/agent-eval-cases.schema.json)
21
+
22
+ ## CLI validation
23
+
24
+ The CLI validates both `<name>.agent.yaml` and `eval/eval.yaml` at runtime. Schema errors
25
+ surface before commands execute — you do not need to validate YAML manually:
26
+
27
+ - **`<name>.agent.yaml`** is parsed and checked when you run `push`, `status`, `eval`, or
28
+ other commands that read the project.
29
+ - **`eval/eval.yaml`** (and any `include:` fragments) is validated at the start of
30
+ `cognite agents eval` before cases run.
31
+
32
+ Use the scaffolded templates and examples as your reference for valid field shapes.
33
+
34
+ ## Design principle: discover via tools
35
+
36
+ Agents should **retrieve** answers with declared tools, not rely on eval YAML to inject
37
+ facts into the chat. Evals should validate that behavior.
38
+
39
+ - Use `dataModels`, `instanceSpaces`, and `appContext` to scope **where** the agent
40
+ operates (plant, site, spaces) — not to paste answer text the agent should have found.
41
+ - **`faithfulness` `groundTruth`** is supplied to the **LLM judge only**. It does not replace
42
+ tool use when you are testing retrieval.
43
+
44
+ **Do not** put expected answer facts in `appContext` to make a discovery test pass:
45
+
46
+ ```yaml
47
+ # Wrong — agent sees the answer without using tools
48
+ appContext: "Pump P-101 was shut down on 2024-03-15."
49
+ turns:
50
+ - input: "When was P-101 shut down?"
51
+ scorers:
52
+ - type: faithfulness
53
+ groundTruth: "Pump P-101 was shut down on 2024-03-15."
54
+ ```
55
+
56
+ ```yaml
57
+ # Right — judge checks grounding; agent must still retrieve in production
58
+ turns:
59
+ - input: "When was P-101 shut down?"
60
+ scorers:
61
+ - type: faithfulness
62
+ groundTruth: |
63
+ Pump P-101 was shut down on 2024-03-15 due to bearing wear.
64
+ ```
65
+
66
+ ## Two-layer prompts
67
+
68
+ - **`instructions`** in `<name>.agent.yaml` is the builder-editable system guidance for this agent.
69
+ - The platform may apply additional system behavior that is not editable in this file.
70
+
71
+ ## Workflow
72
+
73
+ `create` → edit `<name>.agent.yaml` → `cognite agents push` → `cognite agents open` (manual test)
74
+ → `cognite agents eval` → `cognite agents publish` when ready.
75
+
76
+ Other commands: `pull`, `list`, `status`, `unpublish`. See `README.md` for examples.
77
+
78
+ **Eval runs against deployed config.** Push first, or run `cognite agents eval --upsert`.
79
+ To evaluate a deployed agent without a local `<name>.agent.yaml` (e.g. Cognite system agents
80
+ you cannot pull), use `cognite agents eval --system-agent` or
81
+ `cognite agents eval --external-id <id>`. Pass `[dir]` at a folder that contains
82
+ `eval.yaml` (flat suite) or an agent project with `eval/eval.yaml`. Do not put both
83
+ layouts in the same directory.
84
+ `--system-agent` and `--external-id` cannot be used together.
85
+ Auth: `cognite auth login`; optional env vars are documented in the CLI package
86
+ `env.example` (do not commit secrets).
87
+
88
+ ## Eval essentials
89
+
90
+ - Cases live in `eval/eval.yaml`; split suites with `include:` (paths relative to `eval/`).
91
+ - Filter runs: `--tag`, `--case` (repeatable), `--fail-fast`, `-v`.
92
+ - Use `--system-agent` to evaluate the Cognite-managed system agent without `<name>.agent.yaml`,
93
+ or `--external-id <id>` for any other deployed agent. These flags skip `<name>.agent.yaml`
94
+ entirely — pass `[dir]` at a folder with `eval.yaml`, or point at this project for
95
+ `eval/eval.yaml`.
96
+ - Multi-turn cases thread the conversation cursor; scorers run on the turns that declare them.
97
+
98
+ | Scorer | Use when | Required / notable fields |
99
+ |--------|----------|---------------------------|
100
+ | `correctness` | General answer quality | `criteria` |
101
+ | `faithfulness` | Output must match judge-supplied facts | `groundTruth` |
102
+ | `toolSelection` | Whether the agent picked the right tools (names only) | Optional `tools`; use runtime names (see below) |
103
+ | `toolInvocation` | Whether tool arguments match the question | Optional `tools`; put parameter details in each tool `description` (see below) |
104
+
105
+ Phoenix metric docs: [Correctness](https://arize.com/docs/phoenix/evaluation/pre-built-metrics/correctness),
106
+ [Faithfulness](https://arize.com/docs/phoenix/evaluation/pre-built-metrics/faithfulness),
107
+ [Tool Selection](https://arize.com/docs/phoenix/evaluation/pre-built-metrics/tool-selection),
108
+ [Tool Invocation](https://arize.com/docs/phoenix/evaluation/pre-built-metrics/tool-invocation).
109
+
110
+ ### Tool scorers: `tools` field and gotchas
111
+
112
+ `toolSelection` and `toolInvocation` need a resolved tool list for the LLM judge.
113
+ The judge does a **literal name membership check** — if the names don't match what
114
+ the agent actually called, the scorer will report `incorrect` even when tool use
115
+ was appropriate.
116
+
117
+ **Eval `tools` are NOT `<name>.agent.yaml` tools.** `<name>.agent.yaml` declares tools for the
118
+ agent runtime (config-time names like `query`). Eval `tools` declare what the
119
+ *judge* should expect the agent to *call* at runtime (e.g. `find_assets`, `execute`).
120
+ These are often different names.
121
+
122
+ **Three categories of tools:**
123
+
124
+ - **Custom tools** (user-defined): config name = runtime name. Tool scorers work
125
+ with tools from `<name>.agent.yaml` — no eval `tools` needed.
126
+ - **Cognite platform tools** (`query`, `ask_document`, etc.): the runtime decomposes
127
+ these into sub-tools (`find_assets`, `list_views`) whose names differ from config.
128
+ Declare runtime tool names in eval `tools`, or use `correctness`/`faithfulness`
129
+ to evaluate outcomes instead.
130
+ - **System tools** (sandbox `execute`, `commandTool`): never in any config. Declare
131
+ them in eval `tools`, or use `correctness`.
132
+
133
+ **Discovering runtime tool names:** Run eval once with `-v` or `--report-dir` and
134
+ look at the `toolsCalled:` output to see what the agent actually invoked.
135
+
136
+ **Tool list cascade** (most specific wins, whole-array replace — not merge-by-name):
137
+
138
+ ```
139
+ scorer.tools → case.tools → included-file.tools → root eval.yaml tools → <name>.agent.yaml tools
140
+ ```
141
+
142
+ With `--external-id` or `--system-agent`, `<name>.agent.yaml` is skipped entirely —
143
+ declare eval `tools` at root, file, case, or scorer level.
144
+
145
+ **Empty resolution skips the scorer.** If no tools resolve after the full cascade,
146
+ the scorer is skipped with a stderr warning (not a misleading "incorrect" verdict).
147
+ Other scorers on the same turn still run. A case whose *only* scorers were all
148
+ skipped fails the verdict (zero scores).
149
+
150
+ **`toolInvocation` description quality:** The judge evaluates arguments against
151
+ whatever you put in each tool's `description`. Include parameter details for
152
+ accurate invocation scoring:
153
+
154
+ ```yaml
155
+ tools:
156
+ - name: find_assets
157
+ description: |
158
+ Find assets in the knowledge graph.
159
+ Parameters: filter (string, required), limit (integer, optional).
160
+ ```
161
+
162
+ Without parameter details, the judge can only check whether arguments "seem
163
+ reasonable" for the user's question — it cannot verify schema compliance.
164
+
165
+ ## Eval YAML inheritance
166
+
167
+ Fields resolve at three levels for session context and case-level tools: root
168
+ `eval/eval.yaml` → included file → individual case. Scorer-level `tools` on a turn
169
+ override case/file/root (and `<name>.agent.yaml` fallback) for that scorer only.
170
+
171
+ - **`tags`** — union (file-level tags merge into each case's tags, deduplicated).
172
+ - **`dataModels`, `instanceSpaces`, `appContext`** — per-field replace (most specific wins; no deep merge).
173
+ - **`tools`** — whole-array replace at each level (not merge-by-name). Used by
174
+ `toolSelection` / `toolInvocation`; does not change what tools the agent can call —
175
+ only what the judge considers when scoring.
176
+
177
+ ## Conventions for AI assistants
178
+
179
+ - Minimize scope when editing YAML; match existing case `id` style and tags.
180
+ - Do not commit credentials; use environment variables.
181
+ - For detailed eval authoring or debugging workflows, use project skills under
182
+ `.cursor/skills` or `.claude/skills` when they are present.
@@ -1,77 +1,41 @@
1
1
  # Eval cases for {{displayName}}
2
- #
3
- # Each case is a conversation with the agent plus one or more "scorers" that
4
- # judge the responses. An LLM judge grades every scored turn. Run the suite with:
5
- #
6
- # cognite agents eval
7
- #
8
- # Supported scorer types:
9
- # - correctness: compares the answer to a reference description you provide
10
- # (`reference`). Use it when you can describe a good answer.
11
- # - faithfulness: checks the answer is grounded in the supplied `context` and
12
- # does not hallucinate. Use it for retrieval / grounded answers.
13
- # - toolSelection: checks whether the agent picked an appropriate tool (or
14
- # correctly used none) for the question, based on the tools
15
- # configured in agent.yaml. Requires no extra fields, but only
16
- # makes sense once you've added tools (see README.md's
17
- # "Adding tools" section).
18
- # - toolInvocation: checks whether the agent invoked tools with correct
19
- # arguments and formatting. Complements toolSelection — use
20
- # both when you need full tool-calling coverage. Requires no
21
- # extra fields.
22
- #
23
- # These are placeholders — edit the inputs, references, and context to match what
24
- # your agent actually does, then add more cases over time.
2
+ # Run with: cognite agents eval
3
+ # Add more cases and scorer types as you add tools. See README.md.
25
4
 
26
5
  # To split cases across multiple files as your suite grows, add:
27
6
  # include:
28
7
  # - cases/maintenance.yaml
29
8
 
9
+ # Optional: tools for toolSelection / toolInvocation scorers (judge rubric — NOT the same
10
+ # as <name>.agent.yaml tools). <name>.agent.yaml configures the runtime (e.g. query); eval tools use
11
+ # names the agent actually calls (e.g. find_assets, execute). Omit when <name>.agent.yaml names
12
+ # match runtime calls; required when using --external-id / --system-agent.
13
+ # tools:
14
+ # - name: find_assets
15
+ # description: |
16
+ # Find assets in the knowledge graph.
17
+ # Parameters: filter (string, required), limit (integer, optional).
18
+
30
19
  cases:
31
- # Single-turn case scored for correctness.
20
+ # Single-turn case: the agent should explain what it can help with.
32
21
  - id: greeting
33
22
  turns:
34
23
  - input: "Hi, what can you help me with?"
35
24
  scorers:
36
25
  - type: correctness
37
- # Describe what a good answer looks like; the judge compares against this.
38
- reference: >-
26
+ criteria: >-
39
27
  A friendly greeting that briefly explains what this agent can help
40
28
  the user with.
41
29
 
42
- # Single-turn case scored for faithfulness against supplied context.
43
- - id: grounded-answer
44
- turns:
45
- - input: "Where is the main compressor located?"
46
- scorers:
47
- - type: faithfulness
48
- # The answer must be grounded in this context and not invent facts.
49
- context: >-
50
- The main compressor (unit C-101) is installed on Deck 2 of the
51
- North platform, next to the gas separation train.
52
-
53
- # Single-turn case scored for tool selection. Assumes you've added the
54
- # `find_assets` tool from README.md's "Adding tools" example — the judge
55
- # checks whether the agent picked an appropriate tool (or none) based on
56
- # the tools listed in agent.yaml.
57
- - id: find-assets-tool
58
- turns:
59
- - input: "Find assets related to compressors in the knowledge graph."
60
- scorers:
61
- - type: toolSelection
62
- - type: toolInvocation
63
-
64
30
  # Multi-turn case: the agent should carry context across turns.
65
- - id: assets-followup
31
+ - id: follow-up
66
32
  turns:
67
- - input: "List the assets in the cooling system."
33
+ - input: "What can you help me with?"
68
34
  scorers:
69
35
  - type: correctness
70
- reference: "Lists the assets that belong to the cooling system."
71
- - input: "Now show only the ones that are currently active."
36
+ criteria: "Describes the agent's capabilities."
37
+ - input: "Can you elaborate on the first thing you mentioned?"
72
38
  scorers:
73
39
  - type: correctness
74
- # Relies on the previous turn — the judge sees the earlier turns as context.
75
- reference: >-
76
- Narrows the previously listed cooling-system assets down to only
77
- the active ones.
40
+ criteria: >-
41
+ Expands on a capability mentioned in the previous response.
@@ -1,6 +1,6 @@
1
1
  # {{displayName}}
2
2
 
3
- > Edit `agent.yaml` to configure your agent — tools, model, instructions.
3
+ > Edit `<name>.agent.yaml` to configure your agent — tools, model, instructions.
4
4
 
5
5
  ## Quick start
6
6
 
@@ -19,24 +19,28 @@ cognite agents publish
19
19
 
20
20
  | Path | Purpose |
21
21
  |------|---------|
22
- | `agent.yaml` | Agent definition (externalId, tools, model, instructions) |
22
+ | `<name>.agent.yaml` | Agent definition (externalId, tools, model, instructions), named after this folder |
23
23
  | `eval/eval.yaml` | Example eval cases — run with `cognite agents eval` |
24
24
  | `README.md` | This file |
25
25
 
26
26
  ## Evaluating the agent
27
27
 
28
28
  `eval/eval.yaml` contains starter test cases (single-turn and multi-turn) that
29
- grade the agent's responses with an LLM judge. After pushing the agent, run:
29
+ grade the agent's responses with an LLM judge. The default cases are designed to
30
+ pass on a freshly pushed agent — push first, then run:
30
31
 
31
32
  ```bash
32
33
  cognite agents eval
33
34
  ```
34
35
 
35
36
  Edit the cases to match what your agent does, and add more over time.
37
+ Add tools in `<name>.agent.yaml` before adding tool-scorer eval cases (`toolSelection`, `toolInvocation`).
36
38
 
37
39
  ## Adding tools
38
40
 
39
- Edit the `tools` array in `agent.yaml`. Available tool types:
41
+ Edit the `tools` array in `<name>.agent.yaml`. Common tool types (illustrative — may not
42
+ reflect all available types; check the Cognite documentation or the agent builder
43
+ UI in Fusion for the latest list):
40
44
 
41
45
  - `analyzeData` — analyze tabular or structured data
42
46
  - `analyzeImage` — analyze images and P&ID diagrams
@@ -74,5 +78,8 @@ tools:
74
78
 
75
79
  ## Deployment with Toolkit
76
80
 
77
- The generated `agent.yaml` is compatible with [Cognite Toolkit](https://docs.cognite.com/cdf/deploy/toolkit/).
78
- Place it in your Toolkit module under `agents/` and deploy with `cdf deploy`.
81
+ The generated `<name>.agent.yaml` is compatible with [Cognite Toolkit](https://docs.cognite.com/cdf/deploy/toolkit/).
82
+ Place it in your Toolkit module under `agents/` and deploy with `cdf deploy`. Toolkit
83
+ treats the `<name>` part as a label and reads the `externalId` from inside the file,
84
+ so you can rename the file freely — the CLI keeps working as long as the folder holds
85
+ one definition.
@@ -0,0 +1,44 @@
1
+ ---
2
+ name: check-agent
3
+ description: >-
4
+ Review <name>.agent.yaml and eval setup locally — description, instructions, tool alignment,
5
+ and common eval mismatches. Use when reviewing an agent, linting config, or asking
6
+ if anything looks wrong before push or publish.
7
+ ---
8
+
9
+ # Check agent
10
+
11
+ Produce a short markdown report from **local files only**. Do not call CDF APIs unless the user explicitly asks; for deployed state, suggest `cognite agents status`.
12
+
13
+ ## Workflow
14
+
15
+ 1. Read `<name>.agent.yaml` — `name`, `description`, `instructions`, `tools`, `exampleQuestions`, labels (e.g. published).
16
+ 2. Read `eval/eval.yaml` and any `include:` files under `eval/`.
17
+ 3. Read `AGENTS.md` when you need eval or prompt conventions.
18
+ 4. Run checks and label each finding **error**, **warn**, or **info** with a concrete fix:
19
+
20
+ | Check | Severity | Rule |
21
+ |-------|----------|------|
22
+ | `description` missing or empty | warn | Add a clear user-facing description. |
23
+ | `instructions` empty or obvious scaffold placeholder | warn | Replace with real guidance (see write-instructions skill). |
24
+ | Tool named in `instructions` but not in `tools[]` | error | Add the tool or remove the mention. |
25
+ | Tool in `tools[]` never mentioned in `instructions` | info | Document when/how to use it. |
26
+ | `toolSelection` / `toolInvocation` in eval but no tools resolve (no eval `tools` at any cascade level and no `<name>.agent.yaml` `tools`) | error | Add a `tools` field at root, file, case, or scorer level in eval yaml, or add tools to `<name>.agent.yaml`. With `--external-id`/`--system-agent`, `<name>.agent.yaml` is not loaded. |
27
+ | `labels` includes published but `exampleQuestions` empty | warn | Add starter questions for Fusion. |
28
+ | Eval case ids duplicated | error | Rename ids in `eval/eval.yaml`. |
29
+
30
+ 5. Optionally skim `README.md` for project-specific tool setup the checks above cannot see.
31
+
32
+ Keep the report scannable: bullet list grouped by severity, then suggested command order (`check-agent` → edit → `push` → `eval`).
33
+
34
+ ## Anti-patterns
35
+
36
+ - Do not block on network or credentials for a default review.
37
+ - Do not rewrite `instructions` in full during a review — flag issues and offer the write-instructions skill if the user wants a rewrite.
38
+ - Do not invent tool config schemas — point to `README.md` and `<name>.agent.yaml` examples.
39
+
40
+ ## Cross-references
41
+
42
+ - To improve `instructions` → **write-instructions** skill, then re-run this check.
43
+ - To add or fix eval coverage → **write-eval-case** skill.
44
+ - After a failed eval → **debug-eval** skill.
@@ -0,0 +1,36 @@
1
+ ---
2
+ name: debug-eval
3
+ description: >-
4
+ Diagnose Cognite agent eval failures from CLI output — config drift, deployment,
5
+ invoke errors, and scorer rationales. Use when eval failed, a scorer failed, or
6
+ the user pastes eval run output.
7
+ ---
8
+
9
+ # Debug eval
10
+
11
+ Work through failures systematically using the user’s eval output (paste or summary).
12
+
13
+ ## Workflow
14
+
15
+ 1. Identify the failing **case id**, **turn**, and **scorer type** (if any). Note exit code and whether the whole suite or one case failed.
16
+ 2. **Config drift** — local `<name>.agent.yaml` / `eval/eval.yaml` may differ from what CDF runs. Suggest `cognite agents push` or `cognite agents eval --upsert` so eval matches the project on disk.
17
+ 3. **Not deployed** — if push was never done or status is stale, suggest `cognite agents push` and `cognite agents status` (run `cognite agents status --help` for flags).
18
+ 4. **Invoke / runtime errors** — auth, routing, or agent errors before scoring. Suggest `cognite auth login`, confirm project/cluster flags, and re-run with verbosity from `cognite agents eval --help` (e.g. `-v`).
19
+ 5. **Scorer failures** — read the judge rationale. For `correctness`, compare the response to `criteria`. For `faithfulness`, check `groundTruth` vs actual tool-retrieved facts. For tool scorers, check where the tool list resolved from (scorer → case → file → root `eval/eval.yaml` → `<name>.agent.yaml`); confirm runtime tool names match what the agent called (`toolsCalled:` output). A "Skipping … no tools available" warning means no tools resolved at all — add a `tools` field at the appropriate cascade level.
20
+ - **Common gotcha:** `<name>.agent.yaml` declares config-time names (e.g. `query`) but the agent calls runtime sub-tools (e.g. `find_assets`). Override with runtime names in eval `tools`.
21
+ - **`--external-id` / `--system-agent`:** `<name>.agent.yaml` tools are not loaded; tools must come from eval yaml.
22
+ 6. **Narrow the run** — suggest isolating with `--case` (repeatable), `--tag`, or `--fail-fast` per `cognite agents eval --help`.
23
+ 7. For scorer semantics or field meaning, read **AGENTS.md** rather than guessing.
24
+
25
+ Summarize likely root cause, concrete next step, and whether the fix is config, deployment, auth, instructions, or the eval case itself.
26
+
27
+ ## Anti-patterns
28
+
29
+ - Do not assume eval uses local YAML without push/`--upsert` unless the user confirmed deployment state.
30
+ - Do not change `criteria` or `groundTruth` to match a bad hallucination — fix retrieval, instructions, or the case intent.
31
+ - Do not list every CLI flag from memory — delegate to `--help`.
32
+
33
+ ## Cross-references
34
+
35
+ - If the case design or scorers are wrong → **write-eval-case** skill.
36
+ - If the agent behavior but instructions are weak → **write-instructions** skill, then **check-agent** for alignment.
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: write-eval-case
3
+ description: >-
4
+ Guide authoring eval cases in eval/eval.yaml — scorer choice, multi-turn patterns,
5
+ and YAML structure. Use when adding tests, extending the eval suite, or validating
6
+ agent behavior for a Cognite agent project.
7
+ ---
8
+
9
+ # Write eval case
10
+
11
+ Help the user add or edit cases in `eval/eval.yaml` (or an `include:` fragment under `eval/`).
12
+
13
+ ## Workflow
14
+
15
+ 1. Read `<name>.agent.yaml` — note declared tools, model, and what the agent is meant to do.
16
+ 2. Read `AGENTS.md` — use the eval essentials table for scorer types and required fields, plus inheritance rules for `tags`, `dataModels`, `instanceSpaces`, and `appContext`.
17
+ 3. Ask what behavior to test: single-turn vs multi-turn, happy path vs edge case, and whether tool use should be exercised.
18
+ 4. Choose scorers using the AGENTS.md table:
19
+ - `correctness` when a good answer can be described in `criteria`.
20
+ - `faithfulness` when grounding against judge-only `groundTruth` matters (retrieval / facts).
21
+ - `toolSelection` / `toolInvocation` when tools are available via the cascade: scorer `tools` → case `tools` → file `tools` → root `eval/eval.yaml` `tools` → `<name>.agent.yaml` `tools`. Use runtime names (e.g. `find_assets`, `execute`), not config-time names (e.g. `query`). For `toolInvocation`, include parameter details in each tool's `description`.
22
+ 5. Draft YAML: unique `id`, optional `tags`, one or more `turns` with `input` and `scorers` on the turns you want judged.
23
+ 6. Validate locally: every case has at least one scored turn; no duplicate `id` values across the suite; tool scorers have tools resolvable via the cascade (eval yaml or `<name>.agent.yaml`).
24
+ 7. Remind the user that eval runs against **deployed** config — run `cognite agents push` first, or use `cognite agents eval --upsert`. For run filters and flags, run `cognite agents eval --help`.
25
+
26
+ Match existing `id` and tag style in the file. Prefer small, focused cases over one huge conversation.
27
+
28
+ ## Anti-patterns
29
+
30
+ - Do not put answer facts in `appContext` so the agent passes without using tools — see AGENTS.md “discover via tools”.
31
+ - Do not add `toolSelection` or `toolInvocation` when no tools resolve from the cascade (eval yaml levels + `<name>.agent.yaml`). If tools are empty, these scorers are skipped with a warning — not scored as "incorrect."
32
+ - Do not use `<name>.agent.yaml` config-time names (e.g. `query`) in eval `tools` when the agent calls different runtime sub-tools (e.g. `find_assets`). Run eval with `-v` to discover actual tool names.
33
+ - Do not duplicate case `id` values or leave turns unscored when the user expects a pass/fail result.
34
+ - Do not inline full scorer schemas in chat — point to `AGENTS.md` and the scaffolded examples in `eval/eval.yaml`.
35
+
36
+ ## Cross-references
37
+
38
+ - If the agent cannot pass because instructions are vague or wrong → use the **write-instructions** skill, then re-run eval.
39
+ - If a run fails and the case looks correct → use the **debug-eval** skill.
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: write-instructions
3
+ description: >-
4
+ Guide writing or improving agent instructions in <name>.agent.yaml — purpose, constraints,
5
+ tool usage, and response style. Use when improving the system prompt, clarifying
6
+ behavior, or aligning instructions with declared tools.
7
+ ---
8
+
9
+ # Write instructions
10
+
11
+ Edit the `instructions` field in `<name>.agent.yaml`. Platform system behavior may apply on top; you only control the builder-editable layer.
12
+
13
+ ## Workflow
14
+
15
+ 1. Read `<name>.agent.yaml` — current `instructions`, `description`, `tools`, and any `appContext`-related fields you should stay consistent with.
16
+ 2. Read `AGENTS.md` — **Two-layer prompts** (your instructions vs platform behavior) and **discover via tools** (agents should retrieve with tools, not rely on hidden cheat sheets).
17
+ 3. Clarify with the user: primary audience, tone, allowed/refused actions, and which tools must be used for which tasks.
18
+ 4. Structure the prompt clearly:
19
+ - **Purpose** — what the agent is for in one short block.
20
+ - **Working principles** — how to reason, when to use tools, how to handle uncertainty.
21
+ - **Constraints** — safety, data scope, “do not” rules, org/project facts that must not be guessed.
22
+ - **Response style** — format, brevity, widgets or tables if the project uses them.
23
+ 5. For every entry in `tools[]`, add explicit guidance: when to call it, what inputs mean, and what to do if the tool fails.
24
+ 6. Remove contradictions, vague placeholders, and duplicate rules. Prefer specific, testable guidance evals can target.
25
+ 7. After edits, suggest `cognite agents push` and a targeted `cognite agents eval` (see `cognite agents eval --help`).
26
+
27
+ Propose changes as a unified diff or full `instructions` block the user can paste into `<name>.agent.yaml`.
28
+
29
+ ## Anti-patterns
30
+
31
+ - Do not promise capabilities no tool or platform feature provides.
32
+ - Do not embed secrets, tokens, or user credentials in instructions.
33
+ - Do not tell the agent to ignore tools when evals expect tool use (or the reverse).
34
+ - Do not paste entire scorer or CLI reference docs — link to `AGENTS.md` and `--help`.
35
+
36
+ ## Cross-references
37
+
38
+ - After rewriting → run **check-agent** to verify tool/instruction alignment and eval consistency.
39
+ - If evals fail on grounding or retrieval → **debug-eval** skill; if cases need updates → **write-eval-case** skill.
@@ -12,7 +12,6 @@ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>app.json'
12
12
  "org": "<%= org %>",
13
13
  "project": "<%= project %>",
14
14
  "baseUrl": "<%= baseUrl %>",
15
- "published": false,
16
15
  "deployClientId": "",
17
16
  "deploySecretName": "<%= (org + '_' + project + '_' + cluster).replace(/-/g, '_').toUpperCase() %>"
18
17
  }
@@ -28,7 +28,7 @@ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>package.json'
28
28
  "dependencies": {
29
29
  "@cognite/aura": "^0.3.5",
30
30
  "@cognite/sdk": "^10.10.0",
31
- "@cognite/app-sdk": "^0.8.0",
31
+ "@cognite/app-sdk": "^0.9.0",
32
32
  "@tabler/icons-react": "^3.35.0",
33
33
  "@tanstack/react-query": "^5.90.10",
34
34
  "clsx": "^2.1.1",
@@ -0,0 +1,12 @@
1
+ var ke=Object.defineProperty;var ie=n=>{throw TypeError(n)};var s=(n,e)=>ke(n,"name",{value:e,configurable:!0});var se=(n,e,t)=>e.has(n)||ie("Cannot "+t);var D=(n,e,t)=>(se(n,e,"read from private field"),t?t.call(n):e.get(n)),oe=(n,e,t)=>e.has(n)?ie("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(n):e.set(n,t),ae=(n,e,t,r)=>(se(n,e,"write to private field"),r?r.call(n,t):e.set(n,t),t);import{existsSync as dt}from"fs";import{mkdir as lt,readFile as ut}from"fs/promises";import{basename as gt,dirname as ft}from"path";var M=class M extends Error{constructor(e,t={}){super(e),this.name="HintedError",t.cause!==void 0&&(this.cause=t.cause);let r=this.deriveDefaults(t);this.hint=t.hint??r.hint,this.helpUrl=t.helpUrl??r.helpUrl,this.shouldReport=t.shouldReport??!0}deriveDefaults(e){return{hint:Ce(e.cause)}}};s(M,"HintedError");var l=M;var pe="https://docs.cognite.com/cdf/access/",xe="https://status.cognite.com";function Ie(n){switch(n){case 401:return{hint:"Your credentials are invalid or expired. Check your client ID and secret.",helpUrl:pe};case 403:return{hint:"You don't have the required CDF capabilities. Please contact your CDF admin.",helpUrl:pe};case 413:return{hint:"The deployment exceeds the App Hosting size limit. Reduce the build output \u2014 remove unused assets, code-split bundles, or strip source maps."};case 429:return{hint:"You are being rate limited. Wait a few moments and retry. If this persists, contact CDF support."};case 500:case 502:case 503:case 504:return{hint:"CDF service error. The issue is on the server side. Check the status page and retry shortly.",helpUrl:xe};default:return{}}}s(Ie,"defaultHintForStatus");var j=class j extends l{constructor(e,t){super(e,t),this.name="HintedHttpError",this.httpStatusCode=t.httpStatusCode,this.requestUrl=t.requestUrl,this.responseBody=t.responseBody}deriveDefaults(e){let{httpStatusCode:t}=e,r=Ie(t),i=super.deriveDefaults(e);return{hint:r.hint??i.hint,helpUrl:r.helpUrl}}};s(j,"HintedHttpError");var k=j;function Pe(n,e){if(n)switch(n){case"ENOTFOUND":return e.hostname?`DNS lookup failed for ${e.hostname}. Check your network, VPN, or proxy settings.`:"DNS lookup failed. Check your network, VPN, or proxy settings.";case"ECONNREFUSED":return e.hostname&&e.port?`Connection refused by ${e.hostname}:${e.port}. The service may be down or the port may be wrong.`:"Connection refused. The service may be down or the port may be wrong.";case"ECONNRESET":return"Connection was reset. The server closed the connection unexpectedly; check for proxy/firewall interference and retry.";case"ETIMEDOUT":return"Connection timed out. Check your network, VPN, or proxy settings, and retry.";case"EAI_AGAIN":return"Temporary DNS failure. Retry shortly; if it persists, check your DNS configuration.";case"CERT_HAS_EXPIRED":case"UNABLE_TO_VERIFY_LEAF_SIGNATURE":case"SELF_SIGNED_CERT_IN_CHAIN":return"TLS certificate validation failed. Check system clock and CA trust store; if you use a corporate proxy, ensure its root cert is trusted.";case"EACCES":return e.path?`Permission denied: ${e.path}. Check file ownership and permissions.`:"Permission denied. Check file ownership and permissions.";case"ENOENT":return e.path?`File or directory not found: ${e.path}.`:"File or directory not found.";case"EISDIR":return e.path?`Expected a file but found a directory: ${e.path}.`:"Expected a file but found a directory.";case"ENOSPC":return"No space left on device. Free up disk space and retry.";case"EADDRINUSE":return e.port?`Port ${e.port} is already in use. Stop the process using it or pick a different port.`:"Address is already in use. Stop the conflicting process or change the port.";case"EMFILE":case"ENFILE":return"Too many open files. Close other programs or raise the file descriptor limit.";default:return}}s(Pe,"hintForErrno");function Ce(n){let e=n,t=new Set;for(;e!=null&&!t.has(e)&&(t.add(e),typeof e=="object");){let r=e,i=Pe(r.code,r);if(i!==void 0)return i;e=r.cause}}s(Ce,"hintForCause");import{inspect as be}from"util";var G="[REDACTED]",w,$=class ${constructor(e){oe(this,w);ae(this,w,e)}toString(){return G}toJSON(){return G}[be.custom](){return G}expose(){return D(this,w)}equals(e){return D(this,w)===D(e,w)}static from(e){return new $(e)}};w=new WeakMap,s($,"SensitiveString");var E=$;var ce="https://docs.cognite.com/cdf/access/";function g(n){return n!==null&&typeof n=="object"}s(g,"isRecord");function C(n){return n instanceof Error&&"status"in n&&typeof n.status=="number"}s(C,"isHttpError");function Re(n){switch(n){case 401:return`Your credentials are invalid or expired. Check your client ID and secret.
2
+ See: ${ce}`;case 403:return`You don't have the required CDF capabilities. Please contact your CDF admin.
3
+ See: ${ce}`;default:return}}s(Re,"httpStatusHint");function f(n){let e=n instanceof Error?n:new Error(String(n));if(!C(e))return null;let t=Re(e.status);return t?Object.assign(new Error(`${e.message}
4
+ ${t}`),{cause:e}):null}s(f,"enrichedHttpError");function Te(n){if(!g(n))return null;let e=n.missing;if(Array.isArray(e))return e;let t=n.data;if(g(t)){let r=t.error;if(g(r)&&Array.isArray(r.missing))return r.missing;if(Array.isArray(t.missing))return t.missing}return null}s(Te,"findMissingArray");function De(n,e){if(!C(n)||n.status!==400)return!1;let t=Te(n);return t?t.some(r=>g(r)&&typeof r.externalId=="string"&&e.includes(r.externalId)):!1}s(De,"isMissingExternalIdError");function U(n,e){return C(n)&&n.status===404||De(n,e)}s(U,"isNotFoundError");var le=["DRAFT","PUBLISHED","DEPRECATED","ARCHIVED"],ue=["ACTIVE","PREVIEW"],q=class q extends Error{constructor(e,t){super(`Version ${t} of app ${e} not found`),this.name="AppVersionNotFoundError",this.appExternalId=e,this.version=t}};s(q,"AppVersionNotFoundError");var N=q,J=class J extends Error{constructor(e){super(`App ${e} not found`),this.name="AppNotFoundError",this.appExternalId=e}};s(J,"AppNotFoundError");var V=J;function F(n,e){return n.includes(e)}s(F,"includesValue");function $e(n){return F(le,n)}s($e,"isAppVersionLifecycleState");function Ue(n){return F(ue,n)}s(Ue,"isAppVersionAlias");function Ne(n){return typeof n.version=="string"&&$e(n.lifecycleState)&&typeof n.entrypoint=="string"&&typeof n.createdTime=="number"&&typeof n.createdBy=="string"&&typeof n.appExternalId=="string"&&(n.alias===void 0||Ue(n.alias))&&(n.comment===void 0||typeof n.comment=="string")}s(Ne,"isAppVersion");function de(n){if(!g(n)){let e=JSON.stringify(n)?.slice(0,200)??String(n);throw new Error(`Invalid version response: expected object, got ${e}`)}if(!Ne(n)){let e=JSON.stringify(n).slice(0,300);throw new Error(`Invalid version response: missing or malformed fields. Got: ${e}`)}return n}s(de,"parseAppVersion");function Ve(n){if(!g(n))throw new Error("Invalid app response: not an object");let{externalId:e,name:t,description:r}=n;if(typeof e!="string")throw new Error("Invalid app response: missing externalId");if(typeof t!="string")throw new Error("Invalid app response: missing name");if(r!=null&&typeof r!="string")throw new Error("Invalid app response: malformed description");return{externalId:e,name:t,description:typeof r=="string"?r:void 0}}s(Ve,"parseAppMetadata");var z=class z{constructor(e){this.client=e}get appsBasePath(){return`/api/v1/projects/${encodeURIComponent(this.client.project)}/apphosting/apps`}async createApp(e,t,r){try{await this.client.post(this.appsBasePath,{data:{items:[{externalId:e,name:t,description:r}]}})}catch(i){throw f(i)??i}}async updateApps(e){try{await this.client.post(`${this.appsBasePath}/update`,{data:{items:e}})}catch(t){throw f(t)??t}}async getApp(e){let t=`${this.appsBasePath}/${encodeURIComponent(e)}`;try{let r=await this.client.get(t);return Ve(r.data)}catch(r){throw U(r,[e])?new V(e):f(r)??r}}async uploadVersion(e,t,r,i,o="index.html"){console.log(`\u{1F4E4} Uploading version ${t}...`);let a=new FormData;a.append("file",new Blob([new Uint8Array(r)]),i),a.append("version",t),a.append("entryPath",o);let p=encodeURIComponent(e),c=`${this.appsBasePath}/${p}/versions`,d=await this.client.authenticate();if(!d)throw new l("Failed to authenticate for upload",{hint:"Check your credentials and try again."});let S=E.from(d),h=`${this.client.getBaseUrl()}${c}`,te=new AbortController,we=setTimeout(()=>te.abort(),300*1e3),A;try{A=await fetch(h,{method:"POST",headers:{Authorization:`Bearer ${S.expose()}`},body:a,signal:te.signal})}catch(m){throw m instanceof Error&&m.name==="AbortError"?new l("Upload timed out after 5 minutes",{hint:"The upload took longer than 5 minutes. Try again \u2014 if it keeps timing out, check your network speed or bundle size."}):new l(`Failed to upload version to ${h}`,{cause:m,hint:"Check your network connection. Uploads can also fail behind a proxy that blocks multipart POST requests."})}finally{clearTimeout(we)}if(!A.ok){let m=await A.text(),v;try{v=JSON.parse(m)}catch{}let T=m;if(g(v)){let I=v.error;if(typeof I=="string")T=I;else if(g(I)){let P=I.message,re=I.code;T=typeof P=="string"?P:re!=null?`Unknown error (code: ${re})`:m}else{let P=v.message;T=typeof P=="string"?P:m}}let ne=A.headers.get("x-request-id"),Ae=ne?` | X-Request-ID: ${ne}`:"",ve=g(v)?v:m;throw new k(`Upload failed: ${A.status} \u2014 ${T}${Ae}`,{httpStatusCode:A.status,requestUrl:h,responseBody:ve})}console.log(`\u2705 Version ${t} uploaded`)}async getVersion(e,t){let r=encodeURIComponent(e),i=encodeURIComponent(t),o=`${this.appsBasePath}/${r}/versions/${i}`;try{let a=await this.client.get(o);return de(a.data)}catch(a){throw U(a,[e,t])?new N(e,t):f(a)??a}}async getActiveVersion(e){let t=encodeURIComponent(e),r=`${this.appsBasePath}/${t}/versions/list`;try{let i=await this.client.post(r,{data:{filter:{aliases:["ACTIVE"]}}});if(!g(i.data)||!Array.isArray(i.data.items))throw new Error("Invalid versions/list response: expected an object with an items array");let{items:o}=i.data;if(o.length===0)return null;if(o.length>1)throw new Error(`Unexpected response: ${o.length} versions have the ACTIVE alias, expected at most 1`);return de(o[0])}catch(i){if(U(i,[e]))return null;throw f(i)??i}}async deleteVersions(e,t){let r=encodeURIComponent(e),i=`${this.appsBasePath}/${r}/versions/delete`;try{await this.client.post(i,{data:{items:t.map(o=>({version:o}))}})}catch(o){throw f(o)??o}}async updateVersions(e,t){let r=encodeURIComponent(e),i=`${this.appsBasePath}/${r}/versions/update`;try{await this.client.post(i,{data:{items:t}})}catch(o){throw f(o)??o}}async submitSignatures(e,t,r){let i=encodeURIComponent(e),o=encodeURIComponent(t),a=`${this.appsBasePath}/${i}/versions/${o}/signatures`;try{await this.client.post(a,{data:{items:r}})}catch(p){throw f(p)??p}}async listSignatures(e,t){let r=encodeURIComponent(e),i=encodeURIComponent(t),o=`${this.appsBasePath}/${r}/versions/${i}/signatures/list`;try{let a=await this.client.post(o,{data:{}});return _e(a.data)}catch(a){throw f(a)??a}}};s(z,"AppHostingApi");var O=z,Fe=["VALID","REVOKED","EXPIRED","SIGNED_BEFORE_KEY_ISSUED","IAT_IN_FUTURE","BUNDLE_TOO_OLD","KEY_NOT_IN_REGISTRY","SCOPE_MISMATCH","VERIFICATION_FAILED"],Oe=["developer","certifier"];function _e(n){if(!g(n))throw new Error("Invalid signatures response: expected an object with an items array");let{items:e}=n;if(!Array.isArray(e))throw new Error("Invalid signatures response: items property is missing or not an array");return e.flatMap(t=>{let r=Be(t);return r?[r]:[]})}s(_e,"parseStoredSignatures");function Be(n){if(!g(n))return null;let{signerKid:e,signerRole:t,signatureIat:r,receivedAt:i,createdTime:o,status:a}=n;return typeof e!="string"||e===""||!F(Oe,t)||typeof r!="number"||typeof i!="number"||typeof o!="number"||!F(Fe,a)?null:{signerKid:e,signerRole:t,signatureIat:r,receivedAt:i,createdTime:o,status:a}}s(Be,"parseStoredSignature");function Le(n,e){let t=[];n.name!==e.name&&t.push({field:"name",remote:n.name,local:e.name});let r=n.description??"";return r!==e.description&&t.push({field:"description",remote:r,local:e.description}),t}s(Le,"diffAppMetadata");function He(n){let e=["Cannot deploy: metadata in app.json differs from what's deployed:"];for(let{field:t,remote:r,local:i}of n){let o=`${t}:`.padEnd(14);e.push(` ${o}"${r}" \u2192 "${i}"`)}return e.join(`
5
+ `)}s(He,"formatMetadataDriftError");var Y=class Y{constructor(e){this.api=new O(e)}getVersion(e,t){return this.api.getVersion(e,t)}uploadVersion(e,t,r,i,o){return this.api.uploadVersion(e,t,r,i,o)}async ensureApp(e,t,r){console.log("\u{1F50D} Ensuring app exists...");try{await this.api.createApp(e,t,r),console.log(`\u2705 App '${e}' created`)}catch(i){if(C(i)&&i.status===409){console.log(`\u2705 App '${e}' already exists`),await this.checkMetadataDrift(e,t,r);return}throw i}}async checkMetadataDrift(e,t,r){let i;try{i=await this.getApp(e)}catch{return}let o=Le(i,{name:t,description:r});if(o.length!==0)throw new l(He(o),{hint:"Run npx @cognite/cli apps metadata update to sync before deploying",shouldReport:!1})}getApp(e){return this.api.getApp(e)}async updateAppMetadata(e,t,r){await this.api.updateApps([{externalId:e,update:{name:{set:t},description:r?{set:r}:{setNull:!0}}}])}async submitSignatures(e,t,r){r.length!==0&&(console.log(`\u{1F50F} Submitting ${r.length} signature${r.length===1?"":"s"} for version ${t}...`),await this.api.submitSignatures(e,t,r),console.log("\u2705 Signatures stored"))}listSignatures(e,t){return this.api.listSignatures(e,t)}async publishVersion(e,t){await this.api.updateVersions(e,[{version:t,update:{lifecycleState:{set:"PUBLISHED"}}}])}async publishAndActivate(e,t){console.log(`\u{1F680} Publishing and activating version ${t}...`),await this.api.updateVersions(e,[{version:t,update:{lifecycleState:{set:"PUBLISHED"},alias:{set:"ACTIVE"}}}]),console.log(`\u2705 Version ${t} is now PUBLISHED and ACTIVE`)}getActiveVersion(e){return this.api.getActiveVersion(e)}async deactivateVersion(e,t){await this.api.updateVersions(e,[{version:t,update:{alias:{setNull:!0}}}])}async deleteVersion(e,t){await this.api.deleteVersions(e,[t])}async deprecateVersion(e,t){await this.api.updateVersions(e,[{version:t,update:{lifecycleState:{set:"DEPRECATED"}}}])}async archiveVersion(e,t){await this.api.updateVersions(e,[{version:t,update:{lifecycleState:{set:"ARCHIVED"}}}])}async activateVersion(e,t){let r=null;try{r=await this.api.getActiveVersion(e)}catch{r=null}let i=r&&r.version!==t?r.version:void 0;return await this.api.updateVersions(e,[{version:t,update:{alias:{set:"ACTIVE"}}}]),{supersededVersion:i}}async deploy(e,t,r,i,o,a,p=!1){console.log(`
6
+ \u{1F680} Deploying application via App Hosting API...
7
+ `),await this.ensureApp(e,t,r),await this.uploadVersion(e,i,o,a),p&&await this.publishAndActivate(e,i),console.log(`
8
+ \u2705 Deployment successful!`)}};s(Y,"AppHostingClient");var b=Y;import{execFileSync as L}from"child_process";import y from"fs";import u from"path";import{parseAndValidateManifestConfig as Ye}from"@cognite/app-sdk/vite";import{BlobReader as Ke,Uint8ArrayWriter as We,ZipWriter as Xe}from"@zip.js/zip.js";import{execFileSync as Me}from"child_process";function je(n={}){let{execFileSync:e=Me}=n;try{return e("git",["--version"],{stdio:"ignore"}),!0}catch{return!1}}s(je,"isGitInstalled");function ge(n={}){if(!je(n))throw new l("Git is not installed or not found on PATH.",{hint:"Install Git (https://git-scm.com) and ensure it is on your PATH, then try again.",shouldReport:!1})}s(ge,"throwIfGitMissing");import Ge from"path";var _=".cognite-bundles";function fe(n,e){return`${n}-${e}.zip`}s(fe,"bundleFileName");function B(n,e,t){return Ge.join(n,_,fe(e,t))}s(B,"bundlePath");import{existsSync as qe,readFileSync as Je}from"fs";var x=[".dev.sig",".cert.sig"];function ze(n,e={}){let t=e.existsSync??qe,r=e.readFileSync??((o,a)=>Je(o,a)),i=[];for(let o of x){let a=`${n}${o}`;if(!t(a))continue;let p=r(a,"utf8").trim();p.length>0&&i.push(p)}return i}s(ze,"discoverSignatures");var K="package.json",W="package-lock.json",he="manifest.json",X=".cognite",Ze=[/^\.env(\..+)?$/i,/^\.secrets?$/i,/^\.token/i,/^\.cognite/i,/\.(key|pem|p12|pfx|jks|crt)$/i];function Qe(n){let[e,t,...r]=n.split("/");return e!==_||t===void 0||r.length>0?!1:t.endsWith(".zip")||x.some(i=>t.endsWith(`.zip${i}`))}s(Qe,"isBundleArtifact");var Z=class Z{constructor(e="dist"){this.distPath=u.isAbsolute(e)?e:u.join(process.cwd(),e),this.appRoot=u.dirname(this.distPath)}validateBuildDirectory(){if(!y.existsSync(this.distPath))throw new Error(`Build directory "${this.distPath}" not found. Run build first.`);let e=u.join(this.appRoot,K);if(!y.existsSync(e))throw new Error(`"${e}" not found. It is required for deployment.`);let t=u.join(this.appRoot,W);if(!y.existsSync(t))throw new Error(`"${t}" not found. It is required for deployment.`)}async createZip(e="app.zip",t=!1){this.validateBuildDirectory(),console.log("\u{1F4E6} Packaging application...");let r=new Xe(new We,{level:9}),i=s(async(c,d)=>{await r.add(d,new Ke(await y.openAsBlob(c))),t&&console.log(` \u{1F4C4} ${d}`)},"addFile"),o=s(async c=>{let d=await y.promises.readdir(c,{withFileTypes:!0});for(let S of d){let h=u.join(c,S.name);S.isDirectory()?await o(h):await i(h,u.relative(this.distPath,h).replace(/\\/g,"/"))}},"addDir"),a;try{await o(this.distPath);let c=u.join(this.appRoot,K);await i(c,u.posix.join(X,K));let d=u.join(this.appRoot,he);if(y.existsSync(d)){let h=y.readFileSync(d,"utf-8");Ye(h,d),await i(d,u.posix.join(X,he))}let S=u.join(this.appRoot,W);await i(S,u.posix.join(X,W)),a=await r.close()}catch(c){let d=c instanceof Error?c.message:String(c);throw new Error(`Failed to create zip: ${d}`)}try{await y.promises.writeFile(e,a)}catch(c){throw new l(`Failed to write bundle to ${e}`,{cause:c})}let p=(a.byteLength/1024/1024).toFixed(2);return console.log(`\u2705 App packaged: ${e} (${p} MB)`),e}async createSourceArchive(e){console.log("\u{1F4E6} Packaging source for review...");let t;try{t=L("git",["-C",this.appRoot,"rev-parse","--show-toplevel"],{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()}catch(c){throw ge(),new l("Source packaging requires a git repository.",{hint:"Run `git init` first.",shouldReport:!1,cause:c})}let r=L("git",["-C",this.appRoot,"rev-parse","--show-prefix"],{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim(),i=r?r.replace(/\/$/,""):".",o=i==="."?"HEAD":`HEAD:${i}`;this.validateNoSensitiveFiles(t,o);try{L("git",["-C",t,"archive","--format=zip",`--output=${e}`,o])}catch(c){let d=c instanceof Error?c.message:String(c);throw new Error(`Failed to create source archive: ${d}`)}let p=(y.statSync(e).size/1024/1024).toFixed(2);return console.log(`\u2705 Source packaged: ${u.basename(e)} (${p} MB)`),e}validateNoSensitiveFiles(e,t){let r=L("git",["-C",e,"ls-tree","-r","--name-only",t],{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim().split(`
9
+ `).filter(Boolean),i=s(a=>{let p=a.replace(/\\/g,"/");return!Qe(p)&&p.split("/").some(c=>Ze.some(d=>d.test(c)))},"isSensitive"),o=r.filter(i);if(o.length>0)throw new Error(`Source archive would include sensitive files \u2014 remove them from git tracking first:
10
+ `+o.map(a=>` ${a}`).join(`
11
+ `)+`
12
+ Hint: git rm --cached <file>`)}};s(Z,"ApplicationPackager");var R=Z;import{CogniteClient as ct}from"@cognite/sdk";function et(n){return Math.floor(Math.random()*Math.min(2**n*250,15e3))}s(et,"exponentialBackoffWithJitter");function tt(n){return new Promise(e=>setTimeout(e,n))}s(tt,"sleep");async function me(n,e={}){let t=e.maxAttempts??5,r=e.shouldRetry??(()=>!0),i=e.delayInMsCalculator??et;if(t<1)throw new Error("`maxAttempts` must be 1 or greater");if(t>100)throw new Error("`maxAttempts` must be 100 or less");let o=1;for(;;)try{return await n()}catch(a){if(o>=t||!r(a))throw a;let p=i(o);e.onAttemptFail?.(a,o,p),await tt(p),o++}}s(me,"retryAsync");var nt="https://auth.cognite.com/oauth2/token",rt=s(n=>typeof n=="object"&&n!==null&&"access_token"in n&&typeof n.access_token=="string","hasAccessToken");async function ye({idp:n,tokenUrl:e,init:t,missingTokenHint:r}){let i;try{i=await me(()=>fetch(e,t),{maxAttempts:3})}catch(p){throw new l(`Failed to fetch access token from ${e}`,{cause:p})}if(!i.ok){let p=await i.text();throw new k(`Failed to get token from ${n}: ${i.status} ${i.statusText}`,{httpStatusCode:i.status,requestUrl:e,responseBody:p})}let o=await i.text(),a;try{a=JSON.parse(o)}catch{throw new l(`Unexpected response from ${n} authentication (invalid JSON)`,{hint:r})}if(!rt(a))throw new l(`No access token in ${n} authentication response`,{hint:r});return E.from(a.access_token)}s(ye,"fetchOAuthToken");var it=s(n=>{let e=n.DEPLOYMENT_SECRETS;if(!e)return{};try{let t=JSON.parse(e),r={};for(let[i,o]of Object.entries(t))if(typeof o=="string"){let a=i.toLowerCase().replace(/_/g,"-");r[a]=o}return r}catch(t){return console.error("Error parsing DEPLOYMENT_SECRETS:",t),{}}},"loadSecretsFromEnv"),st=s((n,e)=>{let t;if(e.DEPLOYMENT_SECRET&&(t=e.DEPLOYMENT_SECRET),t||(t=it(e)[n]),t||(t=e[n]),!t)throw new l(`Set the ${n} environment variable (named by deploySecretName in app.json) to your deploy client secret, e.g. in a .env file.`,{shouldReport:!1,hint:"Alternatively, run `cognite auth login` to use your session, or pass --interactive for a one-off browser login."});return E.from(t)},"getSecretFromEnv"),ot=s((n,e)=>{let t=e.expose();return ye({idp:"CDF",tokenUrl:nt,init:{method:"POST",headers:{Authorization:`Basic ${btoa(`${n}:${t}`)}`,"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"client_credentials"})},missingTokenHint:"Check the client ID in app.json and the deployment secret in your environment."})},"getTokenCdf"),Se=s(({idp:n,tokenUrl:e,clientId:t,clientSecret:r,scopes:i,missingTokenHint:o})=>ye({idp:n,tokenUrl:e,init:{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({client_id:t,client_secret:r,grant_type:"client_credentials",...i!==void 0?{scope:i.join(" ")}:{}})},missingTokenHint:o}),"getTokenWithClientCredentials"),at=s((n,e)=>{if(e!==void 0)return e.join(" ");if(!n)throw new Error("Entra ID authentication requires 'baseUrl' to be set in deployment configuration");try{return`${new URL(n).origin}/.default`}catch{throw new Error(`Entra ID authentication requires 'baseUrl' to be a valid CDF URL (e.g., https://cluster.cognitedata.com), got: ${n}`)}},"resolveEntraScope"),pt=s((n,e,t,r,i)=>Se({idp:"Entra ID",tokenUrl:`https://login.microsoftonline.com/${t}/oauth2/v2.0/token`,clientId:n,clientSecret:e.expose(),scopes:i!==void 0?i:[at(r)],missingTokenHint:"Check the client ID and tenant ID in app.json and the deployment secret in your environment."}),"getTokenEntra"),Q=s(async(n,e=process.env)=>{if(e.COGNITE_TOKEN)return E.from(e.COGNITE_TOKEN);let{deployClientId:t,deploySecretName:r,idpType:i="cdf",tenantId:o,baseUrl:a,scopes:p,tokenUrl:c}=n,d=st(r,e);if(i==="oauth"){if(!c)throw new Error("OAuth authentication requires 'tokenUrl' in deployment configuration");return Se({idp:"OAuth",tokenUrl:c,clientId:t,clientSecret:d.expose(),scopes:p,missingTokenHint:"Check the tokenUrl, client ID, scopes, and deployment secret in app.json and your environment."})}if(i==="entra_id"){if(!o)throw new Error("Entra ID authentication requires 'tenantId' in deployment configuration");return pt(t,d,o,a,p)}return ot(t,d)},"getToken");async function H(n,e,t=process.env,r){let i=await Q(n,t),o=t.COGNITE_BASE_URL??n.baseUrl,a=(r??(p=>new ct(p)))({appId:e,project:n.project,baseUrl:o,oidcTokenProvider:s(async()=>i.expose(),"oidcTokenProvider")});return await a.authenticate(),a}s(H,"getSdk");async function Ee(n,e,{existsSync:t=dt,mkdir:r=lt,createZip:i=s((o,a)=>new R(o).createZip(a,!0),"createZipFn")}={}){let{externalId:o,versionTag:a}=n,p=B(e,o,a);if(t(p)){let d=x.some(S=>t(`${p}${S}`))?"A signed bundle already exists here. Re-deploying will invalidate the signing process. Bump versionTag in app.json to deploy as a new version, or delete the bundle and its .sig files then re-sign after deploying.":"Bump versionTag in app.json to deploy as a new version, or delete the existing bundle from .cognite-bundles/ to redeploy the same version.";throw new l(`Bundle already exists: ${p}`,{hint:d,shouldReport:!1})}await r(ft(p),{recursive:!0}),await i(`${e}/dist`,p)}s(Ee,"packageBundle");async function ee(n,e,t,r,{readFile:i=ut,upload:o=s(async(a,p)=>new b(n).deploy(e.externalId,e.name,e.description,e.versionTag,a,p,r),"uploadFn")}={}){let a=B(t,e.externalId,e.versionTag),p;try{p=await i(a)}catch(c){throw new l(`Failed to read bundle file: ${a}`,{cause:c})}await o(p,gt(a))}s(ee,"uploadBundle");var ht=s(async(n,e,t)=>{let r=await H(n,t);await Ee(e,t),await ee(r,e,t,n.published)},"deploy"),mt=s(async(n,e,t)=>{let r=await H(n,t);await ee(r,e,t,n.published)},"deployBundle");export{b as a,_ as b,fe as c,B as d,x as e,ze as f,R as g,Q as h,H as i,Ee as j,ee as k,ht as l,mt as m};