@clipboard-health/groundcrew 2.3.0 → 2.3.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/LICENSE +21 -0
- package/README.md +258 -86
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +22 -10
- package/dist/commands/dispatcher.d.ts.map +1 -1
- package/dist/commands/dispatcher.js +10 -35
- package/dist/commands/doctor.d.ts +4 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +21 -1
- package/dist/commands/eligibility.d.ts +14 -0
- package/dist/commands/eligibility.d.ts.map +1 -1
- package/dist/commands/eligibility.js +44 -0
- package/dist/commands/setupWorkspace.d.ts.map +1 -1
- package/dist/commands/setupWorkspace.js +3 -1
- package/dist/commands/ticketDoctor.d.ts +48 -0
- package/dist/commands/ticketDoctor.d.ts.map +1 -0
- package/dist/commands/ticketDoctor.js +402 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/lib/boardSource.d.ts +55 -0
- package/dist/lib/boardSource.d.ts.map +1 -1
- package/dist/lib/boardSource.js +171 -26
- package/dist/lib/dockerSandbox.d.ts +6 -7
- package/dist/lib/dockerSandbox.d.ts.map +1 -1
- package/dist/lib/dockerSandbox.js +6 -6
- package/dist/lib/workspaces.d.ts.map +1 -1
- package/dist/lib/workspaces.js +9 -4
- package/dist/lib/worktrees.d.ts.map +1 -1
- package/dist/lib/worktrees.js +34 -12
- package/package.json +1 -1
- package/static/groundcrew-wordmark-dark.svg +15 -0
- package/static/groundcrew-wordmark-light.svg +15 -0
- package/static/groundcrew.svg +0 -9
|
@@ -69,6 +69,61 @@ interface ResolvedIssue {
|
|
|
69
69
|
model: string;
|
|
70
70
|
teamId: string;
|
|
71
71
|
}
|
|
72
|
+
export interface RawLinearIssue {
|
|
73
|
+
uuid: string;
|
|
74
|
+
title: string;
|
|
75
|
+
description: string;
|
|
76
|
+
teamId: string;
|
|
77
|
+
labels: {
|
|
78
|
+
name: string;
|
|
79
|
+
}[];
|
|
80
|
+
/** Linear workflow state name, e.g. "Todo", "In Review". May be "" if state was null. */
|
|
81
|
+
stateName: string;
|
|
82
|
+
blockers: Blocker[];
|
|
83
|
+
hasMoreBlockers: boolean;
|
|
84
|
+
}
|
|
85
|
+
export declare function fetchBlockersForTicket(arguments_: {
|
|
86
|
+
client: LinearClient;
|
|
87
|
+
ticket: string;
|
|
88
|
+
uuid: string;
|
|
89
|
+
}): Promise<readonly Blocker[]>;
|
|
90
|
+
export declare function fetchRawLinearIssue(arguments_: {
|
|
91
|
+
client: LinearClient;
|
|
92
|
+
ticket: string;
|
|
93
|
+
}): Promise<RawLinearIssue>;
|
|
94
|
+
export declare function fetchInProgressIssueCount(arguments_: {
|
|
95
|
+
client: LinearClient;
|
|
96
|
+
config: ResolvedConfig;
|
|
97
|
+
}): Promise<number>;
|
|
98
|
+
export type RepositoryResolution = {
|
|
99
|
+
kind: "ok";
|
|
100
|
+
repository: string;
|
|
101
|
+
} | {
|
|
102
|
+
kind: "missing";
|
|
103
|
+
};
|
|
104
|
+
export declare function resolveRepositoryFor(arguments_: {
|
|
105
|
+
description: string | undefined;
|
|
106
|
+
config: ResolvedConfig;
|
|
107
|
+
ticket: string;
|
|
108
|
+
}): RepositoryResolution;
|
|
109
|
+
export type ModelResolution = {
|
|
110
|
+
kind: "matched";
|
|
111
|
+
model: string;
|
|
112
|
+
} | {
|
|
113
|
+
kind: "no-label";
|
|
114
|
+
} | {
|
|
115
|
+
kind: "agent-any";
|
|
116
|
+
} | {
|
|
117
|
+
kind: "disabled-fallback";
|
|
118
|
+
requestedModel: string;
|
|
119
|
+
fallbackModel: string;
|
|
120
|
+
};
|
|
121
|
+
export declare function resolveModelFor(arguments_: {
|
|
122
|
+
labels: {
|
|
123
|
+
name: string;
|
|
124
|
+
}[];
|
|
125
|
+
config: ResolvedConfig;
|
|
126
|
+
}): ModelResolution;
|
|
72
127
|
/**
|
|
73
128
|
* `agent-any` collapses to `models.default` here — manual setup doesn't run
|
|
74
129
|
* the usage-gated `any` resolver, so the caller gets a concrete model name
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"boardSource.d.ts","sourceRoot":"","sources":["../../src/lib/boardSource.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAA6C,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAM7F,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,0FAA0F;IAC1F,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,0FAA0F;IAC1F,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,IAAI,eAAe,CAExE;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,KAAK,EAAE,CAAC;CACjB;AAED,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,YAAmB,UAAU,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,EAMjF;CACF;AAED,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,8DAA8D;IAC9D,KAAK,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;CAC9B;AAED,UAAU,eAAe;IACvB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,GAAG,WAAW,CAUpE;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAEhF;
|
|
1
|
+
{"version":3,"file":"boardSource.d.ts","sourceRoot":"","sources":["../../src/lib/boardSource.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/boardSource.js
CHANGED
|
@@ -129,9 +129,9 @@ async function fetchBoard(client, config) {
|
|
|
129
129
|
const issues = nodes
|
|
130
130
|
.filter((node) => node.children.nodes.length === 0)
|
|
131
131
|
.map((node) => {
|
|
132
|
-
const
|
|
133
|
-
warnIfDisabledFallback(node.identifier,
|
|
134
|
-
const repository =
|
|
132
|
+
const modelResolution = resolveModelFor({ labels: node.labels.nodes, config });
|
|
133
|
+
warnIfDisabledFallback(node.identifier, modelResolution, config);
|
|
134
|
+
const repository = modelResolution.kind === "no-label"
|
|
135
135
|
? undefined
|
|
136
136
|
: parseRepository({
|
|
137
137
|
description: node.description ?? undefined,
|
|
@@ -139,6 +139,16 @@ async function fetchBoard(client, config) {
|
|
|
139
139
|
repositoryRegex,
|
|
140
140
|
ticket: node.identifier,
|
|
141
141
|
});
|
|
142
|
+
let model;
|
|
143
|
+
if (modelResolution.kind === "matched") {
|
|
144
|
+
({ model } = modelResolution);
|
|
145
|
+
}
|
|
146
|
+
else if (modelResolution.kind === "disabled-fallback") {
|
|
147
|
+
model = modelResolution.fallbackModel;
|
|
148
|
+
}
|
|
149
|
+
else if (modelResolution.kind === "agent-any") {
|
|
150
|
+
model = AGENT_ANY_MODEL;
|
|
151
|
+
}
|
|
142
152
|
return {
|
|
143
153
|
id: node.identifier.toLowerCase(),
|
|
144
154
|
uuid: node.id,
|
|
@@ -148,7 +158,7 @@ async function fetchBoard(client, config) {
|
|
|
148
158
|
assignee: node.assignee?.name ?? "Unassigned",
|
|
149
159
|
updatedAt: node.updatedAt,
|
|
150
160
|
repository,
|
|
151
|
-
model
|
|
161
|
+
model,
|
|
152
162
|
teamId: node.team?.id ?? "",
|
|
153
163
|
blockers: blockersFromRelations(node.inverseRelations?.nodes ?? []),
|
|
154
164
|
hasMoreBlockers: node.inverseRelations?.pageInfo.hasNextPage ?? false,
|
|
@@ -174,22 +184,64 @@ function buildRepositoryRegex(config) {
|
|
|
174
184
|
return new RegExp(String.raw `\b(${alternation})\b`);
|
|
175
185
|
}
|
|
176
186
|
const ISSUE_LABEL_PAGE_SIZE = 50;
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
187
|
+
const ISSUE_RELATION_PAGE_SIZE = 50;
|
|
188
|
+
export async function fetchBlockersForTicket(arguments_) {
|
|
189
|
+
const { client, uuid } = arguments_;
|
|
190
|
+
const relations = [];
|
|
191
|
+
let after = null;
|
|
192
|
+
for (;;) {
|
|
193
|
+
// oxlint-disable-next-line no-await-in-loop -- pagination cursor depends on the previous response
|
|
194
|
+
const response = await client.client.rawRequest(`query IssueBlockers($id: String!, $after: String) {
|
|
195
|
+
issue(id: $id) {
|
|
196
|
+
inverseRelations(first: ${ISSUE_RELATION_PAGE_SIZE}, after: $after, includeArchived: false) {
|
|
197
|
+
nodes {
|
|
198
|
+
type
|
|
199
|
+
issue {
|
|
200
|
+
identifier
|
|
201
|
+
title
|
|
202
|
+
state { name }
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
pageInfo { hasNextPage endCursor }
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}`, { id: uuid, after });
|
|
209
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- shape is fixed by our GraphQL query above
|
|
210
|
+
const { issue } = response.data;
|
|
211
|
+
if (issue === null) {
|
|
212
|
+
return [];
|
|
213
|
+
}
|
|
214
|
+
relations.push(...issue.inverseRelations.nodes);
|
|
215
|
+
if (!issue.inverseRelations.pageInfo.hasNextPage) {
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
after = issue.inverseRelations.pageInfo.endCursor;
|
|
219
|
+
}
|
|
220
|
+
return blockersFromRelations(relations);
|
|
221
|
+
}
|
|
222
|
+
export async function fetchRawLinearIssue(arguments_) {
|
|
223
|
+
const { client, ticket } = arguments_;
|
|
184
224
|
const response = await client.client.rawRequest(`query ResolveIssue($id: String!) {
|
|
185
225
|
issue(id: $id) {
|
|
186
226
|
id
|
|
187
227
|
title
|
|
188
228
|
description
|
|
189
229
|
team { id }
|
|
230
|
+
state { name }
|
|
190
231
|
labels(first: ${ISSUE_LABEL_PAGE_SIZE}) {
|
|
191
232
|
nodes { name }
|
|
192
233
|
}
|
|
234
|
+
inverseRelations(first: 50, includeArchived: false) {
|
|
235
|
+
nodes {
|
|
236
|
+
type
|
|
237
|
+
issue {
|
|
238
|
+
identifier
|
|
239
|
+
title
|
|
240
|
+
state { name }
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
pageInfo { hasNextPage }
|
|
244
|
+
}
|
|
193
245
|
}
|
|
194
246
|
}`, { id: ticket.toUpperCase() });
|
|
195
247
|
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- shape is fixed by our GraphQL query above
|
|
@@ -197,26 +249,119 @@ export async function fetchResolvedIssue(arguments_) {
|
|
|
197
249
|
if (issue === null) {
|
|
198
250
|
throw new Error(`Ticket ${ticket.toUpperCase()} not found in Linear`);
|
|
199
251
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
252
|
+
return {
|
|
253
|
+
uuid: issue.id,
|
|
254
|
+
title: issue.title,
|
|
255
|
+
description: issue.description ?? "",
|
|
256
|
+
teamId: issue.team?.id ?? "",
|
|
257
|
+
labels: issue.labels.nodes,
|
|
258
|
+
stateName: issue.state?.name ?? "",
|
|
259
|
+
blockers: blockersFromRelations(issue.inverseRelations?.nodes ?? []),
|
|
260
|
+
hasMoreBlockers: issue.inverseRelations?.pageInfo.hasNextPage ?? false,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
export async function fetchInProgressIssueCount(arguments_) {
|
|
264
|
+
const { client, config } = arguments_;
|
|
265
|
+
let after = null;
|
|
266
|
+
let count = 0;
|
|
267
|
+
for (;;) {
|
|
268
|
+
// oxlint-disable-next-line no-await-in-loop -- pagination cursor depends on the previous response
|
|
269
|
+
const response = await client.client.rawRequest(`query InProgressIssues($slugId: String!, $stateName: String!, $agentLabelPrefix: String!, $after: String) {
|
|
270
|
+
issues(
|
|
271
|
+
filter: {
|
|
272
|
+
project: { slugId: { eq: $slugId } }
|
|
273
|
+
state: { name: { eq: $stateName } }
|
|
274
|
+
labels: { some: { name: { startsWith: $agentLabelPrefix } } }
|
|
275
|
+
}
|
|
276
|
+
first: ${ISSUES_PAGE_SIZE}
|
|
277
|
+
after: $after
|
|
278
|
+
includeArchived: false
|
|
279
|
+
) {
|
|
280
|
+
nodes { id }
|
|
281
|
+
pageInfo { hasNextPage endCursor }
|
|
282
|
+
}
|
|
283
|
+
}`, {
|
|
284
|
+
slugId: config.linear.slugId,
|
|
285
|
+
stateName: config.linear.statuses.inProgress,
|
|
286
|
+
agentLabelPrefix: AGENT_LABEL_PREFIX,
|
|
287
|
+
after,
|
|
288
|
+
});
|
|
289
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- shape is fixed by our GraphQL query above
|
|
290
|
+
const { issues: page } = response.data;
|
|
291
|
+
count += page.nodes.length;
|
|
292
|
+
if (!page.pageInfo.hasNextPage) {
|
|
293
|
+
return count;
|
|
294
|
+
}
|
|
295
|
+
after = page.pageInfo.endCursor;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
export function resolveRepositoryFor(arguments_) {
|
|
299
|
+
const { description, config } = arguments_;
|
|
300
|
+
if (description === undefined || description.length === 0) {
|
|
301
|
+
return { kind: "missing" };
|
|
302
|
+
}
|
|
303
|
+
const repository = buildRepositoryRegex(config).exec(description)?.[1];
|
|
304
|
+
if (repository === undefined) {
|
|
305
|
+
return { kind: "missing" };
|
|
306
|
+
}
|
|
307
|
+
return { kind: "ok", repository };
|
|
308
|
+
}
|
|
309
|
+
export function resolveModelFor(arguments_) {
|
|
310
|
+
const { labels, config } = arguments_;
|
|
311
|
+
const parsed = parseAgentLabels(labels, config);
|
|
312
|
+
if (parsed === undefined) {
|
|
313
|
+
return { kind: "no-label" };
|
|
314
|
+
}
|
|
315
|
+
if (parsed.model === AGENT_ANY_MODEL) {
|
|
316
|
+
return { kind: "agent-any" };
|
|
317
|
+
}
|
|
318
|
+
if (parsed.disabledFallback !== undefined) {
|
|
319
|
+
return {
|
|
320
|
+
kind: "disabled-fallback",
|
|
321
|
+
requestedModel: parsed.disabledFallback,
|
|
322
|
+
fallbackModel: parsed.model,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
return { kind: "matched", model: parsed.model };
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* `agent-any` collapses to `models.default` here — manual setup doesn't run
|
|
329
|
+
* the usage-gated `any` resolver, so the caller gets a concrete model name
|
|
330
|
+
* instead of a sentinel that downstream code can't interpret.
|
|
331
|
+
*/
|
|
332
|
+
export async function fetchResolvedIssue(arguments_) {
|
|
333
|
+
const { client, config, ticket } = arguments_;
|
|
334
|
+
const raw = await fetchRawLinearIssue({ client, ticket });
|
|
335
|
+
const repositoryResolution = resolveRepositoryFor({
|
|
336
|
+
description: raw.description,
|
|
203
337
|
config,
|
|
204
|
-
repositoryRegex: buildRepositoryRegex(config),
|
|
205
338
|
ticket: ticket.toUpperCase(),
|
|
206
339
|
});
|
|
340
|
+
if (repositoryResolution.kind === "missing") {
|
|
341
|
+
throw new RepositoryResolutionError({
|
|
342
|
+
ticket: ticket.toUpperCase(),
|
|
343
|
+
repositories: config.workspace.knownRepositories,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
207
346
|
// Manual setup is an explicit per-ticket opt-in by the user, so an
|
|
208
347
|
// unlabeled ticket still resolves to `models.default` — different from
|
|
209
348
|
// the auto-pickup path, where unlabeled tickets are ignored.
|
|
210
|
-
const
|
|
211
|
-
warnIfDisabledFallback(ticket,
|
|
212
|
-
|
|
349
|
+
const modelResolution = resolveModelFor({ labels: raw.labels, config });
|
|
350
|
+
warnIfDisabledFallback(ticket, modelResolution, config);
|
|
351
|
+
let model = config.models.default;
|
|
352
|
+
if (modelResolution.kind === "matched") {
|
|
353
|
+
({ model } = modelResolution);
|
|
354
|
+
}
|
|
355
|
+
else if (modelResolution.kind === "disabled-fallback") {
|
|
356
|
+
model = modelResolution.fallbackModel;
|
|
357
|
+
}
|
|
213
358
|
return {
|
|
214
|
-
uuid:
|
|
215
|
-
title:
|
|
216
|
-
description,
|
|
217
|
-
repository,
|
|
359
|
+
uuid: raw.uuid,
|
|
360
|
+
title: raw.title,
|
|
361
|
+
description: raw.description,
|
|
362
|
+
repository: repositoryResolution.repository,
|
|
218
363
|
model,
|
|
219
|
-
teamId:
|
|
364
|
+
teamId: raw.teamId,
|
|
220
365
|
};
|
|
221
366
|
}
|
|
222
367
|
function parseRepository(arguments_) {
|
|
@@ -278,11 +423,11 @@ function parseAgentLabels(labels, config) {
|
|
|
278
423
|
}
|
|
279
424
|
return fallback;
|
|
280
425
|
}
|
|
281
|
-
function warnIfDisabledFallback(ticket,
|
|
282
|
-
if (
|
|
426
|
+
function warnIfDisabledFallback(ticket, modelResolution, config) {
|
|
427
|
+
if (modelResolution.kind !== "disabled-fallback") {
|
|
283
428
|
return;
|
|
284
429
|
}
|
|
285
|
-
log(`${ticket.toLowerCase()}: agent-${
|
|
430
|
+
log(`${ticket.toLowerCase()}: agent-${modelResolution.requestedModel} label refers to a disabled model; falling back to models.default (${config.models.default})`);
|
|
286
431
|
}
|
|
287
432
|
function blockersFromRelations(relations) {
|
|
288
433
|
return relations
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import type { SandboxDefinition } from "./config.ts";
|
|
2
2
|
/**
|
|
3
|
-
* Derive a deterministic sbx sandbox name from the
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
3
|
+
* Derive a deterministic sbx sandbox name from the sbx agent so every
|
|
4
|
+
* groundcrew model that targets the same agent reuses one sandbox across
|
|
5
|
+
* repositories and tickets. Lowercased and reduced to the sbx-safe
|
|
6
|
+
* charset (`a-z0-9.+-`) so unusual agent names still round-trip cleanly.
|
|
7
|
+
* Keep the `groundcrew-` prefix stable — doctor and teardown use it to
|
|
8
8
|
* identify groundcrew-owned sandboxes.
|
|
9
9
|
*/
|
|
10
10
|
export declare function sandboxNameFor(arguments_: {
|
|
11
|
-
|
|
12
|
-
model: string;
|
|
11
|
+
agent: string;
|
|
13
12
|
}): string;
|
|
14
13
|
/**
|
|
15
14
|
* Probe `sbx ls` to see whether a sandbox with `sandboxName` already
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dockerSandbox.d.ts","sourceRoot":"","sources":["../../src/lib/dockerSandbox.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE;IAAE,
|
|
1
|
+
{"version":3,"file":"dockerSandbox.d.ts","sourceRoot":"","sources":["../../src/lib/dockerSandbox.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAMpE;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAM/F;AAED,UAAU,sBAAsB;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,iBAAiB,CAAC;IAC3B;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,UAAU,EAAE,sBAAsB,EAClC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAqBf"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { runCommandAsync } from "./commandRunner.js";
|
|
2
2
|
/**
|
|
3
|
-
* Derive a deterministic sbx sandbox name from the
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
3
|
+
* Derive a deterministic sbx sandbox name from the sbx agent so every
|
|
4
|
+
* groundcrew model that targets the same agent reuses one sandbox across
|
|
5
|
+
* repositories and tickets. Lowercased and reduced to the sbx-safe
|
|
6
|
+
* charset (`a-z0-9.+-`) so unusual agent names still round-trip cleanly.
|
|
7
|
+
* Keep the `groundcrew-` prefix stable — doctor and teardown use it to
|
|
8
8
|
* identify groundcrew-owned sandboxes.
|
|
9
9
|
*/
|
|
10
10
|
export function sandboxNameFor(arguments_) {
|
|
11
|
-
const raw = `groundcrew-${arguments_.
|
|
11
|
+
const raw = `groundcrew-${arguments_.agent}`.toLowerCase();
|
|
12
12
|
return raw
|
|
13
13
|
.replaceAll(/[^a-z0-9.+-]+/g, "-")
|
|
14
14
|
.replaceAll(/-+/g, "-")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspaces.d.ts","sourceRoot":"","sources":["../../src/lib/workspaces.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAA0B,KAAK,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAI1E,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5C,MAAM,WAAW,SAAS;IACxB,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"workspaces.d.ts","sourceRoot":"","sources":["../../src/lib/workspaces.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAA0B,KAAK,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAI1E,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5C,MAAM,WAAW,SAAS;IACxB,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAsU7C,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,oBAAoB,CAAC;IAChC,QAAQ,EAAE,aAAa,CAAC;IACxB,yDAAyD;IACzD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,gBAAgB;IACxB,MAAM,EAAE,cAAc,CAAC;IACvB,IAAI,EAAE,gBAAgB,CAAC;CACxB;AAED,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,gBAAgB,GAAG,mBAAmB,CAUtF;AA+ND,iBAAe,eAAe,CAC5B,MAAM,EAAE,cAAc,EACtB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,cAAc,CAAC,CAezB;AAED,eAAO,MAAM,UAAU;IACf,IAAI,SAAS,cAAc,QAAQ,QAAQ,WAAW,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvF,KAAK;IACC,KAAK,SAAS,cAAc,QAAQ,MAAM,WAAW,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhF,UAAU,SACN,cAAc,QAChB,MAAM,WACH,WAAW,GACnB,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC;CAI5C,CAAC"}
|
package/dist/lib/workspaces.js
CHANGED
|
@@ -179,6 +179,9 @@ async function applyCmuxStatus(workspaceId, status, signal) {
|
|
|
179
179
|
async function closeCmuxWorkspace(workspaceId, signal) {
|
|
180
180
|
await runWorkspaceCommand("cmux", ["close-workspace", "--workspace", workspaceId], signal);
|
|
181
181
|
}
|
|
182
|
+
function isCmuxSetStatusUnsupported(error) {
|
|
183
|
+
return errorMessage(error).includes('unknown command "set-status"');
|
|
184
|
+
}
|
|
182
185
|
const cmuxAdapter = {
|
|
183
186
|
async open(spec, signal) {
|
|
184
187
|
const inheritedRemote = await probeCurrentCmuxRemote(signal);
|
|
@@ -203,10 +206,12 @@ const cmuxAdapter = {
|
|
|
203
206
|
await applyCmuxStatus(workspaceId, spec.status, signal);
|
|
204
207
|
}
|
|
205
208
|
catch (error) {
|
|
206
|
-
//
|
|
207
|
-
//
|
|
208
|
-
//
|
|
209
|
-
|
|
209
|
+
// Status pills are best-effort. cmux v2+ dropped `set-status` entirely,
|
|
210
|
+
// so swallow that specific gap silently; surface anything else so a real
|
|
211
|
+
// regression doesn't hide behind the same swallow.
|
|
212
|
+
if (!isCmuxSetStatusUnsupported(error)) {
|
|
213
|
+
log(`cmux set-status failed for ${spec.name} (continuing): ${errorMessage(error)}`);
|
|
214
|
+
}
|
|
210
215
|
}
|
|
211
216
|
}
|
|
212
217
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worktrees.d.ts","sourceRoot":"","sources":["../../src/lib/worktrees.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAAE,KAAK,cAAc,EAAc,MAAM,iBAAiB,CAAC;AAIlE,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAElC,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,SAAgB,GAAG,EAAE,MAAM,CAAC;IAE5B,YAAmB,GAAG,EAAE,MAAM,EAI7B;CACF;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,0BAA0B,CAEhG;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,YAAY,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;
|
|
1
|
+
{"version":3,"file":"worktrees.d.ts","sourceRoot":"","sources":["../../src/lib/worktrees.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAAE,KAAK,cAAc,EAAc,MAAM,iBAAiB,CAAC;AAIlE,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAElC,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,SAAgB,GAAG,EAAE,MAAM,CAAC;IAE5B,YAAmB,GAAG,EAAE,MAAM,EAI7B;CACF;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,0BAA0B,CAEhG;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,YAAY,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAoUD,iBAAS,IAAI,CAAC,MAAM,EAAE,cAAc,GAAG,aAAa,EAAE,CAErD;AAED,iBAAS,YAAY,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,EAAE,CAE7E;AAED,iBAAe,MAAM,CACnB,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,YAAY,EAClB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,aAAa,CAAC,CAQxB;AAED,iBAAe,MAAM,CACnB,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE,aAAa,EACpB,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,GAClD,OAAO,CAAC,IAAI,CAAC,CAKf;AAED,MAAM,MAAM,YAAY,GAAG,iBAAiB,GAAG,iBAAiB,CAAC;AAEjE,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,aAAa,CAAC;IACrB,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,+DAA+D;IAC/D,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,sCAAsC;IACtC,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,wDAAwD;IACxD,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,cAAc,EAAE,cAAc,CAAC;CAChC;AAKD,iBAAe,QAAQ,CACrB,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,SAAS,aAAa,EAAE,EACjC,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,GAClD,OAAO,CAAC,cAAc,CAAC,CAkDzB;AAED,eAAO,MAAM,SAAS;;;;;;CAMrB,CAAC"}
|
package/dist/lib/worktrees.js
CHANGED
|
@@ -174,23 +174,31 @@ async function removeWorktree(config, entry, options) {
|
|
|
174
174
|
await runCommandAsync("git", removeArguments, longRunningCommandOptions(options.signal));
|
|
175
175
|
}
|
|
176
176
|
catch (error) {
|
|
177
|
-
// git's `fatal:
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
// (modified/untracked files
|
|
177
|
+
// git's `fatal: ...` diagnostic goes to inherited stderr, so the
|
|
178
|
+
// captured error is just "Exit status: 128". Probe the worktree
|
|
179
|
+
// ourselves so the failure message names the condition — dirty
|
|
180
|
+
// (modified/untracked files, fixable with `crew cleanup --force`) or
|
|
181
|
+
// orphan (directory exists on disk but is not registered with the
|
|
182
|
+
// parent repo, requires manual inspection + `rm -rf`).
|
|
181
183
|
if (options.force || options.signal?.aborted === true) {
|
|
182
184
|
throw error;
|
|
183
185
|
}
|
|
184
186
|
const dirtiness = await probeWorktreeDirtiness(entry.dir, options.signal);
|
|
185
|
-
if (dirtiness.kind
|
|
186
|
-
throw
|
|
187
|
+
if (dirtiness.kind === "dirty") {
|
|
188
|
+
throw new Error(describeDirtyWorktree({
|
|
189
|
+
ticket: entry.ticket,
|
|
190
|
+
dir: entry.dir,
|
|
191
|
+
modified: dirtiness.modified,
|
|
192
|
+
untracked: dirtiness.untracked,
|
|
193
|
+
}), { cause: error });
|
|
194
|
+
}
|
|
195
|
+
if (dirtiness.kind === "unknown") {
|
|
196
|
+
const registration = await probeWorktreeRegistration(entry.dir, options.signal);
|
|
197
|
+
if (registration === "orphan") {
|
|
198
|
+
throw new Error(describeOrphanWorktree({ dir: entry.dir }), { cause: error });
|
|
199
|
+
}
|
|
187
200
|
}
|
|
188
|
-
throw
|
|
189
|
-
ticket: entry.ticket,
|
|
190
|
-
dir: entry.dir,
|
|
191
|
-
modified: dirtiness.modified,
|
|
192
|
-
untracked: dirtiness.untracked,
|
|
193
|
-
}), { cause: error });
|
|
201
|
+
throw error;
|
|
194
202
|
}
|
|
195
203
|
}
|
|
196
204
|
else {
|
|
@@ -243,6 +251,20 @@ function describeDirtyWorktree(arguments_) {
|
|
|
243
251
|
const pronoun = modified + untracked === 1 ? "it" : "them";
|
|
244
252
|
return `worktree has ${summary}. Run \`crew cleanup --force ${ticket}\` to discard ${pronoun}, or commit/stash in ${dir} first.`;
|
|
245
253
|
}
|
|
254
|
+
async function probeWorktreeRegistration(worktreeDir, signal) {
|
|
255
|
+
let output;
|
|
256
|
+
try {
|
|
257
|
+
output = await runCommandAsync("git", ["-C", worktreeDir, "rev-parse", "--is-inside-work-tree"], signalProperty(signal));
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
return "unknown";
|
|
261
|
+
}
|
|
262
|
+
return output === "true" ? "registered" : "orphan";
|
|
263
|
+
}
|
|
264
|
+
function describeOrphanWorktree(arguments_) {
|
|
265
|
+
const { dir } = arguments_;
|
|
266
|
+
return `directory exists but is not a registered git worktree. If ${dir} has nothing of value, \`rm -rf\` ${dir} manually; otherwise inspect it before deleting.`;
|
|
267
|
+
}
|
|
246
268
|
function list(config) {
|
|
247
269
|
return listWorktrees(config);
|
|
248
270
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 620 120" width="620" height="120" role="img" aria-label="groundcrew">
|
|
3
|
+
<style>
|
|
4
|
+
.wordmark {
|
|
5
|
+
font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, "Liberation Mono", "DejaVu Sans Mono", monospace;
|
|
6
|
+
font-size: 92px;
|
|
7
|
+
font-weight: 700;
|
|
8
|
+
letter-spacing: -0.04em;
|
|
9
|
+
}
|
|
10
|
+
</style>
|
|
11
|
+
<text class="wordmark" x="20" y="92" textLength="540" lengthAdjust="spacingAndGlyphs" fill="#e4e4e7">groundcrew</text>
|
|
12
|
+
<rect x="572" y="24" width="30" height="72" fill="#77d94e">
|
|
13
|
+
<animate attributeName="opacity" values="1;0" dur="1.2s" calcMode="discrete" keyTimes="0;0.5" repeatCount="indefinite"/>
|
|
14
|
+
</rect>
|
|
15
|
+
</svg>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 620 120" width="620" height="120" role="img" aria-label="groundcrew">
|
|
3
|
+
<style>
|
|
4
|
+
.wordmark {
|
|
5
|
+
font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, "Liberation Mono", "DejaVu Sans Mono", monospace;
|
|
6
|
+
font-size: 92px;
|
|
7
|
+
font-weight: 700;
|
|
8
|
+
letter-spacing: -0.04em;
|
|
9
|
+
}
|
|
10
|
+
</style>
|
|
11
|
+
<text class="wordmark" x="20" y="92" textLength="540" lengthAdjust="spacingAndGlyphs" fill="#18181b">groundcrew</text>
|
|
12
|
+
<rect x="572" y="24" width="30" height="72" fill="#77d94e">
|
|
13
|
+
<animate attributeName="opacity" values="1;0" dur="1.2s" calcMode="discrete" keyTimes="0;0.5" repeatCount="indefinite"/>
|
|
14
|
+
</rect>
|
|
15
|
+
</svg>
|
package/static/groundcrew.svg
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
-
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
3
|
-
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="225 230 575 530" width="1024.0pt" height="944.0pt">
|
|
4
|
-
<path d="M 491.97 239.05 C 526.13 236.93 560.37 240.48 593.00 251.00 C 626.41 261.79 657.69 279.64 683.66 303.32 C 707.08 325.06 726.40 351.86 738.47 381.51 C 744.03 394.32 747.45 407.46 750.90 420.93 C 762.33 420.53 773.79 425.00 781.76 433.25 C 788.68 441.04 792.39 451.62 792.07 462.00 C 792.08 487.67 792.17 513.33 792.05 539.00 C 792.27 545.73 790.51 552.54 787.54 558.55 C 783.74 566.04 777.45 571.67 770.09 575.55 C 769.92 579.70 770.08 583.85 769.99 588.00 C 768.69 602.43 766.81 616.79 757.36 628.43 C 756.74 632.58 757.53 636.52 755.44 640.46 C 752.06 648.40 745.48 652.22 738.31 656.27 C 732.17 659.48 726.14 662.23 719.02 660.89 C 712.87 659.35 707.07 655.43 704.53 649.45 C 703.05 645.51 702.46 641.30 703.50 637.16 C 704.33 631.93 708.45 627.64 712.25 624.25 C 716.71 620.56 721.78 617.56 726.88 614.85 C 732.77 611.92 740.93 611.14 746.43 615.32 C 747.51 614.30 747.88 613.62 748.20 612.15 C 751.08 601.64 751.97 590.54 751.90 579.68 C 745.31 580.33 738.62 579.86 732.00 580.03 C 720.74 580.20 709.30 575.59 703.14 565.80 C 699.76 560.81 698.29 554.97 697.99 549.01 C 698.02 514.60 697.92 480.42 698.18 446.00 C 698.56 440.21 699.47 434.75 703.08 430.01 C 706.08 425.60 710.41 423.81 715.11 421.80 C 706.69 386.13 686.06 353.49 659.23 328.77 C 646.53 316.55 632.06 306.71 616.51 298.46 C 593.44 285.91 568.21 277.82 542.16 274.50 C 536.07 273.94 530.13 272.79 524.00 272.97 C 517.66 272.59 511.34 272.32 504.99 272.77 C 499.95 273.21 495.01 272.70 490.00 273.58 C 454.29 276.95 418.96 289.01 389.27 309.26 C 362.61 326.89 340.47 351.37 325.30 379.49 C 319.33 390.66 314.19 402.41 310.72 414.61 C 309.94 417.28 308.92 419.78 308.91 422.62 C 318.36 424.43 324.44 433.67 324.21 443.00 C 324.27 477.65 324.12 512.34 324.20 547.00 C 324.14 550.61 324.24 554.28 323.83 557.87 C 321.66 565.85 315.98 572.12 308.64 575.78 C 300.05 580.18 291.39 580.22 282.00 580.01 C 267.62 580.66 253.23 576.52 243.12 565.88 C 234.68 557.31 231.16 545.84 230.97 534.00 C 231.02 512.33 230.96 490.67 231.00 469.00 C 231.03 464.43 230.69 460.00 231.64 455.49 C 233.10 443.19 240.79 431.64 251.69 425.73 C 258.00 422.14 265.62 420.75 272.81 420.86 C 278.14 395.31 287.67 370.76 301.76 348.76 C 308.87 337.50 316.93 326.73 326.09 317.05 C 330.25 312.27 334.65 307.58 339.54 303.53 C 365.80 279.49 398.14 261.74 432.05 251.14 C 451.47 244.59 471.61 240.98 491.97 239.05 Z" fill="#78716c" />
|
|
5
|
-
<path d="M 356.00 444.19 C 452.27 444.23 548.55 444.15 644.82 444.23 C 649.66 444.23 654.22 444.56 657.84 448.15 C 661.26 451.27 662.52 455.45 662.47 459.99 C 662.31 525.35 662.51 590.59 662.40 656.00 C 662.38 661.55 662.63 667.04 661.94 672.56 C 659.55 678.86 653.83 683.18 647.00 683.04 C 547.66 683.01 448.31 683.05 348.96 683.02 C 340.58 682.87 333.60 675.32 333.95 667.00 C 333.95 599.00 333.96 531.00 333.94 463.00 C 333.95 460.46 333.79 457.81 334.22 455.29 C 335.23 451.68 337.14 448.37 340.50 446.48 C 345.39 443.64 350.60 444.17 356.00 444.19 Z" fill="#78716c" />
|
|
6
|
-
<path d="M 389.00 483.91 C 392.46 483.66 394.50 486.02 397.14 487.82 C 416.17 501.83 435.17 515.92 454.42 529.63 C 456.37 531.09 458.13 532.56 458.89 534.98 C 459.10 537.05 459.34 539.53 458.56 541.50 C 457.15 543.90 454.68 545.81 452.49 547.46 C 434.16 560.87 415.99 574.32 397.64 587.70 C 395.69 589.05 393.38 590.56 391.00 590.95 C 386.00 590.89 381.37 587.28 381.55 581.96 C 381.26 576.63 385.28 574.69 388.98 571.94 C 404.61 560.64 420.06 549.02 435.97 538.11 C 419.10 525.62 402.11 513.26 385.25 500.75 C 382.37 498.55 379.93 495.86 380.05 491.99 C 380.79 487.65 384.18 483.40 389.00 483.91 Z" fill="#77d94e" />
|
|
7
|
-
<path d="M 672.78 521.32 C 677.82 520.86 682.12 520.21 686.27 523.73 C 691.33 527.85 690.31 533.17 690.62 539.00 C 690.46 604.02 690.92 668.98 690.42 734.01 C 690.17 739.13 688.58 744.11 684.46 747.42 C 681.30 750.32 677.21 751.32 673.00 751.12 C 577.34 751.12 481.66 751.13 386.00 751.08 C 377.59 751.55 369.36 743.47 369.97 735.00 C 370.03 721.31 369.99 707.63 369.97 693.94 C 460.31 694.02 550.66 693.99 641.00 693.96 C 652.00 694.60 663.63 688.89 669.36 679.38 C 672.64 674.56 672.40 668.57 672.51 663.00 C 672.55 618.67 672.51 574.33 672.55 530.00 C 672.50 527.10 672.50 524.21 672.78 521.32 Z" fill="#78716c" />
|
|
8
|
-
<path d="M 473.99 577.90 C 490.65 577.77 507.33 577.94 524.00 577.84 C 527.49 577.86 531.25 577.49 534.68 578.19 C 539.56 579.86 541.50 585.54 539.02 590.00 C 537.21 593.42 533.72 594.68 530.03 594.77 C 512.35 594.96 494.68 594.68 477.00 594.87 C 473.37 594.93 470.04 594.29 467.64 591.35 C 465.40 589.27 465.80 585.98 466.16 583.24 C 467.44 580.11 470.43 577.60 473.99 577.90 Z" fill="#77d94e" />
|
|
9
|
-
</svg>
|