@open-agent-toolkit/cli 0.0.54 → 0.0.56

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.
@@ -57,6 +57,10 @@ Archive lifecycle settings live here as shared repo config:
57
57
  - `archive.s3SyncOnComplete`
58
58
  - `archive.summaryExportPath`
59
59
  - `archive.wrapUpExportPath`
60
+ - `archive.awsProfile`
61
+ - `archive.awsRegion`
62
+
63
+ `archive.awsProfile` and `archive.awsRegion` are forwarded as `AWS_PROFILE` / `AWS_REGION` env vars into every `aws` spawn that runs during `oat-project-complete` and `oat project archive sync`. The per-invocation `oat project archive sync --profile <profile>` and `--region <region>` flags override the config for a single run; an `AWS_PROFILE` / `AWS_REGION` already set in the parent shell sits between the flag and the config in precedence (flag > shell env > config). Raw access keys (`AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`) remain a shell-environment concern — there is no config plumbing for them.
60
64
 
61
65
  Tool-pack installation state also lives here as shared repo config:
62
66
 
@@ -83,6 +83,8 @@ Common keys in `.oat/config.json`:
83
83
  - `archive.s3SyncOnComplete` — upload archived projects to S3 during completion
84
84
  - `archive.summaryExportPath` — export `summary.md` into a durable tracked directory during completion
85
85
  - `archive.wrapUpExportPath` — optional tracked destination for `oat-wrap-up` reports; when unset, the skill falls back to `.oat/repo/reference/wrap-ups`
86
+ - `archive.awsProfile` — optional AWS named profile forwarded as `AWS_PROFILE` to every `aws` invocation in archive flows
87
+ - `archive.awsRegion` — optional AWS region forwarded as `AWS_REGION` to every `aws` invocation in archive flows
86
88
  - `tools.<pack>` — whether a bundled tool pack is currently installed in the repo or user scopes after lifecycle reconciliation
87
89
 
88
90
  Tool-pack state example:
@@ -101,6 +103,8 @@ oat config set archive.s3Uri s3://example-bucket/oat-archive
101
103
  oat config set archive.s3SyncOnComplete true
102
104
  oat config set archive.summaryExportPath .oat/repo/reference/project-summaries
103
105
  oat config set archive.wrapUpExportPath .oat/repo/reference/wrap-ups
106
+ oat config set archive.awsProfile work-sso
107
+ oat config set archive.awsRegion us-east-1
104
108
  ```
105
109
 
106
110
  With those values configured:
@@ -110,6 +114,27 @@ With those values configured:
110
114
  - completion also copies `summary.md` into `<archive.summaryExportPath>/20260401-my-project.md`
111
115
  - `oat project archive sync` can later pull archive data back down from S3 and materialize the latest snapshot into the local bare archive path `.oat/projects/archived/<project>/`
112
116
  - `oat-wrap-up` can write tracked reports into `<archive.wrapUpExportPath>/YYYY-MM-DD-wrap-up-<label>.md`; if the key is unset, the skill uses `.oat/repo/reference/wrap-ups/`
117
+ - every `aws` spawn (preflight `aws sts get-caller-identity`, `aws s3 ls`, `aws s3 sync`) inherits `AWS_PROFILE` / `AWS_REGION` from `archive.awsProfile` / `archive.awsRegion` when the parent shell does not already set them
118
+
119
+ ### Credential resolution
120
+
121
+ Profile and region resolve with the following precedence per `aws` invocation, highest first:
122
+
123
+ 1. CLI flag passed to `oat project archive sync` (`--profile <profile>`, `--region <region>`)
124
+ 2. The parent shell's existing `AWS_PROFILE` / `AWS_REGION` env vars
125
+ 3. The repo's shared `archive.awsProfile` / `archive.awsRegion` config
126
+
127
+ If none of the three are present for a given var, OAT does not inject it — the AWS CLI's own resolution chain takes over.
128
+
129
+ The `oat project archive sync` flags only override for that single invocation:
130
+
131
+ ```bash
132
+ oat project archive sync --profile work-sso --region us-east-1
133
+ ```
134
+
135
+ `oat-project-complete` does not accept per-invocation flags. Set the shared config (or your shell env) ahead of time if completion needs a specific profile.
136
+
137
+ Raw access keys (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and friends) remain a shell-environment concern. OAT does not expose config keys for them — set them in your shell before running `oat-project-complete` or `oat project archive sync` and they are inherited by the spawned `aws` process unchanged.
113
138
 
114
139
  ## Repo-local and user state
115
140
 
@@ -59,6 +59,47 @@ Skill behavior is defined by frontmatter plus the process contract in each `SKIL
59
59
  - Use `create-agnostic-skill` when you want a reusable workflow skill that is not OAT-specific.
60
60
  - Use existing lifecycle skills as examples for progress banners, prerequisites, and artifact updates.
61
61
 
62
+ ## Reading project state
63
+
64
+ Skills that need fields from the active project's `state.md` (e.g. `phase`, `phaseStatus`, `workflowMode`, `docsUpdated`, `lastCommit`) MUST query the CLI instead of hand-parsing YAML with `grep`/`awk`.
65
+
66
+ For one field, use `--field`:
67
+
68
+ ```bash
69
+ WORKFLOW_MODE=$(oat project status --field project.workflowMode 2>/dev/null || echo null)
70
+ ```
71
+
72
+ If the skill is reading a resolved project path instead of the active project pointer, add `--project-path`:
73
+
74
+ ```bash
75
+ WORKFLOW_MODE=$(oat project status --project-path "$PROJECT_PATH" --field project.workflowMode 2>/dev/null || echo null)
76
+ ```
77
+
78
+ For multiple fields, use `--shell` so the CLI reads project state once and emits shell-safe assignments:
79
+
80
+ ```bash
81
+ eval "$(oat project status --shell \
82
+ PHASE=project.phase \
83
+ PHASE_STATUS=project.phaseStatus \
84
+ WORKFLOW_MODE=project.workflowMode 2>/dev/null)"
85
+ ```
86
+
87
+ Skill snippets assume `oat` is available on `PATH`. Environments without a global install, including CI or cloud runners, can provide an `oat` shim backed by `npx`:
88
+
89
+ ```bash
90
+ mkdir -p .oat/bin
91
+ cat > .oat/bin/oat <<'EOF'
92
+ #!/usr/bin/env bash
93
+ exec npx @open-agent-toolkit/cli "$@"
94
+ EOF
95
+ chmod +x .oat/bin/oat
96
+ export PATH="$PWD/.oat/bin:$PATH"
97
+ ```
98
+
99
+ Create the shim once per checkout or CI job instead of putting `command -v oat` fallback branches in every skill. The same snippet also supports setups where `oat` is intentionally provided on `PATH` by `npx`.
100
+
101
+ The JSON output is a stable contract: the field set consumed by migrated skills is locked by `MIGRATED_FIELDS` in `packages/cli/src/commands/project/status.test.ts`, so removing or renaming any of those keys is a real test failure rather than a silent runtime break. See [CLI Reference](../reference/cli-reference.md) for the full locked field set.
102
+
62
103
  ## Reference artifacts
