@clipboard-health/groundcrew 4.27.1 → 4.29.0
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 +6 -28
- package/crew.config.example.ts +3 -0
- package/dist/lib/config.d.ts +7 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +29 -5
- package/docs/configuration.md +18 -1
- package/docs/development.md +26 -0
- package/package.json +12 -12
- package/static/groundcrew-avatar.png +0 -0
- package/static/groundcrew-mark.svg +20 -23
- package/static/groundcrew-wordmark.svg +30 -0
- package/static/groundcrew-emoji.gif +0 -0
- package/static/groundcrew-wordmark-dark.svg +0 -38
- package/static/groundcrew-wordmark-light.svg +0 -38
package/README.md
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<
|
|
3
|
-
<source media="(prefers-color-scheme: dark)" srcset="./static/groundcrew-wordmark-dark.svg">
|
|
4
|
-
<img alt="groundcrew" src="./static/groundcrew-wordmark-light.svg" height="96">
|
|
5
|
-
</picture>
|
|
2
|
+
<img alt="groundcrew" src="./static/groundcrew-wordmark.svg" height="96">
|
|
6
3
|
</p>
|
|
7
4
|
|
|
8
5
|
<p align="center">
|
|
@@ -10,10 +7,10 @@
|
|
|
10
7
|
</p>
|
|
11
8
|
|
|
12
9
|
<p align="center">
|
|
13
|
-
<a href="https://www.npmjs.com/package/@clipboard-health/groundcrew"><img alt="npm" src="https://img.shields.io/npm/v/@clipboard-health/groundcrew?style=flat-square&label=npm&color=
|
|
14
|
-
<a href="https://www.npmjs.com/package/@clipboard-health/groundcrew"><img alt="downloads" src="https://img.shields.io/npm/dw/@clipboard-health/groundcrew?style=flat-square&label=downloads&color=
|
|
15
|
-
<a href="https://github.com/ClipboardHealth/groundcrew/actions/workflows/ci.yml"><img alt="ci" src="https://img.shields.io/github/actions/workflow/status/ClipboardHealth/groundcrew/ci.yml?style=flat-square&label=ci&color=77d94e&labelColor=
|
|
16
|
-
<a href="./LICENSE"><img alt="license" src="https://img.shields.io/npm/l/@clipboard-health/groundcrew?style=flat-square&label=license&color=
|
|
10
|
+
<a href="https://www.npmjs.com/package/@clipboard-health/groundcrew"><img alt="npm" src="https://img.shields.io/npm/v/@clipboard-health/groundcrew?style=flat-square&label=npm&color=F7C600&labelColor=111111"></a>
|
|
11
|
+
<a href="https://www.npmjs.com/package/@clipboard-health/groundcrew"><img alt="downloads" src="https://img.shields.io/npm/dw/@clipboard-health/groundcrew?style=flat-square&label=downloads&color=111111&labelColor=111111"></a>
|
|
12
|
+
<a href="https://github.com/ClipboardHealth/groundcrew/actions/workflows/ci.yml"><img alt="ci" src="https://img.shields.io/github/actions/workflow/status/ClipboardHealth/groundcrew/ci.yml?style=flat-square&label=ci&color=77d94e&labelColor=111111"></a>
|
|
13
|
+
<a href="./LICENSE"><img alt="license" src="https://img.shields.io/npm/l/@clipboard-health/groundcrew?style=flat-square&label=license&color=111111&labelColor=111111"></a>
|
|
17
14
|
</p>
|
|
18
15
|
|
|
19
16
|
<p align="center">
|
|
@@ -153,28 +150,9 @@ There is no `linear` config block. Groundcrew reads `GROUNDCREW_LINEAR_API_KEY`
|
|
|
153
150
|
- [Credentials](./docs/credentials.md): Linear API keys, 1Password, build secrets, and `preLaunch`.
|
|
154
151
|
- [Prepare worktree hooks](./docs/setup-hooks.md): `.groundcrew/config.json` `hooks.prepareWorktree` for per-repo dependency setup.
|
|
155
152
|
- [Task sources](./docs/task-sources.md): custom shell/Jira/local-plan adapters.
|
|
153
|
+
- [Development](./docs/development.md): local source workflow and README/demo asset regeneration.
|
|
156
154
|
- [Troubleshooting](./docs/troubleshooting.md): common operational pitfalls and fixes.
|
|
157
155
|
|
|
158
|
-
## Development
|
|
159
|
-
|
|
160
|
-
Clone the repo and run the CLI from TypeScript source:
|
|
161
|
-
|
|
162
|
-
```bash
|
|
163
|
-
cd ~/dev/c/groundcrew
|
|
164
|
-
node --run crew -- doctor
|
|
165
|
-
|
|
166
|
-
# With 1Password for GROUNDCREW_LINEAR_API_KEY:
|
|
167
|
-
node --run crew:op -- run --watch
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
Both forms discover config through cosmiconfig. Source edits in `src/**` are picked up on the next invocation. Requires Node >= 24.
|
|
171
|
-
|
|
172
|
-
Regenerate the README demo with VHS:
|
|
173
|
-
|
|
174
|
-
```bash
|
|
175
|
-
./static/render-demo.sh
|
|
176
|
-
```
|
|
177
|
-
|
|
178
156
|
## License
|
|
179
157
|
|
|
180
158
|
[MIT](./LICENSE)
|
package/crew.config.example.ts
CHANGED
|
@@ -120,6 +120,9 @@ export default {
|
|
|
120
120
|
// // `${XDG_CONFIG_HOME:-$HOME/.config}/groundcrew/initial-prompt.md`.
|
|
121
121
|
// // If you uncomment this, also uncomment the readFileSync import above.
|
|
122
122
|
// initial: readFileSync(new URL("./initial-prompt.md", import.meta.url), "utf8"),
|
|
123
|
+
// // Or, instead of `initial`, point at a file (also works in crew.config.json).
|
|
124
|
+
// // Resolved relative to this config's directory; `~` and absolute paths work.
|
|
125
|
+
// // promptFile: "initial-prompt.md",
|
|
123
126
|
// },
|
|
124
127
|
//
|
|
125
128
|
// // Terminal session manager. "auto" picks cmux when on PATH, else tmux.
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -193,7 +193,14 @@ export interface Config {
|
|
|
193
193
|
definitions?: Record<string, UserAgentDefinition>;
|
|
194
194
|
};
|
|
195
195
|
prompts?: {
|
|
196
|
+
/** Inline initial prompt. Mutually exclusive with `promptFile`. */
|
|
196
197
|
initial?: string;
|
|
198
|
+
/**
|
|
199
|
+
* Path to a UTF-8 file whose contents become the initial prompt. Resolved
|
|
200
|
+
* relative to the config file's directory; `~` is expanded; absolute paths
|
|
201
|
+
* are used as-is. Mutually exclusive with `initial`.
|
|
202
|
+
*/
|
|
203
|
+
promptFile?: string;
|
|
197
204
|
};
|
|
198
205
|
/**
|
|
199
206
|
* Terminal session manager that hosts agent processes. Defaults to
|
package/dist/lib/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/config.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { __rewriteRelativeImportExtension } from "tslib";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { pathToFileURL } from "node:url";
|
|
5
5
|
import { cosmiconfig } from "cosmiconfig";
|
|
@@ -518,7 +518,32 @@ function normalizeWorkspace(workspace) {
|
|
|
518
518
|
...(Object.keys(repositoryDirs).length === 0 ? {} : { repositoryDirs }),
|
|
519
519
|
};
|
|
520
520
|
}
|
|
521
|
-
|
|
521
|
+
/**
|
|
522
|
+
* Resolve the initial prompt from the user's `prompts` block. `promptFile` and
|
|
523
|
+
* `initial` are mutually exclusive; when neither is set the built-in default is
|
|
524
|
+
* used. A `promptFile` is resolved relative to the config file's directory
|
|
525
|
+
* (matching the `.ts` `import.meta.url` behavior), with `~` expanded and
|
|
526
|
+
* absolute paths used as-is, then read at load time.
|
|
527
|
+
*/
|
|
528
|
+
function resolveInitialPrompt(prompts, configDir) {
|
|
529
|
+
const { initial, promptFile } = prompts ?? {};
|
|
530
|
+
if (initial !== undefined && promptFile !== undefined) {
|
|
531
|
+
fail("prompts: set either `initial` or `promptFile`, not both");
|
|
532
|
+
}
|
|
533
|
+
if (promptFile !== undefined) {
|
|
534
|
+
requireString(promptFile, "prompts.promptFile");
|
|
535
|
+
const expanded = expandHome(promptFile);
|
|
536
|
+
const resolved = path.isAbsolute(expanded) ? expanded : path.resolve(configDir, expanded);
|
|
537
|
+
try {
|
|
538
|
+
return readFileSync(resolved, "utf8");
|
|
539
|
+
}
|
|
540
|
+
catch (error) {
|
|
541
|
+
fail(`prompts.promptFile could not be read at ${resolved}: ${String(error)}`);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return initial ?? DEFAULT_PROMPT_INITIAL;
|
|
545
|
+
}
|
|
546
|
+
function applyDefaults(user, configDir) {
|
|
522
547
|
// Guard the top-level shape before reading nested fields, so a
|
|
523
548
|
// malformed runtime config produces a `groundcrew config: ...` error
|
|
524
549
|
// instead of a raw `TypeError: Cannot read properties of undefined`.
|
|
@@ -559,7 +584,7 @@ function applyDefaults(user) {
|
|
|
559
584
|
definitions: mergeDefinitions(user.agents?.definitions),
|
|
560
585
|
},
|
|
561
586
|
prompts: {
|
|
562
|
-
initial: user.prompts
|
|
587
|
+
initial: resolveInitialPrompt(user.prompts, configDir),
|
|
563
588
|
},
|
|
564
589
|
workspaceKind: normalizeWorkspaceKind(user.workspaceKind, "workspaceKind") ?? "auto",
|
|
565
590
|
local: {
|
|
@@ -571,7 +596,6 @@ function applyDefaults(user) {
|
|
|
571
596
|
};
|
|
572
597
|
}
|
|
573
598
|
function validatePromptPlaceholders(template) {
|
|
574
|
-
/* v8 ignore next @preserve -- a no-placeholder prompt is unusual but tests with placeholders consistently match at least once */
|
|
575
599
|
const placeholders = template.match(PROMPT_PLACEHOLDER_RE) ?? [];
|
|
576
600
|
const unknown = placeholders.find((placeholder) => !ALLOWED_PROMPT_PLACEHOLDERS.has(placeholder));
|
|
577
601
|
if (unknown !== undefined) {
|
|
@@ -741,7 +765,7 @@ export async function loadConfigWithSource() {
|
|
|
741
765
|
}
|
|
742
766
|
debug(`Loaded config from ${filepath}`);
|
|
743
767
|
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- runtime fields are validated by applyDefaults/validate
|
|
744
|
-
const resolved = applyDefaults(userConfig);
|
|
768
|
+
const resolved = applyDefaults(userConfig, path.dirname(filepath));
|
|
745
769
|
validate(resolved);
|
|
746
770
|
setLogFile(resolved.logging.file);
|
|
747
771
|
cached = Object.freeze({
|
package/docs/configuration.md
CHANGED
|
@@ -157,6 +157,22 @@ export default {
|
|
|
157
157
|
|
|
158
158
|
This keeps package defaults portable while letting your private config reference team-specific statuses, tools, plugins, or review loops.
|
|
159
159
|
|
|
160
|
+
### Loading the prompt from a file (`prompts.promptFile`)
|
|
161
|
+
|
|
162
|
+
`readFileSync` works for `.ts` configs but not for `crew.config.json`, which has no way to reference an external file. Set `prompts.promptFile` instead and groundcrew reads the file's contents into the initial prompt at load time:
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"prompts": {
|
|
167
|
+
"promptFile": "prompt-initial.md"
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
- The path is resolved **relative to the config file's directory** (matching the `.ts` `import.meta.url` behavior); a leading `~` is expanded and absolute paths are used as-is.
|
|
173
|
+
- `prompts.initial` and `prompts.promptFile` are **mutually exclusive** — setting both is a hard error. Set neither to keep the built-in default.
|
|
174
|
+
- Placeholder validation runs on the loaded file contents, so an unknown `{{placeholder}}` in the file fails the same way it would inline.
|
|
175
|
+
|
|
160
176
|
## Default Hooks
|
|
161
177
|
|
|
162
178
|
Repo-local `.groundcrew/config.json` is the preferred place for
|
|
@@ -199,7 +215,8 @@ and hook contract.
|
|
|
199
215
|
| `models.definitions.<name>.sandbox` | optional | Docker Sandboxes binding for the model. Required at launch when `local.runner` resolves to `sdx`. Field: `agent` (required sbx agent name). Groundcrew assumes the `groundcrew-<agent>` sandbox already exists. |
|
|
200
216
|
| `models.definitions.<name>.preLaunch` | optional | Host-only shell snippet run before the agent exec and outside Safehouse/sdx. Exports survive into the launch shell; under the default `safehouse` runner they are only forwarded to the agent when listed via `preLaunchEnv` or when `cmd` includes its own `safehouse --env-pass=NAMES`. `{{worktree}}` is substituted. A non-zero exit aborts launch. Not supported when `local.runner` resolves to `sdx` in v1. |
|
|
201
217
|
| `models.definitions.<name>.preLaunchEnv` | optional | Companion to `preLaunch`: list of env var names to append to groundcrew's `safehouse-clearance` `--env-pass=` flag, so `preLaunch` exports reach the agent without overriding `cmd` and losing the project's egress allowlist. Each entry must match `[A-Za-z_][A-Za-z0-9_]*`. Under `runner: "none"` exports already inherit and `preLaunchEnv` is a no-op. An empty array is a uniform no-op in every runner; a non-empty list is rejected when `cmd` already starts with `safehouse` or when `runner` resolves to `sdx`. |
|
|
202
|
-
| `prompts.initial` | unattended template | First message sent to the agent: the execution wrapper around each task. The task description is the task-specific prompt. Placeholders: `{{task}}`, `{{worktree}}`, `{{title}}`, `{{description}}`. Override only to change the execution contract for every task, such as team-wide review rules or tool conventions.
|
|
218
|
+
| `prompts.initial` | unattended template | First message sent to the agent: the execution wrapper around each task. The task description is the task-specific prompt. Placeholders: `{{task}}`, `{{worktree}}`, `{{title}}`, `{{description}}`. Override only to change the execution contract for every task, such as team-wide review rules or tool conventions. Mutually exclusive with `prompts.promptFile`. |
|
|
219
|
+
| `prompts.promptFile` | optional | Path to a UTF-8 file whose contents become `prompts.initial`, read at load time. Resolved relative to the config file's directory; `~` is expanded and absolute paths are used as-is. The JSON-friendly alternative to inlining a large prompt or `readFileSync`. Mutually exclusive with `prompts.initial`. |
|
|
203
220
|
| `workspaceKind` | `"auto"` | Terminal session manager. `"auto"` picks `cmux` when on PATH, else `tmux`. Set to `"cmux"`, `"tmux"`, or `"zellij"` to fail loudly when the chosen backend is missing. |
|
|
204
221
|
| `local.runner` | `"auto"` | Local isolation backend. `"auto"` uses `safehouse` on macOS and `sdx` on Linux/WSL. Explicit: `"safehouse"`, `"sdx"`, `"none"`. `"none"` is never picked implicitly. |
|
|
205
222
|
| `logging.file` | XDG state path | Append-mode log file. `log()` / `logEvent()` tee here in addition to stdout. Defaults to `${XDG_STATE_HOME:-$HOME/.local/state}/groundcrew/groundcrew.log`. |
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Development
|
|
2
|
+
|
|
3
|
+
Clone the repo and run the CLI from TypeScript source:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
cd ~/dev/c/groundcrew
|
|
7
|
+
node --run crew -- doctor
|
|
8
|
+
|
|
9
|
+
# With 1Password for GROUNDCREW_LINEAR_API_KEY:
|
|
10
|
+
node --run crew:op -- run --watch
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Both forms discover config through cosmiconfig. Source edits in `src/**` are picked up on the next invocation. Requires Node >= 24.
|
|
14
|
+
|
|
15
|
+
Regenerate the README demo with VHS:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
./static/render-demo.sh
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Regenerate the Slack bot avatar (also used as the emoji upload; Slack scales it down) after editing the mark:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
sed 's/width="120" height="120"/width="512" height="512"/' static/groundcrew-mark.svg > /tmp/mark512.svg
|
|
25
|
+
sips -s format png /tmp/mark512.svg --out static/groundcrew-avatar.png
|
|
26
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clipboard-health/groundcrew",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.29.0",
|
|
4
4
|
"description": "Linear-driven orchestrator that launches AI coding agents in git worktrees, with workspace lifecycle and usage tracking.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -46,24 +46,24 @@
|
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
|
-
"architecture:check": "depcruise src bin crew.config.example.ts vitest.config.ts",
|
|
49
|
+
"architecture:check": "depcruise --config config/dependencyCruiser.cjs src bin crew.config.example.ts vitest.config.ts",
|
|
50
50
|
"build": "tsgo --build --force tsconfig.lib.json",
|
|
51
51
|
"build:dev": "tsgo --build tsconfig.lib.json",
|
|
52
|
-
"cpd": "jscpd .",
|
|
52
|
+
"cpd": "jscpd --config config/jscpd.json .",
|
|
53
53
|
"crew": "node --run build:dev && node ./bin/run.js",
|
|
54
54
|
"crew:op": "node --run build:dev && op run --env-file \"${XDG_CONFIG_HOME:-$HOME/.config}/groundcrew/op.env\" -- node ./bin/run.js",
|
|
55
|
-
"format": "oxfmt",
|
|
56
|
-
"format:check": "oxfmt --check",
|
|
57
|
-
"hook:pre-commit": "lint-staged",
|
|
55
|
+
"format": "oxfmt --config config/oxfmt.json",
|
|
56
|
+
"format:check": "oxfmt --config config/oxfmt.json --check",
|
|
57
|
+
"hook:pre-commit": "lint-staged --config config/lintStaged.config.js",
|
|
58
58
|
"hook:pre-push": "node --run verify",
|
|
59
|
-
"knip": "knip",
|
|
60
|
-
"lint": "oxlint --deny-warnings",
|
|
61
|
-
"markdown:lint": "markdownlint-cli2",
|
|
59
|
+
"knip": "knip --config config/knip.json",
|
|
60
|
+
"lint": "oxlint --config config/oxlint.config.ts --deny-warnings",
|
|
61
|
+
"markdown:lint": "markdownlint-cli2 --config config/markdownlint-cli2.jsonc",
|
|
62
62
|
"prepack": "node --run build",
|
|
63
63
|
"prepare": "husky",
|
|
64
|
-
"spell:check": "cspell --no-summary --no-progress --no-must-find-files",
|
|
64
|
+
"spell:check": "cspell --config config/cspell.json --no-summary --no-progress --no-must-find-files",
|
|
65
65
|
"sync-ai-rules": "node ./node_modules/@clipboard-health/ai-rules/scripts/sync.js common",
|
|
66
|
-
"syncpack:lint": "syncpack lint",
|
|
66
|
+
"syncpack:lint": "syncpack lint --config config/syncpack.config.ts",
|
|
67
67
|
"test": "vitest run --coverage",
|
|
68
68
|
"verify": "node scripts/verifyAll.mts"
|
|
69
69
|
},
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"@tsconfig/node24": "24.0.4",
|
|
83
83
|
"@tsconfig/strictest": "2.0.8",
|
|
84
84
|
"@types/node": "25.9.2",
|
|
85
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
85
|
+
"@typescript/native-preview": "7.0.0-dev.20260606.1",
|
|
86
86
|
"@vitest/coverage-v8": "4.1.8",
|
|
87
87
|
"cspell": "10.0.1",
|
|
88
88
|
"dependency-cruiser": "17.4.3",
|
|
Binary file
|
|
@@ -2,28 +2,25 @@
|
|
|
2
2
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" width="120" height="120" role="img" aria-label="groundcrew">
|
|
3
3
|
<title>groundcrew</title>
|
|
4
4
|
<!--
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
Taxiway sign tile: yellow field, inset inscription border, fork arrow.
|
|
6
|
+
One task stream splitting onto parallel worktrees.
|
|
7
|
+
Field #F7C600, ink #111111. Fork stem (22,60) to (48,60), branches to
|
|
8
|
+
(92.2,29) and (92.2,91) with chevron heads. Stroke 11, round caps/joins.
|
|
9
|
+
At 16px (favicon), drop the inscription border and bump the fork stroke
|
|
10
|
+
to 16.
|
|
11
|
+
|
|
12
|
+
Regenerate groundcrew-avatar.png (Slack bot avatar; also fine as the
|
|
13
|
+
emoji upload; Slack scales it down) with the sips commands in the
|
|
14
|
+
README's Development section. The exact command can't live here: it
|
|
15
|
+
needs a double-hyphen flag, which is illegal inside an XML comment.
|
|
9
16
|
-->
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
<line x1="102" y1="108" x2="32" y2="11" stroke="#FF6D00" stroke-width="20" stroke-linecap="round">
|
|
20
|
-
<animate attributeName="opacity"
|
|
21
|
-
values="1;0.38;1;1"
|
|
22
|
-
keyTimes="0;0.25;0.5;1"
|
|
23
|
-
calcMode="spline"
|
|
24
|
-
keySplines="0.42 0 0.58 1;0.42 0 0.58 1;0 0 1 1"
|
|
25
|
-
dur="2.4s"
|
|
26
|
-
begin="-1.2s"
|
|
27
|
-
repeatCount="indefinite"/>
|
|
28
|
-
</line>
|
|
17
|
+
<!-- rounded rectangles as explicit paths: the macOS renderers (sips and
|
|
18
|
+
qlmanage) that cut the PNG avatar mishandle rx on rect -->
|
|
19
|
+
<path d="M24 0 H96 A24 24 0 0 1 120 24 V96 A24 24 0 0 1 96 120 H24 A24 24 0 0 1 0 96 V24 A24 24 0 0 1 24 0 Z" fill="#F7C600"/>
|
|
20
|
+
<path d="M21 9 H99 A12 12 0 0 1 111 21 V99 A12 12 0 0 1 99 111 H21 A12 12 0 0 1 9 99 V21 A12 12 0 0 1 21 9 Z" fill="none" stroke="#111111" stroke-width="6"/>
|
|
21
|
+
<path
|
|
22
|
+
d="M22 60 H48
|
|
23
|
+
M48 60 L92.2 29 M75.3 27.5 L92.2 29 L87.8 45.4
|
|
24
|
+
M48 60 L92.2 91 M75.3 92.5 L92.2 91 L87.8 74.6"
|
|
25
|
+
fill="none" stroke="#111111" stroke-width="11" stroke-linecap="round" stroke-linejoin="round"/>
|
|
29
26
|
</svg>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 730 128" width="730" height="128" role="img" aria-label="groundcrew">
|
|
3
|
+
<title>groundcrew</title>
|
|
4
|
+
<style>
|
|
5
|
+
.wordmark {
|
|
6
|
+
font-family: Overpass, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
7
|
+
font-size: 68px;
|
|
8
|
+
font-weight: 800;
|
|
9
|
+
}
|
|
10
|
+
</style>
|
|
11
|
+
<!--
|
|
12
|
+
Airport taxiway sign lockup, self-contained on light and dark pages.
|
|
13
|
+
Location panel (yellow-on-black, flush inscription border) names the
|
|
14
|
+
tool; direction panel (black-on-yellow) carries the fork arrow - one
|
|
15
|
+
task stream splitting onto parallel worktrees.
|
|
16
|
+
Field #F7C600, ink #111111. textLength normalizes the wordmark width
|
|
17
|
+
across font fallbacks.
|
|
18
|
+
-->
|
|
19
|
+
<rect width="730" height="128" rx="14" fill="#F7C600"/>
|
|
20
|
+
<path d="M570 0 H14 A14 14 0 0 0 0 14 V114 A14 14 0 0 0 14 128 H570 Z" fill="#111111"/>
|
|
21
|
+
<path d="M568 2 H14 A12 12 0 0 0 2 14 V114 A12 12 0 0 0 14 126 H568 Z" fill="none" stroke="#F7C600" stroke-width="4"/>
|
|
22
|
+
<text class="wordmark" x="285" y="89" text-anchor="middle" textLength="490" lengthAdjust="spacingAndGlyphs" fill="#F7C600">GROUNDCREW</text>
|
|
23
|
+
<g transform="translate(593,4)">
|
|
24
|
+
<path
|
|
25
|
+
d="M22 60 H48
|
|
26
|
+
M48 60 L92.2 29 M75.3 27.5 L92.2 29 L87.8 45.4
|
|
27
|
+
M48 60 L92.2 91 M75.3 92.5 L92.2 91 L87.8 74.6"
|
|
28
|
+
fill="none" stroke="#111111" stroke-width="11" stroke-linecap="round" stroke-linejoin="round"/>
|
|
29
|
+
</g>
|
|
30
|
+
</svg>
|
|
Binary file
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 680 120" width="680" height="120" role="img" aria-label="groundcrew">
|
|
3
|
-
<title>groundcrew</title>
|
|
4
|
-
<style>
|
|
5
|
-
.wordmark {
|
|
6
|
-
font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, "Liberation Mono", "DejaVu Sans Mono", monospace;
|
|
7
|
-
font-size: 92px;
|
|
8
|
-
font-weight: 700;
|
|
9
|
-
letter-spacing: -0.04em;
|
|
10
|
-
}
|
|
11
|
-
</style>
|
|
12
|
-
<!--
|
|
13
|
-
Logomark: crossed marshaling wands.
|
|
14
|
-
Handles at (18,108) and (102,108), cross at (60,50), tips at (88,11) and (32,11).
|
|
15
|
-
SMIL animation: wands alternate dimming, 2.4s cycle.
|
|
16
|
-
Right wand offset by -1.2s so both open fully opaque.
|
|
17
|
-
-->
|
|
18
|
-
<line x1="18" y1="108" x2="88" y2="11" stroke="#FF6D00" stroke-width="20" stroke-linecap="round">
|
|
19
|
-
<animate attributeName="opacity"
|
|
20
|
-
values="1;0.38;1;1"
|
|
21
|
-
keyTimes="0;0.25;0.5;1"
|
|
22
|
-
calcMode="spline"
|
|
23
|
-
keySplines="0.42 0 0.58 1;0.42 0 0.58 1;0 0 1 1"
|
|
24
|
-
dur="2.4s"
|
|
25
|
-
repeatCount="indefinite"/>
|
|
26
|
-
</line>
|
|
27
|
-
<line x1="102" y1="108" x2="32" y2="11" stroke="#FF6D00" stroke-width="20" stroke-linecap="round">
|
|
28
|
-
<animate attributeName="opacity"
|
|
29
|
-
values="1;0.38;1;1"
|
|
30
|
-
keyTimes="0;0.25;0.5;1"
|
|
31
|
-
calcMode="spline"
|
|
32
|
-
keySplines="0.42 0 0.58 1;0.42 0 0.58 1;0 0 1 1"
|
|
33
|
-
dur="2.4s"
|
|
34
|
-
begin="-1.2s"
|
|
35
|
-
repeatCount="indefinite"/>
|
|
36
|
-
</line>
|
|
37
|
-
<text class="wordmark" x="136" y="92" textLength="540" lengthAdjust="spacingAndGlyphs" fill="#e4e4e7">groundcrew</text>
|
|
38
|
-
</svg>
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 680 120" width="680" height="120" role="img" aria-label="groundcrew">
|
|
3
|
-
<title>groundcrew</title>
|
|
4
|
-
<style>
|
|
5
|
-
.wordmark {
|
|
6
|
-
font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, "Liberation Mono", "DejaVu Sans Mono", monospace;
|
|
7
|
-
font-size: 92px;
|
|
8
|
-
font-weight: 700;
|
|
9
|
-
letter-spacing: -0.04em;
|
|
10
|
-
}
|
|
11
|
-
</style>
|
|
12
|
-
<!--
|
|
13
|
-
Logomark: crossed marshaling wands.
|
|
14
|
-
Handles at (18,108) and (102,108), cross at (60,50), tips at (88,11) and (32,11).
|
|
15
|
-
SMIL animation: wands alternate dimming, 2.4s cycle.
|
|
16
|
-
Right wand offset by -1.2s so both open fully opaque.
|
|
17
|
-
-->
|
|
18
|
-
<line x1="18" y1="108" x2="88" y2="11" stroke="#FF6D00" stroke-width="20" stroke-linecap="round">
|
|
19
|
-
<animate attributeName="opacity"
|
|
20
|
-
values="1;0.38;1;1"
|
|
21
|
-
keyTimes="0;0.25;0.5;1"
|
|
22
|
-
calcMode="spline"
|
|
23
|
-
keySplines="0.42 0 0.58 1;0.42 0 0.58 1;0 0 1 1"
|
|
24
|
-
dur="2.4s"
|
|
25
|
-
repeatCount="indefinite"/>
|
|
26
|
-
</line>
|
|
27
|
-
<line x1="102" y1="108" x2="32" y2="11" stroke="#FF6D00" stroke-width="20" stroke-linecap="round">
|
|
28
|
-
<animate attributeName="opacity"
|
|
29
|
-
values="1;0.38;1;1"
|
|
30
|
-
keyTimes="0;0.25;0.5;1"
|
|
31
|
-
calcMode="spline"
|
|
32
|
-
keySplines="0.42 0 0.58 1;0.42 0 0.58 1;0 0 1 1"
|
|
33
|
-
dur="2.4s"
|
|
34
|
-
begin="-1.2s"
|
|
35
|
-
repeatCount="indefinite"/>
|
|
36
|
-
</line>
|
|
37
|
-
<text class="wordmark" x="136" y="92" textLength="540" lengthAdjust="spacingAndGlyphs" fill="#18181b">groundcrew</text>
|
|
38
|
-
</svg>
|