sprag-cli 3.80.0 → 3.80.1

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.
package/docs/TEAM.ko.md CHANGED
@@ -24,7 +24,7 @@ Sprag 은 기본적으로 로컬에서만 동작합니다. 팀 기능은 켜야
24
24
 
25
25
  하루 단위 집계 업로드는 마지막 성공 이후 5분에 한 번 이하로 실행됩니다. SessionStart 훅(그리고 작은 로컬 파일만 읽는 프롬프트 훅)이 띄운 분리된 자식 프로세스가 보냅니다. 네트워크가 끊기는 등 동기화가 실패하면 5분 주기 대신 15분, 30분, 60분 뒤에 다시 시도합니다(최대 60분 간격). 마지막으로 올린 날짜를 기억해 두었다가 그 전날부터 최대 30일 치를 다시 보내므로, 며칠 꺼져 있던 컴퓨터도 처음 성공하는 동기화에서 빠진 날을 따라잡습니다. 하루 단위 행은 덮어쓰기라 다시 보내도 안전합니다. 프롬프트 수집을 켠 엔터프라이즈 팀의 프롬프트 업로드는 따로 30분 타이머로 움직입니다("프롬프트 사용량 (엔터프라이즈)" 절 참고). statusline 을 그리는 경로에서는 절대 실행되지 않습니다.
26
26
 
27
- 팀에 참여한 동안 statusline 에 `team` 칩이 나타나 멤버 ID 와 가상 사무실(Sprag 타운)에서 받은 동물을 보여 줍니다. 예를 들면 `member-1e500474 🦊 여우` 입니다. 동물은 5분마다 도는 전체 동기화가 서버에서 받아 `team.json` 에 저장한 순위로 정합니다. 서버가 아직 이 기능을 지원하지 않거나 마지막으로 받은 지 하루가 넘었다면 멤버 ID 만 표시합니다. 칩을 그릴 때는 로컬 파일만 읽습니다. 버전 칩 바로 앞에 놓이며, `--segments team` 으로 이 칩만 따로 볼 수 있습니다.
27
+ 팀에 참여한 동안 statusline 에 `team` 칩이 나타나 멤버 ID 와 가상 사무실(Sprag 타운)에서 받은 동물을 보여 줍니다. 예를 들면 `member-1e500474 🦊 여우 12명 중 3위` 처럼 조직에서 순위에 오른 사람 가운데 몇 위인지도 함께 보여 줍니다. 동물은 5분마다 도는 전체 동기화가 서버에서 받아 `team.json` 에 저장한 순위로 정합니다. 서버가 아직 이 기능을 지원하지 않거나 마지막으로 받은 지 하루가 넘었다면 멤버 ID 만 표시합니다. 칩을 그릴 때는 로컬 파일만 읽습니다. 버전 칩 바로 앞에 놓이며, `--segments team` 으로 이 칩만 따로 볼 수 있습니다.
28
28
 
29
29
  목적지는 `https://hiycfjwswtkixyoqkznm.supabase.co/rest/v1/rpc/*` 입니다(Supabase, ap-northeast-2 리전). 호출하는 RPC 는 `team_join`, `ledger_upsert`, `team_rules_get`, `team_rule_propose`, `team_leave`, `prompt_chunk_put`(엔터프라이즈 프롬프트 수집일 때만), `member_set_sync`(업로드 스위치 상태 호출, "업로드 스위치" 참고), `member_set_info`(OS 이름과 버전, `arch` 인자는 항상 빈 값), `member_standing`(statusline 칩에 쓸 본인의 사무실 동물과 순위만 받고 다른 사람의 수치는 받지 않음) 입니다.
30
30
 
package/docs/TEAM.md CHANGED
@@ -24,7 +24,7 @@ Not sent: prompts, transcripts, file paths, project names, rule text, API keys.
24
24
 
25
25
  The daily aggregate upload runs at most once every 5 minutes after the last successful one, from a detached child process that the SessionStart hook (and the prompt hook, which only reads a small local file) spawns. If a sync fails, for example because the network is down, it is retried after 15, then 30, then 60 minutes (60 at most) instead of every 5 minutes. The CLI remembers the last day it uploaded and re-sends from the day before it, up to 30 days, so a machine that was offline for days catches up on its first successful sync. Re-sending a day is safe because each day is an upsert. The prompt upload of an Enterprise team with capture on has its own 30-minute timer (see "Prompt usage (Enterprise)"). It never runs on the statusline path.
