litmus-cli 1.4.84-desktop.2 → 1.4.84-desktop.4

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/README.md CHANGED
@@ -98,6 +98,10 @@ litmus connect <token> --ide claude
98
98
  Both configure the same dedicated Litmus SSH key and host alias and verify SSH plus
99
99
  remote runtime/capture configuration before handing off. Codex App uses Settings →
100
100
  Connections → SSH: enable the printed host and choose `/home/candidate/workspace`.
101
+ If the workspace uses your own AI account, first run
102
+ `ssh -t <litmus-host-alias> codex login --device-auth`, open the printed browser
103
+ link, and enter the one-time code. Enable device code login in ChatGPT security
104
+ settings if prompted. Litmus pre-authenticated workspaces do not need this step.
101
105
  Claude Desktop opens its Code tab with that host and folder prefilled (v2.110.0 or
102
106
  later); confirm the connection. Neither requires downloading the assessment locally.
103
107
  Keep edits in the workspace folder, without a separate worktree, and submit through
@@ -8,6 +8,7 @@ export type DesktopApp = "codex" | "claude";
8
8
  export declare const DESKTOP_WORKSPACE_FOLDER = "/home/candidate/workspace";
9
9
  export declare function claudeDesktopUrl(alias: string): string;
10
10
  export declare function desktopAppInstructions(app: DesktopApp, alias: string): string[];
11
- /** Read only configuration presence; never print credentials or candidate files. */
11
+ /** Validate remote configuration without printing credentials or candidate content. */
12
+ export declare function desktopAppConfigurationScript(app: DesktopApp): string;
12
13
  export declare function desktopAppProbeCommand(app: DesktopApp): string;
13
14
  //# sourceMappingURL=desktop-app.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"desktop-app.d.ts","sourceRoot":"","sources":["../../src/lib/desktop-app.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAA;AAC3C,eAAO,MAAM,wBAAwB,8BAA8B,CAAA;AAEnE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAc/E;AAED,oFAAoF;AACpF,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAI9D"}
1
+ {"version":3,"file":"desktop-app.d.ts","sourceRoot":"","sources":["../../src/lib/desktop-app.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAA;AAC3C,eAAO,MAAM,wBAAwB,8BAA8B,CAAA;AAEnE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAiB/E;AAED,uFAAuF;AACvF,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAgDrE;AAID,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAQ9D"}
@@ -14,17 +14,74 @@ export function desktopAppInstructions(app, alias) {
14
14
  "Use the project folder directly rather than creating a worktree. Submit from your Litmus assessment page.",
15
15
  ];
16
16
  return [
17
+ "If this workspace uses your own AI account, sign in to Codex on the workspace first:",
18
+ ` ssh -t ${alias} codex login --device-auth`,
19
+ "Open the printed link in your browser and enter the one-time code. Enable device code login in your ChatGPT security settings if needed.",
17
20
  "Open Codex App, then Settings > Connections > SSH.",
18
21
  `Add or enable SSH host: ${alias}`,
19
22
  `Choose project folder: ${DESKTOP_WORKSPACE_FOLDER}`,
20
23
  "Start a chat in that remote project. Submit from your Litmus assessment page.",
21
24
  ];
22
25
  }