63
104
 
64
105
  - `.agents/skills/*/SKILL.md`
@@ -37,7 +37,10 @@ The CLI is also a standalone value path. You can use `oat init`, `oat sync`, `oa
37
37
  Notable inspection commands introduced in the current CLI surface:
38
38
 
39
39
  - `oat config dump --json` - merged config with source attribution
40
- - `oat project status --json` - full parsed state for the active tracked project
40
+ - `oat project status --json` - full parsed state for the active tracked project. **Stable contract for skills:** the JSON output is a typed read interface for OAT skills; the field set consumed by migrated skills is locked by `MIGRATED_FIELDS` in `packages/cli/src/commands/project/status.test.ts`. Removing or renaming any of `project.{name, path, phase, phaseStatus, workflowMode, docsUpdated, lastCommit, prStatus, prUrl}` is a breaking change and will fail the contract test.
41
+ - `oat project status --field <path>` - print one arbitrary dot-path field from the same status payload, e.g. `project.workflowMode` or `project.timestamps.stateUpdated`. Missing/null fields print `null`; object and array fields print compact JSON.
42
+ - `oat project status --project-path <path>` - read from a repo-relative or absolute project path instead of `.oat/config.local.json`'s active project pointer. Combine it with `--field` or `--shell` when a skill has already resolved the target project path.
43
+ - `oat project status --shell NAME=path ...` - print shell-safe assignments for one or more fields from one status read, e.g. `WORKFLOW_MODE='quick'`. This is the preferred multi-field read API for skills. See [Writing Skills → Reading project state](../contributing/skills.md#reading-project-state) for examples and the `npx`-backed `oat` shim contract.
41
44
  - `oat project list --json` - summary state for tracked projects under the configured projects root
42
45
  - `oat project complete-state <project-path>` - apply the canonical completed-state mutation to a project's `state.md`; used by `oat-project-complete` during lifecycle closeout
43
46
  - `oat project validate-plan --project-path <path>` - validates `oat_plan_parallel_groups` metadata in `plan.md`; exits non-zero on invalid. See [Implementation Execution](../workflows/projects/implementation-execution.md#validating-plan-metadata).
@@ -1,6 +1,6 @@
1
1
  {
2
- "cli": "0.0.54",
3
- "docs-config": "0.0.54",
4
- "docs-theme": "0.0.54",
5
- "docs-transforms": "0.0.54"
2
+ "cli": "0.0.56",
3
+ "docs-config": "0.0.56",
4
+ "docs-theme": "0.0.56",
5
+ "docs-transforms": "0.0.56"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-complete
3
- version: 1.4.3
3
+ version: 1.4.4
4
4
  description: Use when all implementation work is finished and the project is ready to close. Marks the OAT project lifecycle as complete.
5
5
  disable-model-invocation: true
6
6
  user-invocable: true
@@ -183,8 +183,7 @@ fi
183
183
  #### 3.3: Documentation Sync Status
184
184
 
185
185
  ```bash
186
- STATE_FILE="${PROJECT_PATH}/state.md"
187
- DOCS_UPDATED=$(grep "^oat_docs_updated:" "$STATE_FILE" 2>/dev/null | awk '{print $2}' || true)
186
+ DOCS_UPDATED=$(oat project status --field project.docsUpdated 2>/dev/null || echo null)
188
187
 
189
188
  # Read policy from config (default: false = soft suggestion)
190
189
  REQUIRE_DOCS=$(oat config get documentation.requireForProjectCompletion 2>/dev/null || echo "false")
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-plan
3
- version: 1.3.1
3
+ version: 1.3.2
4
4
  description: Use when design.md is complete and executable implementation tasks are needed. Breaks design into bite-sized TDD tasks in canonical plan.md format.
5
5
  disable-model-invocation: true
6
6
  user-invocable: true
@@ -105,8 +105,7 @@ PROJECTS_ROOT="${PROJECTS_ROOT%/}"
105
105
  ### Step 1: Determine Workflow Mode and Route
106
106
 
107
107
  ```bash
108
- WORKFLOW_MODE=$(grep "^oat_workflow_mode:" "$PROJECT_PATH/state.md" 2>/dev/null | awk '{print $2}')
109
- WORKFLOW_MODE="${WORKFLOW_MODE:-spec-driven}"
108
+ WORKFLOW_MODE=$(oat project status --field project.workflowMode 2>/dev/null || echo null)
110
109
  ```
111
110
 
112
111
  **Mode: `quick`** — **STOP.** Print:
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-pr-final
3
- version: 1.3.3
3
+ version: 1.3.4
4
4
  description: Use when an active OAT project has completed all phases and is ready for final merge to main. Generates the final OAT lifecycle PR description from artifacts and review status, then creates the PR automatically.
5
5
  disable-model-invocation: true
6
6
  user-invocable: true
@@ -134,8 +134,7 @@ Rules:
134
134
  Resolve workflow mode from `state.md` (default `spec-driven`):
135
135
 
136
136
  ```bash
137
- WORKFLOW_MODE=$(grep "^oat_workflow_mode:" "$PROJECT_PATH/state.md" 2>/dev/null | head -1 | awk '{print $2}')
138
- WORKFLOW_MODE=${WORKFLOW_MODE:-spec-driven}
137
+ WORKFLOW_MODE=$(oat project status --field project.workflowMode 2>/dev/null || echo null)
139
138
  ```
140
139
 
141
140
  ```bash
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-pr-progress
3
- version: 1.2.0
3
+ version: 1.2.1
4
4
  description: Use when an active OAT project needs a mid-project PR for a completed phase (pNN). Generates a phase-scoped progress PR description from OAT artifacts and commit history, with optional PR creation.
5
5
  disable-model-invocation: true
6
6
  user-invocable: true
@@ -159,8 +159,7 @@ If scope is `range`/`base_sha`, set:
159
159
  Resolve workflow mode from `state.md` (default `spec-driven`):
160
160
 
161
161
  ```bash
