outcomeci-cli 0.1.0__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.
Files changed (31) hide show
  1. outcomeci_cli-0.1.0/.github/workflows/dependency-scan.yml +23 -0
  2. outcomeci_cli-0.1.0/.github/workflows/homebrew.yml +62 -0
  3. outcomeci_cli-0.1.0/.github/workflows/publish.yml +95 -0
  4. outcomeci_cli-0.1.0/.github/workflows/secret-scan.yml +44 -0
  5. outcomeci_cli-0.1.0/.github/workflows/semantic-release.yml +56 -0
  6. outcomeci_cli-0.1.0/.github/workflows/test.yml +43 -0
  7. outcomeci_cli-0.1.0/.gitignore +7 -0
  8. outcomeci_cli-0.1.0/PKG-INFO +72 -0
  9. outcomeci_cli-0.1.0/README.md +60 -0
  10. outcomeci_cli-0.1.0/packaging/outcomeci-cli.rb +19 -0
  11. outcomeci_cli-0.1.0/pyproject.toml +38 -0
  12. outcomeci_cli-0.1.0/scripts/refresh-homebrew-resources.py +34 -0
  13. outcomeci_cli-0.1.0/scripts/release-range.sh +21 -0
  14. outcomeci_cli-0.1.0/specs/001-standup-runtime/plan.md +11 -0
  15. outcomeci_cli-0.1.0/specs/001-standup-runtime/spec.md +30 -0
  16. outcomeci_cli-0.1.0/specs/001-standup-runtime/tasks.md +14 -0
  17. outcomeci_cli-0.1.0/src/outcomeci/__init__.py +7 -0
  18. outcomeci_cli-0.1.0/src/outcomeci/cli.py +140 -0
  19. outcomeci_cli-0.1.0/src/outcomeci/config.py +142 -0
  20. outcomeci_cli-0.1.0/src/outcomeci/local.py +318 -0
  21. outcomeci_cli-0.1.0/src/outcomeci/manifest.py +52 -0
  22. outcomeci_cli-0.1.0/src/outcomeci/outcome.py +265 -0
  23. outcomeci_cli-0.1.0/src/outcomeci/process.py +87 -0
  24. outcomeci_cli-0.1.0/src/outcomeci/repository.py +51 -0
  25. outcomeci_cli-0.1.0/src/outcomeci/templates.py +126 -0
  26. outcomeci_cli-0.1.0/src/outcomeci/twin.py +40 -0
  27. outcomeci_cli-0.1.0/tests/test_cli.py +72 -0
  28. outcomeci_cli-0.1.0/tests/test_local.py +80 -0
  29. outcomeci_cli-0.1.0/tests/test_manifest.py +44 -0
  30. outcomeci_cli-0.1.0/tests/test_outcome.py +60 -0
  31. outcomeci_cli-0.1.0/tests/test_release.py +33 -0
