machina-cli 0.6.2__tar.gz → 0.6.3__tar.gz
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.
- {machina_cli-0.6.2 → machina_cli-0.6.3}/CHANGELOG.md +5 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/PKG-INFO +1 -1
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs/harness-loop-kit/README.md +21 -0
- machina_cli-0.6.3/docs/harness-loop-kit/nodes.py +202 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/pyproject.toml +1 -1
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/__init__.py +1 -1
- {machina_cli-0.6.2 → machina_cli-0.6.3}/.github/workflows/ci.yml +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/.github/workflows/release.yml +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/.gitignore +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/CLAUDE.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/README.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs/agentic-harness-loop.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs/credentials.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs/harness-loop-kit/PLAYBOOK-SCORECARD.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs/harness-loop-kit/VALIDATION.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs/harness-loop-kit/context-verify.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs/harness-loop-kit/provision.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs/harness-loop-kit/surface-verify.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs/loop-tools-connector.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/.gitignore +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/.vitepress/config.mts +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/.vitepress/theme/custom.css +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/.vitepress/theme/index.ts +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/README.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/agent.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/config.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/connect.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/connector.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/context-graph.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/credentials.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/deploy.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/document.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/execution.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/factory.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/login.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/loop.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/mapping.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/mcp.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/org.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/project.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/prompt.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/skills.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/sports.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/template.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/update.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/commands/workflow.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/guide/authentication.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/guide/configuration.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/guide/installation.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/guide/quickstart.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/guide/repl.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/guide/running.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/index.md +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/package-lock.json +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/package.json +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/public/favicon.ico +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/public/machina-logo-dark.png +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/public/machina-logo-light.png +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/docs-site/vercel.json +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/install.ps1 +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/install.sh +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/browser_auth.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/client.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/__init__.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/agent.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/auth.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/config_cmd.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/connect.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/connector.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/context_graph.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/credentials.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/deploy.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/document.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/execution.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/factory.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/loop.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/mapping.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/mcp.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/org.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/project.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/prompt.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/skills.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/sports.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/template.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/commands/workflow.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/config.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/factory_client.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/loop_client.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/main.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/models/__init__.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/project_client.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/repl.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/update_check.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/src/machina_cli/updater.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/tests/__init__.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/tests/test_cli_output.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/tests/test_connect.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/tests/test_context_graph_timeline.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/tests/test_mcp_url.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/tests/test_org_usage.py +0 -0
- {machina_cli-0.6.2 → machina_cli-0.6.3}/tests/test_sports_integration.py +0 -0
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to machina-cli are documented here.
|
|
4
4
|
|
|
5
|
+
## [0.6.3] - 2026-07-02
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **`machina-nodes` — a shared action-node library for pod workflows** (`docs/harness-loop-kit/nodes.py`). The Pressbox lesson applied to Machina's own engine: workflows are already data walked by an executor — what was missing was a registry of small, composable action nodes, so a new automation is graph wiring instead of another copy-pasted pyscript (the Slack notify logic had been written twice across the verify kits). Ships two nodes: `slack_notify` (posts a ready-composed text; webhook from the same `slack-notify-config` doc the verifies use) and `github_issue` (opens a GitHub issue; token+repo from a `github-issue-config` doc — **inert until configured**, so it deploys everywhere safely). Every node is best-effort (never raises), inert without config, and composed via task inputs. A `machina-nodes-demo` workflow ships as living documentation of the pattern.
|
|
9
|
+
|
|
5
10
|
## [0.6.2] - 2026-07-01
|
|
6
11
|
|
|
7
12
|
### Fixed
|
|
@@ -183,6 +183,27 @@ pelo LLM e persistido pra a montagem de contexto do cliente consumir. O agent
|
|
|
183
183
|
detect → heal → **resolve ids** → persist → repeat. *(Conservador: só links que resolvem a ids
|
|
184
184
|
reais são gravados — o resto fica como órfão.)*
|
|
185
185
|
|
|
186
|
+
## 6.1 `nodes.py` — biblioteca de nós compartilhados (padrão Pressbox)
|
|
187
|
+
|
|
188
|
+
Os workflows da Machina já são *dados* (tasks + conditions + `$.get()`), mas cada
|
|
189
|
+
automação nova vinha copiando código de ação (o notify do Slack foi escrito 2x nos
|
|
190
|
+
verifies). **`nodes.py`** provisiona o connector **`machina-nodes`** — um *registry*
|
|
191
|
+
de nós de ação pequenos e compostos no grafo, não no código:
|
|
192
|
+
|
|
193
|
+
| Nó | Faz | Config |
|
|
194
|
+
| --- | --- | --- |
|
|
195
|
+
| `slack_notify` | posta um texto **já composto** no webhook do pod | doc `slack-notify-config` (o mesmo dos verifies) |
|
|
196
|
+
| `github_issue` | abre issue no GitHub (title/body/labels) | doc `github-issue-config` `{token, repo}` — **inerte até existir** |
|
|
197
|
+
|
|
198
|
+
Regras de todo nó: **best-effort** (nunca lança — automação acessória não pode derrubar
|
|
199
|
+
o workflow que a carrega), **inerte sem config**, **composição via inputs da task**
|
|
200
|
+
(o workflow compõe; o nó só executa). O workflow `machina-nodes-demo` fica provisionado
|
|
201
|
+
como documentação viva do padrão.
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
CLIENT_API_URL=… API_TOKEN=… python3 docs/harness-loop-kit/nodes.py --run # provisiona + smoke no Slack
|
|
205
|
+
```
|
|
206
|
+
|
|
186
207
|
## 7. Pendências honestas (transparência)
|
|
187
208
|
|
|
188
209
|
1. **Redeploy do MCP** ([#287](https://github.com/machina-sports/machina-client-api/issues/287)):
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Machina Nodes — a shared, reusable node library for pod workflows.
|
|
4
|
+
|
|
5
|
+
The Pressbox lesson applied to Machina's own engine: workflows here are already
|
|
6
|
+
data (tasks + conditions + $.get() templating) walked by an executor — what was
|
|
7
|
+
missing is a REGISTRY of small, composable action nodes, so a new automation is
|
|
8
|
+
graph wiring instead of another copy-pasted pyscript. This kit provisions one
|
|
9
|
+
connector, `machina-nodes`, whose commands are those nodes:
|
|
10
|
+
|
|
11
|
+
slack_notify post a ready-composed text to the pod's Slack webhook.
|
|
12
|
+
Resolves the webhook from the `slack-notify-config` document
|
|
13
|
+
(same doc surface-verify/context-verify already use) or an
|
|
14
|
+
explicit input. No text / no webhook -> clean no-op.
|
|
15
|
+
github_issue open a GitHub issue (title/body/labels). Token + default repo
|
|
16
|
+
come from a `github-issue-config` document ({token, repo}) or
|
|
17
|
+
explicit inputs. INERT until that doc exists -- provisioning
|
|
18
|
+
this connector changes nothing until someone drops a token.
|
|
19
|
+
|
|
20
|
+
Design rules every node follows (and future nodes must too):
|
|
21
|
+
- best-effort: a node NEVER raises -- an automation nicety must never fail
|
|
22
|
+
the workflow that carries it. Failures return {..., "error": "..."}.
|
|
23
|
+
- inert by default: missing config -> {"skipped": "..."}, zero side effects.
|
|
24
|
+
- composition over configuration: nodes take READY inputs (text, title);
|
|
25
|
+
composing them is the calling workflow's job, in task inputs -- that keeps
|
|
26
|
+
each node small and every combination possible.
|
|
27
|
+
|
|
28
|
+
A `machina-nodes-demo` workflow is provisioned alongside as living
|
|
29
|
+
documentation of the pattern (one compose-in-inputs -> post task).
|
|
30
|
+
|
|
31
|
+
Usage:
|
|
32
|
+
CLIENT_API_URL="https://<org>-<project>.org.machina.gg" \\
|
|
33
|
+
API_TOKEN="<project X-Api-Token>" \\
|
|
34
|
+
python3 nodes.py # provision the connector + demo workflow
|
|
35
|
+
python3 nodes.py --run # provision + post one marked smoke message
|
|
36
|
+
python3 nodes.py --teardown # remove
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
import json
|
|
40
|
+
import os
|
|
41
|
+
import sys
|
|
42
|
+
|
|
43
|
+
import urllib.request
|
|
44
|
+
import urllib.error
|
|
45
|
+
|
|
46
|
+
BASE = os.environ.get("CLIENT_API_URL", "").rstrip("/")
|
|
47
|
+
TOKEN = os.environ.get("API_TOKEN", "")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _req(method, path, body=None):
|
|
51
|
+
url = f"{BASE}/{path.lstrip('/')}"
|
|
52
|
+
data = json.dumps(body).encode() if body is not None else None
|
|
53
|
+
req = urllib.request.Request(url, data=data, method=method,
|
|
54
|
+
headers={"X-Api-Token": TOKEN, "Content-Type": "application/json"})
|
|
55
|
+
try:
|
|
56
|
+
with urllib.request.urlopen(req, timeout=120) as r:
|
|
57
|
+
return json.loads(r.read() or "{}")
|
|
58
|
+
except urllib.error.HTTPError as e:
|
|
59
|
+
return {"status": False, "error": {"message": f"HTTP {e.code}: {e.read()[:200]}"}}
|
|
60
|
+
except Exception as e: # noqa: BLE001
|
|
61
|
+
return {"status": False, "error": {"message": str(e)}}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _delete_by_name(kind, name):
|
|
65
|
+
d = _req("GET", f"{kind}/{name}").get("data", {})
|
|
66
|
+
if isinstance(d, dict) and d.get("_id"):
|
|
67
|
+
_req("DELETE", f"{kind}/{d['_id']}")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _create(kind, body):
|
|
71
|
+
_delete_by_name(kind, body["name"])
|
|
72
|
+
res = _req("POST", kind, body)
|
|
73
|
+
ok = res.get("status") in (True, "success")
|
|
74
|
+
print(f" {'OK ' if ok else 'ERR'} {kind}/{body['name']}"
|
|
75
|
+
+ ("" if ok else f" -> {json.dumps(res.get('error'))[:120]}"))
|
|
76
|
+
return ok
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
NODES_SRC = r'''"""machina-nodes: small, composable action nodes for pod workflows."""
|
|
80
|
+
import json, urllib.request, urllib.error
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _config_doc(name):
|
|
84
|
+
"""Read a single config document's value by name; {} when absent/unreadable."""
|
|
85
|
+
try:
|
|
86
|
+
from core.document.controller import document_search
|
|
87
|
+
r = document_search(filters={"name": name}, page=1, page_size=1)
|
|
88
|
+
dd = r.get("data") if isinstance(r, dict) else None
|
|
89
|
+
rows = dd.get("data") if isinstance(dd, dict) else (dd if isinstance(dd, list) else [])
|
|
90
|
+
if rows:
|
|
91
|
+
return rows[0].get("value") or {}
|
|
92
|
+
except Exception:
|
|
93
|
+
pass
|
|
94
|
+
return {}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def slack_notify(request_data: dict) -> dict:
|
|
98
|
+
"""Post a ready-composed text to Slack. Webhook: explicit input, else the pod's
|
|
99
|
+
slack-notify-config document. No text / unresolved template / no webhook -> no-op.
|
|
100
|
+
Best-effort: never raises."""
|
|
101
|
+
p = request_data.get("params", {}) or request_data
|
|
102
|
+
text = (p.get("text") or "").strip()
|
|
103
|
+
if not text or text.startswith("$"):
|
|
104
|
+
return {"status": True, "data": {"notified": False, "skipped": "no text"}}
|
|
105
|
+
webhook = (p.get("webhook_url") or "").strip()
|
|
106
|
+
if not webhook or webhook.startswith("$"):
|
|
107
|
+
webhook = (_config_doc("slack-notify-config").get("webhook_url") or "").strip()
|
|
108
|
+
if not webhook:
|
|
109
|
+
return {"status": True, "data": {"notified": False, "skipped": "no webhook configured"}}
|
|
110
|
+
try:
|
|
111
|
+
req = urllib.request.Request(webhook, data=json.dumps({"text": text}).encode(),
|
|
112
|
+
method="POST", headers={"Content-Type": "application/json"})
|
|
113
|
+
with urllib.request.urlopen(req, timeout=15) as r:
|
|
114
|
+
r.read()
|
|
115
|
+
return {"status": True, "data": {"notified": True}}
|
|
116
|
+
except Exception as e:
|
|
117
|
+
return {"status": True, "data": {"notified": False, "error": str(e)[:150]}}
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def github_issue(request_data: dict) -> dict:
|
|
121
|
+
"""Open a GitHub issue. Token + default repo come from the github-issue-config
|
|
122
|
+
document ({token, repo}) or explicit inputs -- INERT until configured. Repo is
|
|
123
|
+
"owner/name". Best-effort: never raises."""
|
|
124
|
+
p = request_data.get("params", {}) or request_data
|
|
125
|
+
title = (p.get("title") or "").strip()
|
|
126
|
+
if not title or title.startswith("$"):
|
|
127
|
+
return {"status": True, "data": {"filed": False, "skipped": "no title"}}
|
|
128
|
+
token = (p.get("token") or "").strip()
|
|
129
|
+
repo = (p.get("repo") or "").strip()
|
|
130
|
+
if not token or not repo or repo.startswith("$"):
|
|
131
|
+
cfg = _config_doc("github-issue-config")
|
|
132
|
+
token = token if token and not token.startswith("$") else (cfg.get("token") or "").strip()
|
|
133
|
+
repo = repo if repo and not repo.startswith("$") else (cfg.get("repo") or "").strip()
|
|
134
|
+
if not token or not repo:
|
|
135
|
+
return {"status": True, "data": {"filed": False, "skipped": "not configured (github-issue-config)"}}
|
|
136
|
+
payload = {"title": title, "body": p.get("body") or ""}
|
|
137
|
+
labels = p.get("labels")
|
|
138
|
+
if isinstance(labels, list) and labels:
|
|
139
|
+
payload["labels"] = labels
|
|
140
|
+
try:
|
|
141
|
+
req = urllib.request.Request(
|
|
142
|
+
"https://api.github.com/repos/%s/issues" % repo,
|
|
143
|
+
data=json.dumps(payload).encode(), method="POST",
|
|
144
|
+
headers={"Authorization": "Bearer " + token,
|
|
145
|
+
"Accept": "application/vnd.github+json",
|
|
146
|
+
# GitHub's API rejects requests without a User-Agent.
|
|
147
|
+
"User-Agent": "machina-nodes",
|
|
148
|
+
"Content-Type": "application/json"})
|
|
149
|
+
with urllib.request.urlopen(req, timeout=20) as r:
|
|
150
|
+
d = json.loads(r.read() or "{}")
|
|
151
|
+
return {"status": True, "data": {"filed": True, "issue_url": d.get("html_url"),
|
|
152
|
+
"number": d.get("number")}}
|
|
153
|
+
except Exception as e:
|
|
154
|
+
return {"status": True, "data": {"filed": False, "error": str(e)[:150]}}
|
|
155
|
+
'''
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def definitions():
|
|
159
|
+
connector = {"name": "machina-nodes", "title": "Machina Nodes", "status": "active",
|
|
160
|
+
"description": "shared action-node registry (slack_notify, github_issue) for workflow composition",
|
|
161
|
+
"filename": "machina_nodes.py", "filetype": "pyscript", "filecontent": NODES_SRC,
|
|
162
|
+
"commands": [{"name": "SlackNotify", "value": "slack_notify"},
|
|
163
|
+
{"name": "GithubIssue", "value": "github_issue"}]}
|
|
164
|
+
# Living documentation of the composition pattern: the workflow composes the
|
|
165
|
+
# message in task INPUTS; the node just posts it. Any workflow can copy this task.
|
|
166
|
+
demo = {"name": "machina-nodes-demo", "title": "Machina Nodes Demo", "status": "active",
|
|
167
|
+
"description": "composition demo: compose in inputs -> slack_notify node",
|
|
168
|
+
"context-variables": {"debugger": {"enabled": True}},
|
|
169
|
+
"inputs": {"text": "$.get('text', '')"},
|
|
170
|
+
"outputs": {"notified": "$.get('nd_out', {})", "workflow-status": "'executed'"},
|
|
171
|
+
"tasks": [
|
|
172
|
+
{"name": "post", "type": "connector",
|
|
173
|
+
"connector": {"command": "slack_notify", "name": "machina-nodes"},
|
|
174
|
+
"inputs": {"text": "$.get('text', '')"},
|
|
175
|
+
"outputs": {"nd_out": "$"}},
|
|
176
|
+
]}
|
|
177
|
+
return [("connector", connector), ("workflow", demo)]
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def main():
|
|
181
|
+
if not BASE or not TOKEN:
|
|
182
|
+
sys.exit("Set CLIENT_API_URL and API_TOKEN environment variables.")
|
|
183
|
+
defs = definitions()
|
|
184
|
+
if "--teardown" in sys.argv:
|
|
185
|
+
print(f"Tearing down machina-nodes on {BASE} ...")
|
|
186
|
+
for kind, body in reversed(defs):
|
|
187
|
+
_delete_by_name(kind, body["name"])
|
|
188
|
+
print(f" removed {kind}/{body['name']}")
|
|
189
|
+
return
|
|
190
|
+
print(f"Provisioning machina-nodes on {BASE} ...")
|
|
191
|
+
ok = all(_create(kind, body) for kind, body in defs)
|
|
192
|
+
print("Done." if ok else "Done with errors — check output above.")
|
|
193
|
+
if "--run" in sys.argv:
|
|
194
|
+
print("\nSmoke: posting one marked message via the demo workflow ...")
|
|
195
|
+
r = _req("POST", "workflow/execute/machina-nodes-demo",
|
|
196
|
+
{"text": ":test_tube: machina-nodes — shared node library is live in this pod "
|
|
197
|
+
"(slack_notify + github_issue registered)."})
|
|
198
|
+
print(" execute status:", r.get("status"), "| error:", r.get("error"))
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
if __name__ == "__main__":
|
|
202
|
+
main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|