162
- WORKFLOW_MODE=$(grep "^oat_workflow_mode:" "$PROJECT_PATH/state.md" 2>/dev/null | head -1 | awk '{print $2}')
163
- WORKFLOW_MODE=${WORKFLOW_MODE:-spec-driven}
162
+ WORKFLOW_MODE=$(oat project status --field project.workflowMode 2>/dev/null || echo null)
164
163
  ```
165
164
 
166
165
  Read (as available):
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-progress
3
- version: 1.2.2
3
+ version: 1.2.3
4
4
  description: Use when resuming work, checking status, or unsure which OAT skill to run next. Evaluates project progress and routes to the appropriate next step.
5
5
  disable-model-invocation: true
6
6
  user-invocable: true
@@ -202,8 +202,8 @@ PLAN_TASKS=$(grep -cE '^### Task p[0-9]+-t[0-9]+:' "$ACTIVE_PROJECT_PATH/plan.md
202
202
  IMPL_COMPLETED=$(grep -cE '^\*\*Status:\*\* completed' "$ACTIVE_PROJECT_PATH/implementation.md" 2>/dev/null || echo 0)
203
203
 
204
204
  # Check for commits since last tracked SHA
205
- LAST_SHA=$(grep "^oat_last_commit:" "$ACTIVE_PROJECT_PATH/state.md" 2>/dev/null | awk '{print $2}')
206
- if [ -n "$LAST_SHA" ]; then
205
+ LAST_SHA=$(oat project status --project-path "$ACTIVE_PROJECT_PATH" --field project.lastCommit 2>/dev/null || echo null)
206
+ if [ -n "$LAST_SHA" ] && [ "$LAST_SHA" != "null" ]; then
207
207
  UNTRACKED_COMMITS=$(git rev-list --count "$LAST_SHA"..HEAD 2>/dev/null || echo 0)
208
208
  else
209
209
  UNTRACKED_COMMITS=0
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-reconcile
3
- version: 1.0.0
3
+ version: 1.0.1
4
4
  description: Use when human-implemented commits need to be mapped back to planned tasks. Reconciles implementation.md and state.md after manual work outside the OAT workflow.
5
5
  disable-model-invocation: true
6
6
  user-invocable: true
@@ -104,9 +104,13 @@ Verify the project is ready for reconciliation:
104
104
 
105
105
  2. **Check project phase:**
106
106
 
107
+ The shell snippet below is indented so it remains inside this numbered list;
108
+ the leading whitespace is shell-safe when copied.
109
+
107
110
  ```bash
108
- PHASE=$(grep "^oat_phase:" "$PROJECT_PATH/state.md" 2>/dev/null | awk '{print $2}')
109
- PHASE_STATUS=$(grep "^oat_phase_status:" "$PROJECT_PATH/state.md" 2>/dev/null | awk '{print $2}')
111
+ eval "$(oat project status --shell \
112
+ PHASE=project.phase \
113
+ PHASE_STATUS=project.phaseStatus 2>/dev/null)"
110
114
  ```
111
115
 
112
116
  - If `PHASE` is `implement`: proceed
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-review-provide
3
- version: 1.3.1
3
+ version: 1.3.2
4
4
  description: Use when completed work in an active OAT project needs a quality gate before merge. Performs a lifecycle-scoped review after a task, phase, or full implementation, unlike oat-review-provide.
5
5
  disable-model-invocation: true
6
6
  user-invocable: true
@@ -122,9 +122,10 @@ If validation passes, derive `{project-name}` as basename of `PROJECT_PATH`.
122
122
  Read `state.md` frontmatter to propose the most likely review type and scope:
123
123
 
124
124
  ```bash
125
- PHASE=$(grep "^oat_phase:" "$PROJECT_PATH/state.md" 2>/dev/null | awk '{print $2}')
126
- PHASE_STATUS=$(grep "^oat_phase_status:" "$PROJECT_PATH/state.md" 2>/dev/null | awk '{print $2}')
127
- WORKFLOW_MODE=$(grep "^oat_workflow_mode:" "$PROJECT_PATH/state.md" 2>/dev/null | awk '{print $2}')
125
+ eval "$(oat project status --shell \
126
+ PHASE=project.phase \
127
+ PHASE_STATUS=project.phaseStatus \
128
+ WORKFLOW_MODE=project.workflowMode 2>/dev/null)"
128
129
  ```
129
130
 
130
131
  Inference rules (first match wins):
@@ -244,11 +245,12 @@ If the review is intentionally inline-only and the user explicitly wants to insp
244
245
 
245
246
  ### Step 2: Validate Artifacts Exist (Mode-Aware)
246
247
 
247
- Resolve workflow mode from state (default `spec-driven`):
248
+ Resolve workflow mode from the resolved project state path:
248
249
 
249
250
  ```bash