@@ -0,0 +1,23 @@
1
+ name: Dependency scan
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+ schedule:
8
+ - cron: "0 7 * * 1"
9
+ workflow_dispatch:
10
+
11
+ jobs:
12
+ audit:
13
+ name: pip-audit
14
+ runs-on: ubuntu-latest
15
+ permissions:
16
+ contents: read
17
+ steps:
18
+ - uses: actions/checkout@v7
19
+ - uses: actions/setup-python@v7
20
+ with:
21
+ python-version: "3.12"
22
+ - run: pip install -e '.[test]' pip-audit
23
+ - run: pip-audit --skip-editable
@@ -0,0 +1,62 @@
1
+ name: Update Homebrew tap
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+ workflow_dispatch:
7
+ inputs:
8
+ tag:
9
+ description: "Released tag to point the formula at, e.g. v0.1.0"
10
+ required: true
11
+ type: string
12
+
13
+ jobs:
14
+ bump:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - name: Resolve version
18
+ id: version
19
+ env:
20
+ TAG: ${{ inputs.tag || github.ref_name }}
21
+ run: echo "version=${TAG#v}" >> "$GITHUB_OUTPUT"
22
+ - name: Wait for PyPI sdist
23
+ id: pypi
24
+ run: |
25
+ VERSION="${{ steps.version.outputs.version }}"
26
+ for i in $(seq 1 30); do
27
+ JSON=$(curl -fsSL "https://pypi.org/pypi/outcomeci-cli/${VERSION}/json" || true)
28
+ URL=$(printf '%s' "$JSON" | jq -r '.urls[]? | select(.packagetype=="sdist") | .url')
29
+ SHA=$(printf '%s' "$JSON" | jq -r '.urls[]? | select(.packagetype=="sdist") | .digests.sha256')
30
+ if [ -n "$URL" ] && [ "$URL" != "null" ]; then break; fi
31
+ sleep 10
32
+ done
33
+ if [ -z "$URL" ] || [ "$URL" = "null" ]; then exit 1; fi
34
+ echo "url=$URL" >> "$GITHUB_OUTPUT"
35
+ echo "sha=$SHA" >> "$GITHUB_OUTPUT"
36
+ - uses: actions/checkout@v7
37
+ with:
38
+ ref: ${{ inputs.tag || github.ref_name }}
39
+ path: source
40
+ - uses: actions/checkout@v7
41
+ with:
42
+ repository: outcomeci/homebrew-tap
43
+ token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
44
+ path: tap
45
+ - name: Update formula and resources
46
+ env:
47
+ VERSION: ${{ steps.version.outputs.version }}
48
+ URL: ${{ steps.pypi.outputs.url }}
49
+ SHA: ${{ steps.pypi.outputs.sha }}
50
+ run: |
51
+ F=tap/Formula/outcomeci-cli.rb
52
+ mkdir -p tap/Formula
53
+ if [ ! -f "$F" ]; then cp source/packaging/outcomeci-cli.rb "$F"; fi
54
+ sed -i -E "s#^ url \".*\"# url \"${URL}\"#" "$F"
55
+ sed -i -E "s#^ sha256 \".*\"# sha256 \"${SHA}\"#" "$F"
56
+ python3 source/scripts/refresh-homebrew-resources.py "$F" "$VERSION"
57
+ git -C tap config user.name "github-actions[bot]"
58
+ git -C tap config user.email "github-actions[bot]@users.noreply.github.com"
59
+ if git -C tap diff --quiet; then exit 0; fi
60
+ git -C tap add Formula/outcomeci-cli.rb
61
+ git -C tap commit -m "outcomeci-cli ${VERSION}"
62
+ git -C tap push
@@ -0,0 +1,95 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+ workflow_dispatch:
7
+ inputs:
8
+ tag:
9
+ description: "Tag to release, e.g. v0.1.0"
10
+ required: true
11
+ type: string
12
+
13
+ permissions:
14
+ contents: read
15
+ id-token: write
16
+
17
+ jobs:
18
+ publish:
19
+ runs-on: ubuntu-latest
20
+ environment: pypi
21
+ steps:
22
+ - uses: actions/checkout@v7
23
+ with:
24
+ ref: ${{ inputs.tag || github.ref_name }}
25
+ - uses: actions/setup-python@v7
26
+ with:
27
+ python-version: "3.12"
28
+ - run: pip install build
29
+ - run: python -m build
30
+ - name: Verify tag matches package
31
+ env:
32
+ TAG: ${{ inputs.tag || github.ref_name }}
33
+ run: |
34
+ python - <<'PY'
35
+ import email, os, pathlib, sys, zipfile
36
+ expected = os.environ["TAG"].removeprefix("v")
37
+ wheel = next(pathlib.Path("dist").glob("*.whl"))
38
+ with zipfile.ZipFile(wheel) as archive:
39
+ path = next(name for name in archive.namelist() if name.endswith(".dist-info/METADATA"))
40
+ actual = email.message_from_bytes(archive.read(path))["Version"]
41
+ if expected != actual:
42
+ sys.exit(f"tag {expected} does not match built package version {actual}")
43
+ PY
44
+ - uses: pypa/gh-action-pypi-publish@release/v1
45
+
46
+ release:
47
+ needs: publish
48
+ runs-on: ubuntu-latest
49
+ permissions:
50
+ contents: write
51
+ id-token: write
52
+ steps:
53
+ - uses: actions/checkout@v7
54
+ with:
55
+ ref: ${{ inputs.tag || github.ref_name }}
56
+ fetch-depth: 0
57
+ - name: Resolve release range
58
+ id: release-range
59
+ env:
60
+ TAG: ${{ inputs.tag || github.ref_name }}
61
+ run: scripts/release-range.sh "$TAG" "$GITHUB_OUTPUT"
62
+ - name: Resolve version
63
+ id: version
64
+ env:
65
+ TAG: ${{ inputs.tag || github.ref_name }}
66
+ run: echo "version=${TAG#v}" >> "$GITHUB_OUTPUT"
67
+ - uses: aws-actions/configure-aws-credentials@v6
68
+ with:
69
+ role-to-assume: ${{ vars.CHANGELOG_AWS_ROLE_ARN }}
70
+ aws-region: ${{ vars.AWS_REGION || 'us-east-1' }}
71
+ - name: Render release notes
72
+ id: changelog
73
+ uses: outcomeci/spareparts-changelog@v0
74
+ with:
75
+ provider: anthropic
76
+ instructions: ${{ vars.CHANGELOG_INSTRUCTIONS }}
77
+ anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
78
+ from: ${{ steps.release-range.outputs.from }}
79
+ to: ${{ steps.release-range.outputs.to }}
80
+ title: ${{ inputs.tag || github.ref_name }}
81
+ write-repository: "false"
82
+ publish-s3: "true"
83
+ s3-bucket: ${{ vars.CHANGELOG_S3_BUCKET }}
84
+ s3-key: releases/outcomeci-cli/${{ steps.version.outputs.version }}.md
85
+ s3-region: ${{ vars.AWS_REGION || 'us-east-1' }}
86
+ publish-linkedin: "false"
87
+ - name: Create GitHub release
88
+ env:
89
+ RELEASE_NOTES: ${{ steps.changelog.outputs.markdown }}
90
+ GH_TOKEN: ${{ github.token }}
91
+ TAG: ${{ inputs.tag || github.ref_name }}
92
+ run: |
93
+ test -n "$RELEASE_NOTES"
94
+ printf '%s\n' "$RELEASE_NOTES" > release-notes.md
95
+ gh release create "$TAG" --notes-file release-notes.md --verify-tag
@@ -0,0 +1,44 @@
1
+ name: Secret scan
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+
8
+ jobs:
9
+ secrets:
10
+ name: trufflehog
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ contents: read
14
+ env:
15
+ TRUFFLEHOG_VERSION: "3.95.9"
16
+ steps:
17
+ - uses: actions/checkout@v7
18
+ with:
19
+ fetch-depth: 0
20
+ - name: Resolve scan base
21
+ id: base
22
+ env:
23
+ EVENT_NAME: ${{ github.event_name }}
24
+ PR_BASE: ${{ github.event.pull_request.base.sha }}
25
+ PUSH_BEFORE: ${{ github.event.before }}
26
+ run: |
27
+ if [ "$EVENT_NAME" = "pull_request" ]; then
28
+ echo "since=$PR_BASE" >> "$GITHUB_OUTPUT"
29
+ elif [ "$PUSH_BEFORE" = "0000000000000000000000000000000000000000" ] || [ -z "$PUSH_BEFORE" ]; then
30
+ echo "since=" >> "$GITHUB_OUTPUT"
31
+ else
32
+ echo "since=$PUSH_BEFORE" >> "$GITHUB_OUTPUT"
33
+ fi
34
+ - name: Install TruffleHog
35
+ run: |
36
+ curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh \
37
+ | sh -s -- -b /usr/local/bin "v${TRUFFLEHOG_VERSION}"
38
+ - name: Scan for secrets
39
+ env:
40
+ SINCE: ${{ steps.base.outputs.since }}
41
+ run: |
42
+ set -- git "file://." --results=verified,unknown --fail --no-update --exclude-detectors=Lob
43
+ if [ -n "$SINCE" ]; then set -- "$@" --since-commit "$SINCE"; fi
44
+ trufflehog "$@"
@@ -0,0 +1,56 @@
1
+ name: Semantic release
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+
7
+ concurrency:
8
+ group: semantic-release
9
+ cancel-in-progress: false
10
+
11
+ permissions:
12
+ contents: write
13
+ actions: write
14
+
15
+ jobs:
16
+ release:
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - uses: actions/checkout@v7
20
+ with:
21
+ fetch-depth: 0
22
+ - uses: actions/setup-python@v7
23
+ with:
24
+ python-version: "3.12"
25
+ - run: pip install "commitizen>=4,<5"
26
+ - name: Create next semantic version tag
27
+ id: version
28
+ shell: bash
29
+ run: |
30
+ set +e
31
+ OUTPUT=$(cz bump --get-next 2>&1)
32
+ STATUS=$?
33
+ set -e
34
+ if [ "$STATUS" -eq 3 ] || [ "$STATUS" -eq 21 ]; then
35
+ echo "released=false" >> "$GITHUB_OUTPUT"
36
+ exit 0
37
+ fi
38
+ if [ "$STATUS" -ne 0 ]; then printf '%s\n' "$OUTPUT"; exit "$STATUS"; fi
39
+ NEXT_VERSION=$(printf '%s\n' "$OUTPUT" | tail -n 1)
40
+ if ! [[ "$NEXT_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+([+-][0-9A-Za-z.-]+)?$ ]]; then
41
+ echo "::error::Commitizen returned an invalid version: $NEXT_VERSION"
42
+ exit 1
43
+ fi
44
+ TAG="v${NEXT_VERSION}"
45
+ git tag "$TAG"
46
+ git push origin "$TAG"
47
+ echo "released=true" >> "$GITHUB_OUTPUT"
48
+ echo "tag=$TAG" >> "$GITHUB_OUTPUT"
49
+ - name: Publish package and update Homebrew
50
+ if: steps.version.outputs.released == 'true'
51
+ env:
52
+ GH_TOKEN: ${{ github.token }}
53
+ TAG: ${{ steps.version.outputs.tag }}
54
+ run: |
55
+ gh workflow run publish.yml --ref main -f tag="$TAG"
56
+ gh workflow run homebrew.yml --ref main -f tag="$TAG"
@@ -0,0 +1,43 @@
1
+ name: Tests
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+
8
+ jobs:
9
+ pytest:
10
+ name: pytest on Python ${{ matrix.python-version }}
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ python-version: ["3.11", "3.12", "3.13"]
16
+ steps:
17
+ - uses: actions/checkout@v7
18
+ with:
19
+ fetch-depth: 0
20
+ - uses: actions/setup-python@v7
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+ - run: pip install -e '.[test]'
24
+ - run: pytest -q
25
+
26
+ build:
27
+ name: build and inspect distribution
28
+ runs-on: ubuntu-latest
29
+ steps:
30
+ - uses: actions/checkout@v7
31
+ with:
32
+ fetch-depth: 0
33
+ - uses: actions/setup-python@v7
34
+ with:
35
+ python-version: "3.12"
36
+ - run: pip install build twine
37
+ - run: python -m build
38
+ - run: twine check dist/*
39
+ - name: Verify installed command
40
+ run: |
41
+ pip install --force-reinstall dist/*.whl
42
+ oci --version
43
+ oci outcome --help
@@ -0,0 +1,7 @@
1
+ .venv/
2
+ dist/
3
+ build/
4
+ *.egg-info/
5
+ __pycache__/
6
+ .pytest_cache/
7
+
@@ -0,0 +1,72 @@
1
+ Metadata-Version: 2.5
2
+ Name: outcomeci-cli
3
+ Version: 0.1.0
4
+ Summary: Portable Standup and outcome workflow runtime for OutcomeCI
5
+ License: Apache-2.0
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: pyyaml>=6.0
8
+ Provides-Extra: test
9
+ Requires-Dist: build>=1.2; extra == 'test'
10
+ Requires-Dist: pytest>=8.3; extra == 'test'
11
+ Description-Content-Type: text/markdown
12
+
13
+ # OutcomeCI CLI
14
+
15
+ `oci` installs and executes the open-source Standup framework used by OutcomeCI.
16
+
17
+ ```console
18
+ pip install outcomeci-cli
19
+ oci init
20
+ oci validate
21
+ oci outcome run --claim /workspace/outcome-claim.json --workspace /workspace
22
+ ```
23
+
24
+ Repository context and workflow instructions live in `.outcomeci/`. The same
25
+ `outcome.yml` contract can run locally or use OutcomeCI Cloud for managed state,
26
+ Digital Twin context, expert messaging, credentials, and runners.
27
+
28
+ To run the discovery phases with a locally installed Codex or Claude Code:
29
+
30
+ ```console
31
+ oci init --backend filesystem
32
+ oci outcome compile outcome.yml
33
+ oci outcome start "Describe the outcome you want"
34
+ oci outcome status
35
+ oci outcome continue <run-id> --approve
36
+ ```
37
+
38
+ `start` performs intake. Each approved `continue` advances to plan and then
39
+ tasks. Local state, artifacts, manifests, transcripts, and usage records are
40
+ written beneath `.outcomeci/outcomes/<run-id>/`. Runner and model defaults come
41
+ from `outcome.yml`; `--agent` and `--model` provide per-invocation overrides.
42
+
43
+ `oci init` also installs repository-local Outcome skills for Codex and Claude
44
+ Code. They use the current interactive session rather than launching a child
45
+ process:
46
+
47
+ ```text
48
+ Codex: $outcome Describe the outcome you want
49
+ Claude Code: /outcome Describe the outcome you want
50
+ ```
51
+
52
+ The skill coordinates `outcome begin`, `compile`, `validate-artifacts`,
53
+ `advance`, and `status`. Managed OutcomeCI runners continue to use `outcome
54
+ run --claim ...`; both modes share workflow compilation and artifact schemas.
55
+
56
+ Filesystem workflows can pin repository evidence explicitly:
57
+
58
+ ```yaml
59
+ spec:
60
+ context:
61
+ provider: filesystem
62
+ include:
63
+ - .outcomeci/context/**
64
+ - docs/**
65
+ exclude:
66
+ - node_modules/**
67
+ - dist/**
68
+ ```
69
+
70
+ Compiled context records each matched path, size, and SHA-256 hash. Context
71
+ changes therefore produce a new workflow revision. Files remain in place and
72
+ are read by the active local agent; they are not copied into `outcome.yml`.
@@ -0,0 +1,60 @@
1
+ # OutcomeCI CLI
2
+
3
+ `oci` installs and executes the open-source Standup framework used by OutcomeCI.
4
+
5
+ ```console
6
+ pip install outcomeci-cli
7
+ oci init
8
+ oci validate
9
+ oci outcome run --claim /workspace/outcome-claim.json --workspace /workspace
10
+ ```
11
+
12
+ Repository context and workflow instructions live in `.outcomeci/`. The same
13
+ `outcome.yml` contract can run locally or use OutcomeCI Cloud for managed state,
14
+ Digital Twin context, expert messaging, credentials, and runners.
15
+
16
+ To run the discovery phases with a locally installed Codex or Claude Code:
17
+
18
+ ```console
19
+ oci init --backend filesystem
20
+ oci outcome compile outcome.yml
21
+ oci outcome start "Describe the outcome you want"
22
+ oci outcome status
23
+ oci outcome continue <run-id> --approve
24
+ ```
25
+
26
+ `start` performs intake. Each approved `continue` advances to plan and then
27
+ tasks. Local state, artifacts, manifests, transcripts, and usage records are
28
+ written beneath `.outcomeci/outcomes/<run-id>/`. Runner and model defaults come
29
+ from `outcome.yml`; `--agent` and `--model` provide per-invocation overrides.
30
+
31
+ `oci init` also installs repository-local Outcome skills for Codex and Claude
32
+ Code. They use the current interactive session rather than launching a child
33
+ process:
34
+
35
+ ```text
36
+ Codex: $outcome Describe the outcome you want
37
+ Claude Code: /outcome Describe the outcome you want
38
+ ```
39
+
40
+ The skill coordinates `outcome begin`, `compile`, `validate-artifacts`,
41
+ `advance`, and `status`. Managed OutcomeCI runners continue to use `outcome
42
+ run --claim ...`; both modes share workflow compilation and artifact schemas.
43
+
44
+ Filesystem workflows can pin repository evidence explicitly:
45
+
46
+ ```yaml
47
+ spec:
48
+ context:
49
+ provider: filesystem
50
+ include:
51
+ - .outcomeci/context/**
52
+ - docs/**
53
+ exclude:
54
+ - node_modules/**
55
+ - dist/**
56
+ ```
57
+
58
+ Compiled context records each matched path, size, and SHA-256 hash. Context
59
+ changes therefore produce a new workflow revision. Files remain in place and
60
+ are read by the active local agent; they are not copied into `outcome.yml`.
@@ -0,0 +1,19 @@
1
+ class OutcomeciCli < Formula
2
+ include Language::Python::Virtualenv
3
+
4
+ desc "Portable Standup and outcome workflow runtime"
5
+ homepage "https://github.com/outcomeci/cli"
6
+ url "https://files.pythonhosted.org/packages/source/o/outcomeci-cli/outcomeci_cli-0.1.0.tar.gz"
7
+ sha256 "0000000000000000000000000000000000000000000000000000000000000000"
8
+
9
+ depends_on "python@3.12"
10
+
11
+ def install
12
+ virtualenv_install_with_resources
13
+ end
14
+
15
+ test do
16
+ assert_match "oci", shell_output("#{bin}/oci --help")
17
+ assert_match version.to_s, shell_output("#{bin}/oci --version")
18
+ end
19
+ end
@@ -0,0 +1,38 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.27", "hatch-vcs"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "outcomeci-cli"
7
+ dynamic = ["version"]
8
+ description = "Portable Standup and outcome workflow runtime for OutcomeCI"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = { text = "Apache-2.0" }
12
+ dependencies = ["PyYAML>=6.0"]
13
+
14
+ [project.scripts]
15
+ oci = "outcomeci.cli:main"
16
+
17
+ [project.optional-dependencies]
18
+ test = ["pytest>=8.3", "build>=1.2"]
19
+
20
+ [tool.hatch.build.targets.wheel]
21
+ packages = ["src/outcomeci"]
22
+
23
+ [tool.hatch.version]
24
+ source = "vcs"
25
+
26
+ [tool.hatch.version.raw-options]
27
+ version_scheme = "no-guess-dev"
28
+
29
+ [tool.commitizen]
30
+ name = "cz_conventional_commits"
31
+ version_provider = "scm"
32
+ version_scheme = "semver2"
33
+ tag_format = "v${version}"
34
+ major_version_zero = true
35
+
36
+ [tool.pytest.ini_options]
37
+ testpaths = ["tests"]
38
+ pythonpath = ["src"]
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env python3
2
+ """Refresh Homebrew Python resource blocks from a published OutcomeCI release."""
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import re
7
+ import subprocess
8
+ import sys
9
+ import tempfile
10
+ import urllib.request
11
+ import venv
12
+
13
+ formula, version = sys.argv[1], sys.argv[2]
14
+ temporary = tempfile.mkdtemp()
15
+ venv.create(f"{temporary}/venv", with_pip=True)
16
+ pip = f"{temporary}/venv/bin/pip"
17
+ subprocess.check_call([pip, "install", "-q", f"outcomeci-cli=={version}"])
18
+ freeze = subprocess.check_output([pip, "list", "--format=freeze"], text=True)
19
+ dependencies = []
20
+ for line in freeze.splitlines():
21
+ if "==" in line:
22
+ name, dependency_version = line.split("==", 1)
23
+ if name.casefold() not in {"outcomeci-cli", "pip", "setuptools", "wheel"}:
24
+ dependencies.append((name, dependency_version))
25
+ blocks = []
26
+ for name, dependency_version in sorted(dependencies, key=lambda item: item[0].casefold()):
27
+ with urllib.request.urlopen(f"https://pypi.org/pypi/{name}/{dependency_version}/json") as response:
28
+ metadata = json.load(response)
29
+ sdist = next(item for item in metadata["urls"] if item["packagetype"] == "sdist")
30
+ blocks.append(f' resource "{metadata["info"]["name"]}" do\n url "{sdist["url"]}"\n sha256 "{sdist["digests"]["sha256"]}"\n end')
31
+ text = open(formula, encoding="utf-8").read()
32
+ text = re.sub(r'\n resource "[^"]+" do\n(?:.*\n)*? end\n', '\n', text)
33
+ text = re.sub(r'( depends_on "python@[^"]+"\n)', r'\1\n' + "\n\n".join(blocks) + "\n", text, count=1)
34
+ open(formula, "w", encoding="utf-8").write(re.sub(r'\n{3,}', '\n\n', text))
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ current_tag=${1:-}
5
+ output_file=${2:-}
6
+ if [[ ! $current_tag =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || [[ -z $output_file ]]; then
7
+ echo "usage: release-range.sh vMAJOR.MINOR.PATCH OUTPUT" >&2
8
+ exit 1
9
+ fi
10
+ git rev-parse --verify "${current_tag}^{commit}" >/dev/null
11
+ previous_tag=$(git tag --merged "$current_tag" --list 'v*' | awk '$0 ~ /^v[0-9]+\.[0-9]+\.[0-9]+$/' | awk -v current="$current_tag" '$0 != current' | sort -V -r | head -n 1)
12
+ if [[ -n $previous_tag ]]; then
13
+ from_revision=$previous_tag
14
+ else
15
+ from_revision=$(git rev-list --max-parents=0 "$current_tag" | tail -n 1)
16
+ fi
17
+ if [[ -z $from_revision ]] || [[ $(git rev-parse "${from_revision}^{commit}") == $(git rev-parse "${current_tag}^{commit}") ]]; then
18
+ echo "release range is empty" >&2
19
+ exit 1
20
+ fi
21
+ printf 'from=%s\nto=%s\n' "$from_revision" "$current_tag" >> "$output_file"
@@ -0,0 +1,11 @@
1
+ # Implementation Plan: Standup Runtime
2
+
3
+ 1. Create a dependency-light Python package and lazy command router.
4
+ 2. Add deterministic repository initialization and update behavior.
5
+ 3. Validate and compile `outcome.yml` plus referenced instruction content.
6
+ 4. Port the bounded Outcome executor, GitHub checkout, agent adapters,
7
+ transcript normalization, and Digital Twin client under OutcomeCI naming.
8
+ 5. Add contract and package tests, build a wheel, and install it into the local
9
+ Outcome runner image.
10
+ 6. Change the API-issued command and runner environment to `oci` / `OUTCOMECI_*`.
11
+
@@ -0,0 +1,30 @@
1
+ # Feature Specification: Standup Runtime
2
+
3
+ ## Goal
4
+
5
+ Publish a clean OutcomeCI CLI that lets engineers initialize and inspect the
6
+ Standup framework while allowing OutcomeCI Cloud to delegate bounded outcome
7
+ phases to Codex or Claude Code through the same workflow contract.
8
+
9
+ ## Requirements
10
+
11
+ - Expose `oci init`, `oci update`, `oci validate`, `oci status`, `oci outcome`,
12
+ and `oci twin` without legacy Spare Parts command aliases.
13
+ - Store repository context under `.outcomeci/` and call the framework Standup.
14
+ - Make `outcome.yml` the orchestration policy and Markdown the readable
15
+ instruction body included in its deterministic compiled revision.
16
+ - Run intake, plan, and tasks against immutable product checkouts while writing
17
+ versioned artifacts and evidence only to the state repository.
18
+ - Accept only bounded, revision-pinned tools and credentials supplied by the
19
+ OutcomeCI API claim.
20
+ - Capture native agent transcripts and normalized token usage.
21
+
22
+ ## Acceptance Criteria
23
+
24
+ - A fresh repository can be initialized and validated.
25
+ - Editing referenced YAML or Markdown changes the compiled workflow revision.
26
+ - A local wheel exposes the `oci` executable.
27
+ - The Outcome runner container can install that wheel and successfully invoke
28
+ `oci outcome run` from an API claim.
29
+ - No public interface writes `.sp/`, invokes `sp`, or generates Huddle naming.
30
+
@@ -0,0 +1,14 @@
1
+ # Tasks: Standup Runtime
2
+
3
+ - [x] Scaffold the `outcomeci-cli` distribution and `oci` entrypoint.
4
+ - [x] Implement `.outcomeci/` initialization, update, validation, and status.
5
+ - [x] Add default `outcome.yml` and Standup/phase instruction templates.
6
+ - [x] Compile referenced instructions into the workflow revision.
7
+ - [x] Port the Digital Twin job-scoped search client.
8
+ - [x] Port agent invocation and bounded phase execution for intake, plan, and tasks.
9
+ - [x] Generate `standup.md`, manifests, transcripts, and usage records.
10
+ - [x] Add tests and build the local wheel.
11
+ - [x] Update API claim command and OutcomeCI environment names.
12
+ - [x] Build the local agent-runner image with the wheel and run initialization/validation smoke checks.
13
+ - [ ] Initialize the development state repository and run a live API-issued claim.
14
+ - [ ] Fold implementation and PR phases into the OutcomeCI executor.
@@ -0,0 +1,7 @@
1
+ """OutcomeCI portable workflow runtime."""
2
+ from importlib.metadata import PackageNotFoundError, version
3
+
4
+ try:
5
+ __version__ = version("outcomeci-cli")
6
+ except PackageNotFoundError:
7
+ __version__ = "0.0.0"