Repository navigation
feat(init): run a team setup script declared as scripts.postInit (Tencent#1012) - #9
hsuchifeng wants to merge 1 commit into
Conversation
`teamai.yaml` can declare `scripts.postInit`, a Node entrypoint `teamai init` runs once with the terminal attached, after the local config and hooks are in place and before the closing pull, so what it collects (`teamai env set`) is delivered by that pull. It is skipped without a terminal, with the command to run later; `teamai script run postInit` runs it again and then syncs MCP servers. Same path containment as postPull; a failing script never fails init.
Code Erosion ReportInformational — never blocks the merge.
Scanned 306 files / 60714 SLOC · high-CC functions 420/4841 * On TypeScript, Rule hits (TS verbosity layer)Standalone
38 distinct lines flagged across |
|
CI note on the Generated by Claude Code |
7e98c8a to
6a7526e
Compare
Summary
Implements Tencent#1012.
scripts.postPullruns headless, so a team whose MCP servers need a personal token has no step a new member sees:teamai initends and the token is still unset. This addsscripts.postInit:teamai init(git and single-repo mode) runs it once with the terminal attached (stdio: inherit, no time limit), after the local config and hooks are in place and before the closing pull, so what the script collects (say, throughteamai env set) is delivered by that same pull. In single-repo mode, which has no closing pull, init runs onemcp injectafter the script.TEAMAI_REPOandTEAMAI_SCOPE(user/project). The same containment aspostPullapplies (assertSafePath): a path resolving outside the clone is rejected with a warning. A non-zero exit is a warning naming the command below, never a failed init.isInteractive(): stdin not a TTY,CI,TEAMAI_NONINTERACTIVE) init skips it and printsTeam setup script <path> needs a terminal and was not run. Run it later with \teamai script run postInit`.`teamai script run postInit(src/script-cmd.ts): runs the script for the scope governing the cwd, whether or not there is a terminal, then one MCP sync (mcpInject); exits with the script's code when it fails. Honors--dry-run(listed inDRY_RUN_PREVIEW).teamai.yamland ignores the key (thescriptsobject already strips unknown entries).docs/usage-guide.mdanddocs/usage-guide.zh-CN.md;commands.mdregenerated.Not done from the issue text:
--yesis not aninitflag today, so it is not a skip trigger; the three existing non-interactive signals are.Type of Change
Test Plan
npx tsc --noEmitpassesnpm run lintpassesnpx vitest run— full unit suite (the dry-run guard's "classifies every command" andcommands-referencecover the new command)npm run build && npx vitest run --config vitest.e2e.config.ts src/__tests__/e2e/post-init-script-1012.test.ts→ 3/3 passed, against a baregitprovider remote in a sandbox HOME (Cursor), with a team that declaresSETUP_TOKENinenv/secrets.yaml, an MCP server using${SETUP_TOKEN}, and ascripts/setup-env.mjsthat prompts for the token and runsteamai env set SETUP_TOKEN --stdin:teamai init <url> --provider git --scope user --agent cursor --forcewith a piped stdin exits 0, prints the "needs a terminal and was not run …teamai script run postInit" line, and the MCP server waits (setup-api: SETUP_TOKEN is not set)teamai script run postInitwith the answer on stdin: the script seesTEAMAI_REPO= the clone andTEAMAI_SCOPE=user, stores the token,MCP inject:follows and~/.cursor/mcp.jsoncarries the resolved header; the token is not in the outputpath: ../outside.mjs→Team setup script ../outside.mjs was not run: …and nothing runsscript runexits 3 with… exited 3. Run it again with \teamai script run postInit`.` and no MCP syncRelated Issues
Implements Tencent#1012
Notes for Reviewers
Independent of the Tencent#1011 PR: the e2e uses a key declared in
env/secrets.yaml, whichteamai env setalready accepts onmain. The init path that runs the script interactively (TTY) is exercised byscript runin the e2e, since no test can own a terminal; init's own call is the same function withexplicitoff.Generated by Claude Code