simplefe

Log | Files | Refs

commit 711c3f2365611c33374430fd49a3efa62b299e73
parent ac40eef32632dbd71c44d2f9b81b49301d274309
Author: Chris Roberts <chris.roberts@learningunix.net>
Date:   Thu, 16 Jul 2026 19:15:01 -0500

Add POST /jobs/<name>/run for the override path

Wires run_job() into the app: looks up the job (reusing the
same 404 behavior as the GET route), then spawns it via
pexpect using the job's prompt pattern and a response supplied
in the request body. Response text is per-request data, not
config, since it's inherently different every call (e.g. rip's
movie name) - see jobs.toml.example for the prompt field shape.

Does not yet handle the "no response, let the script's own
60s timeout apply" case, or rip's second (duplicate-rip)
prompt - both deliberately deferred as separate next steps.

Diffstat:
Mjobs.toml.example | 1+
Msrc/simplefe/app.py | 14+++++++++++++-
Mtests/test_app.py | 26++++++++++++++++++++++++++
3 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/jobs.toml.example b/jobs.toml.example @@ -1,2 +1,3 @@ [jobs.example] path = "/path/to/your/script" +prompt = "Enter something:" diff --git a/src/simplefe/app.py b/src/simplefe/app.py @@ -1,7 +1,9 @@ -from flask import Flask, abort +from flask import Flask, abort, request from simplefe.config import load_jobs +from simplefe.runner import run_job + def create_app(jobs=None): app = Flask(__name__) @@ -26,4 +28,14 @@ def create_app(jobs=None): abort(404) return jobs[name] + @app.route("/jobs/<name>/run", methods=["POST"]) + def trigger_job(name): + jobs = app.config["JOBS"] + if name not in jobs: + abort(404) + job = jobs[name] + response = request.json["response"] + output = run_job(job["path"], job["prompt"], response) + return {"output": output.decode()} + return app diff --git a/tests/test_app.py b/tests/test_app.py @@ -1,3 +1,10 @@ +from pathlib import Path + +from simplefe.app import create_app + +FIXTURES = Path(__file__).parent / "fixtures" + + def test_list_jobs(client): response = client.get("/jobs") assert response.json == {"jobs": ["rip"]} @@ -11,3 +18,22 @@ def test_get_job(client): def test_get_job_not_found(client): response = client.get("/jobs/nonexistent") assert response.status_code == 404 + + +def test_trigger_job(): + fake_job = FIXTURES / "fake_job.py" + app = create_app( + jobs={ + "rip": { + "path": f"python3 {fake_job}", + "prompt": "Enter movie name:", + } + } + ) + app.config.update({"TESTING": True}) + client = app.test_client() + + response = client.post("/jobs/rip/run", json={"response": "The Matrix"}) + + assert response.status_code == 200 + assert "Got: The Matrix" in response.json["output"]