applied-cli 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,432 @@
1
+ import json
2
+ import re
3
+ import uuid
4
+ from pathlib import Path
5
+ from typing import Any, Optional
6
+
7
+ from applied_cli.commands._normalize import (
8
+ AGENT_TYPE_ALIASES,
9
+ MODALITY_ALIASES,
10
+ RESPONSE_TYPE_ALIASES,
11
+ )
12
+ from applied_cli.http import (
13
+ APIError,
14
+ create_agent,
15
+ create_response,
16
+ list_responses,
17
+ patch_response,
18
+ update_agent,
19
+ )
20
+ from applied_cli.runtime import resolve_runtime as _resolve_runtime
21
+
22
+ ALLOWED_RESPONSE_TYPES = {"escalation", "exact", "qa", "context"}
23
+ ALLOWED_CHANNELS = {"chat", "email", "sms"}
24
+
25
+
26
+ def _spec_error(path: str, message: str) -> None:
27
+ raise ValueError(f"spec.{path}: {message}")
28
+
29
+
30
+ def _validate_string(value: Any, *, path: str, required: bool = False) -> str:
31
+ if value is None:
32
+ if required:
33
+ _spec_error(path, "is required")
34
+ return ""
35
+ if not isinstance(value, str):
36
+ _spec_error(path, "must be a string")
37
+ normalized = value.strip()
38
+ if required and not normalized:
39
+ _spec_error(path, "cannot be empty")
40
+ return normalized
41
+
42
+
43
+ def _validate_string_list(value: Any, *, path: str) -> list[str]:
44
+ if value is None:
45
+ return []
46
+ if not isinstance(value, list):
47
+ _spec_error(path, "must be an array of strings")
48
+ out: list[str] = []
49
+ for idx, item in enumerate(value):
50
+ if not isinstance(item, str):
51
+ _spec_error(f"{path}[{idx}]", "must be a string")
52
+ normalized = item.strip()
53
+ if not normalized:
54
+ _spec_error(f"{path}[{idx}]", "cannot be empty")
55
+ out.append(normalized)
56
+ return out
57
+
58
+
59
+ def _validate_bool(value: Any, *, path: str, default: bool) -> bool:
60
+ if value is None:
61
+ return default
62
+ if not isinstance(value, bool):
63
+ _spec_error(path, "must be a boolean")
64
+ return value
65
+
66
+
67
+ def _validate_dict(value: Any, *, path: str) -> dict[str, Any]:
68
+ if value is None:
69
+ return {}
70
+ if not isinstance(value, dict):
71
+ _spec_error(path, "must be an object")
72
+ return value
73
+
74
+
75
+ def _normalize_question(text: str) -> str:
76
+ return re.sub(r"\s+", " ", text.strip().lower())
77
+
78
+
79
+ def load_and_validate_spec(spec_path: str) -> dict[str, Any]:
80
+ try:
81
+ raw_text = Path(spec_path).read_text(encoding="utf-8")
82
+ except OSError as exc:
83
+ raise ValueError(f"spec: unable to read file ({exc})") from exc
84
+ try:
85
+ payload = json.loads(raw_text)
86
+ except json.JSONDecodeError as exc:
87
+ raise ValueError(f"spec: invalid JSON ({exc})") from exc
88
+ if not isinstance(payload, dict):
89
+ _spec_error("", "root must be an object")
90
+
91
+ agent_raw = payload.get("agent")
92
+ if not isinstance(agent_raw, dict):
93
+ _spec_error("agent", "is required and must be an object")
94
+
95
+ agent: dict[str, Any] = {
96
+ "name": _validate_string(agent_raw.get("name"), path="agent.name", required=True),
97
+ "modality": _validate_string(
98
+ agent_raw.get("modality"), path="agent.modality", required=True
99
+ ),
100
+ }
101
+ modality_key = agent["modality"].strip().lower()
102
+ if modality_key not in MODALITY_ALIASES:
103
+ _spec_error(
104
+ "agent.modality",
105
+ "must be one of: all, call, sms, email, chat, internal",
106
+ )
107
+ agent["modality"] = MODALITY_ALIASES[modality_key]
108
+ for field in (
109
+ "description",
110
+ "model",
111
+ "type",
112
+ "email",
113
+ "phone",
114
+ "escalation_mode",
115
+ "escalation_wait_time_mode",
116
+ "prompt",
117
+ "guardrail",
118
+ ):
119
+ if field in agent_raw and agent_raw.get(field) is not None:
120
+ agent[field] = _validate_string(
121
+ agent_raw.get(field), path=f"agent.{field}", required=False
122
+ )
123
+ if "type" in agent:
124
+ normalized_type_key = agent["type"].strip().lower()
125
+ if normalized_type_key not in AGENT_TYPE_ALIASES:
126
+ _spec_error(
127
+ "agent.type",
128
+ "must be one of: generic, customer_support, conversion, sales, marketing, engineering, product",
129
+ )
130
+ agent["type"] = AGENT_TYPE_ALIASES[normalized_type_key]
131
+ if "metadata" in agent_raw:
132
+ agent["metadata"] = _validate_dict(agent_raw.get("metadata"), path="agent.metadata")
133
+ if "suggestions" in agent_raw:
134
+ agent["suggestions"] = _validate_string_list(
135
+ agent_raw.get("suggestions"), path="agent.suggestions"
136
+ )
137
+ if "personality" in agent_raw:
138
+ agent["personality"] = _validate_string_list(
139
+ agent_raw.get("personality"), path="agent.personality"
140
+ )
141
+ for bool_field in ("auto_reply", "use_guardrails"):
142
+ if bool_field in agent_raw:
143
+ agent[bool_field] = _validate_bool(
144
+ agent_raw.get(bool_field), path=f"agent.{bool_field}", default=False
145
+ )
146
+ if "response_delay_in_seconds" in agent_raw:
147
+ delay = agent_raw.get("response_delay_in_seconds")
148
+ if not isinstance(delay, int) or delay < 0:
149
+ _spec_error("agent.response_delay_in_seconds", "must be a non-negative integer")
150
+ agent["response_delay_in_seconds"] = delay
151
+
152
+ responses_raw = payload.get("responses", [])
153
+ if responses_raw is None:
154
+ responses_raw = []
155
+ if not isinstance(responses_raw, list):
156
+ _spec_error("responses", "must be an array")
157
+ responses: list[dict[str, Any]] = []
158
+ for idx, response in enumerate(responses_raw):
159
+ if not isinstance(response, dict):
160
+ _spec_error(f"responses[{idx}]", "must be an object")
161
+ response_type = _validate_string(
162
+ response.get("type"), path=f"responses[{idx}].type", required=True
163
+ ).lower()
164
+ if response_type not in ALLOWED_RESPONSE_TYPES:
165
+ _spec_error(
166
+ f"responses[{idx}].type",
167
+ f"must be one of: {', '.join(sorted(ALLOWED_RESPONSE_TYPES))}",
168
+ )
169
+ question = _validate_string(
170
+ response.get("question"), path=f"responses[{idx}].question", required=True
171
+ )
172
+ answer = _validate_string(
173
+ response.get("answer"), path=f"responses[{idx}].answer", required=True
174
+ )
175
+ entry: dict[str, Any] = {
176
+ "type": RESPONSE_TYPE_ALIASES[response_type],
177
+ "question": question,
178
+ "answer": answer,
179
+ "active": _validate_bool(
180
+ response.get("active"), path=f"responses[{idx}].active", default=True
181
+ ),
182
+ }
183
+ if "guardrail" in response:
184
+ entry["guardrail"] = _validate_string(
185
+ response.get("guardrail"), path=f"responses[{idx}].guardrail"
186
+ )
187
+ if "fields_to_extract" in response:
188
+ fields = response.get("fields_to_extract")
189
+ if not isinstance(fields, list):
190
+ _spec_error(f"responses[{idx}].fields_to_extract", "must be an array")
191
+ entry["fields_to_extract"] = fields
192
+ responses.append(entry)
193
+
194
+ tests_raw = payload.get("tests", [])
195
+ if tests_raw is None:
196
+ tests_raw = []
197
+ if not isinstance(tests_raw, list):
198
+ _spec_error("tests", "must be an array")
199
+ tests: list[dict[str, Any]] = []
200
+ for idx, test in enumerate(tests_raw):
201
+ if not isinstance(test, dict):
202
+ _spec_error(f"tests[{idx}]", "must be an object")
203
+ channel = _validate_string(
204
+ test.get("channel"), path=f"tests[{idx}].channel", required=True
205
+ ).lower()
206
+ if channel not in ALLOWED_CHANNELS:
207
+ _spec_error(
208
+ f"tests[{idx}].channel",
209
+ f"must be one of: {', '.join(sorted(ALLOWED_CHANNELS))}",
210
+ )
211
+ turns = _validate_string_list(test.get("turns"), path=f"tests[{idx}].turns")
212
+ if not turns:
213
+ _spec_error(f"tests[{idx}].turns", "must include at least one message")
214
+ test_entry: dict[str, Any] = {
215
+ "name": _validate_string(
216
+ test.get("name"), path=f"tests[{idx}].name", required=False
217
+ )
218
+ or f"test-{idx + 1}",
219
+ "channel": channel,
220
+ "turns": turns,
221
+ "include_references": _validate_bool(
222
+ test.get("include_references"),
223
+ path=f"tests[{idx}].include_references",
224
+ default=True,
225
+ ),
226
+ "auto_rate": _validate_bool(
227
+ test.get("auto_rate"), path=f"tests[{idx}].auto_rate", default=True
228
+ ),
229
+ }
230
+ for text_field in ("pass_status", "feedback", "reference_notes"):
231
+ if text_field in test and test.get(text_field) is not None:
232
+ test_entry[text_field] = _validate_string(
233
+ test.get(text_field), path=f"tests[{idx}].{text_field}"
234
+ )
235
+ for float_field in ("csat_score", "reference_score"):
236
+ if float_field in test and test.get(float_field) is not None:
237
+ value = test.get(float_field)
238
+ if not isinstance(value, (int, float)):
239
+ _spec_error(f"tests[{idx}].{float_field}", "must be a number")
240
+ test_entry[float_field] = float(value)
241
+ tests.append(test_entry)
242
+
243
+ benchmark_name = _validate_string(
244
+ payload.get("benchmark_name"), path="benchmark_name", required=False
245
+ )
246
+ return {
247
+ "agent": agent,
248
+ "responses": responses,
249
+ "tests": tests,
250
+ "benchmark_name": benchmark_name or "CLI Self-Rated Conversations",
251
+ }
252
+
253
+
254
+ def resolve_runtime(
255
+ *,
256
+ base_url: Optional[str],
257
+ shop_id: Optional[str],
258
+ api_token: Optional[str],
259
+ ) -> tuple[str, str, str]:
260
+ # Compatibility wrapper; prefer importing from applied_cli.runtime directly.
261
+ return _resolve_runtime(base_url=base_url, shop_id=shop_id, api_token=api_token)
262
+
263
+
264
+ def build_agent_payload(spec: dict[str, Any]) -> dict[str, Any]:
265
+ agent = dict(spec["agent"])
266
+ payload: dict[str, Any] = {
267
+ "name": agent["name"],
268
+ "modality": agent["modality"],
269
+ }
270
+ for key in (
271
+ "description",
272
+ "model",
273
+ "type",
274
+ "email",
275
+ "phone",
276
+ "metadata",
277
+ "suggestions",
278
+ "personality",
279
+ "auto_reply",
280
+ "use_guardrails",
281
+ "escalation_mode",
282
+ "escalation_wait_time_mode",
283
+ "response_delay_in_seconds",
284
+ "prompt",
285
+ "guardrail",
286
+ ):
287
+ if key in agent:
288
+ payload[key] = agent[key]
289
+ return payload
290
+
291
+
292
+ def _agent_attached(response_row: dict[str, Any], *, agent_id: str) -> bool:
293
+ agents = response_row.get("agents")
294
+ if not isinstance(agents, list):
295
+ return False
296
+ for item in agents:
297
+ if isinstance(item, dict) and str(item.get("id")) == agent_id:
298
+ return True
299
+ return False
300
+
301
+
302
+ def _response_payload(spec_response: dict[str, Any], *, agent_id: str) -> dict[str, Any]:
303
+ payload: dict[str, Any] = {
304
+ "type": spec_response["type"],
305
+ "question": spec_response["question"],
306
+ "answer": spec_response["answer"],
307
+ "active": bool(spec_response.get("active", True)),
308
+ "agent_ids": [agent_id],
309
+ }
310
+ if spec_response.get("guardrail"):
311
+ payload["guardrail"] = spec_response["guardrail"]
312
+ if "fields_to_extract" in spec_response:
313
+ payload["fields_to_extract"] = spec_response["fields_to_extract"]
314
+ return payload
315
+
316
+
317
+ def upsert_spec_responses(
318
+ *,
319
+ base_url: str,
320
+ shop_id: str,
321
+ api_token: str,
322
+ agent_id: str,
323
+ responses: list[dict[str, Any]],
324
+ dry_run: bool = False,
325
+ ) -> dict[str, Any]:
326
+ if dry_run:
327
+ try:
328
+ uuid.UUID(agent_id)
329
+ except ValueError:
330
+ return {
331
+ "created_ids": [],
332
+ "updated_ids": [],
333
+ "created_count": len(responses),
334
+ "updated_count": 0,
335
+ }
336
+
337
+ existing = list_responses(
338
+ base_url=base_url,
339
+ shop_id=shop_id,
340
+ api_token=api_token,
341
+ agent_id=agent_id,
342
+ limit=500,
343
+ )
344
+ existing_by_key: dict[tuple[str, str], dict[str, Any]] = {}
345
+ for row in existing:
346
+ if not _agent_attached(row, agent_id=agent_id):
347
+ continue
348
+ response_type = str(row.get("type") or "").strip().lower()
349
+ question = _normalize_question(str(row.get("question") or ""))
350
+ if response_type and question:
351
+ existing_by_key[(response_type, question)] = row
352
+
353
+ created: list[str] = []
354
+ updated: list[str] = []
355
+ planned_create = 0
356
+ planned_update = 0
357
+ for spec_response in responses:
358
+ key = (
359
+ spec_response["type"],
360
+ _normalize_question(spec_response["question"]),
361
+ )
362
+ payload = _response_payload(spec_response, agent_id=agent_id)
363
+ matched = existing_by_key.get(key)
364
+ if matched:
365
+ if dry_run:
366
+ planned_update += 1
367
+ continue
368
+ updated_row = patch_response(
369
+ base_url=base_url,
370
+ shop_id=shop_id,
371
+ api_token=api_token,
372
+ response_id=str(matched.get("id")),
373
+ payload=payload,
374
+ )
375
+ updated.append(str(updated_row.get("id")))
376
+ else:
377
+ if dry_run:
378
+ planned_create += 1
379
+ continue
380
+ created_row = create_response(
381
+ base_url=base_url,
382
+ shop_id=shop_id,
383
+ api_token=api_token,
384
+ payload=payload,
385
+ )
386
+ created.append(str(created_row.get("id")))
387
+ return {
388
+ "created_ids": created,
389
+ "updated_ids": updated,
390
+ "created_count": len(created) if not dry_run else planned_create,
391
+ "updated_count": len(updated) if not dry_run else planned_update,
392
+ }
393
+
394
+
395
+ def create_agent_from_spec(
396
+ *,
397
+ base_url: str,
398
+ shop_id: str,
399
+ api_token: str,
400
+ spec: dict[str, Any],
401
+ dry_run: bool = False,
402
+ ) -> dict[str, Any]:
403
+ payload = build_agent_payload(spec)
404
+ if dry_run:
405
+ return {"id": "dry-run", "payload": payload}
406
+ return create_agent(
407
+ base_url=base_url,
408
+ shop_id=shop_id,
409
+ api_token=api_token,
410
+ payload=payload,
411
+ )
412
+
413
+
414
+ def apply_agent_settings_from_spec(
415
+ *,
416
+ base_url: str,
417
+ shop_id: str,
418
+ api_token: str,
419
+ agent_id: str,
420
+ spec: dict[str, Any],
421
+ dry_run: bool = False,
422
+ ) -> dict[str, Any]:
423
+ payload = build_agent_payload(spec)
424
+ if dry_run:
425
+ return {"id": agent_id, "payload": payload}
426
+ return update_agent(
427
+ base_url=base_url,
428
+ shop_id=shop_id,
429
+ api_token=api_token,
430
+ agent_id=agent_id,
431
+ payload=payload,
432
+ )
@@ -0,0 +1,176 @@
1
+ Metadata-Version: 2.4
2
+ Name: applied-cli
3
+ Version: 0.1.0
4
+ Summary: CLI and MCP server for Applied Labs AI support agents
5
+ Author: Applied Labs
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/appliedlabs/applied-cli
8
+ Project-URL: Repository, https://github.com/appliedlabs/applied-cli
9
+ Keywords: applied-labs,ai-agents,support,mcp,claude
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Requires-Python: >=3.11
15
+ Description-Content-Type: text/markdown
16
+ Requires-Dist: httpx>=0.28.1
17
+ Requires-Dist: keyring>=25.6.0
18
+ Requires-Dist: pyyaml>=6.0
19
+ Requires-Dist: typer>=0.16.0
20
+ Provides-Extra: mcp
21
+ Requires-Dist: mcp>=1.2.0; extra == "mcp"
22
+
23
+ # Applied Labs CLI
24
+
25
+ CLI and Claude Code plugin for managing Applied Labs AI support agents.
26
+
27
+ ## Installation
28
+
29
+ ### As a Claude Code Plugin
30
+
31
+ ```bash
32
+ # From a marketplace (once published)
33
+ /plugin install applied-labs@marketplace-name
34
+
35
+ # Or test locally
36
+ claude --plugin-dir /path/to/applied-cli
37
+ ```
38
+
39
+ ### As a standalone CLI
40
+
41
+ ```bash
42
+ pip install applied-cli
43
+
44
+ # Or with MCP server support
45
+ pip install "applied-cli[mcp]"
46
+ ```
47
+
48
+ ## Authentication
49
+
50
+ ```bash
51
+ applied-cli auth login # Opens browser for approval
52
+ applied-cli auth status # Check current shop
53
+ applied-cli auth shops # List available shops
54
+ applied-cli auth use-shop NAME # Switch shops
55
+ ```
56
+
57
+ ## Quick Start
58
+
59
+ ### 1. Set up a new shop
60
+
61
+ ```bash
62
+ # Generate spec template
63
+ applied-cli shop template > my-shop.yaml
64
+
65
+ # Edit the spec with your configuration...
66
+
67
+ # Run setup
68
+ applied-cli shop setup --spec my-shop.yaml --json
69
+ ```
70
+
71
+ ### 2. Test your agent
72
+
73
+ ```bash
74
+ applied-cli chat --agent-id <uuid> --message "Hello"
75
+ ```
76
+
77
+ ### 3. Fix failing scenarios
78
+
79
+ ```bash
80
+ # Get context for failures
81
+ applied-cli test fix context --benchmark-id <uuid> --json
82
+
83
+ # Update knowledge base
84
+ applied-cli knowledge upsert --agent-id <uuid> --type qa \
85
+ --question "What is your return policy?" \
86
+ --answer "30 day returns on all items."
87
+
88
+ # Batch test fixes
89
+ applied-cli test fix batch --source <failing-benchmark> --target <validation-benchmark>
90
+
91
+ # Check progress
92
+ applied-cli test fix status --source <source> --target <target>
93
+ ```
94
+
95
+ ## Command Reference
96
+
97
+ ```
98
+ applied-cli
99
+ ├── auth # Login, logout, switch shops
100
+ ├── shop # Bootstrap new shops from YAML spec
101
+ ├── agent # List, create, update agents
102
+ ├── chat # Send a message to an agent
103
+ ├── conversations # List, show, import conversations
104
+ ├── insights # Generate analytics reports
105
+ ├── knowledge # Q&A entries, escalation rules
106
+ ├── taxonomy # Topic/intent classification
107
+ ├── test # Testing workflows
108
+ │ ├── benchmarks # Scenario collections
109
+ │ ├── scenarios # Individual test cases (includes rate)
110
+ │ ├── runs # Execution records
111
+ │ ├── coverage # Coverage summaries
112
+ │ └── fix # Fix failing scenarios
113
+ └── simulate # Generate test conversations
114
+ ```
115
+
116
+ ## MCP Server
117
+
118
+ The CLI includes an MCP server for Claude integrations:
119
+
120
+ ```bash
121
+ # Run directly (after pip install)
122
+ applied-cli-mcp
123
+
124
+ # Or via uvx (after publishing to PyPI)
125
+ uvx --from "applied-cli[mcp]" applied-cli-mcp
126
+ ```
127
+
128
+ ### Claude Desktop Configuration
129
+
130
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
131
+
132
+ ```json
133
+ {
134
+ "mcpServers": {
135
+ "applied-labs": {
136
+ "command": "applied-cli-mcp"
137
+ }
138
+ }
139
+ }
140
+ ```
141
+
142
+ ## Plugin Skills
143
+
144
+ When installed as a Claude Code plugin, these skills are available:
145
+
146
+ - `/applied-labs:setup-shop` - Guided shop setup workflow
147
+ - `/applied-labs:fix-scenarios` - Fix failing test scenarios
148
+
149
+ ## Environment Variables
150
+
151
+ | Variable | Description |
152
+ |----------|-------------|
153
+ | `APPLIED_ENDPOINT` | `prod`, `dev`, `local`, or full URL |
154
+ | `APPLIED_SHOP_ID` | Pre-select shop UUID |
155
+ | `APPLIED_API_TOKEN` | Skip browser auth |
156
+ | `APPLIED_PROFILE` | Named credential profile |
157
+
158
+ ## Development
159
+
160
+ ```bash
161
+ # Install in development mode
162
+ pip install -e ".[mcp]"
163
+
164
+ # Test CLI
165
+ applied-cli --help
166
+
167
+ # Test MCP server
168
+ applied-cli-mcp
169
+
170
+ # Test as Claude Code plugin
171
+ claude --plugin-dir .
172
+ ```
173
+
174
+ ## License
175
+
176
+ MIT
@@ -0,0 +1,34 @@
1
+ applied_cli/__init__.py,sha256=dKRQ2wgw2GHlPoGnG0-iQ0JFj5dFj_6fKIpH3xcAcC4,28
2
+ applied_cli/auth_store.py,sha256=g8lsP_Vw5cERhc8WewQHVOhkNBzCmG_EmDlCLRt5Qbc,7191
3
+ applied_cli/config.py,sha256=OHcJwhujSZe8TecyIoNu9JZnYm_ydVgEiGKRXZPuZo0,1430
4
+ applied_cli/error_reporting.py,sha256=9e9VCjT-HQUiuATPEFiBXwVqT5ze_yOOp33PHbXP6aA,1227
5
+ applied_cli/http.py,sha256=X-uh7IGVHqINpG0sjE_moNm0CLQil7zETOYR_2pVI2A,45369
6
+ applied_cli/main.py,sha256=Mo9rBNWAIMivZrU46_kpi-W2aFLYrZy2qZUZ0ElmJsw,5527
7
+ applied_cli/mcp_server.py,sha256=D09xjnAt0Bg3kn-Ghc8bhtPD_GyDl66SNoZUGKp4U3s,20955
8
+ applied_cli/runtime.py,sha256=lL9q1EO4bOR9XKbGM5WX9esTaaLIHA3pcbmcdvxTw6I,1725
9
+ applied_cli/shop_spec.py,sha256=ROwW1sWpqf3pMWWxa6BQjpwPTxV7esGk9FBXs5u8qh8,15500
10
+ applied_cli/spec_workflow.py,sha256=fBkC6NBjcu-SA0zESQBwjnFlea7q349rPBJi6_NlLaE,14523
11
+ applied_cli/commands/__init__.py,sha256=8UhFLtjsbXglNTf90b5gflyijI2j6b7CtUEcgo753Wo,27
12
+ applied_cli/commands/_hints.py,sha256=FXTeP7aBTFwzr4n6FqccZV9EJ6K9BzhVdJN89xCQOb4,410
13
+ applied_cli/commands/_normalize.py,sha256=SXeLN_EYy0MnawYQ88IPihfYMHKcd77nkGYy1mZ5RmY,2113
14
+ applied_cli/commands/_parsers.py,sha256=98njCaisw82Dfkl-Fi3FJej3gJR48UPtuXH16W7bDAY,1831
15
+ applied_cli/commands/_ui.py,sha256=OROXC4vN0pVn3hcdUEuBJ3Y1Eobou0aEQ0kzZ3c3p78,863
16
+ applied_cli/commands/agent.py,sha256=ky_7m-Denj_XHnP2E0n0zWXpWt_xNHGw24M3K9Xj2TU,47904
17
+ applied_cli/commands/auth.py,sha256=DpnFrz2M6uTUDodpsP96TwcNW_B4DkXC2oIb4j21Quw,29014
18
+ applied_cli/commands/chat.py,sha256=QWPWMBnVY0GdLBYXVzwrcC1uCP1M6xvr_GOamlH2Gac,12865
19
+ applied_cli/commands/coverage.py,sha256=5yjOkF2OevHD6Ti193umSDMD-cCVbFHnp93oHo6xi0Q,12242
20
+ applied_cli/commands/discover.py,sha256=R5ob-GdS9vtYMO1vpFCgDzwNtoGBaKRhjMmmghvU28c,38702
21
+ applied_cli/commands/fix.py,sha256=2UWB8nm3cbAgORzrZnSNUN91rWob4voqre3wEtGpJbs,44032
22
+ applied_cli/commands/insights.py,sha256=09x2_bRLc-58gJ9RjE3qS6mlEjswgLeIsJsro4cPkBg,19943
23
+ applied_cli/commands/intents.py,sha256=OEwGBj-HdbBWdy2IZYV1f9VbnuKHVJ3--g2K3gBd7pc,14781
24
+ applied_cli/commands/rate.py,sha256=N3tlIpUSOi-w7JRTN4pjYt0IWLDx1uNRtYrJYUIZGdo,17543
25
+ applied_cli/commands/responses.py,sha256=a8c4zFpJyBQlW9NLkR8_YSK01AtYx8edwY_HnQ3YCNI,24380
26
+ applied_cli/commands/shop.py,sha256=K7D_xNzKVHf10Yn6B0XnJ6nyuVoMqb5L590pTr96vkA,65276
27
+ applied_cli/commands/simulate.py,sha256=77IEh30im_Ou4KEcI6TBi0q0ve5oGTGd8nouLPfyOMU,12115
28
+ applied_cli/commands/spec.py,sha256=dv1R392wPxIKs6G-8rmblmkcDOxmVtt0EujFttkE4LM,8504
29
+ applied_cli/presets/demo.yaml,sha256=kDCktFFFY2FK2QAaLIf-nc6-HIsqpRs3jx_0K6KQSaU,7313
30
+ applied_cli-0.1.0.dist-info/METADATA,sha256=jOOh6bMuBaGUfCcRt5cA9mIdrTRLll630T3qj-brqpE,4266
31
+ applied_cli-0.1.0.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
32
+ applied_cli-0.1.0.dist-info/entry_points.txt,sha256=D7ckvwRElXVNC-C-YDQW-Kt-06RWoJjj0MtcieH9ZpY,99
33
+ applied_cli-0.1.0.dist-info/top_level.txt,sha256=FqgB1tOiax6kgE0hvzkIeXiRZL_R8fPojvdX_Old_zk,12
34
+ applied_cli-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ applied-cli = applied_cli.main:app
3
+ applied-cli-mcp = applied_cli.mcp_server:main
@@ -0,0 +1 @@
1
+ applied_cli