@brainervirus/workit-mcp 1.2.1 → 1.3.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/dist/index.js +849 -282
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -6620,11 +6620,11 @@ var require_dist = __commonJS(function(exports, module) {
|
|
|
6620
6620
|
|
|
6621
6621
|
// packages/workit-mcp/src/index.ts
|
|
6622
6622
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
6623
|
-
import
|
|
6623
|
+
import path16 from "node:path";
|
|
6624
6624
|
|
|
6625
6625
|
// packages/workit-mcp/src/server.ts
|
|
6626
|
-
import { existsSync as existsSync7, readFileSync as readFileSync8, realpathSync as
|
|
6627
|
-
import
|
|
6626
|
+
import { existsSync as existsSync7, readFileSync as readFileSync8, realpathSync as realpathSync8 } from "node:fs";
|
|
6627
|
+
import path15 from "node:path";
|
|
6628
6628
|
|
|
6629
6629
|
// node_modules/@modelcontextprotocol/sdk/node_modules/zod/v4/core/core.js
|
|
6630
6630
|
var NEVER = Object.freeze({
|
|
@@ -12477,8 +12477,8 @@ import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
|
12477
12477
|
|
|
12478
12478
|
// packages/workit-core/src/core.ts
|
|
12479
12479
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
12480
|
-
import { existsSync as existsSync5, realpathSync as
|
|
12481
|
-
import
|
|
12480
|
+
import { existsSync as existsSync5, realpathSync as realpathSync7 } from "node:fs";
|
|
12481
|
+
import path11 from "node:path";
|
|
12482
12482
|
|
|
12483
12483
|
// packages/workit-core/src/core/task-contract.ts
|
|
12484
12484
|
import { createHash, randomUUID } from "node:crypto";
|
|
@@ -17785,6 +17785,17 @@ function _array2(Class, element, params) {
|
|
|
17785
17785
|
...normalizeParams2(params)
|
|
17786
17786
|
});
|
|
17787
17787
|
}
|
|
17788
|
+
function _custom2(Class, fn, _params) {
|
|
17789
|
+
const norm = normalizeParams2(_params);
|
|
17790
|
+
norm.abort ?? (norm.abort = true);
|
|
17791
|
+
const schema = new Class({
|
|
17792
|
+
type: "custom",
|
|
17793
|
+
check: "custom",
|
|
17794
|
+
fn,
|
|
17795
|
+
...norm
|
|
17796
|
+
});
|
|
17797
|
+
return schema;
|
|
17798
|
+
}
|
|
17788
17799
|
function _refine2(Class, fn, _params) {
|
|
17789
17800
|
const schema = new Class({
|
|
17790
17801
|
type: "custom",
|
|
@@ -19938,6 +19949,9 @@ var ZodCustom2 = /* @__PURE__ */ $constructor2("ZodCustom", (inst, def) => {
|
|
|
19938
19949
|
ZodType2.init(inst, def);
|
|
19939
19950
|
inst._zod.processJSONSchema = (ctx, json, params) => customProcessor(inst, ctx, json, params);
|
|
19940
19951
|
});
|
|
19952
|
+
function custom2(fn, _params) {
|
|
19953
|
+
return _custom2(ZodCustom2, fn ?? (() => true), _params);
|
|
19954
|
+
}
|
|
19941
19955
|
function refine2(fn, _params = {}) {
|
|
19942
19956
|
return _refine2(ZodCustom2, fn, _params);
|
|
19943
19957
|
}
|
|
@@ -20371,7 +20385,8 @@ var decisionSchema = object4({
|
|
|
20371
20385
|
consumption: object4({
|
|
20372
20386
|
state: _enum2(["reserved", "consumed", "uncertain"]),
|
|
20373
20387
|
at: utc,
|
|
20374
|
-
actionRef: refSchema
|
|
20388
|
+
actionRef: refSchema,
|
|
20389
|
+
historicalActionId: text.optional()
|
|
20375
20390
|
}).strict().nullable()
|
|
20376
20391
|
}).strict();
|
|
20377
20392
|
var findingSchema = object4({
|
|
@@ -20514,7 +20529,7 @@ var taskSummarySchema = object4({
|
|
|
20514
20529
|
requirements: array3(requirementEvaluationSchema),
|
|
20515
20530
|
writer: workspaceRecordSchema.shape.writer
|
|
20516
20531
|
}).strict();
|
|
20517
|
-
var taskListItemSchema = taskSummarySchema.omit({ policy: true, requirements: true });
|
|
20532
|
+
var taskListItemSchema = taskSummarySchema.omit({ policy: true, requirements: true }).extend({ source: provenanceSchema.pick({ host: true, kind: true }) }).strict();
|
|
20518
20533
|
var exportBundleSchema = object4({
|
|
20519
20534
|
schemaVersion: literal3(1),
|
|
20520
20535
|
exportedAt: utc,
|
|
@@ -20539,6 +20554,7 @@ var taskOperations = {
|
|
|
20539
20554
|
list: operation({
|
|
20540
20555
|
action: literal3("list"),
|
|
20541
20556
|
status: _enum2(["open", "closed", "all"]).optional(),
|
|
20557
|
+
query: string5().trim().min(1).max(200).optional(),
|
|
20542
20558
|
limit: number5().int().min(1).max(50).optional()
|
|
20543
20559
|
}),
|
|
20544
20560
|
inspect: operation({
|
|
@@ -20886,6 +20902,7 @@ function requirementId(input) {
|
|
|
20886
20902
|
}
|
|
20887
20903
|
// packages/workit-core/src/core/task-store.ts
|
|
20888
20904
|
import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
|
|
20905
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
20889
20906
|
import * as fs4 from "node:fs";
|
|
20890
20907
|
import { hostname as hostname2 } from "node:os";
|
|
20891
20908
|
import path4 from "node:path";
|
|
@@ -21521,7 +21538,8 @@ var metadataLockSchema = object4({
|
|
|
21521
21538
|
pid: number5().int().nonnegative().safe(),
|
|
21522
21539
|
processStart: string5().nullable(),
|
|
21523
21540
|
host: string5().min(1),
|
|
21524
|
-
nonce: string5().min(1)
|
|
21541
|
+
nonce: string5().min(1),
|
|
21542
|
+
externalAction: literal3(true).optional()
|
|
21525
21543
|
}).strict();
|
|
21526
21544
|
var now = () => new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
21527
21545
|
var cachedRuntimeVersion = null;
|
|
@@ -21573,6 +21591,28 @@ var sameMetadataLock = (left, right) => {
|
|
|
21573
21591
|
const parsed = metadataLockSchema.safeParse(left);
|
|
21574
21592
|
return parsed.success && canonicalJson(parsed.data) === canonicalJson(right);
|
|
21575
21593
|
};
|
|
21594
|
+
var sameDirectoryIdentity = (left, right) => {
|
|
21595
|
+
if (!path4.isAbsolute(left) || !path4.isAbsolute(right))
|
|
21596
|
+
return false;
|
|
21597
|
+
const normalizedLeft = path4.resolve(left);
|
|
21598
|
+
const normalizedRight = path4.resolve(right);
|
|
21599
|
+
try {
|
|
21600
|
+
const a = fs4.statSync(normalizedLeft, { bigint: true });
|
|
21601
|
+
const b = fs4.statSync(normalizedRight, { bigint: true });
|
|
21602
|
+
if (!a.isDirectory() || !b.isDirectory())
|
|
21603
|
+
return false;
|
|
21604
|
+
if (process.platform === "win32" ? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase() : normalizedLeft === normalizedRight)
|
|
21605
|
+
return true;
|
|
21606
|
+
const canonicalLeft = fs4.realpathSync(normalizedLeft);
|
|
21607
|
+
const canonicalRight = fs4.realpathSync(normalizedRight);
|
|
21608
|
+
if (process.platform === "win32" ? canonicalLeft.toLowerCase() === canonicalRight.toLowerCase() : canonicalLeft === canonicalRight)
|
|
21609
|
+
return true;
|
|
21610
|
+
return a.dev === b.dev && a.ino !== 0n && a.ino === b.ino;
|
|
21611
|
+
} catch {
|
|
21612
|
+
return false;
|
|
21613
|
+
}
|
|
21614
|
+
};
|
|
21615
|
+
var externalActionLockRoots = new AsyncLocalStorage;
|
|
21576
21616
|
|
|
21577
21617
|
class TaskStore {
|
|
21578
21618
|
root;
|
|
@@ -21633,7 +21673,7 @@ class TaskStore {
|
|
|
21633
21673
|
const item = this.readRecord(this.workspacePath, workspaceRecordSchema);
|
|
21634
21674
|
if (!item.exists)
|
|
21635
21675
|
return success(null, null, null);
|
|
21636
|
-
if (item.result.ok && item.result.data.root !== this.root)
|
|
21676
|
+
if (item.result.ok && item.result.data.root !== this.root && !sameDirectoryIdentity(item.result.data.root, this.root))
|
|
21637
21677
|
return failure("recovery_required", "workspace root binding is invalid", {
|
|
21638
21678
|
path: this.workspacePath
|
|
21639
21679
|
});
|
|
@@ -21724,6 +21764,29 @@ class TaskStore {
|
|
|
21724
21764
|
const current = this.readWorkspace();
|
|
21725
21765
|
if (!current.ok)
|
|
21726
21766
|
return current;
|
|
21767
|
+
const origin = input.task.origin;
|
|
21768
|
+
if (current.data && origin) {
|
|
21769
|
+
if (origin.workspaceId === current.data.id) {
|
|
21770
|
+
const source = this.readTask(origin.taskId);
|
|
21771
|
+
if (source.ok)
|
|
21772
|
+
return success(source.data.revision, current.data.revision, source.data);
|
|
21773
|
+
if (source.code !== "not_found")
|
|
21774
|
+
return source;
|
|
21775
|
+
return failure("not_found", "source task is not present in this shared workspace");
|
|
21776
|
+
}
|
|
21777
|
+
const tasks = this.listTasks();
|
|
21778
|
+
if (!tasks.ok)
|
|
21779
|
+
return tasks;
|
|
21780
|
+
const prior = tasks.data.filter((task) => task.origin?.workspaceId === origin.workspaceId && task.origin?.taskId === origin.taskId);
|
|
21781
|
+
if (prior.length > 1)
|
|
21782
|
+
return failure("recovery_required", `source task has multiple imported mappings: ${prior.map((task) => task.id).join(", ")}`);
|
|
21783
|
+
if (prior.length === 1) {
|
|
21784
|
+
const existing = prior[0];
|
|
21785
|
+
if (existing.origin.exportDigest !== origin.exportDigest)
|
|
21786
|
+
return failure("revision_conflict", "source task export changed; reconcile the mapped destination task before importing", { taskId: existing.id });
|
|
21787
|
+
return success(existing.revision, current.data.revision, existing);
|
|
21788
|
+
}
|
|
21789
|
+
}
|
|
21727
21790
|
if (current.data ? input.expectedWorkspaceRevision !== current.data.revision : input.expectedWorkspaceRevision !== null)
|
|
21728
21791
|
return failure("revision_conflict", "workspace revision does not match; omit expectedWorkspaceRevision to use the current record", {
|
|
21729
21792
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
@@ -22112,6 +22175,73 @@ class TaskStore {
|
|
|
22112
22175
|
})
|
|
22113
22176
|
};
|
|
22114
22177
|
}
|
|
22178
|
+
externalActionLockOptions() {
|
|
22179
|
+
const options = this.metadataLockOptions();
|
|
22180
|
+
return { ...options, payload: () => ({ ...options.payload(), externalAction: true }) };
|
|
22181
|
+
}
|
|
22182
|
+
async withExternalActionLock(operation, reentrant = false) {
|
|
22183
|
+
const activeRoots = externalActionLockRoots.getStore();
|
|
22184
|
+
if (activeRoots && [...activeRoots].some((root) => root === this.root || sameDirectoryIdentity(root, this.root)))
|
|
22185
|
+
return operation();
|
|
22186
|
+
try {
|
|
22187
|
+
this.initializeMutationStorage();
|
|
22188
|
+
} catch (error) {
|
|
22189
|
+
return failure("storage_error", `unable to initialize store: ${String(error)}`, {
|
|
22190
|
+
path: this.workitDir
|
|
22191
|
+
});
|
|
22192
|
+
}
|
|
22193
|
+
let handle;
|
|
22194
|
+
try {
|
|
22195
|
+
handle = acquireFileLockSync(this.workspacePath, this.externalActionLockOptions());
|
|
22196
|
+
} catch (error) {
|
|
22197
|
+
return this.lockFailure(error);
|
|
22198
|
+
}
|
|
22199
|
+
let result;
|
|
22200
|
+
try {
|
|
22201
|
+
if (!handle.verifyStillHeld())
|
|
22202
|
+
result = failure("recovery_required", "metadata lock was compromised", {
|
|
22203
|
+
path: this.lockPath
|
|
22204
|
+
});
|
|
22205
|
+
else {
|
|
22206
|
+
try {
|
|
22207
|
+
const run = () => operation();
|
|
22208
|
+
result = await (reentrant ? externalActionLockRoots.run(new Set([...activeRoots ?? [], this.root]), run) : run());
|
|
22209
|
+
} catch {
|
|
22210
|
+
result = failure("external_outcome_unknown", "external action outcome is unknown", {
|
|
22211
|
+
outcome: "unknown"
|
|
22212
|
+
});
|
|
22213
|
+
}
|
|
22214
|
+
try {
|
|
22215
|
+
if (!handle.verifyStillHeld())
|
|
22216
|
+
result = failure("external_outcome_unknown", "metadata lock was compromised", {
|
|
22217
|
+
outcome: "unknown",
|
|
22218
|
+
path: this.lockPath
|
|
22219
|
+
});
|
|
22220
|
+
} catch {
|
|
22221
|
+
result = failure("external_outcome_unknown", "metadata lock could not be verified", {
|
|
22222
|
+
outcome: "unknown",
|
|
22223
|
+
path: this.lockPath
|
|
22224
|
+
});
|
|
22225
|
+
}
|
|
22226
|
+
}
|
|
22227
|
+
} catch {
|
|
22228
|
+
result = failure("external_outcome_unknown", "external action lock operation failed", {
|
|
22229
|
+
outcome: "unknown",
|
|
22230
|
+
path: this.lockPath
|
|
22231
|
+
});
|
|
22232
|
+
}
|
|
22233
|
+
try {
|
|
22234
|
+
handle.release();
|
|
22235
|
+
} catch (error) {
|
|
22236
|
+
const released = this.lockFailure(error);
|
|
22237
|
+
const releaseError = released.ok ? "metadata lock release failed" : released.error;
|
|
22238
|
+
return result.ok ? failure("external_outcome_unknown", "external action metadata lock release is uncertain", {
|
|
22239
|
+
outcome: "unknown",
|
|
22240
|
+
path: this.lockPath
|
|
22241
|
+
}) : failure("recovery_required", `${result.error}; ${releaseError}`, result.details);
|
|
22242
|
+
}
|
|
22243
|
+
return result;
|
|
22244
|
+
}
|
|
22115
22245
|
recoveryLockOptions(observed, evidence, gate) {
|
|
22116
22246
|
const options = this.metadataLockOptions();
|
|
22117
22247
|
options.staleRecovery = "remove-if-unchanged";
|
|
@@ -22181,6 +22311,14 @@ class TaskStore {
|
|
|
22181
22311
|
lockFailure(error) {
|
|
22182
22312
|
const value = error;
|
|
22183
22313
|
const code = typeof value?.code === "string" ? value.code : "";
|
|
22314
|
+
if (code === "EEXIST" || code === "file_lock_timeout") {
|
|
22315
|
+
const lock = this.readLockSnapshot();
|
|
22316
|
+
if (lock.ok && lock.data?.data.externalAction)
|
|
22317
|
+
return failure("writer_conflict", "workspace is reserved by a managed external action", {
|
|
22318
|
+
outcome: "not_started",
|
|
22319
|
+
path: this.lockPath
|
|
22320
|
+
});
|
|
22321
|
+
}
|
|
22184
22322
|
const recovery = code === "EEXIST" || code === "file_lock_timeout" || code === "file_lock_stale" || code === "metadata_lock_invalid" || code === "not-file" || /metadata lock|file lock|reclaim/i.test(String(value?.message ?? error));
|
|
22185
22323
|
return failure(recovery ? "recovery_required" : "storage_error", `metadata lock operation failed: ${String(error)}`, { path: this.lockPath });
|
|
22186
22324
|
}
|
|
@@ -22448,21 +22586,23 @@ function assertProductWriteAllowed(input) {
|
|
|
22448
22586
|
}
|
|
22449
22587
|
|
|
22450
22588
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
22451
|
-
import { createHash as
|
|
22589
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
22452
22590
|
import * as fs7 from "node:fs";
|
|
22453
22591
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
22454
|
-
import
|
|
22592
|
+
import path10 from "node:path";
|
|
22455
22593
|
|
|
22456
22594
|
// packages/workit-core/src/core/authority.ts
|
|
22457
|
-
import { createHash as
|
|
22595
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
22458
22596
|
import * as fs6 from "node:fs";
|
|
22459
|
-
import
|
|
22597
|
+
import path9 from "node:path";
|
|
22460
22598
|
|
|
22461
22599
|
// packages/workit-core/src/core/auto-approval.ts
|
|
22462
|
-
import { createHash as
|
|
22463
|
-
import { readFileSync as readFileSync4 } from "node:fs";
|
|
22600
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
22601
|
+
import { readFileSync as readFileSync4, realpathSync as realpathSync3 } from "node:fs";
|
|
22602
|
+
import path8 from "node:path";
|
|
22464
22603
|
|
|
22465
22604
|
// packages/workit-core/src/core/workspaces.ts
|
|
22605
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
22466
22606
|
import { readFileSync as readFileSync3, realpathSync as realpathSync2 } from "node:fs";
|
|
22467
22607
|
import path6 from "node:path";
|
|
22468
22608
|
|
|
@@ -22480,7 +22620,7 @@ import os from "node:os";
|
|
|
22480
22620
|
import path5 from "node:path";
|
|
22481
22621
|
|
|
22482
22622
|
// packages/workit-core/src/core/boundary.ts
|
|
22483
|
-
import { statSync } from "node:fs";
|
|
22623
|
+
import { statSync as statSync2 } from "node:fs";
|
|
22484
22624
|
var EVENT = {
|
|
22485
22625
|
initialization: "initialization",
|
|
22486
22626
|
provenance: "provenance",
|
|
@@ -22508,7 +22648,7 @@ var changedSourcesSinceLoad = (marker) => {
|
|
|
22508
22648
|
const changed = [];
|
|
22509
22649
|
for (const file of marker.files) {
|
|
22510
22650
|
try {
|
|
22511
|
-
if (
|
|
22651
|
+
if (statSync2(file).mtimeMs > marker.loadedAt)
|
|
22512
22652
|
changed.push(file);
|
|
22513
22653
|
} catch {}
|
|
22514
22654
|
}
|
|
@@ -22667,33 +22807,197 @@ var COMMIT_PRESETS = [
|
|
|
22667
22807
|
"custom",
|
|
22668
22808
|
"auto"
|
|
22669
22809
|
];
|
|
22810
|
+
var resolveCommitPolicy = (config, workspace) => {
|
|
22811
|
+
const wp = workspace?.commitPolicy ?? {};
|
|
22812
|
+
if (COMMIT_PRESETS.includes(String(wp.preset ?? ""))) {
|
|
22813
|
+
return {
|
|
22814
|
+
preset: wp.preset,
|
|
22815
|
+
...typeof wp.pattern === "string" ? { pattern: wp.pattern } : {}
|
|
22816
|
+
};
|
|
22817
|
+
}
|
|
22818
|
+
return config.commitPolicy ?? { preset: "conventional" };
|
|
22819
|
+
};
|
|
22670
22820
|
|
|
22671
22821
|
// packages/workit-core/src/core/workspaces.ts
|
|
22822
|
+
var nonBlank = string5().refine((value) => value.trim().length > 0, "must not be blank");
|
|
22823
|
+
var branchPreset = custom2((value) => typeof value === "string" && Object.hasOwn(PRESETS, value), "unsupported branch preset");
|
|
22824
|
+
var commitPreset = custom2((value) => typeof value === "string" && COMMIT_PRESETS.includes(value), "unsupported commit preset");
|
|
22825
|
+
var workspaceBranchPolicySchema = object4({
|
|
22826
|
+
preset: branchPreset,
|
|
22827
|
+
developBranch: nonBlank.optional(),
|
|
22828
|
+
prefixes: object4({
|
|
22829
|
+
feature: nonBlank,
|
|
22830
|
+
bugfix: nonBlank,
|
|
22831
|
+
release: nonBlank,
|
|
22832
|
+
hotfix: nonBlank
|
|
22833
|
+
}).passthrough().optional(),
|
|
22834
|
+
allowed: array3(nonBlank).optional(),
|
|
22835
|
+
protected: array3(nonBlank).optional(),
|
|
22836
|
+
integration: _enum2(["pr", "merge"]).optional()
|
|
22837
|
+
}).strict();
|
|
22838
|
+
var workspaceCommitPolicySchema = object4({ preset: commitPreset, pattern: string5().optional() }).strict();
|
|
22839
|
+
var workspaceProfileSchema = object4({
|
|
22840
|
+
branchPolicy: workspaceBranchPolicySchema.optional(),
|
|
22841
|
+
commitPolicy: workspaceCommitPolicySchema.optional()
|
|
22842
|
+
}).strict().refine((profile) => profile.branchPolicy !== undefined || profile.commitPolicy !== undefined, {
|
|
22843
|
+
message: "a profile must define branchPolicy or commitPolicy"
|
|
22844
|
+
});
|
|
22845
|
+
var versionSourceSchema = discriminatedUnion2("kind", [
|
|
22846
|
+
object4({
|
|
22847
|
+
kind: literal3("package-json"),
|
|
22848
|
+
path: nonBlank,
|
|
22849
|
+
field: nonBlank
|
|
22850
|
+
}).strict(),
|
|
22851
|
+
object4({ kind: literal3("git-tag") }).strict(),
|
|
22852
|
+
object4({ kind: literal3("manual") }).strict()
|
|
22853
|
+
]);
|
|
22854
|
+
var releaseTrackSchema = object4({
|
|
22855
|
+
strategy: branchPreset,
|
|
22856
|
+
productionBranch: nonBlank,
|
|
22857
|
+
integrationBranch: nonBlank,
|
|
22858
|
+
naming: object4({ feature: nonBlank, release: nonBlank, hotfix: nonBlank }).strict(),
|
|
22859
|
+
baseBranch: nonBlank,
|
|
22860
|
+
mergeBackBranches: array3(nonBlank),
|
|
22861
|
+
pullRequestTarget: nonBlank,
|
|
22862
|
+
tagNamespace: string5(),
|
|
22863
|
+
versionSource: versionSourceSchema,
|
|
22864
|
+
requiredChecks: array3(nonBlank)
|
|
22865
|
+
}).strict().superRefine((track, context) => {
|
|
22866
|
+
for (const [field, values] of [
|
|
22867
|
+
["mergeBackBranches", track.mergeBackBranches],
|
|
22868
|
+
["requiredChecks", track.requiredChecks]
|
|
22869
|
+
]) {
|
|
22870
|
+
if (new Set(values).size !== values.length) {
|
|
22871
|
+
context.addIssue({ code: "custom", path: [field], message: "entries must be unique" });
|
|
22872
|
+
}
|
|
22873
|
+
}
|
|
22874
|
+
if (track.versionSource.kind === "package-json" && (path6.posix.isAbsolute(track.versionSource.path.replaceAll("\\", "/")) || /^[A-Za-z]:\//u.test(track.versionSource.path.replaceAll("\\", "/")) || track.versionSource.path.replaceAll("\\", "/").split("/").includes(".."))) {
|
|
22875
|
+
context.addIssue({
|
|
22876
|
+
code: "custom",
|
|
22877
|
+
path: ["versionSource", "path"],
|
|
22878
|
+
message: "must stay inside the repository"
|
|
22879
|
+
});
|
|
22880
|
+
}
|
|
22881
|
+
});
|
|
22882
|
+
var workspaceConfigSchema = object4({
|
|
22883
|
+
name: nonBlank,
|
|
22884
|
+
glob: nonBlank,
|
|
22885
|
+
vcs: object4({
|
|
22886
|
+
provider: _enum2(["gitlab", "github"]),
|
|
22887
|
+
defaultTargetBranch: nonBlank.optional(),
|
|
22888
|
+
tokenFile: nonBlank.optional(),
|
|
22889
|
+
account: nonBlank.optional()
|
|
22890
|
+
}).passthrough().optional(),
|
|
22891
|
+
autoApprove: union3([boolean5(), array3(nonBlank)]).optional(),
|
|
22892
|
+
youtrack: object4({ baseUrl: nonBlank.optional(), link_issues: boolean5().optional() }).passthrough().optional(),
|
|
22893
|
+
issues: object4({ provider: literal3("github").optional(), link_on_pr: boolean5().optional() }).passthrough().optional(),
|
|
22894
|
+
branchPolicy: workspaceBranchPolicySchema.optional(),
|
|
22895
|
+
commitPolicy: workspaceCommitPolicySchema.optional(),
|
|
22896
|
+
defaultProfile: nonBlank.optional(),
|
|
22897
|
+
profiles: record3(nonBlank, workspaceProfileSchema).optional(),
|
|
22898
|
+
releaseTracks: record3(nonBlank, releaseTrackSchema).optional()
|
|
22899
|
+
}).passthrough().superRefine((workspace, context) => {
|
|
22900
|
+
if (workspace.youtrack && workspace.vcs?.provider !== "gitlab") {
|
|
22901
|
+
context.addIssue({
|
|
22902
|
+
code: "custom",
|
|
22903
|
+
path: ["youtrack"],
|
|
22904
|
+
message: `YouTrack issue linking requires the gitlab provider, got ${workspace.vcs?.provider ?? "unset"}`
|
|
22905
|
+
});
|
|
22906
|
+
}
|
|
22907
|
+
if (workspace.issues && workspace.vcs?.provider !== "github") {
|
|
22908
|
+
context.addIssue({
|
|
22909
|
+
code: "custom",
|
|
22910
|
+
path: ["issues"],
|
|
22911
|
+
message: `GitHub issue linking requires the github provider, got ${workspace.vcs?.provider ?? "unset"}`
|
|
22912
|
+
});
|
|
22913
|
+
}
|
|
22914
|
+
if (workspace.defaultProfile !== undefined && !Object.hasOwn(workspace.profiles ?? {}, workspace.defaultProfile)) {
|
|
22915
|
+
context.addIssue({
|
|
22916
|
+
code: "custom",
|
|
22917
|
+
path: ["defaultProfile"],
|
|
22918
|
+
message: `does not name a configured profile`
|
|
22919
|
+
});
|
|
22920
|
+
}
|
|
22921
|
+
});
|
|
22922
|
+
var workspacesFileSchema = object4({ workspaces: array3(workspaceConfigSchema).optional() }).passthrough().superRefine((file, context) => {
|
|
22923
|
+
const names = new Set;
|
|
22924
|
+
for (const [index, workspace] of (file.workspaces ?? []).entries()) {
|
|
22925
|
+
if (names.has(workspace.name)) {
|
|
22926
|
+
context.addIssue({
|
|
22927
|
+
code: "custom",
|
|
22928
|
+
path: ["workspaces", index, "name"],
|
|
22929
|
+
message: `duplicate workspace name ${JSON.stringify(workspace.name)}`
|
|
22930
|
+
});
|
|
22931
|
+
}
|
|
22932
|
+
names.add(workspace.name);
|
|
22933
|
+
}
|
|
22934
|
+
});
|
|
22935
|
+
var workspacesRevision = (contents) => createHash3("sha256").update(contents ?? "<missing>").digest("hex");
|
|
22936
|
+
var validateWorkspacesDocument = (parsed, file) => {
|
|
22937
|
+
if (!isConfigObject(parsed)) {
|
|
22938
|
+
return { status: "malformed", path: file, entries: [], error: `${file} is not a JSON object` };
|
|
22939
|
+
}
|
|
22940
|
+
const validated = workspacesFileSchema.safeParse(parsed, { reportInput: true });
|
|
22941
|
+
if (!validated.success) {
|
|
22942
|
+
const detail = validated.error.issues.map((issue) => {
|
|
22943
|
+
const field = String(issue.path[issue.path.length - 1] ?? "");
|
|
22944
|
+
const attempted = ["provider", "preset", "strategy"].includes(field) && typeof issue.input === "string" ? ` (${JSON.stringify(issue.input)})` : "";
|
|
22945
|
+
return `${issue.path.map(String).join(".") || "workspaces"}: ${issue.message}${attempted}`;
|
|
22946
|
+
}).join("; ");
|
|
22947
|
+
return {
|
|
22948
|
+
status: "invalid",
|
|
22949
|
+
path: file,
|
|
22950
|
+
entries: [],
|
|
22951
|
+
error: `${file} has invalid workspace configuration: ${detail}`
|
|
22952
|
+
};
|
|
22953
|
+
}
|
|
22954
|
+
for (const [index, workspace] of (validated.data.workspaces ?? []).entries()) {
|
|
22955
|
+
const glob = validateWorkspaceGlob(workspace.glob);
|
|
22956
|
+
if (!glob.ok) {
|
|
22957
|
+
return {
|
|
22958
|
+
status: "invalid",
|
|
22959
|
+
path: file,
|
|
22960
|
+
entries: [],
|
|
22961
|
+
error: `${file} workspaces.${index}.glob: ${glob.error}`
|
|
22962
|
+
};
|
|
22963
|
+
}
|
|
22964
|
+
}
|
|
22965
|
+
return {
|
|
22966
|
+
status: "valid",
|
|
22967
|
+
path: file,
|
|
22968
|
+
entries: validated.data.workspaces ?? [],
|
|
22969
|
+
document: parsed
|
|
22970
|
+
};
|
|
22971
|
+
};
|
|
22672
22972
|
var readWorkspacesResult = (dir = configDir()) => {
|
|
22673
22973
|
const file = path6.join(dir, "workspaces.json");
|
|
22674
22974
|
let raw;
|
|
22675
22975
|
try {
|
|
22676
22976
|
raw = readFileSync3(file, "utf8");
|
|
22677
|
-
} catch {
|
|
22678
|
-
|
|
22977
|
+
} catch (error) {
|
|
22978
|
+
if (error.code === "ENOENT")
|
|
22979
|
+
return { status: "missing", path: file, entries: [], revision: workspacesRevision(null) };
|
|
22980
|
+
return {
|
|
22981
|
+
status: "malformed",
|
|
22982
|
+
path: file,
|
|
22983
|
+
entries: [],
|
|
22984
|
+
error: `${file} could not be read: ${error instanceof Error ? error.message : String(error)}`
|
|
22985
|
+
};
|
|
22679
22986
|
}
|
|
22680
22987
|
let parsed;
|
|
22681
22988
|
try {
|
|
22682
22989
|
parsed = JSON.parse(raw);
|
|
22683
22990
|
} catch {
|
|
22684
|
-
return {
|
|
22685
|
-
|
|
22686
|
-
|
|
22687
|
-
|
|
22991
|
+
return {
|
|
22992
|
+
status: "malformed",
|
|
22993
|
+
path: file,
|
|
22994
|
+
entries: [],
|
|
22995
|
+
revision: workspacesRevision(raw),
|
|
22996
|
+
error: `${file} is not valid JSON`
|
|
22997
|
+
};
|
|
22688
22998
|
}
|
|
22689
|
-
|
|
22690
|
-
return {
|
|
22691
|
-
status: "valid",
|
|
22692
|
-
path: file,
|
|
22693
|
-
entries: Array.isArray(list) ? list : []
|
|
22694
|
-
};
|
|
22999
|
+
return { ...validateWorkspacesDocument(parsed, file), revision: workspacesRevision(raw) };
|
|
22695
23000
|
};
|
|
22696
|
-
var loadWorkspacesFrom = (dir) => readWorkspacesResult(dir).entries;
|
|
22697
23001
|
var globToRegExp = (glob) => {
|
|
22698
23002
|
let out = "";
|
|
22699
23003
|
for (let i = 0;i < glob.length; i++) {
|
|
@@ -22728,6 +23032,30 @@ var globToRegExp = (glob) => {
|
|
|
22728
23032
|
return new RegExp(`^${out}$`);
|
|
22729
23033
|
};
|
|
22730
23034
|
var matchWorkspace = (glob, target) => globToRegExp(glob.replaceAll("\\", "/")).test(target.replaceAll("\\", "/"));
|
|
23035
|
+
var UNSUPPORTED_GLOB = /[?[\]{}]/;
|
|
23036
|
+
var UNSUPPORTED_EXTGLOB = /[@+*]\(|!/;
|
|
23037
|
+
var validateWorkspaceGlob = (glob) => {
|
|
23038
|
+
const trimmed = glob.trim();
|
|
23039
|
+
if (!trimmed)
|
|
23040
|
+
return { ok: false, error: "workspace pattern is required" };
|
|
23041
|
+
const m = UNSUPPORTED_GLOB.exec(trimmed);
|
|
23042
|
+
if (m) {
|
|
23043
|
+
return {
|
|
23044
|
+
ok: false,
|
|
23045
|
+
error: `unsupported glob character ${JSON.stringify(m[0])} in workspace pattern ${JSON.stringify(glob)} — the matcher supports * and ** only (e.g. /work/**)`
|
|
23046
|
+
};
|
|
23047
|
+
}
|
|
23048
|
+
const ext = UNSUPPORTED_EXTGLOB.exec(trimmed);
|
|
23049
|
+
if (ext) {
|
|
23050
|
+
const token = ext[0];
|
|
23051
|
+
const kind = token === "!" ? "negation (!)" : `extglob (${token})`;
|
|
23052
|
+
return {
|
|
23053
|
+
ok: false,
|
|
23054
|
+
error: `unsupported glob ${kind} in workspace pattern ${JSON.stringify(glob)} — the matcher supports * and ** only (e.g. /work/**)`
|
|
23055
|
+
};
|
|
23056
|
+
}
|
|
23057
|
+
return { ok: true };
|
|
23058
|
+
};
|
|
22731
23059
|
var realpathOf = (p) => {
|
|
22732
23060
|
const real = realpathSync2.native ?? realpathSync2;
|
|
22733
23061
|
try {
|
|
@@ -22745,29 +23073,137 @@ var canonicalGlob = (glob) => {
|
|
|
22745
23073
|
const real = realpathOf(prefix.replace(/\/+$/, "") || "/");
|
|
22746
23074
|
return real + (prefix.endsWith("/") ? "/" : "") + rest;
|
|
22747
23075
|
};
|
|
22748
|
-
var resolveWorkspaceFrom = (cwd, dir) => {
|
|
23076
|
+
var resolveWorkspaceFrom = (cwd, dir, workspaceName) => {
|
|
23077
|
+
const result = readWorkspacesResult(dir);
|
|
23078
|
+
if (result.status === "malformed" || result.status === "invalid")
|
|
23079
|
+
throw new Error(result.error);
|
|
22749
23080
|
const targets = [cwd, realpathOf(cwd)].map((p) => p.replaceAll("\\", "/"));
|
|
22750
|
-
|
|
22751
|
-
|
|
22752
|
-
continue;
|
|
22753
|
-
const ws = entry;
|
|
22754
|
-
if (typeof ws.glob !== "string" || !ws.glob)
|
|
22755
|
-
continue;
|
|
23081
|
+
const matches = [];
|
|
23082
|
+
for (const ws of result.entries) {
|
|
22756
23083
|
const glob = ws.glob.replaceAll("\\", "/");
|
|
22757
23084
|
const canonical = canonicalGlob(glob);
|
|
23085
|
+
let matched = false;
|
|
22758
23086
|
for (const target of targets) {
|
|
22759
|
-
if (matchWorkspace(glob, target))
|
|
22760
|
-
|
|
22761
|
-
|
|
22762
|
-
|
|
23087
|
+
if (matchWorkspace(glob, target) || canonical !== glob && matchWorkspace(canonical, target)) {
|
|
23088
|
+
matched = true;
|
|
23089
|
+
break;
|
|
23090
|
+
}
|
|
22763
23091
|
}
|
|
23092
|
+
if (matched)
|
|
23093
|
+
matches.push(ws);
|
|
22764
23094
|
}
|
|
22765
|
-
|
|
23095
|
+
if (workspaceName !== undefined) {
|
|
23096
|
+
const selected = matches.find((ws) => ws.name === workspaceName);
|
|
23097
|
+
if (!selected && matches.length > 0) {
|
|
23098
|
+
const matchingNames = matches.map((ws) => ws.name);
|
|
23099
|
+
throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}; matching choices: ${matchingNames.join(", ")}`);
|
|
23100
|
+
}
|
|
23101
|
+
if (selected)
|
|
23102
|
+
return selected;
|
|
23103
|
+
throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}`);
|
|
23104
|
+
}
|
|
23105
|
+
if (matches.length > 1) {
|
|
23106
|
+
throw new Error(`ambiguous workspace for ${cwd}; choose one of: ${matches.map((ws) => ws.name).join(", ")}`);
|
|
23107
|
+
}
|
|
23108
|
+
return matches[0] ?? null;
|
|
23109
|
+
};
|
|
23110
|
+
var runtimeWorkspacePolicySchema = (kind) => {
|
|
23111
|
+
const key = kind === "branch" ? "branchPolicy" : kind === "commit" ? "commitPolicy" : "vcs";
|
|
23112
|
+
const policySchema = kind === "branch" ? workspaceBranchPolicySchema : kind === "commit" ? workspaceCommitPolicySchema : object4({
|
|
23113
|
+
provider: _enum2(["gitlab", "github"]),
|
|
23114
|
+
defaultTargetBranch: nonBlank.optional(),
|
|
23115
|
+
account: nonBlank.optional()
|
|
23116
|
+
}).passthrough();
|
|
23117
|
+
const profileSchema = object4({ [key]: policySchema.optional() }).passthrough();
|
|
23118
|
+
const entrySchema = object4({
|
|
23119
|
+
name: nonBlank,
|
|
23120
|
+
glob: nonBlank,
|
|
23121
|
+
[key]: policySchema.optional(),
|
|
23122
|
+
defaultProfile: nonBlank.optional(),
|
|
23123
|
+
profiles: record3(nonBlank, profileSchema).optional()
|
|
23124
|
+
}).passthrough();
|
|
23125
|
+
return entrySchema;
|
|
23126
|
+
};
|
|
23127
|
+
var resolveRuntimeWorkspaceVcs = (cwd) => resolveRuntimeWorkspaceCandidate(cwd, "vcs");
|
|
23128
|
+
var runtimeWorkspaceIndexSchema = object4({
|
|
23129
|
+
workspaces: array3(object4({ name: nonBlank, glob: nonBlank }).passthrough()).optional()
|
|
23130
|
+
}).passthrough();
|
|
23131
|
+
var resolveRuntimeWorkspaceCandidate = (cwd, kind) => {
|
|
23132
|
+
const file = path6.join(configDir(), "workspaces.json");
|
|
23133
|
+
let raw;
|
|
23134
|
+
try {
|
|
23135
|
+
raw = readFileSync3(file, "utf8");
|
|
23136
|
+
} catch (error) {
|
|
23137
|
+
if (error.code === "ENOENT")
|
|
23138
|
+
return null;
|
|
23139
|
+
throw new Error(`${file} could not be read: ${error instanceof Error ? error.message : String(error)}`);
|
|
23140
|
+
}
|
|
23141
|
+
let parsed;
|
|
23142
|
+
try {
|
|
23143
|
+
parsed = JSON.parse(raw);
|
|
23144
|
+
} catch {
|
|
23145
|
+
throw new Error(`${file} is not valid JSON`);
|
|
23146
|
+
}
|
|
23147
|
+
const validated = runtimeWorkspaceIndexSchema.safeParse(parsed);
|
|
23148
|
+
if (!validated.success) {
|
|
23149
|
+
const detail = validated.error.issues.map((issue) => `${issue.path.map(String).join(".") || "workspaces"}: ${issue.message}`).join("; ");
|
|
23150
|
+
throw new Error(`${file} has invalid workspace matching data: ${detail}`);
|
|
23151
|
+
}
|
|
23152
|
+
const entries = validated.data.workspaces;
|
|
23153
|
+
for (const entry of entries ?? []) {
|
|
23154
|
+
const glob = validateWorkspaceGlob(entry.glob);
|
|
23155
|
+
if (!glob.ok)
|
|
23156
|
+
throw new Error(`${file} workspace ${entry.name}: ${glob.error}`);
|
|
23157
|
+
}
|
|
23158
|
+
const targets = [cwd, realpathOf(cwd)].map((value) => value.replaceAll("\\", "/"));
|
|
23159
|
+
const matches = (entries ?? []).filter((entry) => {
|
|
23160
|
+
const glob = entry.glob.replaceAll("\\", "/");
|
|
23161
|
+
const canonical = canonicalGlob(glob);
|
|
23162
|
+
return targets.some((target) => matchWorkspace(glob, target) || canonical !== glob && matchWorkspace(canonical, target));
|
|
23163
|
+
});
|
|
23164
|
+
const workspaceName = process.env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined;
|
|
23165
|
+
let selected;
|
|
23166
|
+
if (workspaceName) {
|
|
23167
|
+
const named = matches.filter((entry) => entry.name === workspaceName);
|
|
23168
|
+
if (named.length === 1)
|
|
23169
|
+
selected = named[0];
|
|
23170
|
+
else if (named.length > 1)
|
|
23171
|
+
throw new Error(`ambiguous workspace ${JSON.stringify(workspaceName)} for ${cwd}`);
|
|
23172
|
+
else if (matches.length)
|
|
23173
|
+
throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}; matching choices: ${matches.map((entry) => entry.name).join(", ")}`);
|
|
23174
|
+
else
|
|
23175
|
+
throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}`);
|
|
23176
|
+
} else if (matches.length > 1)
|
|
23177
|
+
throw new Error(`ambiguous workspace for ${cwd}; choose one of: ${matches.map((entry) => entry.name).join(", ")}`);
|
|
23178
|
+
else
|
|
23179
|
+
selected = matches[0];
|
|
23180
|
+
if (!selected)
|
|
23181
|
+
return null;
|
|
23182
|
+
const policy = runtimeWorkspacePolicySchema(kind).safeParse(selected);
|
|
23183
|
+
if (!policy.success) {
|
|
23184
|
+
const detail = policy.error.issues.map((issue) => `${issue.path.map(String).join(".") || "workspace"}: ${issue.message}`).join("; ");
|
|
23185
|
+
throw new Error(`${file} has invalid ${kind} policy configuration: ${detail}`);
|
|
23186
|
+
}
|
|
23187
|
+
return policy.data;
|
|
23188
|
+
};
|
|
23189
|
+
var resolveRuntimeWorkspacePolicy = (cwd, kind, requestedProfile) => {
|
|
23190
|
+
const candidate = resolveRuntimeWorkspaceCandidate(cwd, kind);
|
|
23191
|
+
if (!candidate)
|
|
23192
|
+
return { policy: undefined, source: "user-default" };
|
|
23193
|
+
const key = kind === "branch" ? "branchPolicy" : "commitPolicy";
|
|
23194
|
+
const profileName = requestedProfile?.trim() || candidate.defaultProfile;
|
|
23195
|
+
if (candidate.defaultProfile && !Object.hasOwn(candidate.profiles ?? {}, candidate.defaultProfile))
|
|
23196
|
+
throw new Error(`workspace ${JSON.stringify(candidate.name)} has no profile ${JSON.stringify(candidate.defaultProfile)}`);
|
|
23197
|
+
const profile = profileName ? candidate.profiles?.[profileName] : undefined;
|
|
23198
|
+
if (profileName && !profile)
|
|
23199
|
+
throw new Error(`workspace ${JSON.stringify(candidate.name)} has no profile ${JSON.stringify(profileName)}`);
|
|
23200
|
+
const profilePolicy = profile?.[key];
|
|
23201
|
+
const workspacePolicy = candidate[key];
|
|
23202
|
+
return {
|
|
23203
|
+
policy: profilePolicy ?? workspacePolicy,
|
|
23204
|
+
source: profilePolicy ? `profile:${profileName}` : workspacePolicy ? `workspace:${candidate.name}` : "user-default"
|
|
23205
|
+
};
|
|
22766
23206
|
};
|
|
22767
|
-
var resolveWorkspace = (cwd) => resolveWorkspaceFrom(cwd, configDir());
|
|
22768
|
-
|
|
22769
|
-
// packages/workit-core/src/core/branch.ts
|
|
22770
|
-
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
22771
23207
|
|
|
22772
23208
|
// packages/workit-core/src/core/git.ts
|
|
22773
23209
|
import { execFileSync } from "node:child_process";
|
|
@@ -22841,7 +23277,6 @@ var gitContext = (workspaceRoot, paths = []) => {
|
|
|
22841
23277
|
import fs5 from "node:fs";
|
|
22842
23278
|
import path7 from "node:path";
|
|
22843
23279
|
import { spawnSync } from "node:child_process";
|
|
22844
|
-
var TOKEN_PLACEHOLDER = "YOUR_TOKEN_HERE";
|
|
22845
23280
|
var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path7.join(configDir(), "vcs.json");
|
|
22846
23281
|
var vcsCwd = (cwd) => cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd();
|
|
22847
23282
|
var remoteProvider = (cwd) => {
|
|
@@ -22855,6 +23290,79 @@ var remoteProvider = (cwd) => {
|
|
|
22855
23290
|
return "gitlab";
|
|
22856
23291
|
return null;
|
|
22857
23292
|
};
|
|
23293
|
+
var remoteEndpoint = (remote) => {
|
|
23294
|
+
const raw = remote.trim();
|
|
23295
|
+
if (!raw)
|
|
23296
|
+
return null;
|
|
23297
|
+
const scp = /^(?:[^@\s]+@)?([^:]+):(.+)$/u.exec(raw);
|
|
23298
|
+
if (scp && !raw.includes("://"))
|
|
23299
|
+
return {
|
|
23300
|
+
host: scp[1].toLowerCase(),
|
|
23301
|
+
path: scp[2].replace(/^\//u, "").replace(/\.git$/u, ""),
|
|
23302
|
+
protocol: "ssh:",
|
|
23303
|
+
port: ""
|
|
23304
|
+
};
|
|
23305
|
+
try {
|
|
23306
|
+
const url = new URL(raw);
|
|
23307
|
+
return {
|
|
23308
|
+
host: url.hostname.toLowerCase(),
|
|
23309
|
+
path: url.pathname.replace(/^\//u, "").replace(/\.git$/u, "").replace(/\/$/u, ""),
|
|
23310
|
+
protocol: url.protocol,
|
|
23311
|
+
port: url.port
|
|
23312
|
+
};
|
|
23313
|
+
} catch {
|
|
23314
|
+
return null;
|
|
23315
|
+
}
|
|
23316
|
+
};
|
|
23317
|
+
var configuredSshEndpoint = (host) => {
|
|
23318
|
+
if (host.startsWith("-"))
|
|
23319
|
+
return null;
|
|
23320
|
+
const resolved = spawnSync("ssh", ["-G", host], {
|
|
23321
|
+
encoding: "utf8",
|
|
23322
|
+
timeout: 5000,
|
|
23323
|
+
maxBuffer: 1024 * 1024,
|
|
23324
|
+
env: { ...process.env, PATH: process.env.PATH ?? "" }
|
|
23325
|
+
});
|
|
23326
|
+
if (resolved.status !== 0)
|
|
23327
|
+
return null;
|
|
23328
|
+
const output = resolved.stdout ?? "";
|
|
23329
|
+
const hostname = /^hostname\s+(\S+)/imu.exec(output)?.[1]?.toLowerCase();
|
|
23330
|
+
if (!hostname)
|
|
23331
|
+
return null;
|
|
23332
|
+
return { host: hostname, port: /^port\s+(\d+)/imu.exec(output)?.[1] ?? "22" };
|
|
23333
|
+
};
|
|
23334
|
+
var sshApiHostAliases = {
|
|
23335
|
+
"github.com": [{ host: "ssh.github.com", port: "443" }],
|
|
23336
|
+
"gitlab.com": [{ host: "altssh.gitlab.com", port: "443" }]
|
|
23337
|
+
};
|
|
23338
|
+
var hostingApiHostMatches = (remote, apiHost, resolveSshEndpoint = configuredSshEndpoint) => {
|
|
23339
|
+
const endpoint = remoteEndpoint(remote);
|
|
23340
|
+
if (!endpoint)
|
|
23341
|
+
return false;
|
|
23342
|
+
let expected;
|
|
23343
|
+
try {
|
|
23344
|
+
const url = new URL(`https://${apiHost}`);
|
|
23345
|
+
if (url.pathname !== "/" || url.search || url.hash || url.username || url.password)
|
|
23346
|
+
return false;
|
|
23347
|
+
expected = {
|
|
23348
|
+
host: url.hostname.toLowerCase().replace(/\.$/u, ""),
|
|
23349
|
+
port: url.port
|
|
23350
|
+
};
|
|
23351
|
+
} catch {
|
|
23352
|
+
return false;
|
|
23353
|
+
}
|
|
23354
|
+
if (endpoint.protocol !== "ssh:") {
|
|
23355
|
+
return endpoint.host.replace(/\.$/u, "") === expected.host && endpoint.port === expected.port;
|
|
23356
|
+
}
|
|
23357
|
+
const resolved = resolveSshEndpoint(endpoint.host);
|
|
23358
|
+
if (!resolved)
|
|
23359
|
+
return false;
|
|
23360
|
+
const hostname = resolved.host.toLowerCase().replace(/\.$/u, "");
|
|
23361
|
+
const port = endpoint.port || resolved.port;
|
|
23362
|
+
if (hostname === expected.host)
|
|
23363
|
+
return port === (expected.port || "22");
|
|
23364
|
+
return Boolean(sshApiHostAliases[expected.host]?.some((alias) => alias.host === hostname && alias.port === port && (!expected.port || expected.port === port)));
|
|
23365
|
+
};
|
|
22858
23366
|
var readVcsConfig = () => {
|
|
22859
23367
|
const file = vcsConfigPath();
|
|
22860
23368
|
let raw;
|
|
@@ -22875,7 +23383,7 @@ var readVcsConfig = () => {
|
|
|
22875
23383
|
return { status: "malformed", path: file, config: {}, error: `${file} is not a JSON object` };
|
|
22876
23384
|
};
|
|
22877
23385
|
function vcsConfig(mode, cwd) {
|
|
22878
|
-
const ws =
|
|
23386
|
+
const ws = resolveRuntimeWorkspaceVcs(vcsCwd(cwd));
|
|
22879
23387
|
const wsVcs = ws?.vcs ?? {};
|
|
22880
23388
|
const wsYt = ws?.youtrack ?? {};
|
|
22881
23389
|
const wsIssues = ws?.issues ?? {};
|
|
@@ -22888,8 +23396,8 @@ function vcsConfig(mode, cwd) {
|
|
|
22888
23396
|
const hasWorkspacePolicy = typeof wp.preset === "string" && Object.hasOwn(PRESETS, wp.preset);
|
|
22889
23397
|
const policyDefault = resolveBranchPolicyFor(root).defaultTargetBranch;
|
|
22890
23398
|
const defaultTarget = String(wsVcs.defaultTargetBranch ?? (hasWorkspacePolicy ? policyDefault : cfg.defaultTargetBranch ?? policyDefault) ?? "develop");
|
|
22891
|
-
const linkIssues = typeof wsYt.link_issues === "boolean" ? wsYt.link_issues : null;
|
|
22892
|
-
const youtrackBaseUrl = typeof wsYt.baseUrl === "string" ? wsYt.baseUrl : null;
|
|
23399
|
+
const linkIssues = provider === "gitlab" && typeof wsYt.link_issues === "boolean" ? wsYt.link_issues : null;
|
|
23400
|
+
const youtrackBaseUrl = provider === "gitlab" && typeof wsYt.baseUrl === "string" ? wsYt.baseUrl : null;
|
|
22893
23401
|
let issuesProvider = null;
|
|
22894
23402
|
let linkOnPr = null;
|
|
22895
23403
|
if (provider === "github" && typeof wsIssues.provider === "string" && wsIssues.provider.toLowerCase() === "github") {
|
|
@@ -22913,9 +23421,8 @@ function vcsConfig(mode, cwd) {
|
|
|
22913
23421
|
if (cfgStatus === "malformed") {
|
|
22914
23422
|
return { ok: false, error: cfgError, configPath: cfgPath };
|
|
22915
23423
|
}
|
|
22916
|
-
if (cfgStatus === "missing")
|
|
23424
|
+
if (cfgStatus === "missing" && provider === null)
|
|
22917
23425
|
return { ok: false, error: `vcs.json is missing: ${cfgPath}`, configPath: cfgPath };
|
|
22918
|
-
}
|
|
22919
23426
|
if (provider === null) {
|
|
22920
23427
|
return {
|
|
22921
23428
|
ok: false,
|
|
@@ -22924,24 +23431,12 @@ function vcsConfig(mode, cwd) {
|
|
|
22924
23431
|
};
|
|
22925
23432
|
}
|
|
22926
23433
|
const prov = cfg[provider] ?? {};
|
|
22927
|
-
const wsTokenFile = typeof wsVcs.tokenFile === "string" && wsVcs.tokenFile.trim() !== "" ? wsVcs.tokenFile : null;
|
|
22928
|
-
const tokenFile = String(wsTokenFile ?? prov.tokenFile ?? path7.join(configDir(), `${provider}.token`));
|
|
22929
|
-
const tokenPath = path7.resolve(tokenFile);
|
|
22930
|
-
let tokenOk = false;
|
|
22931
|
-
if (fs5.existsSync(tokenPath)) {
|
|
22932
|
-
const token = fs5.readFileSync(tokenPath, "utf8").trim();
|
|
22933
|
-
const placeholder = !token || token === TOKEN_PLACEHOLDER || token.startsWith(TOKEN_PLACEHOLDER);
|
|
22934
|
-
tokenOk = !placeholder;
|
|
22935
|
-
}
|
|
22936
23434
|
const out = {
|
|
22937
23435
|
ok: true,
|
|
22938
23436
|
configPath: path7.resolve(cfgPath),
|
|
22939
23437
|
provider,
|
|
22940
23438
|
defaultTargetBranch: defaultTarget,
|
|
22941
23439
|
pr: cfg.pr ?? {},
|
|
22942
|
-
tokenPath,
|
|
22943
|
-
tokenPresent: fs5.existsSync(tokenPath),
|
|
22944
|
-
tokenReady: tokenOk,
|
|
22945
23440
|
workspace_name: ws?.name ?? null,
|
|
22946
23441
|
link_issues: linkIssues,
|
|
22947
23442
|
youtrack_base_url: youtrackBaseUrl,
|
|
@@ -22956,16 +23451,58 @@ function vcsConfig(mode, cwd) {
|
|
|
22956
23451
|
} else if (provider === "github") {
|
|
22957
23452
|
out.github = { host: prov.host ?? "github.com" };
|
|
22958
23453
|
}
|
|
22959
|
-
if (mode === "summary")
|
|
22960
|
-
delete out.tokenPath;
|
|
22961
23454
|
return out;
|
|
22962
23455
|
}
|
|
23456
|
+
function vcsCliIdentity(cwd) {
|
|
23457
|
+
const root = vcsCwd(cwd);
|
|
23458
|
+
const cfg = vcsConfig("load", root);
|
|
23459
|
+
if (!cfg.ok)
|
|
23460
|
+
return { ok: false, error: cfg.error ?? "vcs config not ready" };
|
|
23461
|
+
const provider = cfg.provider;
|
|
23462
|
+
if (provider !== "gitlab" && provider !== "github")
|
|
23463
|
+
return { ok: false, error: `unsupported provider: ${provider}` };
|
|
23464
|
+
const bin = provider === "gitlab" ? "glab" : "gh";
|
|
23465
|
+
const host = String(provider === "github" ? cfg.github?.host ?? "github.com" : cfg.gitlab?.host ?? "gitlab.com").toLowerCase();
|
|
23466
|
+
const env = {
|
|
23467
|
+
...process.env,
|
|
23468
|
+
PATH: process.env.PATH ?? "",
|
|
23469
|
+
...provider === "github" ? { GH_HOST: host } : { GITLAB_HOST: host }
|
|
23470
|
+
};
|
|
23471
|
+
const result = spawnSync(bin, ["api", "user"], {
|
|
23472
|
+
cwd: root,
|
|
23473
|
+
encoding: "utf8",
|
|
23474
|
+
env
|
|
23475
|
+
});
|
|
23476
|
+
if (result.status !== 0)
|
|
23477
|
+
return { ok: false, provider, error: `${bin} is missing or not authenticated` };
|
|
23478
|
+
try {
|
|
23479
|
+
const user = JSON.parse(result.stdout ?? "");
|
|
23480
|
+
const username = provider === "gitlab" ? user.username : user.login;
|
|
23481
|
+
if (typeof username !== "string" || !username)
|
|
23482
|
+
return { ok: false, provider, error: `invalid ${bin} identity response` };
|
|
23483
|
+
const expected = resolveRuntimeWorkspaceVcs(root)?.vcs?.account;
|
|
23484
|
+
if (expected && username.toLowerCase() !== expected.toLowerCase())
|
|
23485
|
+
return {
|
|
23486
|
+
ok: false,
|
|
23487
|
+
provider,
|
|
23488
|
+
error: `${bin} account ${username} does not match ${expected}`
|
|
23489
|
+
};
|
|
23490
|
+
return { ok: true, provider, host, username, name: user.name };
|
|
23491
|
+
} catch {
|
|
23492
|
+
return { ok: false, provider, error: `invalid JSON from ${bin} api user` };
|
|
23493
|
+
}
|
|
23494
|
+
}
|
|
22963
23495
|
function mergedPrStyle(limit = 6, cwd) {
|
|
22964
23496
|
const cfg = vcsConfig("load", cwd);
|
|
22965
|
-
if (!cfg.ok
|
|
23497
|
+
if (!cfg.ok)
|
|
22966
23498
|
return { ok: false, error: "vcs not configured" };
|
|
22967
23499
|
const provider = cfg.provider;
|
|
22968
|
-
const
|
|
23500
|
+
const host = String(provider === "github" ? cfg.github?.host ?? "github.com" : cfg.gitlab?.host ?? "gitlab.com").toLowerCase();
|
|
23501
|
+
const env = {
|
|
23502
|
+
...process.env,
|
|
23503
|
+
PATH: process.env.PATH ?? "",
|
|
23504
|
+
...provider === "github" ? { GH_HOST: host } : { GITLAB_HOST: host }
|
|
23505
|
+
};
|
|
22969
23506
|
const examples = [];
|
|
22970
23507
|
const descInfo = (desc, caseInsensitiveNotes = false) => ({
|
|
22971
23508
|
hasNotesSection: caseInsensitiveNotes ? /##\s*notes/i.test(desc) : /##\s*Notes/.test(desc),
|
|
@@ -22973,23 +23510,30 @@ function mergedPrStyle(limit = 6, cwd) {
|
|
|
22973
23510
|
`).filter((l) => l.startsWith("## ")).map((l) => l.trim()),
|
|
22974
23511
|
descriptionPreview: desc.slice(0, 600)
|
|
22975
23512
|
});
|
|
23513
|
+
const remoteResult = spawnSync("git", ["remote", "get-url", "--push", "--all", "origin"], {
|
|
23514
|
+
cwd,
|
|
23515
|
+
encoding: "utf8"
|
|
23516
|
+
});
|
|
23517
|
+
const remotes = (remoteResult.stdout ?? "").split(/\r?\n/u).map((value) => value.trim()).filter(Boolean);
|
|
23518
|
+
if (remotes.length === 0)
|
|
23519
|
+
return { ok: false, error: "no origin remote" };
|
|
23520
|
+
if (remotes.length !== 1)
|
|
23521
|
+
return { ok: false, error: "origin has ambiguous push destinations" };
|
|
23522
|
+
const remote = remotes[0];
|
|
23523
|
+
const endpoint = remoteEndpoint(remote);
|
|
23524
|
+
if (!endpoint?.path)
|
|
23525
|
+
return { ok: false, error: "hosting repository could not be resolved" };
|
|
23526
|
+
if (!hostingApiHostMatches(remote, host))
|
|
23527
|
+
return { ok: false, error: "PR style target does not match the provider host" };
|
|
22976
23528
|
if (provider === "gitlab") {
|
|
22977
|
-
const
|
|
22978
|
-
|
|
22979
|
-
|
|
22980
|
-
|
|
22981
|
-
|
|
22982
|
-
if (!m)
|
|
22983
|
-
return { ok: false, error: "not a gitlab.com origin" };
|
|
22984
|
-
const project = m[1];
|
|
22985
|
-
const env = { ...process.env, GITLAB_TOKEN: token };
|
|
22986
|
-
const run = (args) => spawnSync("glab", ["api", ...args], { cwd, encoding: "utf8", env });
|
|
23529
|
+
const run = (args) => spawnSync("glab", ["api", ...args], {
|
|
23530
|
+
cwd,
|
|
23531
|
+
encoding: "utf8",
|
|
23532
|
+
env
|
|
23533
|
+
});
|
|
22987
23534
|
let r = run([
|
|
22988
|
-
`projects/${
|
|
23535
|
+
`projects/${endpoint.path.replaceAll("/", "%2F")}/merge_requests?state=merged&per_page=${limit}&order_by=updated_at&sort=desc`
|
|
22989
23536
|
]);
|
|
22990
|
-
if (r.status !== 0) {
|
|
22991
|
-
r = run([`merge_requests?state=merged&per_page=${limit}&order_by=updated_at&sort=desc`]);
|
|
22992
|
-
}
|
|
22993
23537
|
if (r.status !== 0)
|
|
22994
23538
|
return { ok: false, error: "could not list merge requests" };
|
|
22995
23539
|
for (const mr of JSON.parse(r.stdout ?? "[]")) {
|
|
@@ -23002,7 +23546,18 @@ function mergedPrStyle(limit = 6, cwd) {
|
|
|
23002
23546
|
});
|
|
23003
23547
|
}
|
|
23004
23548
|
} else if (provider === "github") {
|
|
23005
|
-
const r = spawnSync("gh", [
|
|
23549
|
+
const r = spawnSync("gh", [
|
|
23550
|
+
"pr",
|
|
23551
|
+
"list",
|
|
23552
|
+
"--repo",
|
|
23553
|
+
`${host}/${endpoint.path}`,
|
|
23554
|
+
"--state",
|
|
23555
|
+
"merged",
|
|
23556
|
+
"--limit",
|
|
23557
|
+
String(limit),
|
|
23558
|
+
"--json",
|
|
23559
|
+
"title,url,body"
|
|
23560
|
+
], { cwd, encoding: "utf8", env });
|
|
23006
23561
|
if (r.status !== 0)
|
|
23007
23562
|
return { ok: false, error: "could not list pull requests" };
|
|
23008
23563
|
for (const pr of JSON.parse(r.stdout ?? "[]")) {
|
|
@@ -23024,26 +23579,28 @@ function mergedPrStyle(limit = 6, cwd) {
|
|
|
23024
23579
|
}
|
|
23025
23580
|
|
|
23026
23581
|
// packages/workit-core/src/core/branch.ts
|
|
23027
|
-
|
|
23582
|
+
function effectiveWorkspacePolicy(workspaceRoot, kind, profileName) {
|
|
23583
|
+
const selected = resolveRuntimeWorkspacePolicy(workspaceRoot, kind, profileName?.trim() || process.env.WORKFLOW_PROFILE?.trim() || undefined);
|
|
23584
|
+
const config = readConfig();
|
|
23585
|
+
return kind === "branch" ? {
|
|
23586
|
+
branchPolicy: resolveBranchPolicy(config, selected.policy ? { branchPolicy: selected.policy } : null),
|
|
23587
|
+
provenance: { branchPolicy: selected.source }
|
|
23588
|
+
} : {
|
|
23589
|
+
commitPolicy: resolveCommitPolicy(config, selected.policy ? { commitPolicy: selected.policy } : null),
|
|
23590
|
+
provenance: { commitPolicy: selected.source }
|
|
23591
|
+
};
|
|
23592
|
+
}
|
|
23593
|
+
var resolveBranchPolicyFor = (workspaceRoot, profileName) => effectiveWorkspacePolicy(workspaceRoot, "branch", profileName).branchPolicy;
|
|
23028
23594
|
var verifyPushIdentity = (root, provider, account) => {
|
|
23029
23595
|
if (!account || typeof account !== "string")
|
|
23030
23596
|
return { ok: false, error: "push identity requires a configured area account" };
|
|
23031
|
-
const
|
|
23032
|
-
|
|
23033
|
-
|
|
23034
|
-
|
|
23035
|
-
login = execFileSync2(bin, [...probe], {
|
|
23036
|
-
cwd: root,
|
|
23037
|
-
encoding: "utf8",
|
|
23038
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
23039
|
-
}).trim();
|
|
23040
|
-
} catch {
|
|
23041
|
-
return { ok: false, error: `${bin} identity could not be resolved` };
|
|
23042
|
-
}
|
|
23043
|
-
if (!login || login.toLowerCase() !== account.toLowerCase())
|
|
23597
|
+
const identity = vcsCliIdentity(root);
|
|
23598
|
+
if (!identity.ok || identity.provider !== provider)
|
|
23599
|
+
return { ok: false, error: identity.error ?? "hosting CLI identity could not be resolved" };
|
|
23600
|
+
if (identity.username?.toLowerCase() !== account.toLowerCase())
|
|
23044
23601
|
return {
|
|
23045
23602
|
ok: false,
|
|
23046
|
-
error: `push identity ${
|
|
23603
|
+
error: `push identity ${identity.username || "(unknown)"} does not match area account ${account}`
|
|
23047
23604
|
};
|
|
23048
23605
|
return { ok: true };
|
|
23049
23606
|
};
|
|
@@ -23061,7 +23618,7 @@ var operationAutoClass = (operation) => typeof operation === "string" ? OPERATIO
|
|
|
23061
23618
|
var digestOf = (configDirPath) => {
|
|
23062
23619
|
try {
|
|
23063
23620
|
const raw = readFileSync4(`${configDirPath}/workspaces.json`, "utf8");
|
|
23064
|
-
return
|
|
23621
|
+
return createHash4("sha256").update(raw).digest("hex");
|
|
23065
23622
|
} catch {
|
|
23066
23623
|
return null;
|
|
23067
23624
|
}
|
|
@@ -23099,14 +23656,30 @@ var resolveAutoApproval = (root, dir = configDir()) => {
|
|
|
23099
23656
|
};
|
|
23100
23657
|
};
|
|
23101
23658
|
var isStandingReceipt = (value) => typeof value === "object" && value !== null && value.kind === "standing";
|
|
23102
|
-
var
|
|
23659
|
+
var targetOf = (root, descriptor) => {
|
|
23660
|
+
try {
|
|
23661
|
+
const parsed = typeof descriptor === "string" ? JSON.parse(descriptor) : descriptor;
|
|
23662
|
+
const cwd = parsed?.payload?.cwd;
|
|
23663
|
+
if (cwd === undefined)
|
|
23664
|
+
return root;
|
|
23665
|
+
if (typeof cwd !== "string" || !path8.isAbsolute(cwd))
|
|
23666
|
+
return null;
|
|
23667
|
+
return realpathSync3(cwd);
|
|
23668
|
+
} catch {
|
|
23669
|
+
return null;
|
|
23670
|
+
}
|
|
23671
|
+
};
|
|
23672
|
+
var standingApprovalLive = (root, receipt, cls, dir, descriptor) => {
|
|
23103
23673
|
if (!isStandingReceipt(receipt))
|
|
23104
23674
|
return false;
|
|
23105
23675
|
if (typeof cls !== "string" || !AUTO_CLASSES.includes(cls))
|
|
23106
23676
|
return false;
|
|
23107
23677
|
if (receipt.class !== cls)
|
|
23108
23678
|
return false;
|
|
23109
|
-
const
|
|
23679
|
+
const target = targetOf(root, descriptor);
|
|
23680
|
+
if (!target)
|
|
23681
|
+
return false;
|
|
23682
|
+
const resolved = resolveAutoApproval(target, dir);
|
|
23110
23683
|
if (resolved.status !== "on")
|
|
23111
23684
|
return false;
|
|
23112
23685
|
if (resolved.workspace !== receipt.workspace)
|
|
@@ -23142,16 +23715,19 @@ var verifyStandingApproval = (root, task, caller, binding) => {
|
|
|
23142
23715
|
const cls = operationAutoClass(operation);
|
|
23143
23716
|
if (!cls || cls !== standing.class)
|
|
23144
23717
|
return failure("permission_denied", "standing approval does not cover this operation");
|
|
23145
|
-
const
|
|
23718
|
+
const target = targetOf(root, binding.approvedContent);
|
|
23719
|
+
if (!target)
|
|
23720
|
+
return failure("permission_denied", "standing action target is invalid");
|
|
23721
|
+
const resolved = resolveAutoApproval(target);
|
|
23146
23722
|
if (resolved.status !== "on" || resolved.workspace !== standing.workspace || !resolved.classes.includes(cls))
|
|
23147
23723
|
return failure("permission_denied", "standing auto-approval is not live for this operation");
|
|
23148
23724
|
if (cls === "push") {
|
|
23149
|
-
const workspace = resolveWorkspaceFrom(
|
|
23725
|
+
const workspace = resolveWorkspaceFrom(target, configDir());
|
|
23150
23726
|
const provider = workspace?.vcs?.provider;
|
|
23151
23727
|
const account = resolved.account;
|
|
23152
23728
|
if (!provider || !account)
|
|
23153
23729
|
return failure("permission_denied", "auto-push requires a workspace provider and area account");
|
|
23154
|
-
const identity = verifyPushIdentity(
|
|
23730
|
+
const identity = verifyPushIdentity(target, provider, account);
|
|
23155
23731
|
if (!identity.ok)
|
|
23156
23732
|
return failure("permission_denied", identity.error);
|
|
23157
23733
|
}
|
|
@@ -23160,7 +23736,7 @@ var verifyStandingApproval = (root, task, caller, binding) => {
|
|
|
23160
23736
|
host: caller.host,
|
|
23161
23737
|
session: { kind: "host", host: caller.host, handle: caller.actor },
|
|
23162
23738
|
workerId: null,
|
|
23163
|
-
receipts: [standingReceiptFor(
|
|
23739
|
+
receipts: [standingReceiptFor(target, standing.workspace, cls)]
|
|
23164
23740
|
});
|
|
23165
23741
|
};
|
|
23166
23742
|
|
|
@@ -23311,7 +23887,7 @@ function applicableDecision(task, purpose, binding, checkoutRoot) {
|
|
|
23311
23887
|
return [];
|
|
23312
23888
|
return task.decisions.filter((entry) => entry.provenance.kind !== "imported" && decisionMatches(entry, purpose, binding) && (checkoutRoot ? verifyDecisionContentAtRoot(checkoutRoot, entry.data.binding).ok : entry.data.binding.contentRefs.every((reference) => reference.kind !== "file"))).map((entry) => entry.data);
|
|
23313
23889
|
}
|
|
23314
|
-
var digestBytes2 = (bytes) =>
|
|
23890
|
+
var digestBytes2 = (bytes) => createHash5("sha256").update(bytes).digest("hex");
|
|
23315
23891
|
var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
23316
23892
|
let root;
|
|
23317
23893
|
try {
|
|
@@ -23324,23 +23900,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
|
23324
23900
|
continue;
|
|
23325
23901
|
if (!reference.digest)
|
|
23326
23902
|
return failure("invalid_input", "document references require a byte digest");
|
|
23327
|
-
const target =
|
|
23328
|
-
if (target !== root && !target.startsWith(`${root}${
|
|
23903
|
+
const target = path9.resolve(root, reference.path);
|
|
23904
|
+
if (target !== root && !target.startsWith(`${root}${path9.sep}`))
|
|
23329
23905
|
return failure("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
23330
23906
|
fields: [
|
|
23331
23907
|
{ path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
|
|
23332
23908
|
]
|
|
23333
23909
|
});
|
|
23334
23910
|
try {
|
|
23335
|
-
const relative =
|
|
23911
|
+
const relative = path9.relative(root, target);
|
|
23336
23912
|
let current = root;
|
|
23337
|
-
for (const segment of relative.split(
|
|
23913
|
+
for (const segment of relative.split(path9.sep)) {
|
|
23338
23914
|
if (!segment)
|
|
23339
23915
|
continue;
|
|
23340
|
-
current =
|
|
23916
|
+
current = path9.join(current, segment);
|
|
23341
23917
|
const stat = fs6.lstatSync(current);
|
|
23342
23918
|
const real = fs6.realpathSync(current);
|
|
23343
|
-
if (real !== root && !real.startsWith(`${root}${
|
|
23919
|
+
if (real !== root && !real.startsWith(`${root}${path9.sep}`))
|
|
23344
23920
|
return failure("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
23345
23921
|
fields: [
|
|
23346
23922
|
{
|
|
@@ -23418,7 +23994,7 @@ var validateAction = (store, task, workspaceId, input, authority) => {
|
|
|
23418
23994
|
operation = null;
|
|
23419
23995
|
}
|
|
23420
23996
|
const cls = operationAutoClass(operation);
|
|
23421
|
-
if (!cls || !standing.some((receipt) => standingApprovalLive(store.root, receipt, cls)))
|
|
23997
|
+
if (!cls || !standing.some((receipt) => standingApprovalLive(store.root, receipt, cls, undefined, decision.binding.approvedContent)))
|
|
23422
23998
|
return failure("permission_denied", "standing auto-approval is not live for this operation");
|
|
23423
23999
|
}
|
|
23424
24000
|
if (decision.revoked)
|
|
@@ -23720,15 +24296,15 @@ var bindingCovers = scopeCovers;
|
|
|
23720
24296
|
var verifyDecisionContent = verifyContentRefs;
|
|
23721
24297
|
|
|
23722
24298
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
23723
|
-
var digestBytes3 = (value) =>
|
|
23724
|
-
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${
|
|
23725
|
-
var relative = (root, candidate) =>
|
|
24299
|
+
var digestBytes3 = (value) => createHash6("sha256").update(value).digest("hex");
|
|
24300
|
+
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path10.sep}`);
|
|
24301
|
+
var relative = (root, candidate) => path10.relative(root, candidate).split(path10.sep).join("/") || ".";
|
|
23726
24302
|
var canonicalPath = (value) => {
|
|
23727
24303
|
if (typeof value !== "string" || !value)
|
|
23728
24304
|
return null;
|
|
23729
24305
|
if (value.includes("\\") || value.split("/").includes(".."))
|
|
23730
24306
|
return null;
|
|
23731
|
-
const normalized =
|
|
24307
|
+
const normalized = path10.posix.normalize(value);
|
|
23732
24308
|
if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
|
|
23733
24309
|
return null;
|
|
23734
24310
|
return normalized === "." ? "." : normalized.replace(/\/$/, "");
|
|
@@ -23776,14 +24352,14 @@ var gitPaths = (root) => {
|
|
|
23776
24352
|
git: /not a git repository/i.test(stderr) ? false : true
|
|
23777
24353
|
};
|
|
23778
24354
|
}
|
|
23779
|
-
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
24355
|
+
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path10.sep).join("/")) : [];
|
|
23780
24356
|
const stagedDeleted = spawnSync2("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
|
|
23781
24357
|
if (stagedDeleted.status !== 0) {
|
|
23782
24358
|
const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
|
|
23783
24359
|
if (!/not a git repository/i.test(stderr))
|
|
23784
24360
|
return { paths, uncertain: true, git: true };
|
|
23785
24361
|
} else if (stagedDeleted.stdout) {
|
|
23786
|
-
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
24362
|
+
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path10.sep).join("/")));
|
|
23787
24363
|
}
|
|
23788
24364
|
return { paths: [...new Set(paths)], uncertain: false, git: true };
|
|
23789
24365
|
};
|
|
@@ -23798,7 +24374,7 @@ var walk = (root, directory, output) => {
|
|
|
23798
24374
|
for (const name of names) {
|
|
23799
24375
|
if (name === ".git" || name === ".workit")
|
|
23800
24376
|
continue;
|
|
23801
|
-
const target =
|
|
24377
|
+
const target = path10.join(directory, name);
|
|
23802
24378
|
let stat;
|
|
23803
24379
|
try {
|
|
23804
24380
|
stat = fs7.lstatSync(target);
|
|
@@ -23816,12 +24392,12 @@ var walk = (root, directory, output) => {
|
|
|
23816
24392
|
var scopeRoots = (root, scope) => {
|
|
23817
24393
|
const roots = [];
|
|
23818
24394
|
for (const item of scope.paths.length ? scope.paths : ["."]) {
|
|
23819
|
-
const target =
|
|
24395
|
+
const target = path10.resolve(root, item);
|
|
23820
24396
|
if (!inside(root, target))
|
|
23821
24397
|
return failure("invalid_input", `candidate scope escapes checkout: ${item} — keep one task per repository and coordinate a separate linked task in the other checkout`, { fields: [{ path: "scope.paths", reason: `${item} is outside the checkout` }] });
|
|
23822
24398
|
let ancestor = target;
|
|
23823
24399
|
while (!fs7.existsSync(ancestor) && ancestor !== root)
|
|
23824
|
-
ancestor =
|
|
24400
|
+
ancestor = path10.dirname(ancestor);
|
|
23825
24401
|
try {
|
|
23826
24402
|
if (!inside(root, fs7.realpathSync(ancestor)))
|
|
23827
24403
|
return failure("invalid_input", `candidate scope escapes checkout through a symlink: ${item} — keep one task per repository and coordinate a separate linked task in the other checkout`, { fields: [{ path: "scope.paths", reason: `${item} resolves outside the checkout` }] });
|
|
@@ -23873,7 +24449,7 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
23873
24449
|
for (const item of [...names].sort()) {
|
|
23874
24450
|
if (!scopeMatches(item, normalizedScope))
|
|
23875
24451
|
continue;
|
|
23876
|
-
const target =
|
|
24452
|
+
const target = path10.join(checkout, item);
|
|
23877
24453
|
try {
|
|
23878
24454
|
const stat = fs7.lstatSync(target);
|
|
23879
24455
|
if (stat.isSymbolicLink()) {
|
|
@@ -24255,7 +24831,8 @@ var externalActionSchema = discriminatedUnion2("operation", [
|
|
|
24255
24831
|
action: _enum2(["setup", "reapply_stash"]).optional(),
|
|
24256
24832
|
sdd_dir: string5().optional(),
|
|
24257
24833
|
target_branch: string5().optional(),
|
|
24258
|
-
stash: _enum2(["yes", "no"]).optional()
|
|
24834
|
+
stash: _enum2(["yes", "no"]).optional(),
|
|
24835
|
+
cwd: string5().min(1).optional()
|
|
24259
24836
|
}).strict()
|
|
24260
24837
|
}).strict(),
|
|
24261
24838
|
object4({
|
|
@@ -24263,12 +24840,13 @@ var externalActionSchema = discriminatedUnion2("operation", [
|
|
|
24263
24840
|
payload: object4({
|
|
24264
24841
|
message: string5().min(1).optional(),
|
|
24265
24842
|
plan_steps: array3(chainStepSchema).min(1).max(32).optional(),
|
|
24266
|
-
plan_branch: string5().min(1).optional()
|
|
24843
|
+
plan_branch: string5().min(1).optional(),
|
|
24844
|
+
cwd: string5().min(1).optional()
|
|
24267
24845
|
}).strict()
|
|
24268
24846
|
}).strict(),
|
|
24269
24847
|
object4({
|
|
24270
24848
|
operation: literal3("git.push"),
|
|
24271
|
-
payload: object4({ branch: string5().min(1).optional() }).strict()
|
|
24849
|
+
payload: object4({ branch: string5().min(1).optional(), cwd: string5().min(1).optional() }).strict()
|
|
24272
24850
|
}).strict(),
|
|
24273
24851
|
object4({
|
|
24274
24852
|
operation: literal3("hosting.pull_request"),
|
|
@@ -24277,16 +24855,22 @@ var externalActionSchema = discriminatedUnion2("operation", [
|
|
|
24277
24855
|
body: string5().optional(),
|
|
24278
24856
|
draft: boolean5().optional(),
|
|
24279
24857
|
target_branch: string5().optional(),
|
|
24280
|
-
babysit: boolean5().optional()
|
|
24858
|
+
babysit: boolean5().optional(),
|
|
24859
|
+
cwd: string5().min(1).optional()
|
|
24281
24860
|
}).strict()
|
|
24282
24861
|
}).strict(),
|
|
24283
24862
|
object4({
|
|
24284
24863
|
operation: literal3("hosting.merge"),
|
|
24285
24864
|
payload: object4({
|
|
24286
24865
|
target_branch: string5().min(1).optional(),
|
|
24287
|
-
source_branch: string5().min(1).optional()
|
|
24866
|
+
source_branch: string5().min(1).optional(),
|
|
24867
|
+
cwd: string5().min(1).optional()
|
|
24288
24868
|
}).strict()
|
|
24289
24869
|
}).strict(),
|
|
24870
|
+
object4({
|
|
24871
|
+
operation: literal3("hosting.delete_branch"),
|
|
24872
|
+
payload: object4({ branch: string5().min(1), cwd: string5().min(1).optional() }).strict()
|
|
24873
|
+
}).strict(),
|
|
24290
24874
|
object4({
|
|
24291
24875
|
operation: literal3("youtrack.update"),
|
|
24292
24876
|
payload: object4({
|
|
@@ -24342,12 +24926,13 @@ var externalActionSchema = discriminatedUnion2("operation", [
|
|
|
24342
24926
|
issueRef: string5().optional(),
|
|
24343
24927
|
mode: string5().optional(),
|
|
24344
24928
|
specPath: string5().optional(),
|
|
24345
|
-
planPath: string5().optional()
|
|
24929
|
+
planPath: string5().optional(),
|
|
24930
|
+
cwd: string5().min(1).optional()
|
|
24346
24931
|
}).strict()
|
|
24347
24932
|
}).strict()
|
|
24348
24933
|
]);
|
|
24349
24934
|
// packages/workit-core/src/core/task-engine.ts
|
|
24350
|
-
import { realpathSync as
|
|
24935
|
+
import { realpathSync as realpathSync6 } from "node:fs";
|
|
24351
24936
|
|
|
24352
24937
|
// packages/workit-core/src/core/policy-resolver.ts
|
|
24353
24938
|
var resolverInputSchema = object4({
|
|
@@ -24892,6 +25477,18 @@ var portableTask = (task) => {
|
|
|
24892
25477
|
};
|
|
24893
25478
|
for (const entry of clone.assessments)
|
|
24894
25479
|
demote(entry.data.facts, entry.data.signals, entry.data.consequences);
|
|
25480
|
+
const sourceDecisions = new Map(task.decisions.map((entry) => [entry.id, entry]));
|
|
25481
|
+
for (const entry of clone.decisions) {
|
|
25482
|
+
const consumption = sourceDecisions.get(entry.id)?.data.consumption;
|
|
25483
|
+
if (!consumption)
|
|
25484
|
+
continue;
|
|
25485
|
+
entry.data.consumption = {
|
|
25486
|
+
...consumption,
|
|
25487
|
+
state: consumption.state === "reserved" ? "uncertain" : consumption.state,
|
|
25488
|
+
actionRef: { kind: "record", collection: "decisions", id: entry.id },
|
|
25489
|
+
...consumption.historicalActionId ? { historicalActionId: consumption.historicalActionId } : consumption.actionRef.kind === "host" ? { historicalActionId: consumption.actionRef.handle } : {}
|
|
25490
|
+
};
|
|
25491
|
+
}
|
|
24895
25492
|
clone.candidates = [];
|
|
24896
25493
|
return clone;
|
|
24897
25494
|
};
|
|
@@ -25017,7 +25614,11 @@ var importedTask = (source, bundle, destinationWorkspaceId, context, timestamp)
|
|
|
25017
25614
|
taskId: "",
|
|
25018
25615
|
workspaceId: destinationWorkspaceId
|
|
25019
25616
|
},
|
|
25020
|
-
consumption:
|
|
25617
|
+
consumption: data.consumption ? {
|
|
25618
|
+
...data.consumption,
|
|
25619
|
+
state: data.consumption.state === "reserved" ? "uncertain" : data.consumption.state,
|
|
25620
|
+
actionRef: { kind: "record", collection: "decisions", id: entry.id }
|
|
25621
|
+
} : null
|
|
25021
25622
|
}
|
|
25022
25623
|
};
|
|
25023
25624
|
}),
|
|
@@ -25058,7 +25659,7 @@ class WorkitCore {
|
|
|
25058
25659
|
}
|
|
25059
25660
|
contextRootError() {
|
|
25060
25661
|
try {
|
|
25061
|
-
if (
|
|
25662
|
+
if (realpathSync6(this.context.root) !== this.store.root)
|
|
25062
25663
|
return failure("invalid_input", "operation context root does not match the task store root");
|
|
25063
25664
|
} catch {
|
|
25064
25665
|
return failure("invalid_input", "operation context root cannot be resolved");
|
|
@@ -25217,7 +25818,7 @@ class WorkitCore {
|
|
|
25217
25818
|
return parsed;
|
|
25218
25819
|
const input = parsed.data;
|
|
25219
25820
|
if ((this.context.workerId ?? null) !== null) {
|
|
25220
|
-
if (input.action !== "inspect")
|
|
25821
|
+
if (input.action !== "inspect" && input.action !== "list")
|
|
25221
25822
|
return failure("permission_denied", "helpers cannot control task lifecycle or scope");
|
|
25222
25823
|
}
|
|
25223
25824
|
switch (input.action) {
|
|
@@ -25244,7 +25845,18 @@ class WorkitCore {
|
|
|
25244
25845
|
return listed;
|
|
25245
25846
|
const status = input.status ?? "open";
|
|
25246
25847
|
const limit = input.limit ?? 20;
|
|
25247
|
-
const
|
|
25848
|
+
const query = input.query?.toLowerCase().split(/\s+/);
|
|
25849
|
+
const selected = listed.data.filter((task) => status === "all" ? true : status === "closed" ? task.status === "closed" : task.status !== "closed").filter((task) => !query || query.every((term) => JSON.stringify({
|
|
25850
|
+
id: task.id,
|
|
25851
|
+
workspaceId: task.workspaceId,
|
|
25852
|
+
origin: task.origin,
|
|
25853
|
+
createdAt: task.createdAt,
|
|
25854
|
+
updatedAt: task.updatedAt,
|
|
25855
|
+
source: task.intent.provenance,
|
|
25856
|
+
objective: task.intent.data.objective,
|
|
25857
|
+
progress: task.progress,
|
|
25858
|
+
decisions: task.decisions.map(({ data }) => data)
|
|
25859
|
+
}).toLowerCase().includes(term))).sort((left, right) => right.updatedAt.localeCompare(left.updatedAt)).slice(0, limit);
|
|
25248
25860
|
if (selected.length === 0)
|
|
25249
25861
|
return success(null, null, []);
|
|
25250
25862
|
const workspace = this.store.readWorkspace();
|
|
@@ -25263,7 +25875,11 @@ class WorkitCore {
|
|
|
25263
25875
|
status: task.status,
|
|
25264
25876
|
closure: task.closure,
|
|
25265
25877
|
progress: task.progress,
|
|
25266
|
-
writer: task.status === "closed" ? null : workspace.data.writer
|
|
25878
|
+
writer: task.status === "closed" ? null : workspace.data.writer,
|
|
25879
|
+
source: {
|
|
25880
|
+
host: task.intent.provenance.host,
|
|
25881
|
+
kind: task.intent.provenance.kind
|
|
25882
|
+
}
|
|
25267
25883
|
}));
|
|
25268
25884
|
return success(null, null, tasks);
|
|
25269
25885
|
}
|
|
@@ -26359,7 +26975,7 @@ class WorkitCore {
|
|
|
26359
26975
|
if (view.task.workspaceId !== view.workspace.id)
|
|
26360
26976
|
return failure("invalid_input", "task and workspace bindings are invalid");
|
|
26361
26977
|
try {
|
|
26362
|
-
if (
|
|
26978
|
+
if (realpathSync6(view.workspace.root) !== this.store.root)
|
|
26363
26979
|
return failure("invalid_input", "task view root does not match the task store");
|
|
26364
26980
|
} catch {
|
|
26365
26981
|
return failure("invalid_input", "task view root cannot be resolved");
|
|
@@ -26636,22 +27252,22 @@ function resolveGitRevision(root, value) {
|
|
|
26636
27252
|
}
|
|
26637
27253
|
}
|
|
26638
27254
|
function resolveInside(root, candidate) {
|
|
26639
|
-
const base =
|
|
26640
|
-
const target =
|
|
26641
|
-
if (target !== base && !target.startsWith(base +
|
|
27255
|
+
const base = realpathSync7(root);
|
|
27256
|
+
const target = path11.resolve(base, candidate);
|
|
27257
|
+
if (target !== base && !target.startsWith(base + path11.sep)) {
|
|
26642
27258
|
throw new Error("path must stay inside repository root");
|
|
26643
27259
|
}
|
|
26644
27260
|
let ancestor = target;
|
|
26645
27261
|
while (!existsSync5(ancestor))
|
|
26646
|
-
ancestor =
|
|
26647
|
-
const canonicalAncestor =
|
|
26648
|
-
if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base +
|
|
27262
|
+
ancestor = path11.dirname(ancestor);
|
|
27263
|
+
const canonicalAncestor = realpathSync7(ancestor);
|
|
27264
|
+
if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path11.sep)) {
|
|
26649
27265
|
throw new Error("path must stay inside repository root");
|
|
26650
27266
|
}
|
|
26651
27267
|
return target;
|
|
26652
27268
|
}
|
|
26653
27269
|
function run2(root, executable, args, env = {}) {
|
|
26654
|
-
const cwd =
|
|
27270
|
+
const cwd = realpathSync7(root);
|
|
26655
27271
|
const result = spawnSync3(executable, args, {
|
|
26656
27272
|
cwd,
|
|
26657
27273
|
encoding: "utf8",
|
|
@@ -26724,18 +27340,19 @@ var redactSecrets = (value) => applyPatterns(value);
|
|
|
26724
27340
|
|
|
26725
27341
|
// packages/workit-core/src/core/pr-create.ts
|
|
26726
27342
|
import fs8 from "node:fs";
|
|
26727
|
-
import
|
|
27343
|
+
import path12 from "node:path";
|
|
27344
|
+
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
26728
27345
|
function parseGhIssue(value) {
|
|
26729
27346
|
const m = /issues\/(\d+)/.exec(value);
|
|
26730
27347
|
return m ? m[1] : String(value).trim().replace(/^#/, "");
|
|
26731
27348
|
}
|
|
26732
27349
|
function whichOnPath(tool) {
|
|
26733
27350
|
const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
|
|
26734
|
-
for (const dir of (process.env.PATH ?? "").split(
|
|
27351
|
+
for (const dir of (process.env.PATH ?? "").split(path12.delimiter)) {
|
|
26735
27352
|
if (!dir)
|
|
26736
27353
|
continue;
|
|
26737
27354
|
for (const name of names) {
|
|
26738
|
-
const candidate =
|
|
27355
|
+
const candidate = path12.join(dir, name);
|
|
26739
27356
|
try {
|
|
26740
27357
|
fs8.accessSync(candidate, fs8.constants.X_OK);
|
|
26741
27358
|
return candidate;
|
|
@@ -26745,11 +27362,21 @@ function whichOnPath(tool) {
|
|
|
26745
27362
|
return null;
|
|
26746
27363
|
}
|
|
26747
27364
|
var hostingCliAvailable = (provider) => whichOnPath(provider === "gitlab" ? "glab" : "gh") !== null;
|
|
27365
|
+
var pushRemote = (cwd) => {
|
|
27366
|
+
const result = spawnSync4("git", ["remote", "get-url", "--push", "--all", "origin"], {
|
|
27367
|
+
cwd,
|
|
27368
|
+
encoding: "utf8"
|
|
27369
|
+
});
|
|
27370
|
+
if (result.status !== 0)
|
|
27371
|
+
return null;
|
|
27372
|
+
const urls = (result.stdout ?? "").split(/\r?\n/u).map((url) => url.trim()).filter(Boolean);
|
|
27373
|
+
return urls.length === 1 ? urls[0] : null;
|
|
27374
|
+
};
|
|
26748
27375
|
|
|
26749
27376
|
// packages/workit-core/src/core/repo-context.ts
|
|
26750
|
-
import { spawnSync as
|
|
27377
|
+
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
26751
27378
|
import { existsSync as existsSync6, readFileSync as readFileSync7, readdirSync as readdirSync4 } from "node:fs";
|
|
26752
|
-
import
|
|
27379
|
+
import path13 from "node:path";
|
|
26753
27380
|
var isSafeContextRange = (value) => value.length <= 4096 && (() => {
|
|
26754
27381
|
try {
|
|
26755
27382
|
gitRevisionParts(value);
|
|
@@ -26776,7 +27403,7 @@ var invalidRange = (cwd) => ({
|
|
|
26776
27403
|
cwd
|
|
26777
27404
|
});
|
|
26778
27405
|
var runGit = (cwd, args) => {
|
|
26779
|
-
const result =
|
|
27406
|
+
const result = spawnSync5("git", args, { cwd, encoding: "utf8" });
|
|
26780
27407
|
return {
|
|
26781
27408
|
stdout: (result.stdout ?? "").trimEnd(),
|
|
26782
27409
|
stderr: (result.stderr ?? "").trimEnd(),
|
|
@@ -26883,7 +27510,7 @@ var findPrTemplate = (cwd) => {
|
|
|
26883
27510
|
]) {
|
|
26884
27511
|
const parts = rel.split("/");
|
|
26885
27512
|
const base = parts[parts.length - 1];
|
|
26886
|
-
const dir = parts.length > 1 ?
|
|
27513
|
+
const dir = parts.length > 1 ? path13.join(cwd, ...parts.slice(0, -1)) : cwd;
|
|
26887
27514
|
const actual = probeCaseInsensitive(dir, base);
|
|
26888
27515
|
if (actual)
|
|
26889
27516
|
return [...parts.slice(0, -1), actual].join("/");
|
|
@@ -26914,7 +27541,7 @@ var diffStatForRange = (cwd, range) => {
|
|
|
26914
27541
|
return runGit(cwd, ["diff", "--stat", "--"]).stdout;
|
|
26915
27542
|
};
|
|
26916
27543
|
var packageScripts = (cwd, keys) => {
|
|
26917
|
-
const pkgPath =
|
|
27544
|
+
const pkgPath = path13.join(cwd, "package.json");
|
|
26918
27545
|
if (!existsSync6(pkgPath))
|
|
26919
27546
|
return [];
|
|
26920
27547
|
try {
|
|
@@ -26940,9 +27567,9 @@ var documentationFiles = (cwd) => {
|
|
|
26940
27567
|
if (entry.isDirectory()) {
|
|
26941
27568
|
if (excluded.has(entry.name))
|
|
26942
27569
|
continue;
|
|
26943
|
-
walk(
|
|
27570
|
+
walk(path13.join(dir, entry.name), depth + 1);
|
|
26944
27571
|
} else if (entry.isFile() && (entry.name === "README.md" || entry.name.endsWith(".md"))) {
|
|
26945
|
-
matches.push("./" +
|
|
27572
|
+
matches.push("./" + path13.relative(cwd, path13.join(dir, entry.name)).replaceAll("\\", "/"));
|
|
26946
27573
|
}
|
|
26947
27574
|
}
|
|
26948
27575
|
};
|
|
@@ -26958,7 +27585,7 @@ var readTrimmed = (file, maxLines) => {
|
|
|
26958
27585
|
`);
|
|
26959
27586
|
};
|
|
26960
27587
|
function prReadyContext(root, range) {
|
|
26961
|
-
const cwd =
|
|
27588
|
+
const cwd = path13.resolve(repoRoot(root));
|
|
26962
27589
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
26963
27590
|
return invalidRange(cwd);
|
|
26964
27591
|
let stdout = "";
|
|
@@ -27016,7 +27643,7 @@ ${status.stderr}` : "");
|
|
|
27016
27643
|
stdout += `template_path: ${template}
|
|
27017
27644
|
|
|
27018
27645
|
`;
|
|
27019
|
-
stdout += readTrimmed(
|
|
27646
|
+
stdout += readTrimmed(path13.join(cwd, template), 220);
|
|
27020
27647
|
} else {
|
|
27021
27648
|
stdout += `template_path: none
|
|
27022
27649
|
|
|
@@ -27026,7 +27653,7 @@ ${status.stderr}` : "");
|
|
|
27026
27653
|
stdout += `
|
|
27027
27654
|
`;
|
|
27028
27655
|
stdout += printSection("Recent Validation Signals");
|
|
27029
|
-
if (existsSync6(
|
|
27656
|
+
if (existsSync6(path13.join(cwd, "package.json"))) {
|
|
27030
27657
|
stdout += `package.json detected. Common scripts:
|
|
27031
27658
|
`;
|
|
27032
27659
|
const found = packageScripts(cwd, ["lint", "format:check", "test", "build"]);
|
|
@@ -27035,7 +27662,7 @@ ${status.stderr}` : "");
|
|
|
27035
27662
|
`) + `
|
|
27036
27663
|
`;
|
|
27037
27664
|
}
|
|
27038
|
-
if (existsSync6(
|
|
27665
|
+
if (existsSync6(path13.join(cwd, "Cargo.toml")) || existsSync6(path13.join(cwd, "src-tauri/Cargo.toml"))) {
|
|
27039
27666
|
stdout += `Rust project detected.
|
|
27040
27667
|
`;
|
|
27041
27668
|
}
|
|
@@ -27068,7 +27695,7 @@ var CHANGELOG_RULES = `- Use an [Unreleased] section.
|
|
|
27068
27695
|
- Apply with the native workit_changelog_apply tool only (not hand-edits under Unreleased).
|
|
27069
27696
|
- If Unreleased already has duplicate category headings, normalize_only first.`;
|
|
27070
27697
|
function changelogContext(root, range) {
|
|
27071
|
-
const cwd =
|
|
27698
|
+
const cwd = path13.resolve(repoRoot(root));
|
|
27072
27699
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
27073
27700
|
return invalidRange(cwd);
|
|
27074
27701
|
const resolvedRange = rangeArgOrDefault(range, cwd);
|
|
@@ -27086,7 +27713,7 @@ function changelogContext(root, range) {
|
|
|
27086
27713
|
stdout += CHANGELOG_RULES + `
|
|
27087
27714
|
`;
|
|
27088
27715
|
stdout += printSection("Existing CHANGELOG.md");
|
|
27089
|
-
const changelogPath =
|
|
27716
|
+
const changelogPath = path13.join(cwd, "CHANGELOG.md");
|
|
27090
27717
|
if (existsSync6(changelogPath)) {
|
|
27091
27718
|
stdout += readTrimmed(changelogPath, 260) + `
|
|
27092
27719
|
`;
|
|
@@ -27106,7 +27733,7 @@ function changelogContext(root, range) {
|
|
|
27106
27733
|
return { stdout, stderr: "", exitCode: 0, cwd };
|
|
27107
27734
|
}
|
|
27108
27735
|
function docsRefreshContext(root, range) {
|
|
27109
|
-
const cwd =
|
|
27736
|
+
const cwd = path13.resolve(repoRoot(root));
|
|
27110
27737
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
27111
27738
|
return invalidRange(cwd);
|
|
27112
27739
|
const resolvedRange = rangeArgOrDefault(range, cwd);
|
|
@@ -27128,7 +27755,7 @@ function docsRefreshContext(root, range) {
|
|
|
27128
27755
|
`) + `
|
|
27129
27756
|
`;
|
|
27130
27757
|
stdout += printSection("README Preview");
|
|
27131
|
-
const readme =
|
|
27758
|
+
const readme = path13.join(cwd, "README.md");
|
|
27132
27759
|
if (existsSync6(readme)) {
|
|
27133
27760
|
stdout += readTrimmed(readme, 220) + `
|
|
27134
27761
|
`;
|
|
@@ -27137,7 +27764,7 @@ function docsRefreshContext(root, range) {
|
|
|
27137
27764
|
`;
|
|
27138
27765
|
}
|
|
27139
27766
|
stdout += printSection("Package Scripts");
|
|
27140
|
-
const pkgPath =
|
|
27767
|
+
const pkgPath = path13.join(cwd, "package.json");
|
|
27141
27768
|
if (existsSync6(pkgPath)) {
|
|
27142
27769
|
try {
|
|
27143
27770
|
const pkg = JSON.parse(readFileSync7(pkgPath, "utf8"));
|
|
@@ -27151,7 +27778,7 @@ function docsRefreshContext(root, range) {
|
|
|
27151
27778
|
return { stdout, stderr: "", exitCode: 0, cwd };
|
|
27152
27779
|
}
|
|
27153
27780
|
function releaseNotesContext(root, rangeOrTag) {
|
|
27154
|
-
const cwd =
|
|
27781
|
+
const cwd = path13.resolve(repoRoot(root));
|
|
27155
27782
|
if (!rangeOrTag) {
|
|
27156
27783
|
return { stdout: "", stderr: `ERROR: release tag or range required
|
|
27157
27784
|
`, exitCode: 1, cwd };
|
|
@@ -27189,7 +27816,7 @@ function releaseNotesContext(root, rangeOrTag) {
|
|
|
27189
27816
|
`;
|
|
27190
27817
|
stdout += printSection("Existing Release Files");
|
|
27191
27818
|
for (const rel of ["CHANGELOG.md", "RELEASE_NOTES.md", ".github/releases.md"]) {
|
|
27192
|
-
if (existsSync6(
|
|
27819
|
+
if (existsSync6(path13.join(cwd, rel)))
|
|
27193
27820
|
stdout += rel + `
|
|
27194
27821
|
`;
|
|
27195
27822
|
}
|
|
@@ -27217,19 +27844,7 @@ function releaseNotesContext(root, rangeOrTag) {
|
|
|
27217
27844
|
}
|
|
27218
27845
|
|
|
27219
27846
|
// packages/workit-core/src/core/tracker-issues.ts
|
|
27220
|
-
import
|
|
27221
|
-
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
27222
|
-
var trackerRequest = async (url, init) => {
|
|
27223
|
-
try {
|
|
27224
|
-
const res = await fetch(url, { method: init.method, headers: init.headers });
|
|
27225
|
-
const text = await res.text();
|
|
27226
|
-
if (!res.ok)
|
|
27227
|
-
return { status: res.status, stdout: "", stderr: text.slice(0, 200) };
|
|
27228
|
-
return { status: 0, stdout: text, stderr: "" };
|
|
27229
|
-
} catch (err) {
|
|
27230
|
-
return { status: 1, stdout: "", stderr: err instanceof Error ? err.message : "network error" };
|
|
27231
|
-
}
|
|
27232
|
-
};
|
|
27847
|
+
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
27233
27848
|
var repoPathFromRemote = (remote) => {
|
|
27234
27849
|
let rest = (remote || "").trim().replace(/\/+$/, "");
|
|
27235
27850
|
if (!rest)
|
|
@@ -27250,7 +27865,11 @@ var defaultCli = (bin, available) => {
|
|
|
27250
27865
|
if (!available)
|
|
27251
27866
|
return null;
|
|
27252
27867
|
return (args, root) => {
|
|
27253
|
-
const out =
|
|
27868
|
+
const out = spawnSync6(bin, args, {
|
|
27869
|
+
cwd: root,
|
|
27870
|
+
encoding: "utf8",
|
|
27871
|
+
env: { ...process.env, PATH: process.env.PATH ?? "" }
|
|
27872
|
+
});
|
|
27254
27873
|
return Promise.resolve({
|
|
27255
27874
|
status: out.status ?? 1,
|
|
27256
27875
|
stdout: out.stdout ?? "",
|
|
@@ -27258,49 +27877,22 @@ var defaultCli = (bin, available) => {
|
|
|
27258
27877
|
});
|
|
27259
27878
|
};
|
|
27260
27879
|
};
|
|
27261
|
-
var tryCliTriple = async (cli, args, root, id, idKeys, bodyKeys) => {
|
|
27880
|
+
var tryCliTriple = async (cli, name, args, root, id, idKeys, bodyKeys) => {
|
|
27262
27881
|
if (!cli)
|
|
27263
|
-
return
|
|
27882
|
+
return { error: `${name} CLI is unavailable`, kind: "creds" };
|
|
27264
27883
|
const run = cli(args, root);
|
|
27265
27884
|
if (!run)
|
|
27266
|
-
return
|
|
27885
|
+
return { error: `${name} CLI is unavailable`, kind: "creds" };
|
|
27267
27886
|
const out = await run;
|
|
27268
27887
|
if (out.status !== 0)
|
|
27269
|
-
return
|
|
27888
|
+
return { error: `${name} CLI is not authenticated or the issue is unavailable`, kind: "creds" };
|
|
27270
27889
|
try {
|
|
27271
|
-
|
|
27890
|
+
const triple = parseTriple(JSON.parse(out.stdout), id, idKeys, bodyKeys);
|
|
27891
|
+
return triple ? { data: triple } : { error: `unexpected ${name} issue response`, kind: "request" };
|
|
27272
27892
|
} catch {
|
|
27273
|
-
return
|
|
27893
|
+
return { error: `invalid ${name} issue response`, kind: "request" };
|
|
27274
27894
|
}
|
|
27275
27895
|
};
|
|
27276
|
-
var originRemote = (root) => {
|
|
27277
|
-
const out = spawnSync5("git", ["remote", "get-url", "origin"], { cwd: root, encoding: "utf8" });
|
|
27278
|
-
return out.status === 0 ? (out.stdout ?? "").trim() || null : null;
|
|
27279
|
-
};
|
|
27280
|
-
var trackerCreds = (root, provider) => {
|
|
27281
|
-
const cfg = vcsConfig("load", root);
|
|
27282
|
-
if (!cfg || cfg.provider !== provider || typeof cfg.tokenPath !== "string" || !cfg.tokenPath)
|
|
27283
|
-
return { error: `unconfigured ${provider} provider` };
|
|
27284
|
-
let token = "";
|
|
27285
|
-
try {
|
|
27286
|
-
token = fs9.readFileSync(cfg.tokenPath, "utf8").trim();
|
|
27287
|
-
} catch {
|
|
27288
|
-
return { error: `missing ${provider} token` };
|
|
27289
|
-
}
|
|
27290
|
-
if (!token)
|
|
27291
|
-
return { error: `empty ${provider} token file` };
|
|
27292
|
-
if (provider === "gitlab") {
|
|
27293
|
-
const gitlab = cfg.gitlab;
|
|
27294
|
-
const apiUrl = String(gitlab?.apiUrl ?? "https://gitlab.com/api/v4").replace(/\/+$/, "");
|
|
27295
|
-
return { token, api: apiUrl };
|
|
27296
|
-
}
|
|
27297
|
-
const github = cfg.github;
|
|
27298
|
-
const host = String(github?.host ?? "github.com").toLowerCase();
|
|
27299
|
-
return {
|
|
27300
|
-
token,
|
|
27301
|
-
api: host === "github.com" ? "https://api.github.com" : `https://${host}/api/v3`
|
|
27302
|
-
};
|
|
27303
|
-
};
|
|
27304
27896
|
var parseTriple = (parsed, id, idKeys, bodyKeys) => {
|
|
27305
27897
|
const title = parsed.title;
|
|
27306
27898
|
if (typeof title !== "string")
|
|
@@ -27323,62 +27915,36 @@ var fetchGitHubIssueBody = async (ref, root, deps = {}) => {
|
|
|
27323
27915
|
const id = parseGhIssue(ref);
|
|
27324
27916
|
if (!/^\d+$/.test(id))
|
|
27325
27917
|
return { error: `invalid GitHub issue ref "${ref}"`, kind: "input" };
|
|
27326
|
-
const
|
|
27918
|
+
const remote = (deps.remote ?? pushRemote)(root);
|
|
27919
|
+
const repo = repoPathFromRemote(remote ?? "");
|
|
27327
27920
|
if (!repo)
|
|
27328
27921
|
return { error: "no origin remote to resolve the repository", kind: "input" };
|
|
27329
|
-
const
|
|
27330
|
-
|
|
27331
|
-
|
|
27332
|
-
|
|
27333
|
-
|
|
27334
|
-
|
|
27335
|
-
const out = await (deps.request ?? trackerRequest)(`${credentials.api}/repos/${repo}/issues/${id}`, {
|
|
27336
|
-
method: "GET",
|
|
27337
|
-
headers: {
|
|
27338
|
-
Authorization: `Bearer ${credentials.token}`,
|
|
27339
|
-
Accept: "application/vnd.github+json"
|
|
27340
|
-
}
|
|
27341
|
-
});
|
|
27342
|
-
if (out.status !== 0)
|
|
27343
|
-
return { error: out.stderr || "GitHub issue fetch failed", kind: "request" };
|
|
27344
|
-
try {
|
|
27345
|
-
const triple = parseTriple(JSON.parse(out.stdout), id, ["number"], ["body"]);
|
|
27346
|
-
if (!triple)
|
|
27347
|
-
return { error: "unexpected GitHub issue shape", kind: "request" };
|
|
27348
|
-
return { data: triple };
|
|
27349
|
-
} catch {
|
|
27350
|
-
return { error: "invalid GitHub issue response", kind: "request" };
|
|
27351
|
-
}
|
|
27922
|
+
const cfg = vcsConfig("load", root);
|
|
27923
|
+
const host = (deps.host ?? (cfg.ok && cfg.provider === "github" ? cfg.github?.host : null) ?? "github.com").toLowerCase();
|
|
27924
|
+
if (!remote || !hostingApiHostMatches(remote, host))
|
|
27925
|
+
return { error: "hosting API host does not match the push destination", kind: "input" };
|
|
27926
|
+
const repoArg = host === "github.com" ? repo : `${host}/${repo}`;
|
|
27927
|
+
return tryCliTriple(deps.cli ?? defaultCli("gh", hostingCliAvailable("github")), "gh", ["issue", "view", id, "--repo", repoArg, "--json", "number,title,body,state"], root, id, ["number"], ["body"]);
|
|
27352
27928
|
};
|
|
27353
27929
|
var fetchGitLabIssueBody = async (ref, root, deps = {}) => {
|
|
27354
27930
|
const id = parseGhIssue(ref);
|
|
27355
27931
|
if (!/^\d+$/.test(id))
|
|
27356
27932
|
return { error: `invalid GitLab issue ref "${ref}"`, kind: "input" };
|
|
27357
|
-
const
|
|
27933
|
+
const remote = (deps.remote ?? pushRemote)(root);
|
|
27934
|
+
const repo = repoPathFromRemote(remote ?? "");
|
|
27358
27935
|
if (!repo)
|
|
27359
27936
|
return { error: "no origin remote to resolve the project", kind: "input" };
|
|
27360
|
-
const
|
|
27361
|
-
|
|
27362
|
-
|
|
27363
|
-
|
|
27364
|
-
|
|
27365
|
-
|
|
27366
|
-
const out = await (deps.request ?? trackerRequest)(`${credentials.api}/projects/${encodeURIComponent(repo)}/issues/${id}`, { method: "GET", headers: { "PRIVATE-TOKEN": credentials.token } });
|
|
27367
|
-
if (out.status !== 0)
|
|
27368
|
-
return { error: out.stderr || "GitLab issue fetch failed", kind: "request" };
|
|
27369
|
-
try {
|
|
27370
|
-
const triple = parseTriple(JSON.parse(out.stdout), id, ["iid"], ["description"]);
|
|
27371
|
-
if (!triple)
|
|
27372
|
-
return { error: "unexpected GitLab issue shape", kind: "request" };
|
|
27373
|
-
return { data: triple };
|
|
27374
|
-
} catch {
|
|
27375
|
-
return { error: "invalid GitLab issue response", kind: "request" };
|
|
27376
|
-
}
|
|
27937
|
+
const cfg = vcsConfig("load", root);
|
|
27938
|
+
const host = (deps.host ?? (cfg.ok && cfg.provider === "gitlab" ? cfg.gitlab?.host : null) ?? "gitlab.com").toLowerCase();
|
|
27939
|
+
if (!remote || !hostingApiHostMatches(remote, host))
|
|
27940
|
+
return { error: "hosting API host does not match the push destination", kind: "input" };
|
|
27941
|
+
const repoArg = host === "gitlab.com" ? repo : `https://${host}/${repo}`;
|
|
27942
|
+
return tryCliTriple(deps.cli ?? defaultCli("glab", hostingCliAvailable("gitlab")), "glab", ["issue", "view", id, "-R", repoArg, "-F", "json"], root, id, ["iid"], ["description"]);
|
|
27377
27943
|
};
|
|
27378
27944
|
|
|
27379
27945
|
// packages/workit-core/src/core/youtrack.ts
|
|
27380
|
-
import
|
|
27381
|
-
import
|
|
27946
|
+
import fs9 from "node:fs";
|
|
27947
|
+
import path14 from "node:path";
|
|
27382
27948
|
|
|
27383
27949
|
// packages/workit-core/src/core/templates.ts
|
|
27384
27950
|
var repoRoot2 = assetRoot();
|
|
@@ -27390,23 +27956,23 @@ var resolveWorkspaceRoot = (explicit) => explicit || process.cwd();
|
|
|
27390
27956
|
|
|
27391
27957
|
// packages/workit-core/src/core/youtrack.ts
|
|
27392
27958
|
var ISSUE_RE = /^[A-Z]+-\d+$/;
|
|
27393
|
-
var
|
|
27394
|
-
var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ??
|
|
27395
|
-
var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ??
|
|
27959
|
+
var TOKEN_PLACEHOLDER = "YOUR_TOKEN_HERE";
|
|
27960
|
+
var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path14.join(configDir(), "youtrack.json");
|
|
27961
|
+
var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path14.join(resolveConfigDir(), "youtrack.json");
|
|
27396
27962
|
var youTrackTokenModeOk = (p) => {
|
|
27397
27963
|
if (process.platform === "win32")
|
|
27398
27964
|
return true;
|
|
27399
|
-
const mode =
|
|
27965
|
+
const mode = fs9.statSync(p).mode & 511;
|
|
27400
27966
|
return mode === 384;
|
|
27401
27967
|
};
|
|
27402
27968
|
function readYouTrackConfig(required) {
|
|
27403
27969
|
const cfgPath = youTrackConfigPath();
|
|
27404
|
-
if (!
|
|
27970
|
+
if (!fs9.existsSync(cfgPath)) {
|
|
27405
27971
|
return required ? { error: "ERROR: missing youtrack.json", path: cfgPath } : { config: {}, path: cfgPath };
|
|
27406
27972
|
}
|
|
27407
27973
|
let parsed;
|
|
27408
27974
|
try {
|
|
27409
|
-
parsed = JSON.parse(
|
|
27975
|
+
parsed = JSON.parse(fs9.readFileSync(cfgPath, "utf8"));
|
|
27410
27976
|
} catch {
|
|
27411
27977
|
return { error: `${cfgPath} is not valid JSON`, path: cfgPath };
|
|
27412
27978
|
}
|
|
@@ -27417,11 +27983,11 @@ function readYouTrackConfig(required) {
|
|
|
27417
27983
|
}
|
|
27418
27984
|
var readYouTrackContextConfig = () => {
|
|
27419
27985
|
const cfgPath = youTrackReadOnlyConfigPath();
|
|
27420
|
-
if (!
|
|
27986
|
+
if (!fs9.existsSync(cfgPath))
|
|
27421
27987
|
return { data: {} };
|
|
27422
27988
|
let parsed;
|
|
27423
27989
|
try {
|
|
27424
|
-
parsed = JSON.parse(
|
|
27990
|
+
parsed = JSON.parse(fs9.readFileSync(cfgPath, "utf8"));
|
|
27425
27991
|
} catch {
|
|
27426
27992
|
return { error: "YouTrack configuration is unavailable" };
|
|
27427
27993
|
}
|
|
@@ -27446,12 +28012,12 @@ function youTrackGreeting(configOverride) {
|
|
|
27446
28012
|
const cfgPath = configOverride ?? youTrackConfigPath();
|
|
27447
28013
|
let parsed;
|
|
27448
28014
|
try {
|
|
27449
|
-
parsed = JSON.parse(
|
|
28015
|
+
parsed = JSON.parse(fs9.readFileSync(cfgPath, "utf8"));
|
|
27450
28016
|
} catch {
|
|
27451
28017
|
return {
|
|
27452
28018
|
stdout: "",
|
|
27453
28019
|
exitCode: 1,
|
|
27454
|
-
stderr:
|
|
28020
|
+
stderr: fs9.existsSync(cfgPath) ? `${cfgPath} is not valid JSON` : `missing youtrack.json: ${cfgPath}`
|
|
27455
28021
|
};
|
|
27456
28022
|
}
|
|
27457
28023
|
if (!isConfigObject(parsed)) {
|
|
@@ -27497,15 +28063,15 @@ var youTrackToken = () => {
|
|
|
27497
28063
|
if ("error" in loaded)
|
|
27498
28064
|
return loaded;
|
|
27499
28065
|
const tokenFile = String(loaded.config.tokenFile ?? "");
|
|
27500
|
-
const tokenPath = tokenFile ?
|
|
27501
|
-
if (!tokenPath || !
|
|
28066
|
+
const tokenPath = tokenFile ? path14.isAbsolute(tokenFile) ? path14.resolve(tokenFile) : path14.resolve(process.cwd(), tokenFile) : "";
|
|
28067
|
+
if (!tokenPath || !fs9.existsSync(tokenPath))
|
|
27502
28068
|
return { error: "missing youtrack.token" };
|
|
27503
28069
|
if (!youTrackTokenModeOk(tokenPath))
|
|
27504
28070
|
return { error: "youtrack.token mode must be 0600" };
|
|
27505
|
-
const token =
|
|
28071
|
+
const token = fs9.readFileSync(tokenPath, "utf8").trim();
|
|
27506
28072
|
if (!token)
|
|
27507
28073
|
return { error: "empty token file" };
|
|
27508
|
-
if (token ===
|
|
28074
|
+
if (token === TOKEN_PLACEHOLDER || token.startsWith(TOKEN_PLACEHOLDER)) {
|
|
27509
28075
|
return {
|
|
27510
28076
|
error: "token file still has placeholder YOUR_TOKEN_HERE — edit the file locally, then run /wk-status"
|
|
27511
28077
|
};
|
|
@@ -27568,9 +28134,9 @@ function resolveYouTrackFromPaths(spec_path, plan_path, workspace_root) {
|
|
|
27568
28134
|
} catch {
|
|
27569
28135
|
continue;
|
|
27570
28136
|
}
|
|
27571
|
-
if (!
|
|
28137
|
+
if (!fs9.existsSync(full))
|
|
27572
28138
|
continue;
|
|
27573
|
-
const text =
|
|
28139
|
+
const text = fs9.readFileSync(full, "utf8");
|
|
27574
28140
|
const m = text.match(/^\*\*YouTrack:\*\*\s*`?([A-Z]+-\d+)`?/m);
|
|
27575
28141
|
if (m)
|
|
27576
28142
|
return m[1];
|
|
@@ -27804,6 +28370,7 @@ var readExternalContext = async (root, payload) => {
|
|
|
27804
28370
|
}
|
|
27805
28371
|
}
|
|
27806
28372
|
};
|
|
28373
|
+
var targetWriterActionLease = Symbol("target-writer-action-lease");
|
|
27807
28374
|
|
|
27808
28375
|
// packages/workit-mcp/src/server.ts
|
|
27809
28376
|
class McpCapabilityUnavailableError extends Error {
|
|
@@ -27848,13 +28415,13 @@ var rootVariants = (workspaceRoot) => {
|
|
|
27848
28415
|
if (!workspaceRoot)
|
|
27849
28416
|
return [];
|
|
27850
28417
|
const roots = new Set;
|
|
27851
|
-
for (const candidate of [workspaceRoot,
|
|
27852
|
-
if (
|
|
28418
|
+
for (const candidate of [workspaceRoot, path15.resolve(workspaceRoot)]) {
|
|
28419
|
+
if (path15.isAbsolute(candidate) && candidate !== path15.parse(candidate).root)
|
|
27853
28420
|
roots.add(candidate);
|
|
27854
28421
|
}
|
|
27855
28422
|
try {
|
|
27856
|
-
const canonical =
|
|
27857
|
-
if (canonical !==
|
|
28423
|
+
const canonical = realpathSync8(workspaceRoot);
|
|
28424
|
+
if (canonical !== path15.parse(canonical).root)
|
|
27858
28425
|
roots.add(canonical);
|
|
27859
28426
|
} catch {}
|
|
27860
28427
|
return [...roots].sort((left, right) => right.length - left.length);
|
|
@@ -27955,11 +28522,11 @@ var thrownResult = (tool, error, workspaceRoot) => {
|
|
|
27955
28522
|
};
|
|
27956
28523
|
function createMcpServer(host, contextProvider) {
|
|
27957
28524
|
assertMcpHost(host);
|
|
27958
|
-
const here =
|
|
28525
|
+
const here = path15.dirname(fileURLToPath2(import.meta.url));
|
|
27959
28526
|
const sourceMarker = markSourcesLoaded([
|
|
27960
|
-
|
|
27961
|
-
|
|
27962
|
-
|
|
28527
|
+
path15.join(here, "server.ts"),
|
|
28528
|
+
path15.join(here, "..", "..", "workit-core", "src", "core", "task-contract.ts"),
|
|
28529
|
+
path15.join(here, "..", "..", "workit-core", "src", "core", "task-engine.ts")
|
|
27963
28530
|
].filter((file) => existsSync7(file)));
|
|
27964
28531
|
let staleWarned = false;
|
|
27965
28532
|
const server = new Server({ name: "workit", version: VERSION }, { capabilities: { tools: {}, resources: {} } });
|
|
@@ -28139,8 +28706,8 @@ var main = async () => {
|
|
|
28139
28706
|
process.exitCode = 2;
|
|
28140
28707
|
}
|
|
28141
28708
|
};
|
|
28142
|
-
var entryPath = process.argv[1] ?
|
|
28143
|
-
if (entryPath ===
|
|
28709
|
+
var entryPath = process.argv[1] ? path16.resolve(process.argv[1]) : "";
|
|
28710
|
+
if (entryPath === path16.resolve(fileURLToPath3(import.meta.url)))
|
|
28144
28711
|
await main();
|
|
28145
28712
|
export {
|
|
28146
28713
|
McpCapabilityUnavailableError,
|