Skip to content

Merging dev into main - #9

Merged
aboutte merged 29 commits into
mainfrom
dev
Sep 28, 2026
Merged

aboutte merged 29 commits into
mainfrom
dev

Conversation

@aboutte

@aboutte aboutte commented Sep 23, 2026

Copy link
Copy Markdown
Collaborator

What this changes

How it was verified

  • ./run.sh --reset, then built and deployed a sample end to end
  • ./scripts/build-extension.sh on the affected sample, then deployed it and created one in the UI
  • npm ci && npm run build in the affected frontend/
  • ./stop.sh --wipe && ./run.sh from a clean slate
  • Ran /duplo-extension and confirmed the guidance still matches reality
  • Docs only — no runtime behaviour changed
Output
paste the relevant command output here

Blast radius

  • This changes .env.example — image tags or ports here are adopted into every user's
    .env on their next ./run.sh after an upgrade. Say so plainly above.
  • This changes scripts/upgrade_dev_kit.sh or scripts/init-project.sh — the adoption path
  • This changes a workflow under .github/workflows/
  • None of the above

Checks

  • No .env, tokens, keys, or customer identifiers in the diff
  • No build output committed — dist/, node_modules/, **/bin/, **/obj/, backend/sdk-packages/
  • Commits are conventional, imperative, and focused
  • If a vendored ng-common-lib tarball was added or bumped, its NOTICE sits beside it

helpdesk-dev-pipeline and others added 14 commits September 20, 2026 20:33
…tion)

Run the dev-kit agent on your own Claude Code subscription instead of a
separately-billed API key, so ticket work and local extension development
bill to the same place.

The agent embeds the Claude Code CLI, so it can authenticate this way. It
needs a long-lived token from `claude setup-token`, which has to be minted
on the developer's own machine because it opens a browser — it is not the
short-lived credential in the OS keychain, and not an sk-ant-api… API key.
Those are three different auth schemes to the CLI.

Requires the matching agent-side change (CLAUDE_CODE_OAUTH_TOKEN branch in
core/agent_setup/llm_provider.py). Until an agent image carrying that ships,
selecting this provider writes the right .env and the agent still falls
through to Bedrock.

- scripts/_provider_subscription.sh — the arm itself, factored out like the
  gateway arm: prompt, token-shape validation, and the load-bearing blanks.
  Subscription auth sits next-to-last in the agent's precedence chain, on
  purpose — a token exported in someone's shell must never displace a
  deliberately configured provider. The cost is that this arm has to clear
  ANTHROPIC_API_KEY and ANTHROPIC_BASE_URL, or either would win the chain
  and the token would never be read; same load-bearing blanking as
  bedrock-instance-role's AWS keys.
- run.sh — menu option 5, --model subscription, --subscription-token,
  --subscription-model, the --reset key list, and the startup summary.
- scripts/switch-llm.sh — switch to and from it in place, with the usual
  credential stashing.
- docker-compose.yml, .env.example, docs/configuration.md,
  docs/cli-reference.md — passthrough and documentation.

Two rough edges are caught rather than left to fail obscurely: an
sk-ant-api… key pasted at the prompt gets a note (it would otherwise be
sent as a bearer token and 401), and a us.anthropic.* inference-profile id
carried over from a Bedrock run is replaced with the bare default (the
first-party API rejects the prefix outright).

Ticket titles are not generated on this path, as on the anthropic and
gateway arms: the title LLM is Bedrock-only and no-ops without AWS
credentials. Documented at each mention rather than fixed here.

tests/test-provider-subscription.sh (11 checks) and
tests/test-run-subscription-wiring.sh (11 checks) mirror the gateway
suites; the existing gateway suites still pass (16 + 9). shellcheck clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…al dashboard UI

The preset instructions didn't match what the OpenRouter dashboard
actually shows, which made them unfollowable:

- Presets live under the workspace sidebar, not Settings
- The provider pin is the 'only' checklist — the form has three
  look-alike checklists (order/only/ignore) and the doc never said
  which one; ticking 'order' pins nothing
- 'Allow fallbacks' is a separate dropdown much further down the form

Rewritten around the three sections you actually touch, with a
screenshot per step and the exact pinning JSON to expect after save.
Section 4 gains the validated one-shot ./run.sh flag form and the
model context windows (incl. glm-5.1 = 204800).

Validated end-to-end 2026-09-22: preset created in the UI, pin
confirmed via curl (provider: Nebius), dev kit started with
--model gateway, agent turn on the ticket answered by the pinned
provider.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
docs(hackday): rewrite Crusoe/Nebius OpenRouter steps to match the real dashboard UI
The three create calls in run.sh piped `curl -fsS ... | python3
json.load(sys.stdin)["data"]["id"]`. On a 4xx, -f makes curl print
nothing, so the studio's explanation was discarded and the run ended
with a bare `curl: (22) ... 400` plus a JSONDecodeError traceback from
python reading empty stdin.

