@proletariat/cli 0.3.34 → 0.3.35
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/commands/agent/auth.d.ts +3 -1
- package/dist/commands/agent/auth.js +8 -11
- package/dist/commands/agent/index.js +11 -2
- package/dist/commands/agent/staff/add.d.ts +1 -0
- package/dist/commands/agent/staff/add.js +1 -0
- package/dist/commands/agent/staff/index.d.ts +15 -0
- package/dist/commands/agent/staff/index.js +83 -0
- package/dist/commands/agent/staff/list.d.ts +1 -0
- package/dist/commands/agent/staff/list.js +1 -0
- package/dist/commands/agent/staff/remove.d.ts +1 -0
- package/dist/commands/agent/staff/remove.js +1 -0
- package/dist/commands/agent/themes/add-names.d.ts +1 -0
- package/dist/commands/agent/themes/add-names.js +1 -0
- package/dist/commands/agent/themes/create.d.ts +1 -0
- package/dist/commands/agent/themes/create.js +1 -0
- package/dist/commands/agent/themes/index.d.ts +10 -0
- package/dist/commands/agent/themes/index.js +144 -0
- package/dist/commands/agent/themes/list.d.ts +1 -0
- package/dist/commands/agent/themes/list.js +1 -0
- package/dist/commands/agent/themes/set.d.ts +1 -0
- package/dist/commands/agent/themes/set.js +1 -0
- package/dist/commands/agents/themes/add-names.d.ts +1 -0
- package/dist/commands/agents/themes/add-names.js +1 -0
- package/dist/commands/agents/themes/create.d.ts +1 -0
- package/dist/commands/agents/themes/create.js +1 -0
- package/dist/commands/agents/themes/list.d.ts +1 -0
- package/dist/commands/agents/themes/list.js +1 -0
- package/dist/commands/category/list.js +1 -1
- package/dist/commands/label/create.d.ts +20 -0
- package/dist/commands/label/create.js +56 -0
- package/dist/commands/label/delete.d.ts +17 -0
- package/dist/commands/label/delete.js +31 -0
- package/dist/commands/label/group/create.d.ts +20 -0
- package/dist/commands/label/group/create.js +54 -0
- package/dist/commands/label/group/list.d.ts +14 -0
- package/dist/commands/label/group/list.js +51 -0
- package/dist/commands/label/index.d.ts +15 -0
- package/dist/commands/label/index.js +58 -0
- package/dist/commands/label/list.d.ts +16 -0
- package/dist/commands/label/list.js +82 -0
- package/dist/commands/link/list.js +3 -2
- package/dist/commands/mcp-server.js +2 -1
- package/dist/commands/phase/template/apply.d.ts +26 -0
- package/dist/commands/phase/template/apply.js +14 -0
- package/dist/commands/phase/template/create.d.ts +23 -0
- package/dist/commands/phase/template/create.js +14 -0
- package/dist/commands/phase/template/delete.d.ts +18 -0
- package/dist/commands/phase/template/delete.js +61 -0
- package/dist/commands/phase/template/list.d.ts +17 -0
- package/dist/commands/phase/template/list.js +88 -0
- package/dist/commands/phase/template/update.d.ts +1 -0
- package/dist/commands/phase/template/update.js +1 -0
- package/dist/commands/priority/add.js +1 -1
- package/dist/commands/project/update.js +0 -2
- package/dist/commands/roadmap/generate.js +1 -2
- package/dist/commands/session/health.js +1 -1
- package/dist/commands/spec/link/depends.d.ts +18 -0
- package/dist/commands/spec/link/depends.js +86 -0
- package/dist/commands/spec/link/index.d.ts +17 -0
- package/dist/commands/spec/link/index.js +92 -0
- package/dist/commands/spec/link/remove.d.ts +18 -0
- package/dist/commands/spec/link/remove.js +90 -0
- package/dist/commands/support/logs.js +2 -2
- package/dist/commands/template/apply.js +5 -4
- package/dist/commands/template/create.js +1 -1
- package/dist/commands/ticket/link/block.d.ts +15 -0
- package/dist/commands/ticket/link/block.js +95 -0
- package/dist/commands/ticket/link/index.d.ts +14 -0
- package/dist/commands/ticket/link/index.js +96 -0
- package/dist/commands/ticket/list.d.ts +1 -0
- package/dist/commands/ticket/list.js +6 -0
- package/dist/commands/ticket/resolve.js +1 -1
- package/dist/commands/ticket/template/apply.d.ts +26 -0
- package/dist/commands/ticket/template/apply.js +14 -0
- package/dist/commands/ticket/template/delete.d.ts +18 -0
- package/dist/commands/ticket/template/delete.js +61 -0
- package/dist/commands/ticket/template/list.d.ts +17 -0
- package/dist/commands/ticket/template/list.js +77 -0
- package/dist/commands/ticket/template/save.d.ts +17 -0
- package/dist/commands/ticket/template/save.js +97 -0
- package/dist/commands/ticket/view.d.ts +1 -0
- package/dist/commands/ticket/view.js +1 -0
- package/dist/commands/work/ready.js +17 -0
- package/dist/commands/work/resolve.js +1 -1
- package/dist/commands/work/spawn.js +4 -4
- package/dist/commands/work/start.d.ts +1 -0
- package/dist/commands/work/start.js +52 -17
- package/dist/lib/database/index.d.ts +1 -1
- package/dist/lib/database/index.js +20 -0
- package/dist/lib/execution/devcontainer.js +3 -1
- package/dist/lib/execution/runners.d.ts +7 -2
- package/dist/lib/execution/runners.js +18 -10
- package/dist/lib/execution/types.d.ts +1 -0
- package/dist/lib/flags/resolver.js +1 -0
- package/dist/lib/mcp/helpers.d.ts +1 -2
- package/dist/lib/mcp/tools/diet.js +1 -0
- package/dist/lib/mcp/tools/index.d.ts +1 -0
- package/dist/lib/mcp/tools/index.js +1 -0
- package/dist/lib/mcp/tools/label.d.ts +6 -0
- package/dist/lib/mcp/tools/label.js +338 -0
- package/dist/lib/mcp/tools/ticket.js +53 -17
- package/dist/lib/multiline-input.js +6 -18
- package/dist/lib/pmo/base-command.d.ts +0 -1
- package/dist/lib/pmo/base-command.js +0 -1
- package/dist/lib/pmo/schema.d.ts +6 -0
- package/dist/lib/pmo/schema.js +44 -0
- package/dist/lib/pmo/storage/base.d.ts +6 -0
- package/dist/lib/pmo/storage/base.js +116 -2
- package/dist/lib/pmo/storage/index.d.ts +23 -1
- package/dist/lib/pmo/storage/index.js +59 -1
- package/dist/lib/pmo/storage/labels.d.ts +55 -0
- package/dist/lib/pmo/storage/labels.js +346 -0
- package/dist/lib/pmo/storage/tickets.js +17 -0
- package/dist/lib/pmo/storage/types.d.ts +24 -0
- package/dist/lib/pmo/types.d.ts +44 -0
- package/dist/lib/pmo/utils.js +1 -1
- package/oclif.manifest.json +5702 -3660
- package/package.json +1 -1
package/dist/lib/pmo/schema.js
CHANGED
|
@@ -41,6 +41,10 @@ export const PMO_TABLES = {
|
|
|
41
41
|
// Roadmap tables (ordered collections of projects for documentation)
|
|
42
42
|
roadmaps: 'pmo_roadmaps', // Named roadmap definitions
|
|
43
43
|
roadmap_projects: 'pmo_roadmap_projects', // Many-to-many: roadmaps ↔ projects with ordering
|
|
44
|
+
// Label system tables
|
|
45
|
+
label_groups: 'pmo_label_groups',
|
|
46
|
+
labels: 'pmo_labels',
|
|
47
|
+
ticket_labels: 'pmo_ticket_labels',
|
|
44
48
|
// Legacy tables (deprecated, kept for migration)
|
|
45
49
|
columns: 'pmo_columns', // DEPRECATED: use workflow_statuses
|
|
46
50
|
board_tickets: 'pmo_board_tickets', // DEPRECATED: tickets now use status_id directly
|
|
@@ -427,6 +431,37 @@ export const PMO_TABLE_SCHEMAS = {
|
|
|
427
431
|
suggested_subtasks TEXT NOT NULL DEFAULT '[]',
|
|
428
432
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
429
433
|
)`,
|
|
434
|
+
// Label groups (workspace-scoped grouping for labels)
|
|
435
|
+
label_groups: `
|
|
436
|
+
CREATE TABLE IF NOT EXISTS ${PMO_TABLES.label_groups} (
|
|
437
|
+
id TEXT PRIMARY KEY,
|
|
438
|
+
name TEXT NOT NULL UNIQUE,
|
|
439
|
+
description TEXT,
|
|
440
|
+
is_exclusive INTEGER NOT NULL DEFAULT 1,
|
|
441
|
+
is_required INTEGER NOT NULL DEFAULT 0,
|
|
442
|
+
position INTEGER NOT NULL DEFAULT 0,
|
|
443
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
444
|
+
)`,
|
|
445
|
+
// Labels (workspace-scoped, optionally grouped)
|
|
446
|
+
labels: `
|
|
447
|
+
CREATE TABLE IF NOT EXISTS ${PMO_TABLES.labels} (
|
|
448
|
+
id TEXT PRIMARY KEY,
|
|
449
|
+
name TEXT NOT NULL,
|
|
450
|
+
color TEXT,
|
|
451
|
+
description TEXT,
|
|
452
|
+
group_id TEXT REFERENCES ${PMO_TABLES.label_groups}(id) ON DELETE SET NULL,
|
|
453
|
+
position INTEGER NOT NULL DEFAULT 0,
|
|
454
|
+
is_builtin INTEGER NOT NULL DEFAULT 0,
|
|
455
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
456
|
+
UNIQUE(name, group_id)
|
|
457
|
+
)`,
|
|
458
|
+
// Junction table: ticket-label associations (replaces JSON labels field)
|
|
459
|
+
ticket_labels: `
|
|
460
|
+
CREATE TABLE IF NOT EXISTS ${PMO_TABLES.ticket_labels} (
|
|
461
|
+
ticket_id TEXT NOT NULL REFERENCES ${PMO_TABLES.tickets}(id) ON DELETE CASCADE,
|
|
462
|
+
label_id TEXT NOT NULL REFERENCES ${PMO_TABLES.labels}(id) ON DELETE CASCADE,
|
|
463
|
+
PRIMARY KEY (ticket_id, label_id)
|
|
464
|
+
)`,
|
|
430
465
|
// Roadmap definitions (named collections of projects for documentation)
|
|
431
466
|
roadmaps: `
|
|
432
467
|
CREATE TABLE IF NOT EXISTS ${PMO_TABLES.roadmaps} (
|
|
@@ -502,6 +537,12 @@ export const PMO_INDEXES = `
|
|
|
502
537
|
CREATE INDEX IF NOT EXISTS idx_pmo_roadmap_projects_position ON ${PMO_TABLES.roadmap_projects}(roadmap_id, position);
|
|
503
538
|
CREATE INDEX IF NOT EXISTS idx_pmo_categories_type ON ${PMO_TABLES.categories}(type);
|
|
504
539
|
CREATE INDEX IF NOT EXISTS idx_pmo_categories_position ON ${PMO_TABLES.categories}(type, position);
|
|
540
|
+
CREATE INDEX IF NOT EXISTS idx_pmo_label_groups_position ON ${PMO_TABLES.label_groups}(position);
|
|
541
|
+
CREATE INDEX IF NOT EXISTS idx_pmo_labels_group ON ${PMO_TABLES.labels}(group_id);
|
|
542
|
+
CREATE INDEX IF NOT EXISTS idx_pmo_labels_position ON ${PMO_TABLES.labels}(group_id, position);
|
|
543
|
+
CREATE INDEX IF NOT EXISTS idx_pmo_labels_builtin ON ${PMO_TABLES.labels}(is_builtin);
|
|
544
|
+
CREATE INDEX IF NOT EXISTS idx_pmo_ticket_labels_ticket ON ${PMO_TABLES.ticket_labels}(ticket_id);
|
|
545
|
+
CREATE INDEX IF NOT EXISTS idx_pmo_ticket_labels_label ON ${PMO_TABLES.ticket_labels}(label_id);
|
|
505
546
|
`;
|
|
506
547
|
// =============================================================================
|
|
507
548
|
// Combined Schema
|
|
@@ -540,6 +581,9 @@ export const PMO_SCHEMA_SQL = [
|
|
|
540
581
|
PMO_TABLE_SCHEMAS.id_sequences, // Sequence counters for ID generation
|
|
541
582
|
PMO_TABLE_SCHEMAS.actions, // Work actions (reusable agent prompts)
|
|
542
583
|
PMO_TABLE_SCHEMAS.ticket_templates, // Ticket templates for quick creation
|
|
584
|
+
PMO_TABLE_SCHEMAS.label_groups, // Label groups (before labels for FK)
|
|
585
|
+
PMO_TABLE_SCHEMAS.labels, // Labels (before ticket_labels for FK)
|
|
586
|
+
PMO_TABLE_SCHEMAS.ticket_labels, // Ticket-label junction table
|
|
543
587
|
PMO_TABLE_SCHEMAS.roadmaps, // Named roadmap definitions
|
|
544
588
|
PMO_TABLE_SCHEMAS.roadmap_projects, // Roadmap-to-project associations
|
|
545
589
|
// Legacy tables (kept for migration, will be dropped after data migrated)
|
|
@@ -42,6 +42,12 @@ export declare function seedBuiltinCategories(db: Database.Database): void;
|
|
|
42
42
|
* Preserves any existing user-defined priority scale.
|
|
43
43
|
*/
|
|
44
44
|
export declare function seedDefaultPriorities(db: Database.Database): void;
|
|
45
|
+
/**
|
|
46
|
+
* Seed built-in label groups and labels.
|
|
47
|
+
* Creates Function, Type, and Area groups with their labels.
|
|
48
|
+
* Migrates existing ticket category values to Function labels.
|
|
49
|
+
*/
|
|
50
|
+
export declare function seedBuiltinLabels(db: Database.Database): void;
|
|
45
51
|
/**
|
|
46
52
|
* Update board timestamp for a project.
|
|
47
53
|
*/
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { PMO_TABLES, PMO_SCHEMA_SQL, validateTicketSchema } from '../schema.js';
|
|
6
6
|
import { TICKET_CATEGORIES, STATE_CATEGORY_ORDER } from '../types.js';
|
|
7
7
|
import { BUILTIN_TEMPLATES } from '../templates-builtin.js';
|
|
8
|
-
import {
|
|
8
|
+
import { setWorkspacePriorities, DEFAULT_PRIORITIES } from '../utils.js';
|
|
9
9
|
const T = PMO_TABLES;
|
|
10
10
|
/**
|
|
11
11
|
* Initialize PMO tables in the database.
|
|
@@ -20,6 +20,7 @@ export function initializePMOTables(db) {
|
|
|
20
20
|
seedBuiltinActions(db);
|
|
21
21
|
seedBuiltinTicketTemplates(db);
|
|
22
22
|
seedDefaultPriorities(db); // Seed default priority scale if not set
|
|
23
|
+
seedBuiltinLabels(db); // Seed built-in label groups and labels
|
|
23
24
|
validateTicketSchema(db);
|
|
24
25
|
}
|
|
25
26
|
/**
|
|
@@ -538,6 +539,8 @@ Requirements:
|
|
|
538
539
|
- Use \`--clear-subtasks\` if replacing existing subtasks
|
|
539
540
|
- Use \`--clear-ac\` if replacing existing acceptance criteria
|
|
540
541
|
|
|
542
|
+
**Tip:** Use \`prlt ticket view <id>\` to see full ticket details at any time.
|
|
543
|
+
|
|
541
544
|
After updating, output a brief summary of your grooming changes.`,
|
|
542
545
|
suggestedForCategories: ['backlog'],
|
|
543
546
|
defaultMoveToCategory: 'unstarted',
|
|
@@ -984,7 +987,6 @@ export function seedBuiltinCategories(db) {
|
|
|
984
987
|
* Preserves any existing user-defined priority scale.
|
|
985
988
|
*/
|
|
986
989
|
export function seedDefaultPriorities(db) {
|
|
987
|
-
const existing = getWorkspacePriorities(db);
|
|
988
990
|
// getWorkspacePriorities returns DEFAULT_PRIORITIES if not set,
|
|
989
991
|
// but we need to check if it's actually stored in the DB
|
|
990
992
|
const row = db.prepare(`SELECT value FROM ${T.settings} WHERE key = 'priorities'`).get();
|
|
@@ -993,6 +995,118 @@ export function seedDefaultPriorities(db) {
|
|
|
993
995
|
setWorkspacePriorities(db, [...DEFAULT_PRIORITIES]);
|
|
994
996
|
}
|
|
995
997
|
}
|
|
998
|
+
/**
|
|
999
|
+
* Seed built-in label groups and labels.
|
|
1000
|
+
* Creates Function, Type, and Area groups with their labels.
|
|
1001
|
+
* Migrates existing ticket category values to Function labels.
|
|
1002
|
+
*/
|
|
1003
|
+
export function seedBuiltinLabels(db) {
|
|
1004
|
+
const now = new Date().toISOString();
|
|
1005
|
+
const insertGroup = db.prepare(`
|
|
1006
|
+
INSERT OR IGNORE INTO ${T.label_groups} (id, name, description, is_exclusive, is_required, position, created_at)
|
|
1007
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
1008
|
+
`);
|
|
1009
|
+
const insertLabel = db.prepare(`
|
|
1010
|
+
INSERT OR IGNORE INTO ${T.labels} (id, name, color, description, group_id, position, is_builtin, created_at)
|
|
1011
|
+
VALUES (?, ?, ?, ?, ?, ?, 1, ?)
|
|
1012
|
+
`);
|
|
1013
|
+
// Built-in label groups
|
|
1014
|
+
const groups = [
|
|
1015
|
+
{
|
|
1016
|
+
id: 'function',
|
|
1017
|
+
name: 'Function',
|
|
1018
|
+
description: 'Business function category (diet enforcement)',
|
|
1019
|
+
isExclusive: true,
|
|
1020
|
+
isRequired: true,
|
|
1021
|
+
position: 0,
|
|
1022
|
+
labels: [
|
|
1023
|
+
{ id: 'fn-ship', name: 'ship', description: 'Core product development', color: '#2da44e' },
|
|
1024
|
+
{ id: 'fn-grow', name: 'grow', description: 'Marketing, adoption, community', color: '#bf8700' },
|
|
1025
|
+
{ id: 'fn-support', name: 'support', description: 'Docs, error messages, onboarding', color: '#0969da' },
|
|
1026
|
+
{ id: 'fn-bizops', name: 'bizops', description: 'Infrastructure, CI/CD, operations', color: '#8250df' },
|
|
1027
|
+
{ id: 'fn-strategy', name: 'strategy', description: 'Design decisions, spikes, retros, planning', color: '#cf222e' },
|
|
1028
|
+
],
|
|
1029
|
+
},
|
|
1030
|
+
{
|
|
1031
|
+
id: 'type',
|
|
1032
|
+
name: 'Type',
|
|
1033
|
+
description: 'Work type classification',
|
|
1034
|
+
isExclusive: true,
|
|
1035
|
+
isRequired: false,
|
|
1036
|
+
position: 1,
|
|
1037
|
+
labels: [
|
|
1038
|
+
{ id: 'type-bug', name: 'bug', description: 'Bug fix', color: '#cf222e' },
|
|
1039
|
+
{ id: 'type-feature', name: 'feature', description: 'New feature', color: '#2da44e' },
|
|
1040
|
+
{ id: 'type-improvement', name: 'improvement', description: 'Enhancement to existing feature', color: '#0969da' },
|
|
1041
|
+
{ id: 'type-task', name: 'task', description: 'General task', color: '#6e7781' },
|
|
1042
|
+
],
|
|
1043
|
+
},
|
|
1044
|
+
{
|
|
1045
|
+
id: 'area',
|
|
1046
|
+
name: 'Area',
|
|
1047
|
+
description: 'System area (non-exclusive)',
|
|
1048
|
+
isExclusive: false,
|
|
1049
|
+
isRequired: false,
|
|
1050
|
+
position: 2,
|
|
1051
|
+
labels: [
|
|
1052
|
+
{ id: 'area-cli', name: 'cli', description: 'CLI tool', color: '#0969da' },
|
|
1053
|
+
{ id: 'area-pmo', name: 'pmo', description: 'Project management', color: '#8250df' },
|
|
1054
|
+
{ id: 'area-agent', name: 'agent', description: 'Agent system', color: '#2da44e' },
|
|
1055
|
+
{ id: 'area-docker', name: 'docker', description: 'Docker integration', color: '#bf8700' },
|
|
1056
|
+
{ id: 'area-mcp', name: 'mcp', description: 'MCP server', color: '#cf222e' },
|
|
1057
|
+
{ id: 'area-desktop', name: 'desktop', description: 'Desktop app', color: '#6e7781' },
|
|
1058
|
+
],
|
|
1059
|
+
},
|
|
1060
|
+
];
|
|
1061
|
+
for (const group of groups) {
|
|
1062
|
+
insertGroup.run(group.id, group.name, group.description, group.isExclusive ? 1 : 0, group.isRequired ? 1 : 0, group.position, now);
|
|
1063
|
+
for (let i = 0; i < group.labels.length; i++) {
|
|
1064
|
+
const label = group.labels[i];
|
|
1065
|
+
insertLabel.run(label.id, label.name, label.color, label.description, group.id, i, now);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
// Migrate existing category column values to Function label group
|
|
1069
|
+
// Only run if there are tickets with category set but no Function label yet
|
|
1070
|
+
migrateCategoryToFunctionLabels(db);
|
|
1071
|
+
}
|
|
1072
|
+
/**
|
|
1073
|
+
* Migrate existing ticket category values to Function label group entries.
|
|
1074
|
+
* Maps known category names to function labels (e.g., 'ship' -> fn-ship).
|
|
1075
|
+
* This is idempotent - only creates associations that don't exist yet.
|
|
1076
|
+
*/
|
|
1077
|
+
function migrateCategoryToFunctionLabels(db) {
|
|
1078
|
+
// Map of old category values to function label IDs
|
|
1079
|
+
// The ticket's category field contains values like 'feature', 'bug', etc.
|
|
1080
|
+
// The diet system uses ship/grow/support/bizops/strategy which are different
|
|
1081
|
+
// from ticket categories. The diet categories map to the Function label group.
|
|
1082
|
+
// Since existing categories (feature, bug, etc.) don't map to Function labels,
|
|
1083
|
+
// we only migrate if the category field happens to contain a Function label name.
|
|
1084
|
+
const functionLabelMap = {
|
|
1085
|
+
ship: 'fn-ship',
|
|
1086
|
+
grow: 'fn-grow',
|
|
1087
|
+
support: 'fn-support',
|
|
1088
|
+
bizops: 'fn-bizops',
|
|
1089
|
+
strategy: 'fn-strategy',
|
|
1090
|
+
};
|
|
1091
|
+
const tickets = db.prepare(`
|
|
1092
|
+
SELECT id, category FROM ${T.tickets}
|
|
1093
|
+
WHERE category IS NOT NULL AND category != ''
|
|
1094
|
+
`).all();
|
|
1095
|
+
const insertTicketLabel = db.prepare(`
|
|
1096
|
+
INSERT OR IGNORE INTO ${T.ticket_labels} (ticket_id, label_id)
|
|
1097
|
+
VALUES (?, ?)
|
|
1098
|
+
`);
|
|
1099
|
+
for (const ticket of tickets) {
|
|
1100
|
+
const labelId = functionLabelMap[ticket.category.toLowerCase()];
|
|
1101
|
+
if (labelId) {
|
|
1102
|
+
// Check label exists before inserting
|
|
1103
|
+
const labelExists = db.prepare(`SELECT id FROM ${T.labels} WHERE id = ?`).get(labelId);
|
|
1104
|
+
if (labelExists) {
|
|
1105
|
+
insertTicketLabel.run(ticket.id, labelId);
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
996
1110
|
/**
|
|
997
1111
|
* Update board timestamp for a project.
|
|
998
1112
|
*/
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import Database from 'better-sqlite3';
|
|
11
11
|
import { DrizzleDB } from '../../database/drizzle.js';
|
|
12
|
-
import { AcceptanceCriterion, Board, BoardConfig, BoardView, BoardViewFilter, BoardViewFilters, Category, CategoryFilter, CategoryType, Column, CreateTicketInput, Epic, EpicDependency, EpicDependencyType, EpicFilter, PhaseFilter, PhaseTemplate, PhaseTemplateFilter, PMOStorage, Project, ProjectFilter, ProjectPhase, Roadmap, RoadmapFilter, RoadmapProject, Spec, SpecDependency, SpecDependencyType, SpecFilter, StateCategory, Subtask, SyncResult, SyncStatus, Ticket, TicketDependency, TicketDependencyType, TicketFilter, TicketTemplate, TicketTemplateFilter, WorkAction, WorkActionFilter, Workflow, WorkflowFilter, WorkflowStatus } from '../types.js';
|
|
12
|
+
import { AcceptanceCriterion, Board, BoardConfig, BoardView, BoardViewFilter, BoardViewFilters, Category, CategoryFilter, CategoryType, Column, CreateTicketInput, Epic, EpicDependency, EpicDependencyType, EpicFilter, PhaseFilter, PhaseTemplate, PhaseTemplateFilter, PMOStorage, Project, ProjectFilter, ProjectPhase, Roadmap, RoadmapFilter, RoadmapProject, Spec, SpecDependency, SpecDependencyType, SpecFilter, StateCategory, Subtask, SyncResult, SyncStatus, Ticket, TicketDependency, TicketDependencyType, TicketFilter, TicketTemplate, TicketTemplateFilter, WorkAction, WorkActionFilter, Workflow, WorkflowFilter, WorkflowStatus, Label, LabelFilter, LabelGroup, LabelGroupFilter } from '../types.js';
|
|
13
13
|
export declare class SQLiteStorage implements PMOStorage {
|
|
14
14
|
readonly type: "sqlite";
|
|
15
15
|
private db;
|
|
@@ -29,6 +29,7 @@ export declare class SQLiteStorage implements PMOStorage {
|
|
|
29
29
|
private viewStorage;
|
|
30
30
|
private roadmapStorage;
|
|
31
31
|
private categoryStorage;
|
|
32
|
+
private labelStorage;
|
|
32
33
|
constructor(dbPath: string);
|
|
33
34
|
/**
|
|
34
35
|
* Get the underlying database connection.
|
|
@@ -203,6 +204,27 @@ export declare class SQLiteStorage implements PMOStorage {
|
|
|
203
204
|
deleteCategory(id: string): Promise<void>;
|
|
204
205
|
getCategoryNames(type: CategoryType): Promise<string[]>;
|
|
205
206
|
isValidCategory(name: string, type: CategoryType): Promise<boolean>;
|
|
207
|
+
listLabelGroups(filter?: LabelGroupFilter): Promise<LabelGroup[]>;
|
|
208
|
+
getLabelGroup(id: string): Promise<LabelGroup | null>;
|
|
209
|
+
getLabelGroupByName(name: string): Promise<LabelGroup | null>;
|
|
210
|
+
createLabelGroup(group: Partial<LabelGroup> & {
|
|
211
|
+
name: string;
|
|
212
|
+
}): Promise<LabelGroup>;
|
|
213
|
+
updateLabelGroup(id: string, changes: Partial<LabelGroup>): Promise<LabelGroup>;
|
|
214
|
+
deleteLabelGroup(id: string): Promise<void>;
|
|
215
|
+
listLabels(filter?: LabelFilter): Promise<Label[]>;
|
|
216
|
+
getLabel(id: string): Promise<Label | null>;
|
|
217
|
+
getLabelByName(name: string, groupId?: string): Promise<Label | null>;
|
|
218
|
+
createLabel(label: Partial<Label> & {
|
|
219
|
+
name: string;
|
|
220
|
+
}): Promise<Label>;
|
|
221
|
+
updateLabel(id: string, changes: Partial<Label>): Promise<Label>;
|
|
222
|
+
deleteLabel(id: string): Promise<void>;
|
|
223
|
+
addLabelToTicket(ticketId: string, labelId: string): Promise<void>;
|
|
224
|
+
removeLabelFromTicket(ticketId: string, labelId: string): Promise<void>;
|
|
225
|
+
getLabelsForTicket(ticketId: string): Promise<Label[]>;
|
|
226
|
+
addLabelToTicketByName(ticketId: string, labelName: string): Promise<void>;
|
|
227
|
+
removeLabelFromTicketByName(ticketId: string, labelName: string): Promise<void>;
|
|
206
228
|
pull(): Promise<SyncResult>;
|
|
207
229
|
push(): Promise<SyncResult>;
|
|
208
230
|
status(): Promise<SyncStatus>;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import Database from 'better-sqlite3';
|
|
11
11
|
import { createDrizzleConnection } from '../../database/drizzle.js';
|
|
12
12
|
import { PMO_TABLES, PMO_SCHEMA_SQL, validateTicketSchema } from '../schema.js';
|
|
13
|
-
import { runMigrations, seedBuiltinWorkflows, seedBuiltinPhases, seedBuiltinPhaseTemplates, seedBuiltinActions, seedBuiltinTicketTemplates, seedBuiltinCategories, updateBoardTimestamp, } from './base.js';
|
|
13
|
+
import { runMigrations, seedBuiltinWorkflows, seedBuiltinPhases, seedBuiltinPhaseTemplates, seedBuiltinActions, seedBuiltinTicketTemplates, seedBuiltinCategories, seedBuiltinLabels, updateBoardTimestamp, } from './base.js';
|
|
14
14
|
import { ProjectStorage } from './projects.js';
|
|
15
15
|
import { TicketStorage } from './tickets.js';
|
|
16
16
|
import { SubtaskStorage, AcceptanceCriteriaStorage } from './subtasks.js';
|
|
@@ -24,6 +24,7 @@ import { ActionStorage } from './actions.js';
|
|
|
24
24
|
import { ViewStorage } from './views.js';
|
|
25
25
|
import { RoadmapStorage } from './roadmaps.js';
|
|
26
26
|
import { CategoryStorage } from './categories.js';
|
|
27
|
+
import { LabelStorage } from './labels.js';
|
|
27
28
|
const T = PMO_TABLES;
|
|
28
29
|
export class SQLiteStorage {
|
|
29
30
|
type = 'sqlite';
|
|
@@ -45,6 +46,7 @@ export class SQLiteStorage {
|
|
|
45
46
|
viewStorage;
|
|
46
47
|
roadmapStorage;
|
|
47
48
|
categoryStorage;
|
|
49
|
+
labelStorage;
|
|
48
50
|
constructor(dbPath) {
|
|
49
51
|
this.dbPath = dbPath;
|
|
50
52
|
// Open database (creates if doesn't exist)
|
|
@@ -74,6 +76,7 @@ export class SQLiteStorage {
|
|
|
74
76
|
this.viewStorage = new ViewStorage(ctx);
|
|
75
77
|
this.roadmapStorage = new RoadmapStorage(ctx);
|
|
76
78
|
this.categoryStorage = new CategoryStorage(ctx);
|
|
79
|
+
this.labelStorage = new LabelStorage(ctx);
|
|
77
80
|
// Ensure PMO tables exist
|
|
78
81
|
this.ensurePMOTables();
|
|
79
82
|
}
|
|
@@ -104,6 +107,7 @@ export class SQLiteStorage {
|
|
|
104
107
|
seedBuiltinActions(this.db);
|
|
105
108
|
seedBuiltinTicketTemplates(this.db);
|
|
106
109
|
seedBuiltinCategories(this.db);
|
|
110
|
+
seedBuiltinLabels(this.db);
|
|
107
111
|
// Validate schema
|
|
108
112
|
validateTicketSchema(this.db);
|
|
109
113
|
}
|
|
@@ -616,6 +620,60 @@ export class SQLiteStorage {
|
|
|
616
620
|
return this.categoryStorage.isValidCategory(name, type);
|
|
617
621
|
}
|
|
618
622
|
// ===========================================================================
|
|
623
|
+
// Label Operations
|
|
624
|
+
// ===========================================================================
|
|
625
|
+
async listLabelGroups(filter) {
|
|
626
|
+
return this.labelStorage.listLabelGroups(filter);
|
|
627
|
+
}
|
|
628
|
+
async getLabelGroup(id) {
|
|
629
|
+
return this.labelStorage.getLabelGroup(id);
|
|
630
|
+
}
|
|
631
|
+
async getLabelGroupByName(name) {
|
|
632
|
+
return this.labelStorage.getLabelGroupByName(name);
|
|
633
|
+
}
|
|
634
|
+
async createLabelGroup(group) {
|
|
635
|
+
return this.labelStorage.createLabelGroup(group);
|
|
636
|
+
}
|
|
637
|
+
async updateLabelGroup(id, changes) {
|
|
638
|
+
return this.labelStorage.updateLabelGroup(id, changes);
|
|
639
|
+
}
|
|
640
|
+
async deleteLabelGroup(id) {
|
|
641
|
+
return this.labelStorage.deleteLabelGroup(id);
|
|
642
|
+
}
|
|
643
|
+
async listLabels(filter) {
|
|
644
|
+
return this.labelStorage.listLabels(filter);
|
|
645
|
+
}
|
|
646
|
+
async getLabel(id) {
|
|
647
|
+
return this.labelStorage.getLabel(id);
|
|
648
|
+
}
|
|
649
|
+
async getLabelByName(name, groupId) {
|
|
650
|
+
return this.labelStorage.getLabelByName(name, groupId);
|
|
651
|
+
}
|
|
652
|
+
async createLabel(label) {
|
|
653
|
+
return this.labelStorage.createLabel(label);
|
|
654
|
+
}
|
|
655
|
+
async updateLabel(id, changes) {
|
|
656
|
+
return this.labelStorage.updateLabel(id, changes);
|
|
657
|
+
}
|
|
658
|
+
async deleteLabel(id) {
|
|
659
|
+
return this.labelStorage.deleteLabel(id);
|
|
660
|
+
}
|
|
661
|
+
async addLabelToTicket(ticketId, labelId) {
|
|
662
|
+
return this.labelStorage.addLabelToTicket(ticketId, labelId);
|
|
663
|
+
}
|
|
664
|
+
async removeLabelFromTicket(ticketId, labelId) {
|
|
665
|
+
return this.labelStorage.removeLabelFromTicket(ticketId, labelId);
|
|
666
|
+
}
|
|
667
|
+
async getLabelsForTicket(ticketId) {
|
|
668
|
+
return this.labelStorage.getLabelsForTicket(ticketId);
|
|
669
|
+
}
|
|
670
|
+
async addLabelToTicketByName(ticketId, labelName) {
|
|
671
|
+
return this.labelStorage.addLabelToTicketByName(ticketId, labelName);
|
|
672
|
+
}
|
|
673
|
+
async removeLabelFromTicketByName(ticketId, labelName) {
|
|
674
|
+
return this.labelStorage.removeLabelFromTicketByName(ticketId, labelName);
|
|
675
|
+
}
|
|
676
|
+
// ===========================================================================
|
|
619
677
|
// Sync Operations (no-op for pure SQLite)
|
|
620
678
|
// ===========================================================================
|
|
621
679
|
async pull() {
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Label storage operations for PMO.
|
|
3
|
+
* Handles CRUD for labels, label groups, and ticket-label associations.
|
|
4
|
+
* Enforces group exclusivity constraints.
|
|
5
|
+
*/
|
|
6
|
+
import { Label, LabelFilter, LabelGroup, LabelGroupFilter } from '../types.js';
|
|
7
|
+
import { StorageContext } from './types.js';
|
|
8
|
+
export declare class LabelStorage {
|
|
9
|
+
private ctx;
|
|
10
|
+
constructor(ctx: StorageContext);
|
|
11
|
+
listLabelGroups(filter?: LabelGroupFilter): Promise<LabelGroup[]>;
|
|
12
|
+
getLabelGroup(id: string): Promise<LabelGroup | null>;
|
|
13
|
+
getLabelGroupByName(name: string): Promise<LabelGroup | null>;
|
|
14
|
+
createLabelGroup(group: Partial<LabelGroup> & {
|
|
15
|
+
name: string;
|
|
16
|
+
}): Promise<LabelGroup>;
|
|
17
|
+
updateLabelGroup(id: string, changes: Partial<LabelGroup>): Promise<LabelGroup>;
|
|
18
|
+
deleteLabelGroup(id: string): Promise<void>;
|
|
19
|
+
listLabels(filter?: LabelFilter): Promise<Label[]>;
|
|
20
|
+
getLabel(id: string): Promise<Label | null>;
|
|
21
|
+
getLabelByName(name: string, groupId?: string): Promise<Label | null>;
|
|
22
|
+
createLabel(label: Partial<Label> & {
|
|
23
|
+
name: string;
|
|
24
|
+
}): Promise<Label>;
|
|
25
|
+
updateLabel(id: string, changes: Partial<Label>): Promise<Label>;
|
|
26
|
+
deleteLabel(id: string): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Add a label to a ticket.
|
|
29
|
+
* Enforces group exclusivity: if the label belongs to an exclusive group,
|
|
30
|
+
* removes any existing label from the same group first.
|
|
31
|
+
*/
|
|
32
|
+
addLabelToTicket(ticketId: string, labelId: string): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Remove a label from a ticket.
|
|
35
|
+
*/
|
|
36
|
+
removeLabelFromTicket(ticketId: string, labelId: string): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Get all labels for a ticket.
|
|
39
|
+
*/
|
|
40
|
+
getLabelsForTicket(ticketId: string): Promise<Label[]>;
|
|
41
|
+
/**
|
|
42
|
+
* Add a label to a ticket by name.
|
|
43
|
+
* Resolves the label name to an ID first.
|
|
44
|
+
* If the label name matches a group:label pattern, resolves within that group.
|
|
45
|
+
*/
|
|
46
|
+
addLabelToTicketByName(ticketId: string, labelName: string): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Remove a label from a ticket by name.
|
|
49
|
+
*/
|
|
50
|
+
removeLabelFromTicketByName(ticketId: string, labelName: string): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Resolve a label by name or group:name pattern.
|
|
53
|
+
*/
|
|
54
|
+
private resolveLabelByName;
|
|
55
|
+
}
|