23
- /** Read only configuration presence; never print credentials or candidate files. */
26
+ /** Validate remote configuration without printing credentials or candidate content. */
27
+ export function desktopAppConfigurationScript(app) {
28
+ const common = `import json,os,pathlib,tomllib,urllib.parse
29
+ home=pathlib.Path.home()
30
+ def require(ok):
31
+ if not ok: raise ValueError("Desktop app configuration is incomplete")
32
+ proxy=urllib.parse.urlparse(os.environ.get("HTTPS_PROXY",""))
33
+ require(proxy.scheme in ("http","https") and bool(proxy.hostname))
34
+ ca=pathlib.Path(os.environ.get("NODE_EXTRA_CA_CERTS","/nonexistent"))
35
+ require(ca.is_file() and os.access(ca,os.R_OK))
36
+ `;
37
+ if (app === "claude")
38
+ return common + `s=json.loads((home/".claude/settings.json").read_text())
39
+ require(isinstance(s,dict) and s.get("disableAllHooks") is not True)
40
+ h=s.get("hooks",{})
41
+ command="node /opt/litmus/lib/hook-logger.cjs claude /home/candidate/workspace --hosted-workspace /home/candidate"
42
+ for event in ("UserPromptSubmit","Stop"):
43
+ entries=[e for g in h.get(event,[]) if g.get("matcher") is None for e in g.get("hooks",[]) if e.get("command")==command and e.get("type")=="command" and isinstance(e.get("timeout"),(int,float)) and e["timeout"]>=15 and not e.get("async",False)]
44
+ require(len(entries)==1)
45
+ env=s.get("env",{})
46
+ require(isinstance(env,dict) and env.get("CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC")=="1")
47
+ for key in ("HTTPS_PROXY","HTTP_PROXY","NODE_EXTRA_CA_CERTS"):
48
+ require(key not in env or env[key]==os.environ.get(key))
49
+ # Authentication may be supplied by Desktop sign-in. If workspace pre-auth is set,
50
+ # both its route and credential must be present; never print either value.
51
+ base=os.environ.get("ANTHROPIC_BASE_URL","")
52
+ if base:
53
+ require(urllib.parse.urlparse(base).scheme in ("http","https") and bool(urllib.parse.urlparse(base).hostname))
54
+ require(bool(os.environ.get("ANTHROPIC_AUTH_TOKEN") or os.environ.get("ANTHROPIC_API_KEY")))
55
+ print("ready")
56
+ `;
57
+ return common + `config=tomllib.loads((home/".codex/config.toml").read_text())
58
+ require(config.get("check_for_update_on_startup") is False)
59
+ require(config.get("sandbox_mode")=="danger-full-access")
60
+ require(config.get("features",{}).get("hooks") is not False)
61
+ daemon=json.loads((home/".codex/app-server-daemon/settings.json").read_text())
62
+ require(daemon.get("updater",{}).get("autoUpdateEnabled") is False)
63
+ provider=config.get("model_provider")
64
+ if provider=="litmus":
65
+ route=config.get("model_providers",{}).get("litmus",{})
66
+ require(route.get("wire_api")=="responses")
67
+ url=urllib.parse.urlparse(route.get("base_url",""))
68
+ require(url.scheme in ("http","https") and bool(url.hostname))
69
+ require(bool(os.environ.get(route.get("env_key",""))))
70
+ require(route.get("http_headers",{}).get("X-Litmus-Client")=="codex")
71
+ else:
72
+ # Personal account sign-in is supported; an unknown provider is not our config.
73
+ require(provider in (None,"openai"))
74
+ print("ready")
75
+ `;
76
+ }
77
+ function shellQuote(value) { return "'" + value.replace(/'/g, "'\\''") + "'"; }
24
78
  export function desktopAppProbeCommand(app) {
25
- if (app === "codex")
26
- return "bash -lc 'command -v codex >/dev/null && codex app-server --help >/dev/null 2>&1 && test -r ~/.codex/config.toml && test -r /etc/codex/hooks.json && test -r /etc/codex/requirements.toml && test -r /opt/litmus/lib/hook-logger.cjs && printf ready'";
27
- // Desktop uploads its own runtime and reads remote user settings, including hooks.
28
- return `python3 -c 'import json,pathlib; p=pathlib.Path.home()/".claude/settings.json"; s=json.loads(p.read_text()); h=s.get("hooks",{}); assert all(any(e.get("command","").split()[:3] == ["node","/opt/litmus/lib/hook-logger.cjs","claude"] for g in h.get(k,[]) for e in g.get("hooks",[])) for k in ("UserPromptSubmit","Stop")); assert isinstance(s.get("env"),dict); print("ready")'`;
79
+ const configuration = `python3 -c ${shellQuote(desktopAppConfigurationScript(app))}`;
80
+ if (app === "codex") {
81
+ // Reuse the image's exact hook/requirements/node verifier, including root ownership,
82
+ // rather than maintaining another approximation of its shell command contract.
83
+ return "bash -lc 'command -v codex >/dev/null && codex app-server --help >/dev/null 2>&1' && python3 /opt/litmus/lib/install_codex_hook.py verify --expect-root-owned --expect-node >/dev/null 2>&1 && test -r /opt/litmus/lib/hook-logger.cjs && " + configuration;
84
+ }
85
+ return "command -v node >/dev/null && test -r /opt/litmus/lib/hook-logger.cjs && " + configuration;
29
86
  }
30
87
  //# sourceMappingURL=desktop-app.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"desktop-app.js","sourceRoot":"","sources":["../../src/lib/desktop-app.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,wBAAwB,GAAG,2BAA2B,CAAA;AAEnE,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,IAAI,CAAC,8BAA8B,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAA;IAC1F,OAAO,8BAA8B,kBAAkB,CAAC,KAAK,CAAC,eAAe,kBAAkB,CAAC,wBAAwB,CAAC,EAAE,CAAA;AAC7H,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,GAAe,EAAE,KAAa;IACnE,IAAI,GAAG,KAAK,QAAQ;QAAE,OAAO;YAC3B,oGAAoG;YACpG,gBAAgB,CAAC,KAAK,CAAC;YACvB,aAAa,KAAK,EAAE;YACpB,mBAAmB,wBAAwB,EAAE;YAC7C,2GAA2G;SAC5G,CAAA;IACD,OAAO;QACL,oDAAoD;QACpD,2BAA2B,KAAK,EAAE;QAClC,0BAA0B,wBAAwB,EAAE;QACpD,+EAA+E;KAChF,CAAA;AACH,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,sBAAsB,CAAC,GAAe;IACpD,IAAI,GAAG,KAAK,OAAO;QAAE,OAAO,uPAAuP,CAAA;IACnR,mFAAmF;IACnF,OAAO,uXAAuX,CAAA;AAChY,CAAC"}
1
+ {"version":3,"file":"desktop-app.js","sourceRoot":"","sources":["../../src/lib/desktop-app.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,wBAAwB,GAAG,2BAA2B,CAAA;AAEnE,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,IAAI,CAAC,8BAA8B,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAA;IAC1F,OAAO,8BAA8B,kBAAkB,CAAC,KAAK,CAAC,eAAe,kBAAkB,CAAC,wBAAwB,CAAC,EAAE,CAAA;AAC7H,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,GAAe,EAAE,KAAa;IACnE,IAAI,GAAG,KAAK,QAAQ;QAAE,OAAO;YAC3B,oGAAoG;YACpG,gBAAgB,CAAC,KAAK,CAAC;YACvB,aAAa,KAAK,EAAE;YACpB,mBAAmB,wBAAwB,EAAE;YAC7C,2GAA2G;SAC5G,CAAA;IACD,OAAO;QACL,sFAAsF;QACtF,YAAY,KAAK,4BAA4B;QAC7C,0IAA0I;QAC1I,oDAAoD;QACpD,2BAA2B,KAAK,EAAE;QAClC,0BAA0B,wBAAwB,EAAE;QACpD,+EAA+E;KAChF,CAAA;AACH,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,6BAA6B,CAAC,GAAe;IAC3D,MAAM,MAAM,GAAG;;;;;;;;CAQhB,CAAA;IACC,IAAI,GAAG,KAAK,QAAQ;QAAE,OAAO,MAAM,GAAG;;;;;;;;;;;;;;;;;;CAkBvC,CAAA;IACC,OAAO,MAAM,GAAG;;;;;;;;;;;;;;;;;;CAkBjB,CAAA;AACD,CAAC;AAED,SAAS,UAAU,CAAC,KAAa,IAAY,OAAO,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,GAAG,CAAA,CAAC,CAAC;AAE9F,MAAM,UAAU,sBAAsB,CAAC,GAAe;IACpD,MAAM,aAAa,GAAG,cAAc,UAAU,CAAC,6BAA6B,CAAC,GAAG,CAAC,CAAC,EAAE,CAAA;IACpF,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;QACpB,qFAAqF;QACrF,+EAA+E;QAC/E,OAAO,4OAA4O,GAAG,aAAa,CAAA;IACrQ,CAAC;IACD,OAAO,2EAA2E,GAAG,aAAa,CAAA;AACpG,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "litmus-cli",
3
- "version": "1.4.84-desktop.2",
3
+ "version": "1.4.84-desktop.4",
4
4
  "description": "CLI tool for Litmus engineering assessments",
5
5
  "license": "MIT",
6
6
  "author": "elenazhao",