schub 0.1.25 → 0.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/api/server.js +521 -1221
- package/dist/dashboard/assets/{EquationComponent-CmMddHEw.js → EquationComponent-DYTYbmpl.js} +1 -1
- package/dist/dashboard/assets/index-raRkw0ib.js +354 -0
- package/dist/dashboard/index.html +1 -1
- package/dist/index.js +7458 -10106
- package/dist/services/runtime.js +133 -384
- package/drizzle/0010_restructure_templates.sql +11 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +1 -1
- package/skills/create-proposal/SKILL.md +17 -20
- package/skills/create-sub-tickets/SKILL.md +2 -14
- package/skills/create-ticket/SKILL.md +0 -1
- package/skills/refine-ticket/SKILL.md +3 -3
- package/skills/review-ticket/SKILL.md +40 -0
- package/skills/update-documentation/SKILL.md +30 -0
- package/templates/{create-proposal/adr-template.md → adr-template.md} +3 -3
- package/templates/{create-proposal/cookbook-template.md → cookbook-template.md} +1 -1
- package/templates/{create-proposal/proposal-template.md → proposal-template.md} +10 -2
- package/templates/{review-proposal/q&a-template.md → q&a-template.md} +2 -2
- package/templates/{review-proposal/review-me-template.md → review-me-template.md} +2 -2
- package/templates/{create-ticket/ticket-template.md → ticket-template.md} +1 -2
- package/dist/dashboard/assets/index-UwpVAg9D.js +0 -354
- package/skills/review-proposal/SKILL.md +0 -40
- package/templates/create-tasks/task-template.md +0 -69
package/dist/services/runtime.js
CHANGED
|
@@ -1200,9 +1200,6 @@ __export(exports_schema, {
|
|
|
1200
1200
|
templates: () => templates,
|
|
1201
1201
|
sessions: () => sessions,
|
|
1202
1202
|
repos: () => repos,
|
|
1203
|
-
proposals: () => proposals,
|
|
1204
|
-
proposal_statuses: () => proposal_statuses,
|
|
1205
|
-
proposal_files: () => proposal_files,
|
|
1206
1203
|
projects: () => projects,
|
|
1207
1204
|
project_repos: () => project_repos,
|
|
1208
1205
|
project_docs: () => project_docs,
|
|
@@ -2576,34 +2573,10 @@ var ticket_statuses = sqliteTable("ticket_statuses", {
|
|
|
2576
2573
|
created_at: text("created_at").notNull(),
|
|
2577
2574
|
updated_at: text("updated_at").notNull()
|
|
2578
2575
|
});
|
|
2579
|
-
var proposal_statuses = sqliteTable("proposal_statuses", {
|
|
2580
|
-
id: text("id").primaryKey(),
|
|
2581
|
-
project_id: text("project_id").notNull().references(() => projects.id, { onDelete: "cascade" }),
|
|
2582
|
-
name: text("name").notNull(),
|
|
2583
|
-
sort_order: integer("sort_order").notNull(),
|
|
2584
|
-
is_default: integer("is_default").notNull(),
|
|
2585
|
-
created_at: text("created_at").notNull(),
|
|
2586
|
-
updated_at: text("updated_at").notNull()
|
|
2587
|
-
});
|
|
2588
|
-
var proposals = sqliteTable("proposals", {
|
|
2589
|
-
id: text("id").primaryKey(),
|
|
2590
|
-
shorthand: text("shorthand").notNull(),
|
|
2591
|
-
project_id: text("project_id").notNull().references(() => projects.id, { onDelete: "cascade" }),
|
|
2592
|
-
repo_id: text("repo_id").references(() => repos.id, { onDelete: "set null" }),
|
|
2593
|
-
input: text("input"),
|
|
2594
|
-
status: text("status").notNull().default("draft"),
|
|
2595
|
-
archived: integer("archived").notNull().default(0),
|
|
2596
|
-
staged: integer("staged").notNull().default(0),
|
|
2597
|
-
created_at: text("created_at").notNull(),
|
|
2598
|
-
updated_at: text("updated_at").notNull()
|
|
2599
|
-
}, (table) => [uniqueIndex("proposals_project_shorthand_idx").on(table.project_id, table.shorthand)]);
|
|
2600
2576
|
var tickets = sqliteTable("tickets", {
|
|
2601
2577
|
id: text("id").primaryKey(),
|
|
2602
2578
|
shorthand: text("shorthand").notNull(),
|
|
2603
2579
|
project_id: text("project_id").notNull().references(() => projects.id, { onDelete: "cascade" }),
|
|
2604
|
-
proposal_id: text("proposal_id").references(() => proposals.id, {
|
|
2605
|
-
onDelete: "set null"
|
|
2606
|
-
}),
|
|
2607
2580
|
status_id: text("status_id").references(() => ticket_statuses.id, {
|
|
2608
2581
|
onDelete: "set null"
|
|
2609
2582
|
}),
|
|
@@ -2697,12 +2670,6 @@ var project_doc_files = sqliteTable("project_doc_files", {
|
|
|
2697
2670
|
file_id: text("file_id").notNull().references(() => files.id, { onDelete: "cascade" }),
|
|
2698
2671
|
created_at: text("created_at").notNull()
|
|
2699
2672
|
}, (table) => [uniqueIndex("project_doc_files_project_doc_file_idx").on(table.project_doc_id, table.file_id)]);
|
|
2700
|
-
var proposal_files = sqliteTable("proposal_files", {
|
|
2701
|
-
id: text("id").primaryKey(),
|
|
2702
|
-
proposal_id: text("proposal_id").notNull().references(() => proposals.id, { onDelete: "cascade" }),
|
|
2703
|
-
file_id: text("file_id").notNull().references(() => files.id, { onDelete: "cascade" }),
|
|
2704
|
-
created_at: text("created_at").notNull()
|
|
2705
|
-
});
|
|
2706
2673
|
var ticket_files = sqliteTable("ticket_files", {
|
|
2707
2674
|
id: text("id").primaryKey(),
|
|
2708
2675
|
ticket_id: text("ticket_id").notNull().references(() => tickets.id, { onDelete: "cascade" }),
|
|
@@ -2723,7 +2690,8 @@ var templates = sqliteTable("templates", {
|
|
|
2723
2690
|
}),
|
|
2724
2691
|
name: text("name").notNull(),
|
|
2725
2692
|
template_type: text("template_type").notNull(),
|
|
2726
|
-
|
|
2693
|
+
file_id: text("file_id").notNull().references(() => files.id),
|
|
2694
|
+
is_default: integer("is_default").notNull().default(0),
|
|
2727
2695
|
created_at: text("created_at").notNull(),
|
|
2728
2696
|
updated_at: text("updated_at").notNull()
|
|
2729
2697
|
});
|
|
@@ -16557,7 +16525,6 @@ var sessionSelectSchema = createSelectSchema(sessions, {
|
|
|
16557
16525
|
});
|
|
16558
16526
|
var ticketTagSelectSchema = createSelectSchema(ticket_tags);
|
|
16559
16527
|
var workspaceSelectSchema = createSelectSchema(workspaces);
|
|
16560
|
-
var proposalSelectSchema = createSelectSchema(proposals);
|
|
16561
16528
|
var ticketAttemptSchema = exports_external.object({
|
|
16562
16529
|
id: exports_external.string(),
|
|
16563
16530
|
label: exports_external.string(),
|
|
@@ -16747,7 +16714,6 @@ var createFilesService = (db, storageRoot) => {
|
|
|
16747
16714
|
}).where(eq(files.id, fileId)).run();
|
|
16748
16715
|
return updated;
|
|
16749
16716
|
};
|
|
16750
|
-
const listForProposal = (proposalId) => db.select({ file: files }).from(proposal_files).innerJoin(files, eq(proposal_files.file_id, files.id)).where(eq(proposal_files.proposal_id, proposalId)).orderBy(proposal_files.created_at).all().map((row) => row.file);
|
|
16751
16717
|
const listForProjectDocs = (projectDocId) => db.select({ file: files }).from(project_doc_files).innerJoin(files, eq(project_doc_files.file_id, files.id)).where(eq(project_doc_files.project_doc_id, projectDocId)).orderBy(project_doc_files.created_at).all().map((row) => row.file);
|
|
16752
16718
|
const attachToProjectDocs = (projectDocId, fileId) => {
|
|
16753
16719
|
const existing = get(fileId);
|
|
@@ -16772,26 +16738,6 @@ var createFilesService = (db, storageRoot) => {
|
|
|
16772
16738
|
db.delete(project_doc_files).where(and(eq(project_doc_files.project_doc_id, projectDocId), eq(project_doc_files.file_id, fileId))).run();
|
|
16773
16739
|
return true;
|
|
16774
16740
|
};
|
|
16775
|
-
const attachToProposal = (proposalId, fileId) => {
|
|
16776
|
-
const existing = get(fileId);
|
|
16777
|
-
if (!existing)
|
|
16778
|
-
return null;
|
|
16779
|
-
const link = {
|
|
16780
|
-
id: crypto.randomUUID(),
|
|
16781
|
-
proposal_id: proposalId,
|
|
16782
|
-
file_id: fileId,
|
|
16783
|
-
created_at: nowTimestamp()
|
|
16784
|
-
};
|
|
16785
|
-
db.insert(proposal_files).values(link).run();
|
|
16786
|
-
return existing;
|
|
16787
|
-
};
|
|
16788
|
-
const detachFromProposal = (proposalId, fileId) => {
|
|
16789
|
-
const existing = db.select().from(proposal_files).where(and(eq(proposal_files.proposal_id, proposalId), eq(proposal_files.file_id, fileId))).get();
|
|
16790
|
-
if (!existing)
|
|
16791
|
-
return false;
|
|
16792
|
-
db.delete(proposal_files).where(and(eq(proposal_files.proposal_id, proposalId), eq(proposal_files.file_id, fileId))).run();
|
|
16793
|
-
return true;
|
|
16794
|
-
};
|
|
16795
16741
|
const listForTicket = (ticketId) => db.select({ file: files }).from(ticket_files).innerJoin(files, eq(ticket_files.file_id, files.id)).where(eq(ticket_files.ticket_id, ticketId)).orderBy(ticket_files.created_at).all().map((row) => row.file);
|
|
16796
16742
|
const attachToTicket = (ticketId, fileId) => {
|
|
16797
16743
|
const existing = get(fileId);
|
|
@@ -16822,9 +16768,6 @@ var createFilesService = (db, storageRoot) => {
|
|
|
16822
16768
|
listForProjectDocs,
|
|
16823
16769
|
attachToProjectDocs,
|
|
16824
16770
|
detachFromProjectDocs,
|
|
16825
|
-
listForProposal,
|
|
16826
|
-
attachToProposal,
|
|
16827
|
-
detachFromProposal,
|
|
16828
16771
|
listForTicket,
|
|
16829
16772
|
attachToTicket,
|
|
16830
16773
|
detachFromTicket
|
|
@@ -17531,15 +17474,6 @@ var DEFAULT_TICKET_STATUSES = [
|
|
|
17531
17474
|
column_actions: []
|
|
17532
17475
|
}
|
|
17533
17476
|
];
|
|
17534
|
-
var DEFAULT_PROPOSAL_STATUSES = [
|
|
17535
|
-
{ name: "draft", is_default: 1 },
|
|
17536
|
-
{ name: "pending review", is_default: 0 },
|
|
17537
|
-
{ name: "wip", is_default: 0 },
|
|
17538
|
-
{ name: "in-review", is_default: 0 },
|
|
17539
|
-
{ name: "accepted", is_default: 0 },
|
|
17540
|
-
{ name: "rejected", is_default: 0 },
|
|
17541
|
-
{ name: "done", is_default: 0 }
|
|
17542
|
-
];
|
|
17543
17477
|
var DEFAULT_TICKET_TAGS = [
|
|
17544
17478
|
{ name: "bug", color: "red" },
|
|
17545
17479
|
{ name: "feature", color: "blue" },
|
|
@@ -17602,15 +17536,6 @@ var createProjectsService = (db) => {
|
|
|
17602
17536
|
created_at: timestamp,
|
|
17603
17537
|
updated_at: timestamp
|
|
17604
17538
|
}))).run();
|
|
17605
|
-
db.insert(proposal_statuses).values(DEFAULT_PROPOSAL_STATUSES.map((status, index) => ({
|
|
17606
|
-
id: crypto.randomUUID(),
|
|
17607
|
-
project_id: project.id,
|
|
17608
|
-
name: status.name,
|
|
17609
|
-
sort_order: index + 1,
|
|
17610
|
-
is_default: status.is_default,
|
|
17611
|
-
created_at: timestamp,
|
|
17612
|
-
updated_at: timestamp
|
|
17613
|
-
}))).run();
|
|
17614
17539
|
db.insert(ticket_tags).values(DEFAULT_TICKET_TAGS.map((tag) => ({
|
|
17615
17540
|
id: crypto.randomUUID(),
|
|
17616
17541
|
project_id: project.id,
|
|
@@ -17663,165 +17588,9 @@ var createProjectsService = (db) => {
|
|
|
17663
17588
|
return { list, get, getSnapshot, getSnapshotPatch, subscribe, create, update, remove };
|
|
17664
17589
|
};
|
|
17665
17590
|
|
|
17666
|
-
// ../schub-db/src/services/proposal-statuses.ts
|
|
17667
|
-
var createProposalStatusesService = (db) => {
|
|
17668
|
-
const list = (projectId) => db.select().from(proposal_statuses).where(eq(proposal_statuses.project_id, projectId)).orderBy(proposal_statuses.sort_order).all();
|
|
17669
|
-
const get = (projectId, statusId) => {
|
|
17670
|
-
const status = db.select().from(proposal_statuses).where(and(eq(proposal_statuses.project_id, projectId), eq(proposal_statuses.id, statusId))).get();
|
|
17671
|
-
return status ?? null;
|
|
17672
|
-
};
|
|
17673
|
-
const getByName = (projectId, statusName) => {
|
|
17674
|
-
const status = db.select().from(proposal_statuses).where(and(eq(proposal_statuses.project_id, projectId), eq(proposal_statuses.name, statusName))).get();
|
|
17675
|
-
return status ?? null;
|
|
17676
|
-
};
|
|
17677
|
-
const getDefault = (projectId) => {
|
|
17678
|
-
const explicitDefault = db.select().from(proposal_statuses).where(and(eq(proposal_statuses.project_id, projectId), eq(proposal_statuses.is_default, 1))).orderBy(proposal_statuses.sort_order).get();
|
|
17679
|
-
if (explicitDefault) {
|
|
17680
|
-
return explicitDefault;
|
|
17681
|
-
}
|
|
17682
|
-
return list(projectId)[0] ?? null;
|
|
17683
|
-
};
|
|
17684
|
-
return { list, get, getByName, getDefault };
|
|
17685
|
-
};
|
|
17686
|
-
|
|
17687
|
-
// ../schub-db/src/services/proposals.ts
|
|
17688
|
-
var nowTimestamp4 = () => new Date().toISOString();
|
|
17689
|
-
var parseShorthandSequence = (shorthand) => {
|
|
17690
|
-
const match = shorthand.match(/^[CP](\d+)/i);
|
|
17691
|
-
if (!match) {
|
|
17692
|
-
return null;
|
|
17693
|
-
}
|
|
17694
|
-
return Number.parseInt(match[1], 10);
|
|
17695
|
-
};
|
|
17696
|
-
var formatShorthand = (sequence) => `P${sequence.toString().padStart(4, "0")}`;
|
|
17697
|
-
var normalizeProposalShorthand = (shorthand) => {
|
|
17698
|
-
const sequence = parseShorthandSequence(shorthand);
|
|
17699
|
-
if (sequence === null) {
|
|
17700
|
-
throw new Error(`Invalid proposal shorthand '${shorthand}'.`);
|
|
17701
|
-
}
|
|
17702
|
-
return formatShorthand(sequence);
|
|
17703
|
-
};
|
|
17704
|
-
var createProposalsService = (db) => {
|
|
17705
|
-
const getDefaultStatusName = (projectId) => {
|
|
17706
|
-
const explicitDefault = db.select({ name: proposal_statuses.name }).from(proposal_statuses).where(and(eq(proposal_statuses.project_id, projectId), eq(proposal_statuses.is_default, 1))).orderBy(proposal_statuses.sort_order).get();
|
|
17707
|
-
if (explicitDefault) {
|
|
17708
|
-
return explicitDefault.name;
|
|
17709
|
-
}
|
|
17710
|
-
const firstStatus = db.select({ name: proposal_statuses.name }).from(proposal_statuses).where(eq(proposal_statuses.project_id, projectId)).orderBy(proposal_statuses.sort_order).get();
|
|
17711
|
-
return firstStatus?.name ?? "draft";
|
|
17712
|
-
};
|
|
17713
|
-
const assertKnownStatus = (projectId, status) => {
|
|
17714
|
-
const normalizedStatus = status.trim().toLowerCase();
|
|
17715
|
-
const exists = db.select({ name: proposal_statuses.name }).from(proposal_statuses).where(eq(proposal_statuses.project_id, projectId)).all().some((candidate) => candidate.name.trim().toLowerCase() === normalizedStatus);
|
|
17716
|
-
if (!exists) {
|
|
17717
|
-
throw new Error(`Proposal status '${status}' does not exist for project '${projectId}'.`);
|
|
17718
|
-
}
|
|
17719
|
-
};
|
|
17720
|
-
const allocateProposalShorthand = () => {
|
|
17721
|
-
return db.transaction((tx) => {
|
|
17722
|
-
const priorShorthands = tx.select({ shorthand: proposals.shorthand }).from(proposals).all();
|
|
17723
|
-
const maxSequence = priorShorthands.reduce((max, proposal) => {
|
|
17724
|
-
if (!proposal.shorthand) {
|
|
17725
|
-
return max;
|
|
17726
|
-
}
|
|
17727
|
-
const parsed = parseShorthandSequence(proposal.shorthand);
|
|
17728
|
-
if (parsed === null) {
|
|
17729
|
-
return max;
|
|
17730
|
-
}
|
|
17731
|
-
return Math.max(max, parsed);
|
|
17732
|
-
}, 0);
|
|
17733
|
-
return formatShorthand(maxSequence + 1);
|
|
17734
|
-
});
|
|
17735
|
-
};
|
|
17736
|
-
const list = (projectId) => db.select().from(proposals).where(eq(proposals.project_id, projectId)).orderBy(proposals.created_at).all();
|
|
17737
|
-
const get = (projectId, proposalId) => {
|
|
17738
|
-
const proposal = db.select().from(proposals).where(and(eq(proposals.project_id, projectId), eq(proposals.id, proposalId))).get();
|
|
17739
|
-
return proposal ?? null;
|
|
17740
|
-
};
|
|
17741
|
-
const create = (projectId, input) => {
|
|
17742
|
-
const timestamp = nowTimestamp4();
|
|
17743
|
-
const shorthand = allocateProposalShorthand();
|
|
17744
|
-
const defaultStatus = getDefaultStatusName(projectId);
|
|
17745
|
-
const proposal = {
|
|
17746
|
-
id: crypto.randomUUID(),
|
|
17747
|
-
shorthand,
|
|
17748
|
-
project_id: projectId,
|
|
17749
|
-
repo_id: input.repo_id ?? null,
|
|
17750
|
-
input: input.input ?? null,
|
|
17751
|
-
status: defaultStatus,
|
|
17752
|
-
archived: 0,
|
|
17753
|
-
staged: input.staged ?? 0,
|
|
17754
|
-
created_at: timestamp,
|
|
17755
|
-
updated_at: timestamp
|
|
17756
|
-
};
|
|
17757
|
-
db.insert(proposals).values(proposal).run();
|
|
17758
|
-
return proposal;
|
|
17759
|
-
};
|
|
17760
|
-
const createWithShorthand = (projectId, shorthand, input) => {
|
|
17761
|
-
const timestamp = nowTimestamp4();
|
|
17762
|
-
const normalizedShorthand = normalizeProposalShorthand(shorthand);
|
|
17763
|
-
const defaultStatus = getDefaultStatusName(projectId);
|
|
17764
|
-
const proposal = {
|
|
17765
|
-
id: crypto.randomUUID(),
|
|
17766
|
-
shorthand: normalizedShorthand,
|
|
17767
|
-
project_id: projectId,
|
|
17768
|
-
repo_id: null,
|
|
17769
|
-
input: input.input ?? null,
|
|
17770
|
-
status: defaultStatus,
|
|
17771
|
-
archived: 0,
|
|
17772
|
-
staged: input.staged ?? 0,
|
|
17773
|
-
created_at: timestamp,
|
|
17774
|
-
updated_at: timestamp
|
|
17775
|
-
};
|
|
17776
|
-
db.insert(proposals).values(proposal).run();
|
|
17777
|
-
return proposal;
|
|
17778
|
-
};
|
|
17779
|
-
const update = (projectId, proposalId, input) => {
|
|
17780
|
-
const existing = get(projectId, proposalId);
|
|
17781
|
-
if (!existing)
|
|
17782
|
-
return null;
|
|
17783
|
-
const proposalInput = input.input === undefined ? existing.input : input.input;
|
|
17784
|
-
const repo_id = input.repo_id === undefined ? existing.repo_id : input.repo_id;
|
|
17785
|
-
const status = input.status ?? existing.status;
|
|
17786
|
-
const archived = input.archived === undefined ? existing.archived : input.archived;
|
|
17787
|
-
const staged = input.staged === undefined ? existing.staged : input.staged;
|
|
17788
|
-
if (input.status !== undefined) {
|
|
17789
|
-
assertKnownStatus(projectId, status);
|
|
17790
|
-
}
|
|
17791
|
-
const updated = {
|
|
17792
|
-
...existing,
|
|
17793
|
-
repo_id,
|
|
17794
|
-
input: proposalInput,
|
|
17795
|
-
status,
|
|
17796
|
-
archived,
|
|
17797
|
-
staged,
|
|
17798
|
-
updated_at: nowTimestamp4()
|
|
17799
|
-
};
|
|
17800
|
-
db.update(proposals).set({
|
|
17801
|
-
repo_id: updated.repo_id,
|
|
17802
|
-
input: updated.input,
|
|
17803
|
-
status: updated.status,
|
|
17804
|
-
archived: updated.archived,
|
|
17805
|
-
staged: updated.staged,
|
|
17806
|
-
updated_at: updated.updated_at
|
|
17807
|
-
}).where(and(eq(proposals.project_id, projectId), eq(proposals.id, proposalId))).run();
|
|
17808
|
-
return updated;
|
|
17809
|
-
};
|
|
17810
|
-
const remove = (projectId, proposalId) => {
|
|
17811
|
-
const existing = get(projectId, proposalId);
|
|
17812
|
-
if (!existing)
|
|
17813
|
-
return false;
|
|
17814
|
-
const timestamp = nowTimestamp4();
|
|
17815
|
-
db.update(tickets).set({ proposal_id: null, updated_at: timestamp }).where(and(eq(tickets.project_id, projectId), eq(tickets.proposal_id, proposalId))).run();
|
|
17816
|
-
db.delete(proposals).where(and(eq(proposals.project_id, projectId), eq(proposals.id, proposalId))).run();
|
|
17817
|
-
return true;
|
|
17818
|
-
};
|
|
17819
|
-
return { list, get, create, createWithShorthand, update, remove };
|
|
17820
|
-
};
|
|
17821
|
-
|
|
17822
17591
|
// ../schub-db/src/services/repos.ts
|
|
17823
17592
|
import { basename } from "node:path";
|
|
17824
|
-
var
|
|
17593
|
+
var nowTimestamp4 = () => new Date().toISOString();
|
|
17825
17594
|
var normalizeRepoPath = (value) => value.replace(/[\\/]+$/, "");
|
|
17826
17595
|
var deriveRepoName = (repoPath) => {
|
|
17827
17596
|
const normalized = normalizeRepoPath(repoPath);
|
|
@@ -17844,7 +17613,7 @@ var createReposService = (db) => {
|
|
|
17844
17613
|
return row?.repo ?? null;
|
|
17845
17614
|
};
|
|
17846
17615
|
const upsertRepo = (input) => {
|
|
17847
|
-
const timestamp =
|
|
17616
|
+
const timestamp = nowTimestamp4();
|
|
17848
17617
|
const displayName = resolveDisplayName(input.display_name);
|
|
17849
17618
|
const pathValue = normalizeRepoPath(input.path);
|
|
17850
17619
|
const name = deriveRepoName(pathValue);
|
|
@@ -17883,13 +17652,13 @@ var createReposService = (db) => {
|
|
|
17883
17652
|
const updated = {
|
|
17884
17653
|
...existing,
|
|
17885
17654
|
display_name: displayName,
|
|
17886
|
-
updated_at:
|
|
17655
|
+
updated_at: nowTimestamp4()
|
|
17887
17656
|
};
|
|
17888
17657
|
db.update(repos).set({ display_name: updated.display_name, updated_at: updated.updated_at }).where(eq(repos.id, repoId)).run();
|
|
17889
17658
|
return updated;
|
|
17890
17659
|
};
|
|
17891
17660
|
const addToProject = (projectId, input) => {
|
|
17892
|
-
const timestamp =
|
|
17661
|
+
const timestamp = nowTimestamp4();
|
|
17893
17662
|
const repo = upsertRepo({ path: input.git_repo_path, display_name: input.display_name });
|
|
17894
17663
|
const existingLink = db.select().from(project_repos).where(and(eq(project_repos.project_id, projectId), eq(project_repos.repo_id, repo.id))).get();
|
|
17895
17664
|
if (!existingLink) {
|
|
@@ -17917,7 +17686,7 @@ var createReposService = (db) => {
|
|
|
17917
17686
|
};
|
|
17918
17687
|
|
|
17919
17688
|
// ../schub-db/src/services/sessions.ts
|
|
17920
|
-
var
|
|
17689
|
+
var nowTimestamp5 = () => new Date().toISOString();
|
|
17921
17690
|
var SESSION_STATUSES = ["in_progress", "completed", "failed"];
|
|
17922
17691
|
var normalizeSessionStatus = (status) => {
|
|
17923
17692
|
if (!status)
|
|
@@ -17966,7 +17735,7 @@ var createSessionsService = (db) => {
|
|
|
17966
17735
|
return session ? formatSession(session) : null;
|
|
17967
17736
|
};
|
|
17968
17737
|
const create = (input) => {
|
|
17969
|
-
const timestamp =
|
|
17738
|
+
const timestamp = nowTimestamp5();
|
|
17970
17739
|
const session = {
|
|
17971
17740
|
id: input.id?.trim() || crypto.randomUUID(),
|
|
17972
17741
|
title: input.title,
|
|
@@ -18008,7 +17777,7 @@ var createSessionsService = (db) => {
|
|
|
18008
17777
|
agent,
|
|
18009
17778
|
agent_session_id: agentSessionId,
|
|
18010
17779
|
content,
|
|
18011
|
-
updated_at:
|
|
17780
|
+
updated_at: nowTimestamp5()
|
|
18012
17781
|
};
|
|
18013
17782
|
db.update(sessions).set({
|
|
18014
17783
|
title: updated.title,
|
|
@@ -18035,21 +17804,106 @@ var createSessionsService = (db) => {
|
|
|
18035
17804
|
};
|
|
18036
17805
|
|
|
18037
17806
|
// ../schub-db/src/services/templates.ts
|
|
18038
|
-
var
|
|
17807
|
+
var nowTimestamp6 = () => new Date().toISOString();
|
|
18039
17808
|
var createTemplatesService = (db) => {
|
|
18040
|
-
const list = () => db.select(
|
|
17809
|
+
const list = () => db.select({
|
|
17810
|
+
id: templates.id,
|
|
17811
|
+
project_id: templates.project_id,
|
|
17812
|
+
name: templates.name,
|
|
17813
|
+
template_type: templates.template_type,
|
|
17814
|
+
file_id: templates.file_id,
|
|
17815
|
+
is_default: templates.is_default,
|
|
17816
|
+
created_at: templates.created_at,
|
|
17817
|
+
updated_at: templates.updated_at,
|
|
17818
|
+
file_name: files.file_name,
|
|
17819
|
+
storage_path: files.storage_path,
|
|
17820
|
+
mime_type: files.mime_type,
|
|
17821
|
+
size_bytes: files.size_bytes
|
|
17822
|
+
}).from(templates).innerJoin(files, eq(templates.file_id, files.id)).orderBy(templates.created_at).all();
|
|
17823
|
+
const listByProject = (projectId) => db.select({
|
|
17824
|
+
id: templates.id,
|
|
17825
|
+
project_id: templates.project_id,
|
|
17826
|
+
name: templates.name,
|
|
17827
|
+
template_type: templates.template_type,
|
|
17828
|
+
file_id: templates.file_id,
|
|
17829
|
+
is_default: templates.is_default,
|
|
17830
|
+
created_at: templates.created_at,
|
|
17831
|
+
updated_at: templates.updated_at,
|
|
17832
|
+
file_name: files.file_name,
|
|
17833
|
+
storage_path: files.storage_path,
|
|
17834
|
+
mime_type: files.mime_type,
|
|
17835
|
+
size_bytes: files.size_bytes
|
|
17836
|
+
}).from(templates).innerJoin(files, eq(templates.file_id, files.id)).where(eq(templates.project_id, projectId)).orderBy(templates.created_at).all();
|
|
18041
17837
|
const get = (templateId) => {
|
|
18042
|
-
const
|
|
18043
|
-
|
|
17838
|
+
const row = db.select({
|
|
17839
|
+
id: templates.id,
|
|
17840
|
+
project_id: templates.project_id,
|
|
17841
|
+
name: templates.name,
|
|
17842
|
+
template_type: templates.template_type,
|
|
17843
|
+
file_id: templates.file_id,
|
|
17844
|
+
is_default: templates.is_default,
|
|
17845
|
+
created_at: templates.created_at,
|
|
17846
|
+
updated_at: templates.updated_at,
|
|
17847
|
+
file_name: files.file_name,
|
|
17848
|
+
storage_path: files.storage_path,
|
|
17849
|
+
mime_type: files.mime_type,
|
|
17850
|
+
size_bytes: files.size_bytes
|
|
17851
|
+
}).from(templates).innerJoin(files, eq(templates.file_id, files.id)).where(eq(templates.id, templateId)).get();
|
|
17852
|
+
return row ?? null;
|
|
17853
|
+
};
|
|
17854
|
+
const getDefault = (projectId, templateType) => {
|
|
17855
|
+
const row = db.select({
|
|
17856
|
+
id: templates.id,
|
|
17857
|
+
project_id: templates.project_id,
|
|
17858
|
+
name: templates.name,
|
|
17859
|
+
template_type: templates.template_type,
|
|
17860
|
+
file_id: templates.file_id,
|
|
17861
|
+
is_default: templates.is_default,
|
|
17862
|
+
created_at: templates.created_at,
|
|
17863
|
+
updated_at: templates.updated_at,
|
|
17864
|
+
file_name: files.file_name,
|
|
17865
|
+
storage_path: files.storage_path,
|
|
17866
|
+
mime_type: files.mime_type,
|
|
17867
|
+
size_bytes: files.size_bytes
|
|
17868
|
+
}).from(templates).innerJoin(files, eq(templates.file_id, files.id)).where(and(eq(templates.project_id, projectId), eq(templates.template_type, templateType), eq(templates.is_default, 1))).get();
|
|
17869
|
+
return row ?? null;
|
|
17870
|
+
};
|
|
17871
|
+
const getByName = (name, projectId) => {
|
|
17872
|
+
const row = db.select({
|
|
17873
|
+
id: templates.id,
|
|
17874
|
+
project_id: templates.project_id,
|
|
17875
|
+
name: templates.name,
|
|
17876
|
+
template_type: templates.template_type,
|
|
17877
|
+
file_id: templates.file_id,
|
|
17878
|
+
is_default: templates.is_default,
|
|
17879
|
+
created_at: templates.created_at,
|
|
17880
|
+
updated_at: templates.updated_at,
|
|
17881
|
+
file_name: files.file_name,
|
|
17882
|
+
storage_path: files.storage_path,
|
|
17883
|
+
mime_type: files.mime_type,
|
|
17884
|
+
size_bytes: files.size_bytes
|
|
17885
|
+
}).from(templates).innerJoin(files, eq(templates.file_id, files.id)).where(and(eq(templates.name, name), eq(templates.project_id, projectId))).get();
|
|
17886
|
+
return row ?? null;
|
|
17887
|
+
};
|
|
17888
|
+
const checkNameUniqueness = (name, projectId, excludeId) => {
|
|
17889
|
+
if (!projectId)
|
|
17890
|
+
return;
|
|
17891
|
+
const existing = db.select({ id: templates.id }).from(templates).where(and(eq(templates.name, name), eq(templates.project_id, projectId))).get();
|
|
17892
|
+
if (existing && existing.id !== excludeId) {
|
|
17893
|
+
throw new Error(`Duplicate template name '${name}' in project '${projectId}'.`);
|
|
17894
|
+
}
|
|
18044
17895
|
};
|
|
18045
17896
|
const create = (input) => {
|
|
18046
|
-
const
|
|
17897
|
+
const projectId = input.project_id ?? null;
|
|
17898
|
+
checkNameUniqueness(input.name, projectId);
|
|
17899
|
+
const timestamp = nowTimestamp6();
|
|
18047
17900
|
const template = {
|
|
18048
17901
|
id: crypto.randomUUID(),
|
|
18049
|
-
project_id:
|
|
17902
|
+
project_id: projectId,
|
|
18050
17903
|
name: input.name,
|
|
18051
17904
|
template_type: input.template_type,
|
|
18052
|
-
|
|
17905
|
+
file_id: input.file_id,
|
|
17906
|
+
is_default: input.is_default ?? 0,
|
|
18053
17907
|
created_at: timestamp,
|
|
18054
17908
|
updated_at: timestamp
|
|
18055
17909
|
};
|
|
@@ -18057,39 +17911,42 @@ var createTemplatesService = (db) => {
|
|
|
18057
17911
|
return template;
|
|
18058
17912
|
};
|
|
18059
17913
|
const update = (templateId, input) => {
|
|
18060
|
-
const existing =
|
|
17914
|
+
const existing = db.select().from(templates).where(eq(templates.id, templateId)).get();
|
|
18061
17915
|
if (!existing)
|
|
18062
17916
|
return null;
|
|
18063
|
-
const
|
|
17917
|
+
const projectId = input.project_id === undefined ? existing.project_id : input.project_id ?? null;
|
|
17918
|
+
checkNameUniqueness(input.name, projectId, templateId);
|
|
18064
17919
|
const updated = {
|
|
18065
17920
|
...existing,
|
|
18066
|
-
project_id,
|
|
17921
|
+
project_id: projectId,
|
|
18067
17922
|
name: input.name,
|
|
18068
17923
|
template_type: input.template_type,
|
|
18069
|
-
|
|
18070
|
-
|
|
17924
|
+
file_id: input.file_id,
|
|
17925
|
+
is_default: input.is_default ?? existing.is_default,
|
|
17926
|
+
updated_at: nowTimestamp6()
|
|
18071
17927
|
};
|
|
18072
17928
|
db.update(templates).set({
|
|
18073
17929
|
project_id: updated.project_id,
|
|
18074
17930
|
name: updated.name,
|
|
18075
17931
|
template_type: updated.template_type,
|
|
18076
|
-
|
|
17932
|
+
file_id: updated.file_id,
|
|
17933
|
+
is_default: updated.is_default,
|
|
18077
17934
|
updated_at: updated.updated_at
|
|
18078
17935
|
}).where(eq(templates.id, templateId)).run();
|
|
18079
17936
|
return updated;
|
|
18080
17937
|
};
|
|
18081
17938
|
const remove = (templateId) => {
|
|
18082
|
-
const existing =
|
|
17939
|
+
const existing = db.select().from(templates).where(eq(templates.id, templateId)).get();
|
|
18083
17940
|
if (!existing)
|
|
18084
17941
|
return false;
|
|
18085
17942
|
db.delete(templates).where(eq(templates.id, templateId)).run();
|
|
18086
17943
|
return true;
|
|
18087
17944
|
};
|
|
18088
|
-
return { list, get, create, update, remove };
|
|
17945
|
+
return { list, listByProject, get, getDefault, getByName, create, update, remove };
|
|
18089
17946
|
};
|
|
18090
17947
|
|
|
18091
17948
|
// ../schub-db/src/services/ticket-statuses.ts
|
|
18092
|
-
var
|
|
17949
|
+
var nowTimestamp7 = () => new Date().toISOString();
|
|
18093
17950
|
var TICKET_STATUS_COLORS = ["gray", "blue", "cyan", "green", "yellow", "orange", "red", "purple", "pink"];
|
|
18094
17951
|
var TICKET_COLUMN_ACTIONS = ["archive_all"];
|
|
18095
17952
|
var isAllowedTicketStatusColor = (color) => TICKET_STATUS_COLORS.includes(color);
|
|
@@ -18143,7 +18000,7 @@ var createTicketStatusesService = (db) => {
|
|
|
18143
18000
|
assertValidTicketColumnActions(input.column_actions ?? []);
|
|
18144
18001
|
const normalizedName = normalizeTicketStatusName(input.name);
|
|
18145
18002
|
assertValidTicketStatusName(normalizedName);
|
|
18146
|
-
const timestamp =
|
|
18003
|
+
const timestamp = nowTimestamp7();
|
|
18147
18004
|
const columnActions = normalizeTicketColumnActions(input.column_actions ?? []);
|
|
18148
18005
|
const status = {
|
|
18149
18006
|
id: crypto.randomUUID(),
|
|
@@ -18185,7 +18042,7 @@ var createTicketStatusesService = (db) => {
|
|
|
18185
18042
|
can_create: input.can_create,
|
|
18186
18043
|
can_attempt_on_drop: input.can_attempt_on_drop,
|
|
18187
18044
|
column_actions: JSON.stringify(columnActions),
|
|
18188
|
-
updated_at:
|
|
18045
|
+
updated_at: nowTimestamp7()
|
|
18189
18046
|
};
|
|
18190
18047
|
db.update(ticket_statuses).set({
|
|
18191
18048
|
name: updated.name,
|
|
@@ -18216,9 +18073,9 @@ var createTicketStatusesService = (db) => {
|
|
|
18216
18073
|
}
|
|
18217
18074
|
if (!remaining.some((status) => status.is_default === 1)) {
|
|
18218
18075
|
db.update(ticket_statuses).set({ is_default: 0 }).where(eq(ticket_statuses.project_id, projectId)).run();
|
|
18219
|
-
db.update(ticket_statuses).set({ is_default: 1, updated_at:
|
|
18076
|
+
db.update(ticket_statuses).set({ is_default: 1, updated_at: nowTimestamp7() }).where(eq(ticket_statuses.id, defaultStatus.id)).run();
|
|
18220
18077
|
}
|
|
18221
|
-
db.update(tickets).set({ status_id: defaultStatus.id, updated_at:
|
|
18078
|
+
db.update(tickets).set({ status_id: defaultStatus.id, updated_at: nowTimestamp7() }).where(eq(tickets.status_id, statusId)).run();
|
|
18222
18079
|
db.delete(ticket_statuses).where(and(eq(ticket_statuses.project_id, projectId), eq(ticket_statuses.id, statusId))).run();
|
|
18223
18080
|
return { ok: true, reassignedTo: defaultStatus.id };
|
|
18224
18081
|
};
|
|
@@ -18226,7 +18083,7 @@ var createTicketStatusesService = (db) => {
|
|
|
18226
18083
|
};
|
|
18227
18084
|
|
|
18228
18085
|
// ../schub-db/src/services/ticket-tags.ts
|
|
18229
|
-
var
|
|
18086
|
+
var nowTimestamp8 = () => new Date().toISOString();
|
|
18230
18087
|
var normalizeTagName = (name) => name.trim().toLowerCase().replace(/[\s-]+/g, "_");
|
|
18231
18088
|
var createTicketTagsService = (db) => {
|
|
18232
18089
|
const list = (projectId) => db.select().from(ticket_tags).where(eq(ticket_tags.project_id, projectId)).orderBy(ticket_tags.name).all();
|
|
@@ -18235,7 +18092,7 @@ var createTicketTagsService = (db) => {
|
|
|
18235
18092
|
return tag ?? null;
|
|
18236
18093
|
};
|
|
18237
18094
|
const create = (projectId, input) => {
|
|
18238
|
-
const timestamp =
|
|
18095
|
+
const timestamp = nowTimestamp8();
|
|
18239
18096
|
const tag = {
|
|
18240
18097
|
id: crypto.randomUUID(),
|
|
18241
18098
|
project_id: projectId,
|
|
@@ -18255,7 +18112,7 @@ var createTicketTagsService = (db) => {
|
|
|
18255
18112
|
...existing,
|
|
18256
18113
|
name: normalizeTagName(input.name),
|
|
18257
18114
|
color: input.color,
|
|
18258
|
-
updated_at:
|
|
18115
|
+
updated_at: nowTimestamp8()
|
|
18259
18116
|
};
|
|
18260
18117
|
db.update(ticket_tags).set({
|
|
18261
18118
|
name: updated.name,
|
|
@@ -18301,7 +18158,7 @@ var createTicketTagsService = (db) => {
|
|
|
18301
18158
|
id: crypto.randomUUID(),
|
|
18302
18159
|
ticket_id: ticketId,
|
|
18303
18160
|
ticket_tag_id: tagId,
|
|
18304
|
-
created_at:
|
|
18161
|
+
created_at: nowTimestamp8()
|
|
18305
18162
|
}))).run();
|
|
18306
18163
|
});
|
|
18307
18164
|
return listIdsForTicket(ticketId);
|
|
@@ -18310,7 +18167,7 @@ var createTicketTagsService = (db) => {
|
|
|
18310
18167
|
};
|
|
18311
18168
|
|
|
18312
18169
|
// ../schub-db/src/services/tickets.ts
|
|
18313
|
-
var
|
|
18170
|
+
var nowTimestamp9 = () => new Date().toISOString();
|
|
18314
18171
|
var formatTicketId = (sequence) => `TK${sequence.toString().padStart(4, "0")}`;
|
|
18315
18172
|
var parseTicketSequence = (value) => {
|
|
18316
18173
|
const match = value.match(/^TK(\d+)$/i);
|
|
@@ -18377,13 +18234,12 @@ var createTicketsService = (db) => {
|
|
|
18377
18234
|
throw new Error("Parent ticket not found");
|
|
18378
18235
|
}
|
|
18379
18236
|
}
|
|
18380
|
-
const timestamp =
|
|
18237
|
+
const timestamp = nowTimestamp9();
|
|
18381
18238
|
const shorthand = allocateTicketShorthand();
|
|
18382
18239
|
const ticket = {
|
|
18383
18240
|
id: crypto.randomUUID(),
|
|
18384
18241
|
shorthand,
|
|
18385
18242
|
project_id: input.project_id,
|
|
18386
|
-
proposal_id: input.proposal_id ?? null,
|
|
18387
18243
|
status_id: input.status_id ?? null,
|
|
18388
18244
|
parent_id: input.parent_id ?? null,
|
|
18389
18245
|
title: input.title ?? null,
|
|
@@ -18406,7 +18262,7 @@ var createTicketsService = (db) => {
|
|
|
18406
18262
|
const existing = get(ticketId);
|
|
18407
18263
|
if (!existing)
|
|
18408
18264
|
return null;
|
|
18409
|
-
if (input.parent_id !== undefined) {
|
|
18265
|
+
if (input.parent_id !== undefined && input.parent_id !== existing.parent_id) {
|
|
18410
18266
|
validateParentId(existing.id, input.parent_id, get);
|
|
18411
18267
|
}
|
|
18412
18268
|
const title = input.title === undefined ? existing.title : input.title;
|
|
@@ -18415,7 +18271,6 @@ var createTicketsService = (db) => {
|
|
|
18415
18271
|
const parallelizable = input.parallelizable === undefined ? existing.parallelizable : input.parallelizable;
|
|
18416
18272
|
const complexity = input.complexity === undefined ? existing.complexity : input.complexity;
|
|
18417
18273
|
const status_id = input.status_id === undefined ? existing.status_id : input.status_id;
|
|
18418
|
-
const proposal_id = input.proposal_id === undefined ? existing.proposal_id : input.proposal_id;
|
|
18419
18274
|
const parent_id = input.parent_id === undefined ? existing.parent_id : input.parent_id;
|
|
18420
18275
|
const blocked_reason = input.blocked_reason === undefined ? existing.blocked_reason : input.blocked_reason;
|
|
18421
18276
|
const depends_on = input.depends_on === undefined ? existing.depends_on : input.depends_on;
|
|
@@ -18429,13 +18284,12 @@ var createTicketsService = (db) => {
|
|
|
18429
18284
|
parallelizable,
|
|
18430
18285
|
complexity,
|
|
18431
18286
|
status_id,
|
|
18432
|
-
proposal_id,
|
|
18433
18287
|
parent_id,
|
|
18434
18288
|
blocked_reason,
|
|
18435
18289
|
depends_on,
|
|
18436
18290
|
archived,
|
|
18437
18291
|
staged,
|
|
18438
|
-
updated_at:
|
|
18292
|
+
updated_at: nowTimestamp9()
|
|
18439
18293
|
};
|
|
18440
18294
|
db.update(tickets).set({
|
|
18441
18295
|
title: updated.title,
|
|
@@ -18444,7 +18298,6 @@ var createTicketsService = (db) => {
|
|
|
18444
18298
|
parallelizable: updated.parallelizable,
|
|
18445
18299
|
complexity: updated.complexity,
|
|
18446
18300
|
status_id: updated.status_id,
|
|
18447
|
-
proposal_id: updated.proposal_id,
|
|
18448
18301
|
parent_id: updated.parent_id,
|
|
18449
18302
|
blocked_reason: updated.blocked_reason,
|
|
18450
18303
|
depends_on: updated.depends_on,
|
|
@@ -18459,105 +18312,12 @@ var createTicketsService = (db) => {
|
|
|
18459
18312
|
if (!existing)
|
|
18460
18313
|
return false;
|
|
18461
18314
|
db.update(tickets).set({ parent_id: null }).where(eq(tickets.parent_id, existing.id)).run();
|
|
18462
|
-
db.update(tickets).set({ deleted_at:
|
|
18463
|
-
return true;
|
|
18464
|
-
};
|
|
18465
|
-
const getForProposal = (projectId, proposalId, ticketId) => {
|
|
18466
|
-
const ticket = db.select().from(tickets).where(and(eq(tickets.project_id, projectId), eq(tickets.proposal_id, proposalId), or(eq(tickets.id, ticketId), eq(tickets.shorthand, ticketId)), isNull(tickets.deleted_at))).get();
|
|
18467
|
-
return ticket ?? null;
|
|
18468
|
-
};
|
|
18469
|
-
const listByProposal = (projectId, proposalId) => db.select().from(tickets).where(and(eq(tickets.project_id, projectId), eq(tickets.proposal_id, proposalId), isNull(tickets.deleted_at))).orderBy(tickets.created_at).all();
|
|
18470
|
-
const createForProposal = (projectId, proposalId, input) => {
|
|
18471
|
-
if (input.parent_id) {
|
|
18472
|
-
const parent = get(input.parent_id);
|
|
18473
|
-
if (!parent) {
|
|
18474
|
-
throw new Error("Parent ticket not found");
|
|
18475
|
-
}
|
|
18476
|
-
}
|
|
18477
|
-
const timestamp = nowTimestamp10();
|
|
18478
|
-
const shorthand = allocateTicketShorthand();
|
|
18479
|
-
const ticket = {
|
|
18480
|
-
id: crypto.randomUUID(),
|
|
18481
|
-
shorthand,
|
|
18482
|
-
project_id: projectId,
|
|
18483
|
-
proposal_id: proposalId,
|
|
18484
|
-
status_id: input.status_id ?? null,
|
|
18485
|
-
parent_id: input.parent_id ?? null,
|
|
18486
|
-
title: input.title ?? null,
|
|
18487
|
-
input: input.input ?? null,
|
|
18488
|
-
priority: input.priority ?? null,
|
|
18489
|
-
parallelizable: input.parallelizable ?? null,
|
|
18490
|
-
complexity: input.complexity ?? null,
|
|
18491
|
-
blocked_reason: input.blocked_reason ?? null,
|
|
18492
|
-
depends_on: input.depends_on ?? null,
|
|
18493
|
-
archived: input.archived ?? 0,
|
|
18494
|
-
staged: input.staged ?? 0,
|
|
18495
|
-
deleted_at: null,
|
|
18496
|
-
created_at: timestamp,
|
|
18497
|
-
updated_at: timestamp
|
|
18498
|
-
};
|
|
18499
|
-
db.insert(tickets).values(ticket).run();
|
|
18500
|
-
return ticket;
|
|
18501
|
-
};
|
|
18502
|
-
const updateForProposal = (projectId, proposalId, ticketId, input) => {
|
|
18503
|
-
const existing = getForProposal(projectId, proposalId, ticketId);
|
|
18504
|
-
if (!existing)
|
|
18505
|
-
return null;
|
|
18506
|
-
if (input.parent_id !== undefined) {
|
|
18507
|
-
validateParentId(existing.id, input.parent_id, get);
|
|
18508
|
-
}
|
|
18509
|
-
const title = input.title === undefined ? existing.title : input.title;
|
|
18510
|
-
const ticketInput = input.input === undefined ? existing.input : input.input;
|
|
18511
|
-
const priority = input.priority === undefined ? existing.priority : input.priority;
|
|
18512
|
-
const parallelizable = input.parallelizable === undefined ? existing.parallelizable : input.parallelizable;
|
|
18513
|
-
const complexity = input.complexity === undefined ? existing.complexity : input.complexity;
|
|
18514
|
-
const status_id = input.status_id === undefined ? existing.status_id : input.status_id;
|
|
18515
|
-
const parent_id = input.parent_id === undefined ? existing.parent_id : input.parent_id;
|
|
18516
|
-
const blocked_reason = input.blocked_reason === undefined ? existing.blocked_reason : input.blocked_reason;
|
|
18517
|
-
const depends_on = input.depends_on === undefined ? existing.depends_on : input.depends_on;
|
|
18518
|
-
const archived = input.archived === undefined ? existing.archived : input.archived;
|
|
18519
|
-
const staged = input.staged === undefined ? existing.staged : input.staged;
|
|
18520
|
-
const updated = {
|
|
18521
|
-
...existing,
|
|
18522
|
-
title,
|
|
18523
|
-
input: ticketInput,
|
|
18524
|
-
priority,
|
|
18525
|
-
parallelizable,
|
|
18526
|
-
complexity,
|
|
18527
|
-
status_id,
|
|
18528
|
-
parent_id,
|
|
18529
|
-
blocked_reason,
|
|
18530
|
-
depends_on,
|
|
18531
|
-
archived,
|
|
18532
|
-
staged,
|
|
18533
|
-
updated_at: nowTimestamp10()
|
|
18534
|
-
};
|
|
18535
|
-
db.update(tickets).set({
|
|
18536
|
-
title: updated.title,
|
|
18537
|
-
input: updated.input,
|
|
18538
|
-
priority: updated.priority,
|
|
18539
|
-
parallelizable: updated.parallelizable,
|
|
18540
|
-
complexity: updated.complexity,
|
|
18541
|
-
status_id: updated.status_id,
|
|
18542
|
-
parent_id: updated.parent_id,
|
|
18543
|
-
blocked_reason: updated.blocked_reason,
|
|
18544
|
-
depends_on: updated.depends_on,
|
|
18545
|
-
archived: updated.archived,
|
|
18546
|
-
staged: updated.staged,
|
|
18547
|
-
updated_at: updated.updated_at
|
|
18548
|
-
}).where(and(eq(tickets.project_id, projectId), eq(tickets.proposal_id, proposalId), eq(tickets.id, existing.id))).run();
|
|
18549
|
-
return updated;
|
|
18550
|
-
};
|
|
18551
|
-
const removeForProposal = (projectId, proposalId, ticketId) => {
|
|
18552
|
-
const existing = getForProposal(projectId, proposalId, ticketId);
|
|
18553
|
-
if (!existing)
|
|
18554
|
-
return false;
|
|
18555
|
-
db.update(tickets).set({ deleted_at: nowTimestamp10(), updated_at: nowTimestamp10() }).where(and(eq(tickets.project_id, projectId), eq(tickets.proposal_id, proposalId), eq(tickets.id, existing.id))).run();
|
|
18315
|
+
db.update(tickets).set({ deleted_at: nowTimestamp9(), updated_at: nowTimestamp9() }).where(eq(tickets.id, existing.id)).run();
|
|
18556
18316
|
return true;
|
|
18557
18317
|
};
|
|
18558
18318
|
const save = (input) => {
|
|
18559
18319
|
const existing = get(input.id);
|
|
18560
|
-
const timestamp =
|
|
18320
|
+
const timestamp = nowTimestamp9();
|
|
18561
18321
|
const normalizedShorthand = input.shorthand ? normalizeTicketShorthand(input.shorthand) : normalizeTicketShorthand(input.id);
|
|
18562
18322
|
if (existing) {
|
|
18563
18323
|
db.update(tickets).set({
|
|
@@ -18568,7 +18328,6 @@ var createTicketsService = (db) => {
|
|
|
18568
18328
|
parallelizable: input.parallelizable ?? existing.parallelizable,
|
|
18569
18329
|
complexity: input.complexity ?? existing.complexity,
|
|
18570
18330
|
status_id: input.status_id ?? existing.status_id,
|
|
18571
|
-
proposal_id: input.proposal_id ?? existing.proposal_id,
|
|
18572
18331
|
parent_id: input.parent_id ?? existing.parent_id,
|
|
18573
18332
|
blocked_reason: input.blocked_reason ?? existing.blocked_reason,
|
|
18574
18333
|
depends_on: input.depends_on ?? existing.depends_on,
|
|
@@ -18585,7 +18344,6 @@ var createTicketsService = (db) => {
|
|
|
18585
18344
|
parallelizable: input.parallelizable ?? existing.parallelizable,
|
|
18586
18345
|
complexity: input.complexity ?? existing.complexity,
|
|
18587
18346
|
status_id: input.status_id ?? existing.status_id,
|
|
18588
|
-
proposal_id: input.proposal_id ?? existing.proposal_id,
|
|
18589
18347
|
parent_id: input.parent_id ?? existing.parent_id,
|
|
18590
18348
|
blocked_reason: input.blocked_reason ?? existing.blocked_reason,
|
|
18591
18349
|
depends_on: input.depends_on ?? existing.depends_on,
|
|
@@ -18598,7 +18356,6 @@ var createTicketsService = (db) => {
|
|
|
18598
18356
|
id: UUID_PATTERN.test(input.id) ? input.id : crypto.randomUUID(),
|
|
18599
18357
|
shorthand: normalizedShorthand ?? allocateTicketShorthand(),
|
|
18600
18358
|
project_id: input.project_id,
|
|
18601
|
-
proposal_id: input.proposal_id ?? null,
|
|
18602
18359
|
status_id: input.status_id ?? null,
|
|
18603
18360
|
parent_id: input.parent_id ?? null,
|
|
18604
18361
|
title: input.title ?? null,
|
|
@@ -18624,16 +18381,12 @@ var createTicketsService = (db) => {
|
|
|
18624
18381
|
create,
|
|
18625
18382
|
update,
|
|
18626
18383
|
remove,
|
|
18627
|
-
save
|
|
18628
|
-
listByProposal,
|
|
18629
|
-
createForProposal,
|
|
18630
|
-
updateForProposal,
|
|
18631
|
-
removeForProposal
|
|
18384
|
+
save
|
|
18632
18385
|
};
|
|
18633
18386
|
};
|
|
18634
18387
|
|
|
18635
18388
|
// ../schub-db/src/services/workspace-artifacts.ts
|
|
18636
|
-
var
|
|
18389
|
+
var nowTimestamp10 = () => new Date().toISOString();
|
|
18637
18390
|
var createWorkspaceArtifactsService = (db) => {
|
|
18638
18391
|
const list = (ticketId) => db.select({
|
|
18639
18392
|
id: workspace_artifacts.id,
|
|
@@ -18651,7 +18404,7 @@ var createWorkspaceArtifactsService = (db) => {
|
|
|
18651
18404
|
return artifact ?? null;
|
|
18652
18405
|
};
|
|
18653
18406
|
const upsertByPath = (ticketId, input) => {
|
|
18654
|
-
const timestamp =
|
|
18407
|
+
const timestamp = nowTimestamp10();
|
|
18655
18408
|
const existing = db.select().from(workspace_artifacts).where(and(eq(workspace_artifacts.ticket_id, ticketId), eq(workspace_artifacts.relative_path, input.relative_path))).get();
|
|
18656
18409
|
if (existing) {
|
|
18657
18410
|
db.update(workspace_artifacts).set({ file_id: input.file_id }).where(eq(workspace_artifacts.id, existing.id)).run();
|
|
@@ -18696,7 +18449,7 @@ var createWorkspaceArtifactsService = (db) => {
|
|
|
18696
18449
|
};
|
|
18697
18450
|
|
|
18698
18451
|
// ../schub-db/src/services/workspaces.ts
|
|
18699
|
-
var
|
|
18452
|
+
var nowTimestamp11 = () => new Date().toISOString();
|
|
18700
18453
|
var formatWorkspaceShorthand = (sequence) => `A${sequence.toString().padStart(4, "0")}`;
|
|
18701
18454
|
var parseWorkspaceShorthand = (value) => {
|
|
18702
18455
|
if (!value) {
|
|
@@ -18767,7 +18520,7 @@ var createWorkspacesService = (db) => {
|
|
|
18767
18520
|
}).run();
|
|
18768
18521
|
};
|
|
18769
18522
|
const create = (input) => {
|
|
18770
|
-
const timestamp =
|
|
18523
|
+
const timestamp = nowTimestamp11();
|
|
18771
18524
|
const workspaceShorthand = input.workspace_shorthand === undefined || input.workspace_shorthand === null ? null : normalizeWorkspaceShorthand(input.workspace_shorthand);
|
|
18772
18525
|
const workspace = {
|
|
18773
18526
|
id: input.id?.trim() || crypto.randomUUID(),
|
|
@@ -18798,7 +18551,7 @@ var createWorkspacesService = (db) => {
|
|
|
18798
18551
|
worktree_path: input.worktree_path === undefined ? existing.worktree_path ?? null : input.worktree_path,
|
|
18799
18552
|
workspace_shorthand: resolveWorkspaceShorthandForUpdate(input.workspace_shorthand, existing.workspace_shorthand),
|
|
18800
18553
|
ticket_id: input.ticket_id === undefined ? existing.ticket_id : input.ticket_id,
|
|
18801
|
-
updated_at:
|
|
18554
|
+
updated_at: nowTimestamp11()
|
|
18802
18555
|
};
|
|
18803
18556
|
db.update(workspaces).set({
|
|
18804
18557
|
name: updated.name,
|
|
@@ -18841,10 +18594,8 @@ var createDbServices = (config2 = {}) => {
|
|
|
18841
18594
|
const docs = createDocsService();
|
|
18842
18595
|
const files2 = createFilesService(db, storageRoot);
|
|
18843
18596
|
const gitDiff = createGitDiffService();
|
|
18844
|
-
const proposalStatuses = createProposalStatusesService(db);
|
|
18845
18597
|
const projects2 = createProjectsService(db);
|
|
18846
18598
|
const projectDocs = createProjectDocsService(db, files2);
|
|
18847
|
-
const proposals2 = createProposalsService(db);
|
|
18848
18599
|
const repos2 = createReposService(db);
|
|
18849
18600
|
const sessions2 = createSessionsService(db);
|
|
18850
18601
|
const settings = createSettingsService(config2.settingsPath);
|
|
@@ -18859,10 +18610,8 @@ var createDbServices = (config2 = {}) => {
|
|
|
18859
18610
|
docs,
|
|
18860
18611
|
files: files2,
|
|
18861
18612
|
gitDiff,
|
|
18862
|
-
proposalStatuses,
|
|
18863
18613
|
projects: projects2,
|
|
18864
18614
|
projectDocs,
|
|
18865
|
-
proposals: proposals2,
|
|
18866
18615
|
repos: repos2,
|
|
18867
18616
|
sessions: sessions2,
|
|
18868
18617
|
settings,
|