250
- WORKFLOW_MODE=$(grep "^oat_workflow_mode:" "$PROJECT_PATH/state.md" 2>/dev/null | head -1 | awk '{print $2}')
251
- WORKFLOW_MODE=${WORKFLOW_MODE:-spec-driven}
251
+ # Step 1.5 may retarget PROJECT_PATH into another worktree, so read from the
252
+ # resolved project path instead of the active-project pointer.
253
+ WORKFLOW_MODE=$(oat project status --project-path "$PROJECT_PATH" --field project.workflowMode 2>/dev/null || echo null)
252
254
  ```
253
255
 
254
256
  **Required for code review (by mode):**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/config/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGhF,OAAO,EACL,KAAK,SAAS,EACd,KAAK,cAAc,EAGnB,KAAK,UAAU,EAOhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsDpC,UAAU,yBAAyB;IACjC,mBAAmB,EAAE,CACnB,OAAO,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,KAC/C,cAAc,CAAC;IACpB,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,mBAAmB,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,cAAc,KACnB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/D,eAAe,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E,mBAAmB,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,sBAAsB,EAAE,CACtB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;CAC/B;AAskCD,wBAAgB,mBAAmB,CACjC,SAAS,GAAE,OAAO,CAAC,yBAAyB,CAAM,GACjD,OAAO,CA0GT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/config/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGhF,OAAO,EACL,KAAK,SAAS,EACd,KAAK,cAAc,EAGnB,KAAK,UAAU,EAOhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwDpC,UAAU,yBAAyB;IACjC,mBAAmB,EAAE,CACnB,OAAO,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,KAC/C,cAAc,CAAC;IACpB,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,mBAAmB,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,cAAc,KACnB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/D,eAAe,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E,mBAAmB,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,sBAAsB,EAAE,CACtB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;CAC/B;AAwmCD,wBAAgB,mBAAmB,CACjC,SAAS,GAAE,OAAO,CAAC,yBAAyB,CAAM,GACjD,OAAO,CA0GT"}
@@ -14,6 +14,8 @@ const KEY_ORDER = [
14
14
  'archive.s3SyncOnComplete',
15
15
  'archive.summaryExportPath',
16
16
  'archive.wrapUpExportPath',
17
+ 'archive.awsProfile',
18
+ 'archive.awsRegion',
17
19
  'autoReviewAtCheckpoints',
18
20
  'lastPausedProject',
19
21
  'documentation.root',
@@ -172,6 +174,28 @@ const CONFIG_CATALOG = [
172
174
  owningCommand: 'oat config set archive.wrapUpExportPath <value>',
173
175
  description: 'Repository-relative directory where the oat-wrap-up skill writes date-ranged shipping digests. When unset, the skill falls back to `.oat/repo/reference/wrap-ups`.',
174
176
  },
177
+ {
178
+ key: 'archive.awsProfile',
179
+ group: 'Shared Repo (.oat/config.json)',
180
+ file: '.oat/config.json',
181
+ scope: 'shared repo',
182
+ type: 'string',
183
+ defaultValue: 'unset',
184
+ mutability: 'read/write',
185
+ owningCommand: 'oat config set archive.awsProfile <value>',
186
+ description: 'AWS named profile forwarded as AWS_PROFILE to every `aws` invocation made by the archive S3 sync (completion + `oat project archive sync`). Precedence: per-invocation flag > existing shell env > this config value.',
187
+ },
188
+ {
189
+ key: 'archive.awsRegion',
190
+ group: 'Shared Repo (.oat/config.json)',
191
+ file: '.oat/config.json',
192
+ scope: 'shared repo',
193
+ type: 'string',
194
+ defaultValue: 'unset',
195
+ mutability: 'read/write',
196
+ owningCommand: 'oat config set archive.awsRegion <value>',
197
+ description: 'AWS region forwarded as AWS_REGION to every `aws` invocation made by the archive S3 sync (completion + `oat project archive sync`). Precedence: per-invocation flag > existing shell env > this config value.',
198
+ },
175
199
  {
176
200
  key: 'tools.core',
177
201
  group: 'Shared Repo (.oat/config.json)',
@@ -655,6 +679,16 @@ async function setConfigValue(repoRoot, userConfigDir, key, rawValue, surface, d
655
679
  else if (key === 'archive.wrapUpExportPath') {
656
680
  archive.wrapUpExportPath = normalizeSharedRoot(rawValue);
657
681
  }
682
+ else if (key === 'archive.awsProfile' || key === 'archive.awsRegion') {
683
+ const subKey = key.slice('archive.'.length);
684
+ const trimmed = rawValue.trim();
685
+ if (trimmed === '') {
686
+ delete archive[subKey];
687
+ }
688
+ else {
689
+ archive[subKey] = trimmed;
690
+ }
691
+ }
658
692
  await dependencies.writeOatConfig(repoRoot, {
659
693
  ...config,
660
694
  archive,
@@ -11,6 +11,23 @@ export interface EnsureS3ArchiveAccessOptions {
11
11
  mode: 'completion' | 'sync';
12
12
  s3Uri?: string | null;
13
13
  syncOnComplete: boolean;
14
+ /**
15
+ * Config-only fallback AWS profile (e.g., `archive.awsProfile`). This helper
16
+ * applies the value only when the parent env does not already provide
17
+ * `AWS_PROFILE`, matching discovery decision #3 ("config does not clobber an
18
+ * explicit shell env"). Callers that override via flags must layer the
19
+ * override into `dependencies.env` (the helper's second argument) —
20
+ * `buildAwsEnv` is non-clobbering and will not overwrite a value already
21
+ * present in the parent env. Passing a flag value through this option alone
22
+ * is not sufficient.
23
+ */
24
+ awsProfile?: string | null;
25
+ /**
26
+ * Config-only fallback AWS region. Same non-clobbering semantics as
27
+ * `awsProfile`: flag-style overrides must be layered into
28
+ * `dependencies.env`, not passed through this option.
29
+ */
30
+ awsRegion?: string | null;
14
31
  }
15
32
  interface EnsureS3ArchiveAccessDependencies {
16
33
  execFile?: ExecFileLike;
@@ -28,6 +45,17 @@ export interface ArchiveProjectOnCompletionOptions {
28
45
  s3Uri?: string | null;
29
46
  s3SyncOnComplete: boolean;
30
47
  summaryExportPath?: string | null;
48
+ /**
49
+ * Config-only AWS profile (`archive.awsProfile`). The completion path has no
50
+ * flag override; this value is forwarded as-is into the env merge, where the
51
+ * parent env wins if it already supplies `AWS_PROFILE`. Discovery decision #3.
52
+ */
53
+ awsProfile?: string | null;
54
+ /**
55
+ * Config-only AWS region (`archive.awsRegion`). Same non-clobbering semantics
56
+ * as `awsProfile`.
57
+ */
58
+ awsRegion?: string | null;
31
59
  }
32
60
  interface ArchiveProjectOnCompletionDependencies extends EnsureS3ArchiveAccessDependencies {
33
61
  ensureS3ArchiveAccess?: typeof ensureS3ArchiveAccess;
@@ -60,6 +88,31 @@ export interface ArchiveSnapshotMetadata {
60
88
  projectName: string;
61
89
  snapshotName: string;
62
90
  }
91
+ /**
92
+ * Build the env passed to every `aws` spawn in this module.
93
+ *
94
+ * Non-clobbering merge: a non-empty value in `opts` is applied only when
95
+ * `parentEnv` does not already provide that key (treating empty/whitespace
96
+ * parent values as unset). If parent env has a non-empty value, it is left
97
+ * untouched even when `opts` supplies a non-empty value. Callers that need
98
+ * flag-style overrides must set the env entry themselves before calling this
99
+ * helper. This matches discovery decision #3 — config does not clobber an
100
+ * explicit shell env.
101
+ *
102
+ * An empty/whitespace value in `opts` is also treated as unset, and we never
103
+ * inject a key when neither source supplies one — so the spawned process sees
104
+ * the same "unset" signal it would have seen without this plumbing.
105
+ *
106
+ * Exported as a package-internal helper so the archive sync command (which
107
+ * also spawns `aws`) can layer flag/env/config precedence and produce the same
108
+ * env shape without duplicating this logic. This symbol is **not** part of the
109
+ * public package surface — keep usage limited to files inside
110
+ * `commands/project/archive/`.
111
+ */
112
+ export declare function buildAwsEnv(parentEnv: NodeJS.ProcessEnv, opts: {
113
+ awsProfile?: string | null;
114
+ awsRegion?: string | null;
115
+ }): NodeJS.ProcessEnv;
63
116
  export declare function buildRepoArchiveS3Uri(s3Uri: string, repoRoot: string): string;
64
117
  export declare function buildProjectArchiveS3Uri(s3Uri: string, repoRoot: string, projectKey: string): string;
65
118
  export declare function buildArchiveSnapshotName(projectName: string, timestamp: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"archive-utils.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/archive/archive-utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"archive-utils.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/archive/archive-utils.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,aAAa,EACb,cAAc,EACd,SAAS,EACT,SAAS,EACT,UAAU,EACX,MAAM,QAAQ,CAAC;AAIhB,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CAAE,KAChD,OAAO,CAAC,cAAc,CAAC,CAAC;AAE7B,MAAM,WAAW,4BAA4B;IAC3C,IAAI,EAAE,YAAY,GAAG,MAAM,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,UAAU,iCAAiC;IACzC,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED,MAAM,WAAW,2BAA2B;IAC1C,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,iCAAiC;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,UAAU,sCAAuC,SAAQ,iCAAiC;IACxF,qBAAqB,CAAC,EAAE,OAAO,qBAAqB,CAAC;IACrD,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,SAAS,CAAC;IAC7B,aAAa,CAAC,EAAE,OAAO,aAAa,CAAC;IACrC,UAAU,CAAC,EAAE,CACX,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;QAAE,SAAS,EAAE,IAAI,CAAC;QAAC,KAAK,EAAE,IAAI,CAAA;KAAE,KACtC,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,cAAc,CAAC;IACvC,SAAS,CAAC,EAAE,OAAO,SAAS,CAAC;IAC7B,UAAU,CAAC,EAAE,OAAO,UAAU,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,gCAAgC;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,eAAO,MAAM,kCAAkC,6BAA6B,CAAC;AAE7E;;;GAGG;AACH,eAAO,MAAM,wBAAwB,UAAwB,CAAC;AAE9D,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAMD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,MAAM,CAAC,UAAU,EAC5B,IAAI,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC9D,MAAM,CAAC,UAAU,CAqBnB;AA0BD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAER;AAmBD,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,MAAM,CAER;AAED,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,MAAM,GAAG;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CA4BA;AAED,wBAAgB,8BAA8B,CAC5C,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,GAClB,MAAM,CAIR;AA4JD,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,iCAAiC,EAC1C,YAAY,GAAE,sCAA2C,GACxD,OAAO,CAAC,gCAAgC,CAAC,CA6G3C;AAED,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,4BAA4B,EACrC,YAAY,GAAE,iCAAsC,GACnD,OAAO,CAAC,2BAA2B,CAAC,CA+CtC"}
@@ -14,6 +14,43 @@ export const S3_ARCHIVE_SYNC_EXCLUDES = ['reviews/*', 'pr/*'];
14
14
  function normalizeS3Uri(s3Uri) {
15
15
  return s3Uri.trim().replace(/\/+$/, '');
16
16
  }
17
+ /**
18
+ * Build the env passed to every `aws` spawn in this module.
19
+ *
20
+ * Non-clobbering merge: a non-empty value in `opts` is applied only when
21
+ * `parentEnv` does not already provide that key (treating empty/whitespace
22
+ * parent values as unset). If parent env has a non-empty value, it is left
23
+ * untouched even when `opts` supplies a non-empty value. Callers that need
24
+ * flag-style overrides must set the env entry themselves before calling this
25
+ * helper. This matches discovery decision #3 — config does not clobber an
26
+ * explicit shell env.
27
+ *
28
+ * An empty/whitespace value in `opts` is also treated as unset, and we never
29
+ * inject a key when neither source supplies one — so the spawned process sees
30
+ * the same "unset" signal it would have seen without this plumbing.
31
+ *
32
+ * Exported as a package-internal helper so the archive sync command (which
33
+ * also spawns `aws`) can layer flag/env/config precedence and produce the same
34
+ * env shape without duplicating this logic. This symbol is **not** part of the
35
+ * public package surface — keep usage limited to files inside
36
+ * `commands/project/archive/`.
37
+ */
38
+ export function buildAwsEnv(parentEnv, opts) {
39
+ const env = { ...parentEnv };
40
+ const parentHas = (key) => {
41
+ const value = parentEnv[key];
42
+ return typeof value === 'string' && value.trim().length > 0;
43
+ };
44
+ const profile = typeof opts.awsProfile === 'string' ? opts.awsProfile.trim() : '';
45
+ if (profile.length > 0 && !parentHas('AWS_PROFILE')) {
46
+ env.AWS_PROFILE = profile;
47
+ }
48
+ const region = typeof opts.awsRegion === 'string' ? opts.awsRegion.trim() : '';
49
+ if (region.length > 0 && !parentHas('AWS_REGION')) {
50
+ env.AWS_REGION = region;
51
+ }
52
+ return env;
53
+ }
17
54
  function resolveRepoSlug(repoRoot) {
18
55
  return basename(repoRoot).trim().replace(/\s+/g, '-');
19
56
  }
@@ -219,6 +256,8 @@ export async function archiveProjectOnCompletion(options, dependencies = {}) {
219
256
  mode: 'completion',
220
257
  s3Uri: options.s3Uri,
221
258
  syncOnComplete: options.s3SyncOnComplete,
259
+ awsProfile: options.awsProfile,
260
+ awsRegion: options.awsRegion,
222
261
  }, {
223
262
  execFile,
224
263
  env: dependencies.env,
@@ -233,7 +272,10 @@ export async function archiveProjectOnCompletion(options, dependencies = {}) {
233
272
  }
234
273
  await execFile('aws', syncArgs, {
235
274
  cwd: options.repoRoot,
236
- env: dependencies.env ?? process.env,
275
+ env: buildAwsEnv(dependencies.env ?? process.env, {
276
+ awsProfile: options.awsProfile,
277
+ awsRegion: options.awsRegion,
278
+ }),
237
279
  });
238
280
  }
239
281
  catch (error) {
@@ -255,7 +297,12 @@ export async function ensureS3ArchiveAccess(options, dependencies = {}) {
255
297
  return { ok: true, warnings: [] };
256
298
  }
257
299
  const execFile = dependencies.execFile ?? execFileAsync;
258
- const execOptions = { env: dependencies.env ?? process.env };
300
+ const execOptions = {
301
+ env: buildAwsEnv(dependencies.env ?? process.env, {
302
+ awsProfile: options.awsProfile,
303
+ awsRegion: options.awsRegion,
304
+ }),
305
+ };
259
306
  try {
260
307
  await execFile('aws', ['--version'], execOptions);
261
308
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/archive/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAIhD,OAAO,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGhF,OAAO,EAAE,KAAK,SAAS,EAAiB,MAAM,oBAAoB,CAAC;AAGnE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAGL,wBAAwB,EACxB,qBAAqB,EACrB,qBAAqB,EACrB,KAAK,YAAY,EAEjB,8BAA8B,EAC/B,MAAM,iBAAiB,CAAC;AASzB,MAAM,WAAW,iCAAiC;IAChD,mBAAmB,EAAE,CACnB,OAAO,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,KAC/C,cAAc,CAAC;IACpB,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,mBAAmB,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,qBAAqB,EAAE,OAAO,qBAAqB,CAAC;IACpD,qBAAqB,EAAE,OAAO,qBAAqB,CAAC;IACpD,wBAAwB,EAAE,OAAO,wBAAwB,CAAC;IAC1D,8BAA8B,EAAE,OAAO,8BAA8B,CAAC;IACtE,QAAQ,EAAE,YAAY,CAAC;IACvB,eAAe,EAAE,OAAO,EAAE,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;CAC/B;AAwLD,wBAAgB,2BAA2B,CACzC,SAAS,GAAE,OAAO,CAAC,iCAAiC,CAAM,GACzD,OAAO,CAuKT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/archive/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAIhD,OAAO,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGhF,OAAO,EAAE,KAAK,SAAS,EAAiB,MAAM,oBAAoB,CAAC;AAGnE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAIL,wBAAwB,EACxB,qBAAqB,EACrB,qBAAqB,EACrB,KAAK,YAAY,EAEjB,8BAA8B,EAC/B,MAAM,iBAAiB,CAAC;AAsEzB,MAAM,WAAW,iCAAiC;IAChD,mBAAmB,EAAE,CACnB,OAAO,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,KAC/C,cAAc,CAAC;IACpB,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,mBAAmB,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,qBAAqB,EAAE,OAAO,qBAAqB,CAAC;IACpD,qBAAqB,EAAE,OAAO,qBAAqB,CAAC;IACpD,wBAAwB,EAAE,OAAO,wBAAwB,CAAC;IAC1D,8BAA8B,EAAE,OAAO,8BAA8B,CAAC;IACtE,QAAQ,EAAE,YAAY,CAAC;IACvB,eAAe,EAAE,OAAO,EAAE,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;CAC/B;AA4LD,wBAAgB,2BAA2B,CACzC,SAAS,GAAE,OAAO,CAAC,iCAAiC,CAAM,GACzD,OAAO,CAsLT"}
@@ -9,8 +9,51 @@ import { readOatConfig } from '../../../config/oat-config.js';
9
9
  import { CliError } from '../../../errors/cli-error.js';
10
10
  import { resolveProjectRoot } from '../../../fs/paths.js';
11
11
  import { Command } from 'commander';
12
- import { ARCHIVE_SNAPSHOT_METADATA_FILENAME, S3_ARCHIVE_SYNC_EXCLUDES, buildProjectArchiveS3Uri, buildRepoArchiveS3Uri, ensureS3ArchiveAccess, parseArchiveSnapshotName, resolveLocalArchiveProjectPath, } from './archive-utils.js';
12
+ import { ARCHIVE_SNAPSHOT_METADATA_FILENAME, S3_ARCHIVE_SYNC_EXCLUDES, buildAwsEnv, buildProjectArchiveS3Uri, buildRepoArchiveS3Uri, ensureS3ArchiveAccess, parseArchiveSnapshotName, resolveLocalArchiveProjectPath, } from './archive-utils.js';
13
13
  const execFileAsync = promisify(execFileCallback);
14
+ /**
15
+ * Resolve effective AWS profile/region for an archive sync invocation, honoring
16
+ * the discovery decision #3 precedence: flag > parent shell env > config.
17
+ *
18
+ * The returned `env` is suitable for passing into every `aws` spawn in this
19
+ * command. The returned `awsProfile`/`awsRegion` are forwarded to
20
+ * `ensureS3ArchiveAccess` so its non-clobbering merge sees the same source of
21
+ * truth (parent env wins inside the helper, so injecting the flag value into
22
+ * the env up-front is what makes "flag > parent env" hold end-to-end).
23
+ */
24
+ function resolveSyncAwsEnv(processEnv, options, config) {
25
+ const flagProfile = typeof options.profile === 'string' && options.profile.trim().length > 0
26
+ ? options.profile.trim()
27
+ : undefined;
28
+ const flagRegion = typeof options.region === 'string' && options.region.trim().length > 0
29
+ ? options.region.trim()
30
+ : undefined;
31
+ // Layer the flag onto the parent env BEFORE delegating to buildAwsEnv. The
32
+ // helper's non-clobbering rule treats parent env as authoritative, so this
33
+ // is how the flag wins over both parent env and config.
34
+ const effectiveParent = { ...processEnv };
35
+ if (flagProfile !== undefined) {
36
+ effectiveParent.AWS_PROFILE = flagProfile;
37
+ }
38
+ if (flagRegion !== undefined) {
39
+ effectiveParent.AWS_REGION = flagRegion;
40
+ }
41
+ const configProfile = config.archive?.awsProfile;
42
+ const configRegion = config.archive?.awsRegion;
43
+ // Forward the same precedence into `awsProfile`/`awsRegion` for downstream
44
+ // helpers: prefer flag, fall back to config. Parent env is *not* substituted
45
+ // here because callers will pass the returned `env` (which already has the
46
+ // flag layered onto a clone of the parent env) as `dependencies.env` to the
47
+ // helper, so `buildAwsEnv`'s non-clobbering rule preserves "flag > parent
48
+ // env > config" against `effectiveParent` rather than the raw `process.env`.
49
+ const awsProfile = flagProfile ?? configProfile ?? undefined;
50
+ const awsRegion = flagRegion ?? configRegion ?? undefined;
51
+ const env = buildAwsEnv(effectiveParent, {
52
+ awsProfile,
53
+ awsRegion,
54
+ });
55
+ return { env, awsProfile, awsRegion };
56
+ }
14
57
  function defaultDependencies() {
15
58
  return {
16
59
  buildCommandContext,
@@ -39,17 +82,17 @@ function buildArchiveSyncArgs(source, target, options) {
39
82
  }
40
83
  return args;
41
84
  }
42
- async function runArchiveSync(repoRoot, source, target, options, dependencies) {
85
+ async function runArchiveSync(repoRoot, source, target, options, awsEnv, dependencies) {
43
86
  await dependencies.execFile('aws', buildArchiveSyncArgs(source, target, options), {
44
87
  cwd: repoRoot,
45
- env: dependencies.processEnv,
88
+ env: awsEnv,
46
89
  });
47
90
  }
48
- async function listArchiveSnapshots(repoRoot, projectsRoot, s3Uri, dependencies) {
91
+ async function listArchiveSnapshots(repoRoot, projectsRoot, s3Uri, awsEnv, dependencies) {
49
92
  const repoPrefix = `${dependencies.buildRepoArchiveS3Uri(s3Uri, repoRoot)}/`;
50
93
  const { stdout } = await dependencies.execFile('aws', ['s3', 'ls', repoPrefix], {
51
94
  cwd: repoRoot,
52
- env: dependencies.processEnv,
95
+ env: awsEnv,
53
96
  });
54
97
  return stdout
55
98
  .split('\n')
@@ -96,7 +139,7 @@ async function readLocalSnapshotName(repoRoot, target) {
96
139
  return null;
97
140
  }
98
141
  }
99
- async function syncArchiveSnapshot(repoRoot, snapshot, options, dependencies) {
142
+ async function syncArchiveSnapshot(repoRoot, snapshot, options, awsEnv, dependencies) {
100
143
  const currentSnapshotName = await readLocalSnapshotName(repoRoot, snapshot.target);
101
144
  if (!options.force && currentSnapshotName === snapshot.snapshotName) {
102
145
  return false;
@@ -107,7 +150,7 @@ async function syncArchiveSnapshot(repoRoot, snapshot, options, dependencies) {
107
150
  force: true,
108
151
  });
109
152
  }
110
- await runArchiveSync(repoRoot, snapshot.source, snapshot.target, options, dependencies);
153
+ await runArchiveSync(repoRoot, snapshot.source, snapshot.target, options, awsEnv, dependencies);
111
154
  return true;
112
155
  }
113
156
  export function createProjectArchiveCommand(overrides = {}) {
@@ -122,6 +165,8 @@ export function createProjectArchiveCommand(overrides = {}) {
122
165
  .argument('[project-name]', 'Archived project name to sync')
123
166
  .option('--dry-run', 'Preview archive sync without downloading')
124
167
  .option('--force', 'Replace the named local archive before syncing it from S3')
168
+ .option('--profile <profile>', 'AWS profile override for this sync')
169
+ .option('--region <region>', 'AWS region override for this sync')
125
170
  .action(async (projectName, options, command) => {
126
171
  const context = dependencies.buildCommandContext(readGlobalOptions(command));
127
172
  try {
@@ -134,13 +179,16 @@ export function createProjectArchiveCommand(overrides = {}) {
134
179
  if (!s3Uri) {
135
180
  throw new CliError('Archive sync requires `archive.s3Uri` to be configured. Set it with `oat config set archive.s3Uri <s3://...>` and retry.');