Add scripts/_studio_api.sh with studio_create_id, which keeps the
response body, prints the server's message/errors on stderr (tagged
with the error code, e.g. license_limit_exceeded) and returns
non-zero. An expired license now reports "This DuploCloud AI Studio
instance's license has expired..." instead of a traceback.

The workspace create is fatal since everything after it depends on the
id; the permission set and group creates warn and continue, as before.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
feat(agent-skills): add Codex skills symlink
.agents/skills -> ../.claude/skills (the Codex skills symlink added for
GitHub Copilot/Codex support) was missing from FRAMEWORK_DIRS, so
upgrade_dev_kit.sh silently skipped it on every already-adopted repo.
Fresh clones got the symlink from git directly; upgrades never did.

Verified against a simulated pre-PR adopter repo: the unpatched script
exits 0 and reports "Framework upgraded" without ever creating
.agents. With this fix it rsyncs the symlink in on the next upgrade
run (the very first upgrade after this lands will still miss it once,
since scripts/ itself only updates that same run — a second run picks
it up).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
fix(scripts): include .agents in upgrade_dev_kit.sh framework dirs
Bump the vendored platform UI library from 0.2.0 to 0.3.0 for every
sample and the extension skill template. The release is additive: no
export the samples use was removed or changed shape.

Pin ngx-monaco-editor-v2 to 22.0.4. Its 22.0.5 release raised the
monaco-editor peer to ^0.56.0, which the library's ^0.55.1 excludes, so
a fresh install failed with ERESOLVE. 22.0.4 is what the host portal
resolves, and samples track the host.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Catalog every library export, how to import it, and which pieces work
  inside an extension remote (host services only via REMOTE_* tokens)
- Add a need-to-component picker and recipes checked against the
  library source, covering the gotchas that fail without an error
- Correct the error-handling reference: toasts do reach the host from a
  remote, though form errors are still reported inline
- Link the new reference from the skill index and the authoring guide

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
chore: bump ng-common-lib to 0.3.0 and add a UI library reference
fix(run): surface studio API errors instead of a JSON traceback
Update STUDIO_TAG, AGENT_TAG, and UI_TAG to latest build references.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@aboutte
aboutte requested a review from gk-duplo as a code owner September 23, 2026 19:46
jmaggio and others added 15 commits September 24, 2026 09:24
- run.sh, scripts/switch-llm.sh: initialize F_SUBSCRIPTION_TOKEN and
  F_SUBSCRIPTION_MODEL alongside the F_GATEWAY_* vars. Under set -u the
  arm died with "unbound variable" whenever a flag was omitted — after
  the stash step had already blanked the outgoing provider's keys,
  leaving .env half-migrated.
- scripts/switch-llm.sh: namespace stash keys by provider
  (_STASH_<PROVIDER>_<KEY>). CLAUDE_MODEL (and AWS_REGION) are owned by
  several providers with incompatible id formats, so a flat
  _STASH_CLAUDE_MODEL handed e.g. a gateway's anthropic/… id to the
  subscription arm. Legacy flat stashes are still read for keys owned by
  a single provider; a flat stash of a shared key is ignored.