26
26
 
27
- While this machine is joined, the statusline shows a `team` chip with your member id and your animal from the virtual office (Sprag Town), for example `member-1e500474 🦊 Fox`. The animal comes from the standing the full sync fetches every 5 minutes and stores in `team.json`; if the server does not offer it yet, or the last fetch is more than a day old, only the member id is shown. Rendering the chip reads local files only. It sits just before the version chip, and `--segments team` shows it on its own.
27
+ While this machine is joined, the statusline shows a `team` chip with your member id and your animal from the virtual office (Sprag Town), for example `member-1e500474 🦊 Fox #3 of 12`, with your overall rank among the ranked people of the organization. The animal comes from the standing the full sync fetches every 5 minutes and stores in `team.json`; if the server does not offer it yet, or the last fetch is more than a day old, only the member id is shown. Rendering the chip reads local files only. It sits just before the version chip, and `--segments team` shows it on its own.
28
28
 
29
29
  Destination: `https://hiycfjwswtkixyoqkznm.supabase.co/rest/v1/rpc/*` (Supabase, region ap-northeast-2). The calls are the RPCs `team_join`, `ledger_upsert`, `team_rules_get`, `team_rule_propose`, `team_leave`, `prompt_chunk_put` (Enterprise prompt capture only), `member_set_sync` (the upload-switch status call, see "The upload switch") `member_set_info` (OS name and version; the `arch` argument is always empty) and `member_standing` (your own office animal and rank for the statusline chip; it returns nobody else's figures); `sprag team create` also calls `team_create` with your sign-in session.
30
30
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sprag-cli",
3
- "version": "3.80.0",
3
+ "version": "3.80.1",
4
4
  "description": "Model-delegation router for Claude Code and Codex: lookups, checks and test runs go to cheaper models, documents go in as compact Markdown, and a live statusline shows spend and savings.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -371,7 +371,7 @@ const TEAM_STANDING_MAX_AGE_MS = 24 * 60 * 60 * 1000;
371
371
 
372
372
  /**
373
373
  * Team chip: the member id and, once the server has told us, the animal that
374
- * member is in the team's virtual office (`member-1e500474 🦊 Fox`). Renders only
374
+ * member is in the team's virtual office and the rank (`member-1e500474 🦊 Fox #3 of 12`). Renders only
375
375
  * for a joined machine. A missing, unknown or day-old standing leaves just the
376
376
  * member label. Gray like the other identity chips; the emoji brings its own colour.
377
377
  */
@@ -380,7 +380,10 @@ function buildTeamSeg(team, c, now = Date.now()) {
380
380
  const st = team.standing;
381
381
  const fresh = st && Number.isFinite(st.fetchedAt) && now - st.fetchedAt <= TEAM_STANDING_MAX_AGE_MS;
382
382
  const animal = fresh ? speciesLabel(st.grade, team.lang) : null;
383
- return `${c(GRAY)}${team.label}${animal ? ` ${animal}` : ''}${c(RESET)}`;
383
+ // The rank among the ranked people, the same standing the office drawer shows; a ghost has none.
384
+ const ranked = animal && Number.isInteger(st.rank) && Number.isInteger(st.ranked) && st.rank >= 1 && st.ranked >= st.rank;
385
+ const place = ranked ? (team.lang === 'ko' ? ` ${st.ranked}명 중 ${st.rank}위` : ` #${st.rank} of ${st.ranked}`) : '';
386
+ return `${c(GRAY)}${team.label}${animal ? ` ${animal}${place}` : ''}${c(RESET)}`;
384
387
  }
385
388
 
386
389
  /**
package/src/team-sync.js CHANGED
@@ -107,7 +107,9 @@ export function readTeamChip({ dir = userDataDir() } = {}) {
107
107
  return {
108
108
  label,
109
109
  lang: userLanguage(),
110
- standing: st && typeof st.grade === 'string' ? { grade: st.grade, fetchedAt: Number(st.fetchedAt) || 0 } : null,
110
+ standing: st && typeof st.grade === 'string'
111
+ ? { grade: st.grade, rank: Number.isFinite(st.rank) ? st.rank : null, ranked: Number.isFinite(st.ranked) ? st.ranked : null, fetchedAt: Number(st.fetchedAt) || 0 }
112
+ : null,
111
113
  };
112
114
  } catch (e) { debug('team-sync', e); return null; }
113
115
  }