136
181
  }
182
+ const { env: awsEnv, awsProfile, awsRegion, } = resolveSyncAwsEnv(dependencies.processEnv, options, config);
137
183
  await dependencies.ensureS3ArchiveAccess({
138
184
  mode: 'sync',
139
185
  s3Uri,
140
186
  syncOnComplete: config.archive?.s3SyncOnComplete ?? false,
141
- });
187
+ awsProfile,
188
+ awsRegion,
189
+ }, { env: awsEnv });
142
190
  const projectsRoot = await dependencies.resolveProjectsRoot(repoRoot, dependencies.processEnv);
143
- const snapshots = await listArchiveSnapshots(repoRoot, projectsRoot, s3Uri, dependencies);
191
+ const snapshots = await listArchiveSnapshots(repoRoot, projectsRoot, s3Uri, awsEnv, dependencies);
144
192
  const targets = projectName
145
193
  ? snapshots.filter((snapshot) => snapshot.projectName === projectName ||
146
194
  snapshot.snapshotName === projectName)
@@ -169,7 +217,7 @@ export function createProjectArchiveCommand(overrides = {}) {
169
217
  if (!snapshot) {
170
218
  continue;
171
219
  }
172
- const synced = await syncArchiveSnapshot(repoRoot, snapshot, options, dependencies);
220
+ const synced = await syncArchiveSnapshot(repoRoot, snapshot, options, awsEnv, dependencies);
173
221
  if (synced) {
174
222
  appliedTargets.push(snapshot.target);
175
223
  appliedSources.push(snapshot.source);
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/commands/project/status.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAEL,KAAK,YAAY,EAClB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,UAAU,yBAAyB;IACjC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,oBAAoB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC7E,eAAe,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;CACjE;AAmFD,wBAAgB,0BAA0B,CACxC,SAAS,GAAE,OAAO,CAAC,yBAAyB,CAAM,GACjD,OAAO,CAcT"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/commands/project/status.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAEL,KAAK,YAAY,EAClB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,UAAU,yBAAyB;IACjC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,oBAAoB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC7E,eAAe,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;CACjE;AAgND,wBAAgB,0BAA0B,CACxC,SAAS,GAAE,OAAO,CAAC,yBAAyB,CAAM,GACjD,OAAO,CA0BT"}
@@ -1,4 +1,4 @@
1
- import { join } from 'node:path';
1
+ import { isAbsolute, join } from 'node:path';
2
2
  import { buildCommandContext, } from '../../app/command-context.js';
3
3
  import { readGlobalOptions } from '../shared/shared.utils.js';
4
4
  import { resolveActiveProject, } from '../../config/oat-config.js';
@@ -11,6 +11,9 @@ const DEFAULT_DEPENDENCIES = {
11
11
  resolveActiveProject,
12
12
  getProjectState,
13
13
  };
14
+ function resolveTargetProjectPath(repoRoot, projectPath) {
15
+ return isAbsolute(projectPath) ? projectPath : join(repoRoot, projectPath);
16
+ }
14
17
  function formatProjectStatusLines(project) {
15
18
  return [
16
19
  `Project: ${project.name}`,
@@ -22,9 +25,61 @@ function formatProjectStatusLines(project) {
22
25
  `Reason: ${project.recommendation.reason}`,
23
26
  ];
24
27
  }
25
- async function runProjectStatus(context, dependencies) {
28
+ function readDotPath(payload, path) {
29
+ const parts = path.split('.').filter(Boolean);
30
+ let cursor = payload;
31
+ for (const part of parts) {
32
+ if (cursor === null || typeof cursor !== 'object') {
33
+ return undefined;
34
+ }
35
+ if (!Object.prototype.hasOwnProperty.call(cursor, part)) {
36
+ return undefined;
37
+ }
38
+ cursor = cursor[part];
39
+ }
40
+ return cursor;
41
+ }
42
+ function formatRawValue(value) {
43
+ if (value === null || value === undefined) {
44
+ return 'null';
45
+ }
46
+ if (typeof value === 'string' ||
47
+ typeof value === 'number' ||
48
+ typeof value === 'boolean') {
49
+ return String(value);
50
+ }
51
+ return JSON.stringify(value);
52
+ }
53
+ function shellQuote(value) {
54
+ return `'${value.split("'").join("'\\''")}'`;
55
+ }
56
+ const SHELL_ASSIGNMENT_RE = /^([A-Za-z_][A-Za-z0-9_]*)=(.+)$/;
57
+ function formatShellAssignment(assignment, payload) {
58
+ const match = SHELL_ASSIGNMENT_RE.exec(assignment);
59
+ if (!match) {
60
+ return null;
61
+ }
62
+ const name = match[1];
63
+ const path = match[2];
64
+ if (!name || !path) {
65
+ return null;
66
+ }
67
+ const value = formatRawValue(readDotPath(payload, path));
68
+ return `${name}=${shellQuote(value)}`;
69
+ }
70
+ async function runProjectStatus(context, dependencies, options) {
26
71
  try {
72
+ if (options.projectPath && isAbsolute(options.projectPath)) {
73
+ const project = await dependencies.getProjectState(options.projectPath);
74
+ writeProjectStatusOutput(context, options, { status: 'ok', project });
75
+ return;
76
+ }
27
77
  const repoRoot = await dependencies.resolveProjectRoot(context.cwd);
78
+ if (options.projectPath) {
79
+ const project = await dependencies.getProjectState(resolveTargetProjectPath(repoRoot, options.projectPath));
80
+ writeProjectStatusOutput(context, options, { status: 'ok', project });
81
+ return;
82
+ }
28
83
  const activeProject = await dependencies.resolveActiveProject(repoRoot);
29
84
  if (activeProject.status === 'unset') {
30
85
  const message = 'No active project set (.oat/config.local.json has no activeProject).';
@@ -56,15 +111,7 @@ async function runProjectStatus(context, dependencies) {
56
111
  return;
57
112
  }
58
113
  const project = await dependencies.getProjectState(join(repoRoot, activeProject.path));
59
- if (context.json) {
60
- context.logger.json({ status: 'ok', project });
61
- }
62
- else {
63
- for (const line of formatProjectStatusLines(project)) {
64
- context.logger.info(line);
65
- }
66
- }
67
- process.exitCode = 0;
114
+ writeProjectStatusOutput(context, options, { status: 'ok', project });
68
115
  }
69
116
  catch (error) {
70
117
  const message = error instanceof Error ? error.message : String(error);
@@ -77,6 +124,44 @@ async function runProjectStatus(context, dependencies) {
77
124
  process.exitCode = 1;
78
125
  }
79
126
  }
127
+ function writeProjectStatusOutput(context, options, payload) {
128
+ if (options.field && options.shell?.length) {
129
+ context.logger.error('`--field` and `--shell` are mutually exclusive; pass only one.');
130
+ process.exitCode = 1;
131
+ return;
132
+ }
133
+ if (options.field) {
134
+ context.logger.info(formatRawValue(readDotPath(payload, options.field)));
135
+ process.exitCode = 0;
136
+ return;
137
+ }
138
+ if (options.shell?.length) {
139
+ const lines = [];
140
+ for (const assignment of options.shell) {
141
+ const line = formatShellAssignment(assignment, payload);
142
+ if (!line) {
143
+ context.logger.error(`Invalid shell assignment "${assignment}". Expected NAME=path with a shell-safe variable name.`);
144
+ process.exitCode = 1;
145
+ return;
146
+ }
147
+ lines.push(line);
148
+ }
149
+ for (const line of lines) {
150
+ context.logger.info(line);
151
+ }
152
+ process.exitCode = 0;
153
+ return;
154
+ }
155
+ if (context.json) {
156
+ context.logger.json(payload);
157
+ }
158
+ else {
159
+ for (const line of formatProjectStatusLines(payload.project)) {
160
+ context.logger.info(line);
161
+ }
162
+ }
163
+ process.exitCode = 0;
164
+ }
80
165
  export function createProjectStatusCommand(overrides = {}) {
81
166
  const dependencies = {
82
167
  ...DEFAULT_DEPENDENCIES,
@@ -84,8 +169,11 @@ export function createProjectStatusCommand(overrides = {}) {
84
169
  };
85
170
  return new Command('status')
86
171
  .description('Show the current OAT project state')
87
- .action(async (_options, command) => {
172
+ .option('--field <path>', 'Print a single field from the project status payload by dot path')
173
+ .option('--project-path <path>', 'Read status from an explicit project path instead of the active project')
174
+ .option('--shell <assignment...>', 'Print shell-safe NAME=value assignments for one or more NAME=path pairs')
175
+ .action(async (options, command) => {
88
176
  const context = dependencies.buildCommandContext(readGlobalOptions(command));
89
- await runProjectStatus(context, dependencies);
177
+ await runProjectStatus(context, dependencies, options);
90
178
  });
91
179
  }
@@ -13,6 +13,8 @@ export interface OatArchiveConfig {
13
13
  s3SyncOnComplete?: boolean;
14
14
  summaryExportPath?: string;
15
15
  wrapUpExportPath?: string;
16
+ awsProfile?: string;
17
+ awsRegion?: string;
16
18
  }
17
19
  export type WorkflowHillCheckpointDefault = 'every' | 'final';
18
20
  export type WorkflowPostImplementSequence = 'wait' | 'summary' | 'pr' | 'docs-pr';
@@ -1 +1 @@
1
- {"version":3,"file":"oat-config.d.ts","sourceRoot":"","sources":["../../src/config/oat-config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"oat-config.d.ts","sourceRoot":"","sources":["../../src/config/oat-config.ts"],"names":[],"mappings":"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"}
@@ -74,6 +74,13 @@ function isMissingFileError(error) {
74
74
  function trimPathValue(value) {
75
75
  return value.replace(/\/+$/, '').replace(/^\.\//, '').trim();
76
76
  }
77
+ function trimNonEmptyString(value) {
78
+ if (typeof value !== 'string') {
79
+ return undefined;
80
+ }
81
+ const trimmed = value.trim();
82
+ return trimmed.length > 0 ? trimmed : undefined;
83
+ }
77
84
  function normalizeProjectPath(repoRoot, pathValue) {
78
85
  if (pathValue == null) {
79
86
  return null;
@@ -143,6 +150,14 @@ function normalizeOatConfig(parsed) {
143
150
  parsed.archive.wrapUpExportPath.trim()) {
144
151
  archive.wrapUpExportPath = normalizeToPosixPath(parsed.archive.wrapUpExportPath.trim().replace(/\/+$/, ''));
145
152
  }
153
+ const awsProfile = trimNonEmptyString(parsed.archive.awsProfile);
154
+ if (awsProfile !== undefined) {
155
+ archive.awsProfile = awsProfile;
156
+ }
157
+ const awsRegion = trimNonEmptyString(parsed.archive.awsRegion);
158
+ if (awsRegion !== undefined) {
159
+ archive.awsRegion = awsRegion;
160
+ }
146
161
  if (Object.keys(archive).length > 0) {
147
162
  next.archive = archive;
148
163
  }
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/config/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AAEtB,MAAM,MAAM,oBAAoB,GAC5B,QAAQ,GACR,OAAO,GACP,MAAM,GACN,KAAK,GACL,SAAS,CAAC;AAEd,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,oBAAoB,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,cAAc,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,kCAAkC;IACjD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CAChE;AAiED,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,SAAS,GAAE,OAAO,CAAC,kCAAkC,CAAM,GAC1D,OAAO,CAAC,cAAc,CAAC,CAgFzB"}
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/config/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AAEtB,MAAM,MAAM,oBAAoB,GAC5B,QAAQ,GACR,OAAO,GACP,MAAM,GACN,KAAK,GACL,SAAS,CAAC;AAEd,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,oBAAoB,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,cAAc,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,kCAAkC;IACjD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CAChE;AAmED,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,SAAS,GAAE,OAAO,CAAC,kCAAkC,CAAM,GAC1D,OAAO,CAAC,cAAc,CAAC,CAgFzB"}
@@ -13,6 +13,8 @@ const DEFAULT_SHARED_CONFIG = {
13
13
  s3SyncOnComplete: false,
14
14
  summaryExportPath: null,
15
15
  wrapUpExportPath: null,
16
+ awsProfile: null,
17
+ awsRegion: null,
16
18
  },
17
19
  documentation: {
18
20
  root: null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-agent-toolkit/cli",
3
- "version": "0.0.54",
3
+ "version": "0.0.56",
4
4
  "private": false,
5
5
  "description": "Open Agent Toolkit CLI",
6
6
  "homepage": "https://github.com/voxmedia/open-agent-toolkit/tree/main/packages/cli",
@@ -33,7 +33,7 @@
33
33
  "ora": "^9.0.0",
34
34
  "yaml": "2.8.2",
35
35
  "zod": "^3.25.76",
36
- "@open-agent-toolkit/control-plane": "0.0.54"
36
+ "@open-agent-toolkit/control-plane": "0.0.56"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/node": "^22.10.0",