- scripts/_provider_subscription.sh: the leftover-model guard now also
  catches gateway-namespaced ids (*/*), not just Bedrock profile ids.
- tests: subscription suites run under set -euo pipefail like their
  callers; new tests/test-switch-llm-subscription.sh drives the real
  switch-llm.sh end to end in a throwaway root with a stub docker.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… warn

docker compose resolves ${VAR:-} from the calling shell before .env, so an
ANTHROPIC_API_KEY or ANTHROPIC_BASE_URL exported in the user's shell defeated
the subscription arm's load-bearing .env blanks: it reached the agent, won
the precedence chain, and the subscription token was silently never used.

provider_subscription_configure now unsets them in-process (the helper is
sourced, so this affects only run.sh / switch-llm.sh, never the user's
shell), so the compose calls those scripts make are correct, and warns that
a manual `docker compose up` would still pick them up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat(run.sh): add a `subscription` LLM provider (Claude Code subscrip…
- run.sh / scripts/switch-llm.sh now provision Claude Sonnet 5
  (claude-sonnet-5 direct Anthropic, us.anthropic.claude-sonnet-5 either
  Bedrock mode) as CLAUDE_MODEL, and add the matching Opus 5.5 id via a
  new comma-separated CLAUDE_EXTRA_MODELS env var.
- scripts/register-llm.sh registers every id in CLAUDE_MODEL +
  CLAUDE_EXTRA_MODELS and makes the System LLM mapping exactly that set,
  with CLAUDE_MODEL as the default — so the ticket LLM picker offers
  Sonnet 5 (default) and Opus 5.5 side by side. The model-list build is
  bash 3.2 safe (macOS system bash) on every argument shape: blank
  CLAUDE_EXTRA_MODELS, a single positional id, several positional ids,
  and two ids from .env.
- Gateway provider stays single-model (gateway model names are
  provider-specific) and its default moves to claude-sonnet-5.
- The subscription provider (merged from dev/#1) gets the same
  treatment: SUBSCRIPTION_DEFAULT_MODEL moves to claude-sonnet-5, and
  provider_subscription_configure clears CLAUDE_EXTRA_MODELS for the
  same reason it already rejects a carried-over us.anthropic.* /
  gateway-namespaced CLAUDE_MODEL — the first-party API rejects those
  ids on either field.
- Swept the retired claude-sonnet-4-6 / anthropic/claude-sonnet-4.6 ids
  out of scripts, docker-compose.yml fallback, .env.example, docs, and
  tests — no retired id remains in the repo outside hackday/'s
  third-party OpenRouter examples.

Testing: all 5 suites pass, 58 checks — test-provider-gateway.sh 16/16,
test-provider-subscription.sh 15/15, test-run-gateway-wiring.sh 9/9,
test-run-subscription-wiring.sh 11/11, test-switch-llm-subscription.sh
7/7. docker compose config validates; bash -n clean on every touched
script; ./run.sh --help renders.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
feat(scripts): default to Sonnet 5 and offer Opus 5.5 in the LLM picker
Replace the claude-opus-5-5 / us.anthropic.claude-opus-5-5 ids with
claude-opus-5 / us.anthropic.claude-opus-5 in run.sh, switch-llm.sh,
.env.example and the docs, so the ticket LLM picker offers Sonnet 5
(default) alongside Opus 5.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
fix(scripts): use claude-opus-5 as the extra picker model
The subscription arm blanked CLAUDE_EXTRA_MODELS by copying the gateway
arm's rationale ("gateways name models their own way"). That reasoning
does not transfer: this path calls the first-party API with bare model
ids, exactly like the `anthropic` arm, so the picker should offer
claude-opus-5 the same way. Overwrite rather than carry over, since a
leftover us.anthropic.* id would be rejected by the first-party API.

Also trims the pasted token's leading/trailing whitespace. This is
normalization, not validation: no valid opaque bearer token has
whitespace at its edges, so it cannot turn away a good token whatever
shape tokens take next. Deliberately no length or format check — the
token's shape is not a documented contract, and rejecting a valid future
token with a confident error would be worse than the 401 it prevents.

Output trimmed to what the moment needs. The setup-token prompt no
longer re-argues a choice the user just made at the menu; the
Bedrock-only ticket-titles note and the exported-shell-var WARNING are
gone. The unset behind that warning is load-bearing and stays — it keeps
the scripts' own compose calls correct.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The product now handles usage-metrics consent inside the UI itself, so
the dev kit no longer needs to ask, store a choice, or rewrite the
served bundle:

- run.sh: drop the --metrics/--no-metrics flags, the opt-out prompt,
  and the Metrics line in the ready banner
- scripts/_metrics.sh, nginx/metrics-on.conf, nginx/metrics-off.conf:
  deleted
- nginx/default.conf: drop the metrics.conf include; it's now a plain
  same-origin API proxy
- docker-compose.yml: drop the METRICS_CONF volume mount
- .env.example: drop DUPLO_USAGE_METRICS / METRICS_CONF
- .gitleaksignore: deleted (its only entry covered the now-removed
  metrics-on.conf)
- docs: PRIVACY.md, README.md, configuration.md, faq.md,
  cli-reference.md, getting-started/install.md, quickstart.md,
  docs/README.md, hackday/Installing DevKit.md updated to describe
  consent as an in-product UI setting

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…n-and-nginx

feat(run.sh): remove usage-metrics opt-in prompt and nginx toggle
MongoDB 6.0 reached end of life on 2025-07-31. Move the dev kit off the
EOL line and onto 7.0.14, matching the version the helpdesk-helm chart
already pins, so local and deployed environments run the same server.

7.0 is supported until 2027-08-31.

Verified that an existing 6.0 volume upgrades in place with no migration
step: started mongo:6.0 (FCV 6.0), wrote data, then started mongo:7.0.14
against the same volume. It came up healthy, all data read back intact,
and reads and writes both worked. The startup log is clean, reporting
only the informational "current featureCompatibilityVersion: 6.0" line.
FCV stays at 6.0, which is the supported steady state — 7.0-only on-disk
features stay dormant, and nothing in the dev kit depends on them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
chore: bump devkit mongo from 6.0 to 7.0.14
A literal hostname in proxy_pass is resolved once when nginx loads its
config and cached for the container's lifetime. Recreating the studio
(any compose change to it, or to mongo, which it depends_on) moves its
IP on the compose network, so the UI's nginx keeps proxying to the dead
old address — every API call 502s, and since the login page uses two
of those calls (SsoConfig, IsGoogleAuthenticationDisabled) to decide
what to render, it comes up with no auth methods at all.

Use Docker's embedded DNS (127.0.0.11) with a variable in proxy_pass
so nginx re-resolves duplo-ai-studio on every request instead of once.
Verified by force-recreating the studio onto a different IP without
touching the UI container: proxied endpoints stayed 200 throughout.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@aboutte
aboutte merged commit 683b40a into main Sep 28, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants