@tacuchi/agent-workflow-cli 23.0.0 → 25.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -1
- package/dist/adapters/postgres-readonly-tools.js +277 -0
- package/dist/adapters/postgres-readonly-tools.js.map +1 -0
- package/dist/application/checkpoint/markdown.js +85 -5
- package/dist/application/checkpoint/markdown.js.map +1 -1
- package/dist/application/checkpoint-service.js +7 -6
- package/dist/application/checkpoint-service.js.map +1 -1
- package/dist/application/checkpoint-write-service.js +270 -16
- package/dist/application/checkpoint-write-service.js.map +1 -1
- package/dist/application/database-mcp-server.js +168 -0
- package/dist/application/database-mcp-server.js.map +1 -0
- package/dist/application/database-mcp-stdio.js +137 -0
- package/dist/application/database-mcp-stdio.js.map +1 -0
- package/dist/application/database-tool-catalog.js +226 -0
- package/dist/application/database-tool-catalog.js.map +1 -0
- package/dist/application/dsn-reader-service.js +1 -1
- package/dist/application/flow/advance.js +60 -10
- package/dist/application/flow/advance.js.map +1 -1
- package/dist/application/flow/internal-actions.js +1 -1
- package/dist/application/flow/internal-actions.js.map +1 -1
- package/dist/application/flow/submit.js +256 -9
- package/dist/application/flow/submit.js.map +1 -1
- package/dist/application/lifecycle-target.js +16 -19
- package/dist/application/lifecycle-target.js.map +1 -1
- package/dist/application/lock-service.js +96 -31
- package/dist/application/lock-service.js.map +1 -1
- package/dist/application/logging/log-events.js +19 -3
- package/dist/application/logging/log-events.js.map +1 -1
- package/dist/application/logging/logger.js +2 -2
- package/dist/application/logging/logger.js.map +1 -1
- package/dist/application/markdown.js +6 -2
- package/dist/application/markdown.js.map +1 -1
- package/dist/application/mcp-connections-service.js +115 -41
- package/dist/application/mcp-connections-service.js.map +1 -1
- package/dist/application/mcp-doctor-service.js +98 -54
- package/dist/application/mcp-doctor-service.js.map +1 -1
- package/dist/application/mcp-entry-classification.js +60 -0
- package/dist/application/mcp-entry-classification.js.map +1 -0
- package/dist/application/mcp-host-reader.js +102 -86
- package/dist/application/mcp-host-reader.js.map +1 -1
- package/dist/application/mcp-host-receipt-service.js +399 -0
- package/dist/application/mcp-host-receipt-service.js.map +1 -0
- package/dist/application/mcp-host-receipt-store.js +122 -0
- package/dist/application/mcp-host-receipt-store.js.map +1 -0
- package/dist/application/mcp-host-receipts.js +28 -0
- package/dist/application/mcp-host-receipts.js.map +1 -0
- package/dist/application/mcp-host-writer.js +209 -38
- package/dist/application/mcp-host-writer.js.map +1 -1
- package/dist/application/mcp-launch-probe-service.js +142 -0
- package/dist/application/mcp-launch-probe-service.js.map +1 -0
- package/dist/application/mcp-migration-service.js +351 -0
- package/dist/application/mcp-migration-service.js.map +1 -0
- package/dist/application/mcp-native-host-check-service.js +154 -0
- package/dist/application/mcp-native-host-check-service.js.map +1 -0
- package/dist/application/mcp-receipt-registration-service.js +105 -0
- package/dist/application/mcp-receipt-registration-service.js.map +1 -0
- package/dist/application/mcp-receipt-removal-service.js +62 -0
- package/dist/application/mcp-receipt-removal-service.js.map +1 -0
- package/dist/application/mcp-remove-service.js +83 -24
- package/dist/application/mcp-remove-service.js.map +1 -1
- package/dist/application/mcp-scope-common.js +1 -1
- package/dist/application/mcp-scope-common.js.map +1 -1
- package/dist/application/mcp-setup-service.js +59 -24
- package/dist/application/mcp-setup-service.js.map +1 -1
- package/dist/application/mcp-stdio-probe.js +526 -0
- package/dist/application/mcp-stdio-probe.js.map +1 -0
- package/dist/application/mcp-test-connection-service.js +23 -50
- package/dist/application/mcp-test-connection-service.js.map +1 -1
- package/dist/application/parsers/spec-functional.js +220 -0
- package/dist/application/parsers/spec-functional.js.map +1 -0
- package/dist/application/parsers/spec-relation.js +142 -5
- package/dist/application/parsers/spec-relation.js.map +1 -1
- package/dist/application/paths-service.js +13 -0
- package/dist/application/paths-service.js.map +1 -1
- package/dist/application/plan-exec-decision-service.js +57 -4
- package/dist/application/plan-exec-decision-service.js.map +1 -1
- package/dist/application/reseal-service.js +300 -0
- package/dist/application/reseal-service.js.map +1 -0
- package/dist/application/self/host-states.js.map +1 -1
- package/dist/application/self/install-skill.js +4 -34
- package/dist/application/self/install-skill.js.map +1 -1
- package/dist/application/self/mcp-config.js +369 -59
- package/dist/application/self/mcp-config.js.map +1 -1
- package/dist/application/self/mcp-via-state.js +9 -6
- package/dist/application/self/mcp-via-state.js.map +1 -1
- package/dist/application/self/uninstall-skill.js +3 -18
- package/dist/application/self/uninstall-skill.js.map +1 -1
- package/dist/application/self/uninstall.js +4 -23
- package/dist/application/self/uninstall.js.map +1 -1
- package/dist/application/workline-index-service.js +64 -6
- package/dist/application/workline-index-service.js.map +1 -1
- package/dist/application/workspace-init-service.js +4 -6
- package/dist/application/workspace-init-service.js.map +1 -1
- package/dist/cli/commands/checkpoint-write.js +24 -22
- package/dist/cli/commands/checkpoint-write.js.map +1 -1
- package/dist/cli/commands/index.js +7 -0
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/mcp.js +642 -55
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/reseal.js +140 -0
- package/dist/cli/commands/reseal.js.map +1 -0
- package/dist/cli/commands/status.js +5 -1
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/tool.js +141 -0
- package/dist/cli/commands/tool.js.map +1 -0
- package/dist/cli/help-groups.js +7 -1
- package/dist/cli/help-groups.js.map +1 -1
- package/dist/cli/main.js +189 -57
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/parser.js +5 -1
- package/dist/cli/parser.js.map +1 -1
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli/render.js +15 -2
- package/dist/cli/render.js.map +1 -1
- package/dist/cli/tui/components/host-admin-section.js +2 -46
- package/dist/cli/tui/components/host-admin-section.js.map +1 -1
- package/dist/cli/tui/tabs/mcp-tab-helpers.js +71 -0
- package/dist/cli/tui/tabs/mcp-tab-helpers.js.map +1 -1
- package/dist/cli/tui/tabs/mcp-tab.js +101 -42
- package/dist/cli/tui/tabs/mcp-tab.js.map +1 -1
- package/dist/domain/database-tools.js +445 -0
- package/dist/domain/database-tools.js.map +1 -0
- package/dist/domain/effective-contract.js +10 -2
- package/dist/domain/effective-contract.js.map +1 -1
- package/dist/domain/flow/answer.js +4 -0
- package/dist/domain/flow/answer.js.map +1 -1
- package/dist/domain/flow/authority.js +103 -14
- package/dist/domain/flow/authority.js.map +1 -1
- package/dist/domain/flow/directive.js +2 -0
- package/dist/domain/flow/directive.js.map +1 -1
- package/dist/domain/flow/run-state.js +42 -0
- package/dist/domain/flow/run-state.js.map +1 -1
- package/dist/domain/lineage.js +38 -11
- package/dist/domain/lineage.js.map +1 -1
- package/dist/domain/mcp-entry.js +131 -17
- package/dist/domain/mcp-entry.js.map +1 -1
- package/dist/domain/postgres-object-search.js +320 -0
- package/dist/domain/postgres-object-search.js.map +1 -0
- package/dist/domain/redaction.js +47 -0
- package/dist/domain/redaction.js.map +1 -0
- package/dist/domain/workline-mcp-entry.js +6 -9
- package/dist/domain/workline-mcp-entry.js.map +1 -1
- package/dist/ports/postgres-tools.js +10 -0
- package/dist/ports/postgres-tools.js.map +1 -0
- package/package.json +5 -1
- package/skills/w/commands/plan-exec.md +1 -1
- package/skills/w/commands/spec-new.md +6 -5
- package/skills/w/context/MANIFEST.json +1 -1
- package/skills/w/harness/HARNESS.md +1 -1
- package/skills/w/hooks/README.md +13 -9
- package/skills/w/hooks/hooks.template.json +2 -2
- package/skills/w/loops/CHASSIS.md +1 -1
- package/skills/w/loops/plan-exec-loop/LOOP.md +7 -5
- package/skills/w/loops/plan-new-loop/LOOP.md +46 -41
- package/skills/w/loops/plan-refine-loop/LOOP.md +4 -4
- package/skills/w/loops/quick-loop/LOOP.md +12 -13
- package/skills/w/loops/spec-refine-loop/LOOP.md +7 -3
- package/skills/w/modules/COMPACTION.md +1 -1
- package/skills/w/modules/PLAN-INPUT.md +3 -3
- package/skills/w/modules/PROMPT-CONTINUITY.md +1 -1
- package/dist/application/mcp-dbhub-launcher.js +0 -216
- package/dist/application/mcp-dbhub-launcher.js.map +0 -1
- package/dist/application/self/mcp-offer.js +0 -96
- package/dist/application/self/mcp-offer.js.map +0 -1
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
const EXCLUDED_SCHEMAS = "'pg_catalog', 'information_schema', 'pg_toast'";
|
|
2
|
+
/**
|
|
3
|
+
* Builds the PostgreSQL equivalents of DBHub 1.2.1's object discovery
|
|
4
|
+
* queries. All user-provided filters remain placeholders; the only SQL text
|
|
5
|
+
* selected here comes from the closed tool schema.
|
|
6
|
+
*/
|
|
7
|
+
export function buildPostgresObjectSearchQuery(input) {
|
|
8
|
+
switch (input.object_type) {
|
|
9
|
+
case "schema":
|
|
10
|
+
return schemaQuery(input);
|
|
11
|
+
case "table":
|
|
12
|
+
return relationQuery(input, "table");
|
|
13
|
+
case "view":
|
|
14
|
+
return relationQuery(input, "view");
|
|
15
|
+
case "column":
|
|
16
|
+
return columnQuery(input);
|
|
17
|
+
case "procedure":
|
|
18
|
+
return routineQuery(input, "procedure");
|
|
19
|
+
case "function":
|
|
20
|
+
return routineQuery(input, "function");
|
|
21
|
+
case "index":
|
|
22
|
+
return indexQuery(input);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* `pg` maps nullable catalog columns to null, while DBHub omits optional
|
|
27
|
+
* comment/description/routine fields. Keep required nullable fields such as
|
|
28
|
+
* `row_count` and `default` intact so the public shape stays compatible.
|
|
29
|
+
*/
|
|
30
|
+
export function normalizePostgresObjectSearchRows(_input, rows) {
|
|
31
|
+
return rows.map((row) => {
|
|
32
|
+
const normalized = { ...row };
|
|
33
|
+
dropOptional(normalized, "comment");
|
|
34
|
+
dropOptional(normalized, "description");
|
|
35
|
+
dropOptional(normalized, "return_type");
|
|
36
|
+
dropOptional(normalized, "definition");
|
|
37
|
+
return normalized;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function dropOptional(row, field) {
|
|
41
|
+
const value = row[field];
|
|
42
|
+
if (value === null || value === undefined || value === "")
|
|
43
|
+
delete row[field];
|
|
44
|
+
}
|
|
45
|
+
function schemaQuery(input) {
|
|
46
|
+
if (input.detail_level === "names") {
|
|
47
|
+
return {
|
|
48
|
+
sql: `SELECT schema_info.schema_name AS name
|
|
49
|
+
FROM information_schema.schemata schema_info
|
|
50
|
+
WHERE schema_info.schema_name NOT IN (${EXCLUDED_SCHEMAS})
|
|
51
|
+
AND schema_info.schema_name ILIKE $1
|
|
52
|
+
ORDER BY schema_info.schema_name ASC
|
|
53
|
+
LIMIT $2`,
|
|
54
|
+
values: [input.pattern, input.limit],
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
sql: `SELECT schema_info.schema_name AS name,
|
|
59
|
+
count(table_info.table_name)::integer AS table_count
|
|
60
|
+
FROM information_schema.schemata schema_info
|
|
61
|
+
LEFT JOIN information_schema.tables table_info
|
|
62
|
+
ON table_info.table_schema = schema_info.schema_name
|
|
63
|
+
AND table_info.table_type = 'BASE TABLE'
|
|
64
|
+
WHERE schema_info.schema_name NOT IN (${EXCLUDED_SCHEMAS})
|
|
65
|
+
AND schema_info.schema_name ILIKE $1
|
|
66
|
+
GROUP BY schema_info.schema_name
|
|
67
|
+
ORDER BY schema_info.schema_name ASC
|
|
68
|
+
LIMIT $2`,
|
|
69
|
+
values: [input.pattern, input.limit],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function relationQuery(input, objectType) {
|
|
73
|
+
const values = [input.pattern];
|
|
74
|
+
const conditions = [
|
|
75
|
+
`relation_info.table_type = '${objectType === "table" ? "BASE TABLE" : "VIEW"}'`,
|
|
76
|
+
`relation_info.table_schema NOT IN (${EXCLUDED_SCHEMAS})`,
|
|
77
|
+
"relation_info.table_name ILIKE $1",
|
|
78
|
+
];
|
|
79
|
+
if (input.schema !== undefined) {
|
|
80
|
+
values.push(input.schema);
|
|
81
|
+
conditions.push(`relation_info.table_schema = $${values.length}`);
|
|
82
|
+
}
|
|
83
|
+
values.push(input.limit);
|
|
84
|
+
return {
|
|
85
|
+
sql: `SELECT ${relationFields(objectType, input.detail_level)}
|
|
86
|
+
FROM information_schema.tables relation_info
|
|
87
|
+
JOIN pg_catalog.pg_namespace relation_namespace
|
|
88
|
+
ON relation_namespace.nspname = relation_info.table_schema
|
|
89
|
+
JOIN pg_catalog.pg_class relation_class
|
|
90
|
+
ON relation_class.relnamespace = relation_namespace.oid
|
|
91
|
+
AND relation_class.relname = relation_info.table_name
|
|
92
|
+
WHERE ${conditions.join(" AND ")}
|
|
93
|
+
ORDER BY relation_info.table_schema ASC, relation_info.table_name ASC
|
|
94
|
+
LIMIT $${values.length}`,
|
|
95
|
+
values,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function relationFields(objectType, detail) {
|
|
99
|
+
const names = "relation_info.table_name AS name, relation_info.table_schema AS schema";
|
|
100
|
+
if (detail === "names")
|
|
101
|
+
return names;
|
|
102
|
+
const summary = [
|
|
103
|
+
names,
|
|
104
|
+
`(
|
|
105
|
+
SELECT count(*)::integer
|
|
106
|
+
FROM information_schema.columns column_info
|
|
107
|
+
WHERE column_info.table_schema = relation_info.table_schema
|
|
108
|
+
AND column_info.table_name = relation_info.table_name
|
|
109
|
+
) AS column_count`,
|
|
110
|
+
...(objectType === "table"
|
|
111
|
+
? [
|
|
112
|
+
`CASE
|
|
113
|
+
WHEN relation_class.reltuples >= 0 THEN relation_class.reltuples::bigint::double precision
|
|
114
|
+
ELSE NULL
|
|
115
|
+
END AS row_count`,
|
|
116
|
+
]
|
|
117
|
+
: []),
|
|
118
|
+
"obj_description(relation_class.oid, 'pg_class') AS comment",
|
|
119
|
+
];
|
|
120
|
+
if (detail === "summary")
|
|
121
|
+
return summary.join(",\n ");
|
|
122
|
+
const columns = `COALESCE((
|
|
123
|
+
SELECT jsonb_agg(
|
|
124
|
+
jsonb_build_object(
|
|
125
|
+
'name', column_info.column_name,
|
|
126
|
+
'type', column_info.data_type,
|
|
127
|
+
'nullable', column_info.is_nullable = 'YES',
|
|
128
|
+
'default', column_info.column_default
|
|
129
|
+
) || CASE
|
|
130
|
+
WHEN column_description.description IS NULL THEN '{}'::jsonb
|
|
131
|
+
ELSE jsonb_build_object('description', column_description.description)
|
|
132
|
+
END
|
|
133
|
+
ORDER BY column_info.ordinal_position
|
|
134
|
+
)
|
|
135
|
+
FROM information_schema.columns column_info
|
|
136
|
+
LEFT JOIN pg_catalog.pg_description column_description
|
|
137
|
+
ON column_description.objoid = relation_class.oid
|
|
138
|
+
AND column_description.objsubid = column_info.ordinal_position
|
|
139
|
+
WHERE column_info.table_schema = relation_info.table_schema
|
|
140
|
+
AND column_info.table_name = relation_info.table_name
|
|
141
|
+
), '[]'::jsonb) AS columns`;
|
|
142
|
+
const indexes = objectType === "table"
|
|
143
|
+
? `COALESCE((
|
|
144
|
+
SELECT jsonb_agg(
|
|
145
|
+
jsonb_build_object(
|
|
146
|
+
'name', index_info.name,
|
|
147
|
+
'columns', index_info.columns,
|
|
148
|
+
'unique', index_info.unique,
|
|
149
|
+
'primary', index_info.primary
|
|
150
|
+
)
|
|
151
|
+
ORDER BY index_info.name
|
|
152
|
+
)
|
|
153
|
+
FROM (
|
|
154
|
+
SELECT index_class.relname AS name,
|
|
155
|
+
array_agg(attribute.attname ORDER BY indexed_attribute.ordinality) AS columns,
|
|
156
|
+
index_definition.indisunique AS unique,
|
|
157
|
+
index_definition.indisprimary AS primary
|
|
158
|
+
FROM pg_catalog.pg_index index_definition
|
|
159
|
+
JOIN pg_catalog.pg_class index_class ON index_class.oid = index_definition.indexrelid
|
|
160
|
+
CROSS JOIN LATERAL unnest(index_definition.indkey) WITH ORDINALITY
|
|
161
|
+
AS indexed_attribute(attnum, ordinality)
|
|
162
|
+
JOIN pg_catalog.pg_attribute attribute
|
|
163
|
+
ON attribute.attrelid = relation_class.oid
|
|
164
|
+
AND attribute.attnum = indexed_attribute.attnum
|
|
165
|
+
AND attribute.attnum > 0
|
|
166
|
+
AND NOT attribute.attisdropped
|
|
167
|
+
WHERE index_definition.indrelid = relation_class.oid
|
|
168
|
+
GROUP BY index_class.relname, index_definition.indisunique, index_definition.indisprimary
|
|
169
|
+
) index_info
|
|
170
|
+
), '[]'::jsonb) AS indexes`
|
|
171
|
+
: "'[]'::jsonb AS indexes";
|
|
172
|
+
return [...summary, columns, indexes].join(",\n ");
|
|
173
|
+
}
|
|
174
|
+
function columnQuery(input) {
|
|
175
|
+
const values = [input.pattern];
|
|
176
|
+
const conditions = [
|
|
177
|
+
"column_info.column_name ILIKE $1",
|
|
178
|
+
`column_info.table_schema NOT IN (${EXCLUDED_SCHEMAS})`,
|
|
179
|
+
"relation_info.table_type IN ('BASE TABLE', 'VIEW')",
|
|
180
|
+
];
|
|
181
|
+
if (input.schema !== undefined) {
|
|
182
|
+
values.push(input.schema);
|
|
183
|
+
conditions.push(`column_info.table_schema = $${values.length}`);
|
|
184
|
+
}
|
|
185
|
+
if (input.table !== undefined) {
|
|
186
|
+
values.push(input.table);
|
|
187
|
+
conditions.push(`column_info.table_name = $${values.length}`);
|
|
188
|
+
}
|
|
189
|
+
values.push(input.limit);
|
|
190
|
+
const fields = input.detail_level === "names"
|
|
191
|
+
? 'column_info.column_name AS name, column_info.table_name AS "table", column_info.table_schema AS schema'
|
|
192
|
+
: `column_info.column_name AS name,
|
|
193
|
+
column_info.table_name AS "table",
|
|
194
|
+
column_info.table_schema AS schema,
|
|
195
|
+
column_info.data_type AS type,
|
|
196
|
+
column_info.is_nullable = 'YES' AS nullable,
|
|
197
|
+
column_info.column_default AS "default",
|
|
198
|
+
column_description.description AS description`;
|
|
199
|
+
return {
|
|
200
|
+
sql: `SELECT ${fields}
|
|
201
|
+
FROM information_schema.columns column_info
|
|
202
|
+
JOIN information_schema.tables relation_info
|
|
203
|
+
ON relation_info.table_schema = column_info.table_schema
|
|
204
|
+
AND relation_info.table_name = column_info.table_name
|
|
205
|
+
LEFT JOIN pg_catalog.pg_namespace relation_namespace
|
|
206
|
+
ON relation_namespace.nspname = column_info.table_schema
|
|
207
|
+
LEFT JOIN pg_catalog.pg_class relation_class
|
|
208
|
+
ON relation_class.relnamespace = relation_namespace.oid
|
|
209
|
+
AND relation_class.relname = column_info.table_name
|
|
210
|
+
LEFT JOIN pg_catalog.pg_description column_description
|
|
211
|
+
ON column_description.objoid = relation_class.oid
|
|
212
|
+
AND column_description.objsubid = column_info.ordinal_position
|
|
213
|
+
WHERE ${conditions.join(" AND ")}
|
|
214
|
+
ORDER BY column_info.table_schema ASC,
|
|
215
|
+
CASE WHEN relation_info.table_type = 'BASE TABLE' THEN 0 ELSE 1 END ASC,
|
|
216
|
+
column_info.table_name ASC,
|
|
217
|
+
column_info.ordinal_position ASC
|
|
218
|
+
LIMIT $${values.length}`,
|
|
219
|
+
values,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
function routineQuery(input, objectType) {
|
|
223
|
+
const values = [input.pattern];
|
|
224
|
+
const routineType = objectType === "procedure" ? "PROCEDURE" : "FUNCTION";
|
|
225
|
+
const conditions = [
|
|
226
|
+
`routine_info.routine_type = '${routineType}'`,
|
|
227
|
+
`routine_info.routine_schema NOT IN (${EXCLUDED_SCHEMAS})`,
|
|
228
|
+
"routine_info.routine_name ILIKE $1",
|
|
229
|
+
];
|
|
230
|
+
if (input.schema !== undefined) {
|
|
231
|
+
values.push(input.schema);
|
|
232
|
+
conditions.push(`routine_info.routine_schema = $${values.length}`);
|
|
233
|
+
}
|
|
234
|
+
values.push(input.limit);
|
|
235
|
+
const names = "routine_info.routine_name AS name, routine_info.routine_schema AS schema";
|
|
236
|
+
const fields = input.detail_level === "names"
|
|
237
|
+
? names
|
|
238
|
+
: `${names},
|
|
239
|
+
CASE WHEN routine_info.routine_type = 'PROCEDURE' THEN 'procedure' ELSE 'function' END AS type,
|
|
240
|
+
COALESCE(routine_info.external_language, 'sql') AS language,
|
|
241
|
+
CASE WHEN routine_info.data_type = 'void' THEN NULL ELSE routine_info.data_type END AS return_type${input.detail_level === "full"
|
|
242
|
+
? `,
|
|
243
|
+
COALESCE((
|
|
244
|
+
SELECT string_agg(
|
|
245
|
+
parameter_info.parameter_name || ' ' || parameter_info.parameter_mode || ' ' || parameter_info.data_type,
|
|
246
|
+
', ' ORDER BY parameter_info.ordinal_position
|
|
247
|
+
)
|
|
248
|
+
FROM information_schema.parameters parameter_info
|
|
249
|
+
WHERE parameter_info.specific_schema = routine_info.specific_schema
|
|
250
|
+
AND parameter_info.specific_name = routine_info.specific_name
|
|
251
|
+
AND parameter_info.parameter_name IS NOT NULL
|
|
252
|
+
), '') AS parameters,
|
|
253
|
+
NULLIF(routine_info.routine_definition, '') AS definition`
|
|
254
|
+
: ""}`;
|
|
255
|
+
return {
|
|
256
|
+
sql: `SELECT ${fields}
|
|
257
|
+
FROM information_schema.routines routine_info
|
|
258
|
+
WHERE ${conditions.join(" AND ")}
|
|
259
|
+
ORDER BY routine_info.routine_schema ASC,
|
|
260
|
+
routine_info.routine_name ASC,
|
|
261
|
+
routine_info.specific_name ASC
|
|
262
|
+
LIMIT $${values.length}`,
|
|
263
|
+
values,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
function indexQuery(input) {
|
|
267
|
+
const values = [input.pattern];
|
|
268
|
+
const conditions = [
|
|
269
|
+
"index_class.relname ILIKE $1",
|
|
270
|
+
`relation_info.table_schema NOT IN (${EXCLUDED_SCHEMAS})`,
|
|
271
|
+
"relation_info.table_type = 'BASE TABLE'",
|
|
272
|
+
];
|
|
273
|
+
if (input.schema !== undefined) {
|
|
274
|
+
values.push(input.schema);
|
|
275
|
+
conditions.push(`relation_info.table_schema = $${values.length}`);
|
|
276
|
+
}
|
|
277
|
+
if (input.table !== undefined) {
|
|
278
|
+
values.push(input.table);
|
|
279
|
+
conditions.push(`relation_info.table_name = $${values.length}`);
|
|
280
|
+
}
|
|
281
|
+
values.push(input.limit);
|
|
282
|
+
const names = 'index_class.relname AS name, relation_info.table_name AS "table", relation_info.table_schema AS schema';
|
|
283
|
+
const fields = input.detail_level === "names"
|
|
284
|
+
? names
|
|
285
|
+
: `${names},
|
|
286
|
+
array_agg(attribute.attname ORDER BY indexed_attribute.ordinality) AS columns,
|
|
287
|
+
index_definition.indisunique AS unique,
|
|
288
|
+
index_definition.indisprimary AS primary`;
|
|
289
|
+
return {
|
|
290
|
+
sql: `SELECT ${fields}
|
|
291
|
+
FROM information_schema.tables relation_info
|
|
292
|
+
JOIN pg_catalog.pg_namespace relation_namespace
|
|
293
|
+
ON relation_namespace.nspname = relation_info.table_schema
|
|
294
|
+
JOIN pg_catalog.pg_class relation_class
|
|
295
|
+
ON relation_class.relnamespace = relation_namespace.oid
|
|
296
|
+
AND relation_class.relname = relation_info.table_name
|
|
297
|
+
JOIN pg_catalog.pg_index index_definition ON index_definition.indrelid = relation_class.oid
|
|
298
|
+
JOIN pg_catalog.pg_class index_class ON index_class.oid = index_definition.indexrelid
|
|
299
|
+
CROSS JOIN LATERAL unnest(index_definition.indkey) WITH ORDINALITY
|
|
300
|
+
AS indexed_attribute(attnum, ordinality)
|
|
301
|
+
JOIN pg_catalog.pg_attribute attribute
|
|
302
|
+
ON attribute.attrelid = relation_class.oid
|
|
303
|
+
AND attribute.attnum = indexed_attribute.attnum
|
|
304
|
+
AND attribute.attnum > 0
|
|
305
|
+
AND NOT attribute.attisdropped
|
|
306
|
+
WHERE ${conditions.join(" AND ")}
|
|
307
|
+
GROUP BY index_class.relname,
|
|
308
|
+
relation_info.table_name,
|
|
309
|
+
relation_info.table_schema,
|
|
310
|
+
index_definition.indisunique,
|
|
311
|
+
index_definition.indisprimary,
|
|
312
|
+
index_definition.indkey
|
|
313
|
+
ORDER BY relation_info.table_schema ASC,
|
|
314
|
+
relation_info.table_name ASC,
|
|
315
|
+
index_class.relname ASC
|
|
316
|
+
LIMIT $${values.length}`,
|
|
317
|
+
values,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=postgres-object-search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-object-search.js","sourceRoot":"","sources":["../../src/domain/postgres-object-search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure last-line defense for values that may be reflected in operational logs
|
|
3
|
+
* or CLI errors. Domain validation still avoids echoing untrusted values; this
|
|
4
|
+
* catches URI and assignment-shaped credentials from unexpected call paths.
|
|
5
|
+
*/
|
|
6
|
+
const CONNECTION_URI = /\b((?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?):\/\/)[^\s"'<>]+/gi;
|
|
7
|
+
const SECRET_ASSIGNMENT = /((?:--?(?:token|secret|password|passwd|pwd|api[-_]?key|key|auth(?:orization)?|dsn|database[-_]?url|pgpassword|pgpassfile)|["']?(?:token|secret|password|passwd|pwd|api[-_]?key|key|auth(?:orization)?|dsn|database[-_]?url|pgpassword|pgpassfile)["']?)\s*(?:=|:|\s+)\s*)(?:"[^"]*"|'[^']*'|[^\s,}\]]+)/gi;
|
|
8
|
+
const SENSITIVE_KEY = /(?:^|_)(?:access_key|api_key|auth(?:orization)?|client_secret|connection_string|connection_url|connectionstring|connectionurl|credential(?:s)?|database_url|databaseurl|dsn|key|password|passwd|pgpassfile|pgpassword|private_key|pwd|secret|secrets|token|tokens)(?:_|$)/i;
|
|
9
|
+
export function redactSensitiveText(text) {
|
|
10
|
+
return text
|
|
11
|
+
.replace(CONNECTION_URI, "$1***")
|
|
12
|
+
.replace(SECRET_ASSIGNMENT, "$1***")
|
|
13
|
+
.replace(/\bBearer\s+\S+/gi, "Bearer ***");
|
|
14
|
+
}
|
|
15
|
+
/** Detect semantic secret fields even when their opaque value has no recognizable syntax. */
|
|
16
|
+
export function isSensitiveKey(key) {
|
|
17
|
+
const normalized = key
|
|
18
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1_$2")
|
|
19
|
+
.replace(/[-\s]+/g, "_")
|
|
20
|
+
.toLowerCase();
|
|
21
|
+
return SENSITIVE_KEY.test(normalized);
|
|
22
|
+
}
|
|
23
|
+
/** Safe predicate for configuration shapes that must never reflect credentials. */
|
|
24
|
+
export function containsSensitiveData(value) {
|
|
25
|
+
if (typeof value === "string")
|
|
26
|
+
return redactSensitiveText(value) !== value;
|
|
27
|
+
if (Array.isArray(value))
|
|
28
|
+
return value.some(containsSensitiveData);
|
|
29
|
+
if (value !== null && typeof value === "object") {
|
|
30
|
+
return Object.entries(value).some(([key, nested]) => isSensitiveKey(key) || containsSensitiveData(nested));
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
export function redactSensitiveValue(value) {
|
|
35
|
+
if (typeof value === "string")
|
|
36
|
+
return redactSensitiveText(value);
|
|
37
|
+
if (Array.isArray(value))
|
|
38
|
+
return value.map(redactSensitiveValue);
|
|
39
|
+
if (value !== null && typeof value === "object") {
|
|
40
|
+
return Object.fromEntries(Object.entries(value).map(([key, nested]) => [
|
|
41
|
+
key,
|
|
42
|
+
isSensitiveKey(key) ? "***" : redactSensitiveValue(nested),
|
|
43
|
+
]));
|
|
44
|
+
}
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=redaction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redaction.js","sourceRoot":"","sources":["../../src/domain/redaction.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,cAAc,GAAG,kEAAkE,CAAC;AAC1F,MAAM,iBAAiB,GACrB,2SAA2S,CAAC;AAC9S,MAAM,aAAa,GACjB,4QAA4Q,CAAC;AAE/Q,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,IAAI;SACR,OAAO,CAAC,cAAc,EAAE,OAAO,CAAC;SAChC,OAAO,CAAC,iBAAiB,EAAE,OAAO,CAAC;SACnC,OAAO,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC;AAC/C,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,MAAM,UAAU,GAAG,GAAG;SACnB,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;SACtC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,WAAW,EAAE,CAAC;IACjB,OAAO,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AACxC,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,qBAAqB,CAAC,KAAc;IAClD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,mBAAmB,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC;IAC3E,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IACnE,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAC/B,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,qBAAqB,CAAC,MAAM,CAAC,CACxE,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,KAAc;IACjD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACjE,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IACjE,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC;YAC3C,GAAG;YACH,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC;SAC3D,CAAC,CACH,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* La entrada con la que un host
|
|
2
|
+
* La entrada histórica con la que un host ofrecía el servidor de elicitation.
|
|
3
3
|
*
|
|
4
|
-
* Se
|
|
5
|
-
*
|
|
6
|
-
* el comando difirieran entre ellas, instalar dejaría una que retirar no encuentra
|
|
7
|
-
* y observar informaría sobre otra.
|
|
4
|
+
* Se conserva para reconocer esa forma con exactitud. La instalación de skills no
|
|
5
|
+
* vuelve a escribirla: un descriptor MCP global requiere una acción explícita.
|
|
8
6
|
*
|
|
9
7
|
* El comando es el propio binario del CLI, con el envoltorio de Windows que
|
|
10
|
-
* `buildMcpEntry` ya resolvió para el
|
|
8
|
+
* `buildMcpEntry` ya resolvió para el servidor de base de datos: allá el bin global es un
|
|
11
9
|
* `.cmd`, y un host que lo lanza sin shell falla con ENOENT. Repetir el criterio
|
|
12
10
|
* es reusar una decisión ya probada, no copiar código.
|
|
13
11
|
*/
|
|
@@ -20,9 +18,8 @@
|
|
|
20
18
|
*/
|
|
21
19
|
export const WORKLINE_MCP_ENTRY_NAME = "agent-workflow";
|
|
22
20
|
/**
|
|
23
|
-
* El host
|
|
24
|
-
* adentro
|
|
25
|
-
* identifique. Así habilita sólo una vía de elicitation observada para ese host.
|
|
21
|
+
* El host viajaba en los argumentos porque el servidor no podía detectarlo desde
|
|
22
|
+
* adentro. Esta forma existe sólo como firma de una configuración legacy.
|
|
26
23
|
*/
|
|
27
24
|
export function worklineMcpEntry(host, platform = process.platform) {
|
|
28
25
|
const isWin = platform === "win32";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workline-mcp-entry.js","sourceRoot":"","sources":["../../src/domain/workline-mcp-entry.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"workline-mcp-entry.js","sourceRoot":"","sources":["../../src/domain/workline-mcp-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,gBAAgB,CAAC;AAExD;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,WAAmB,OAAO,CAAC,QAAQ;IAChF,MAAM,KAAK,GAAG,QAAQ,KAAK,OAAO,CAAC;IACnC,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC/C,OAAO;QACL,IAAI,EAAE,uBAAuB;QAC7B,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,gBAAgB;QACzC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,gBAAgB,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK;QACxD,GAAG,EAAE,EAAE;KACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** A driver-safe failure that can cross the PostgreSQL seam without secrets. */
|
|
2
|
+
export class PostgresToolError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
constructor(code, message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.code = code;
|
|
7
|
+
this.name = "PostgresToolError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=postgres-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-tools.js","sourceRoot":"","sources":["../../src/ports/postgres-tools.ts"],"names":[],"mappings":"AAeA,gFAAgF;AAChF,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAE/B;IADX,YACW,IAAY,EACrB,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAHN,SAAI,GAAJ,IAAI,CAAQ;QAIrB,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tacuchi/agent-workflow-cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "25.0.0",
|
|
4
4
|
"description": "Runtime CLI for Workline — the stages + loops + artifacts system for agent work. Bundles the universal `w` skill set under `skills/w/` (slash commands `/w:*`: spec-new/spec-refine, plan-new/plan-exec, quick, persist, workspace-init, export-*); `self install --target <host>` copies SKILL + commands + hooks into the host. Pluggable capability skills resolve through `.workflow/skills.toml`. Namespace auto-detected from any `.<ns>/sessions/` dir in CWD; default `workflow`.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -47,6 +47,8 @@
|
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@biomejs/biome": "^1.9.4",
|
|
49
49
|
"@types/node": "^22.10.5",
|
|
50
|
+
"@types/pg": "^8.23.1",
|
|
51
|
+
"@types/pg-cursor": "^2.7.2",
|
|
50
52
|
"@types/react": "^18.3.28",
|
|
51
53
|
"ink-testing-library": "^4.0.0",
|
|
52
54
|
"typescript": "^5.7.3",
|
|
@@ -59,6 +61,8 @@
|
|
|
59
61
|
"@inkjs/ui": "^2.0.0",
|
|
60
62
|
"@inquirer/prompts": "^7.10.1",
|
|
61
63
|
"ink": "^5.2.1",
|
|
64
|
+
"pg": "^8.23.0",
|
|
65
|
+
"pg-cursor": "^2.22.0",
|
|
62
66
|
"react": "^18.3.1",
|
|
63
67
|
"smol-toml": "^1.6.1"
|
|
64
68
|
}
|
|
@@ -37,7 +37,7 @@ checkboxes and `> Estado:` line in the living plan.
|
|
|
37
37
|
## Two gates that send work back
|
|
38
38
|
|
|
39
39
|
- **Entry gate** — a plan that would force execution to invent its own structure is not run in silence. A minor gap is normalized **with your consent**; a structural one hands off to `/w:plan-refine`.
|
|
40
|
-
- **Deviation gate** —
|
|
40
|
+
- **Deviation gate** — the loop owns it, with **four** exits. Local detail is resolved inline. A divergence that leaves the promise intact registers a decision note on `S{NNN}/AC-nn` and execution continues. A **structural** one (a contract, the components, the phase order, the simulation boundary) returns to `/w:plan-refine`; a moved **promise of the product** (result, scope, business rule, the outcome a criterion states) returns to `/w:spec-refine`. What does not compose against this lineage at all escalates to a spec of its own.
|
|
41
41
|
|
|
42
42
|
## More context
|
|
43
43
|
|
|
@@ -56,8 +56,8 @@ Systems / components / sources involved. Known constraints.
|
|
|
56
56
|
- Out: what is NOT included
|
|
57
57
|
|
|
58
58
|
## Acceptance criteria
|
|
59
|
-
- [ ]
|
|
60
|
-
- [ ]
|
|
59
|
+
- [ ] AC-01: functional outcome (EARS style recommended; behavioral ones expand in ## Scenarios)
|
|
60
|
+
- [ ] AC-02: …
|
|
61
61
|
|
|
62
62
|
## Scenarios (opt.)
|
|
63
63
|
Behavior made concrete — GIVEN/WHEN/THEN/AND blocks; each traces to ≥1 acceptance criterion.
|
|
@@ -86,10 +86,11 @@ Pending doubts. ← the spec-refine-loop closes them.
|
|
|
86
86
|
- `Scope` always carries `Out`.
|
|
87
87
|
- **Where the reconnaissance lands** — `Context`: the facts that place the request (sources apparently involved, a module's observed responsibility, the relevant technology), **at most one path per component** as an anchor, never a technical inventory. `Assumptions`: the inferences that let the draft advance. `Open questions`: what would need walking the implementation, a human decision, or an unavailable source.
|
|
88
88
|
- **The code found never widens `Scope`** and never becomes a requirement: **acceptance criteria derive from the user's intent**. The reconnaissance may lend vocabulary, name existing actors and boundaries, and avoid obvious contradictions. It must not invent behavior nobody asked for, turn a current technical decision into a user requirement, or impose an implementation as a criterion.
|
|
89
|
-
- **Acceptance criteria =
|
|
90
|
-
- **
|
|
89
|
+
- **Acceptance criteria = functional, observable outcomes at product level** (the "what"), each labeled `AC-nn`. **That label is what makes it addressable**: a decision note amends it as `S{NNN}/AC-nn`, and the CLI derives the `S{NNN}` from this spec's own file number — spelling the full id on the criterion line is accepted too, never counted twice. What is unaddressable is a criterion with **no label**, and a note naming one the spec does not state is refused with `CONTRACT_ASSERTION_ABSENT`. **The verification strategy — tests, evidence, commands — is the PLAN's** (its `## Validations`): here goes the outcome, there goes how it is proven. Progress is tracked in the PLAN (its Tasks), never by ticking these `- [ ]`; the spec never mutates by execution, only by a re-refine.
|
|
90
|
+
- **A criterion never fixes** a commit SHA or a third-party version as a fact of the contract, a file inventory, or an internal mechanism (a lock, a CAS, the name of a class/function/internal module). **The visible surface IS functional behavior**: for a CLI or an API, its commands, flags, observable messages and output formats are legitimate criteria — what stays out are the internal modules and mechanisms that implement them.
|
|
91
|
+
- **Scenarios = behavior made concrete** (uppercase GIVEN/WHEN/THEN/AND): draft them only when the prompt already describes behavior — deriving the rest is spec-refine work. A scenario earns its place only when it adds GIVEN setup or edge semantics the criterion does not capture — **never restate a criterion 1:1**. They illustrate behavior and **feed** the test derivation `plan-new` does; they are not themselves the executable suite.
|
|
91
92
|
- If **UI** is involved, **record the need and stop there**: mention it in `Requirement`/`Context`. This command creates **no design package** and writes no `## Design references` — the design is composed in `spec-refine` (via the [`design`](../roles/design/ROLE.md) capability, which publishes the package the spec then references). Minting a package from a draft would pin an identity before the requirement is even closed. "UI unspecified" is a first-class refinement gap.
|
|
92
|
-
- The **gaps** the loop detects = weak sections of the schema (vague Requirement, Scope without `Out`,
|
|
93
|
+
- The **gaps** the loop detects = weak sections of the schema (vague Requirement, Scope without `Out`, criteria whose outcome is not observable, open questions, undeclared assumptions, contradictions) **+ UI unspecified** when the requirement involves UI.
|
|
93
94
|
- Equivalent alternative: the user writes the draft by hand. Both paths produce the same file.
|
|
94
95
|
|
|
95
96
|
> **Reuse by escalation:** the live escalation from `/w:quick` (see [`../loops/quick-loop/LOOP.md`](../loops/quick-loop/LOOP.md) § *QUICK delta*) materializes its draft with **this same procedure** (same schema, same single-pass hard rule — **NO RESEARCH**, no reconnaissance: objective and context arrive adopted), with `## Origin` = "escalated from `/w:quick`" + the original prompt. The consent in the structured-choice equals invoking this command.
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"plan.entry-gap-minor": "the plan is all but executable: the gap is derivable from what it already states, so it can be normalized in place",
|
|
52
52
|
"plan.entry-gap-structural": "phases, contracts or journey are missing, or temporary behavior leaves its boundary undeclared",
|
|
53
53
|
"plan.deviation-structural": "the change that appeared while implementing touches a contract, the participating components, the phase order or the simulation boundary",
|
|
54
|
-
"plan.deviation-functional": "the change that appeared while implementing
|
|
54
|
+
"plan.deviation-functional": "the change that appeared while implementing moves the promise of the product: the expected result, the functional scope, a business rule, the actor, or the outcome an acceptance criterion states",
|
|
55
55
|
"plan.deviation-composable": "the change keeps the functional lineage and can be reconciled forward as a durable decision note instead of returning to a refine",
|
|
56
56
|
"plan.deviation-escalation": "what was found does not compose against this lineage and belongs to a spec of its own",
|
|
57
57
|
"plan.closure-lineage": "the divergence stays inside the same functional lineage: it amends how the promise is met, not who promised it",
|
|
@@ -106,7 +106,7 @@ Concrete mechanism per harness (matrix base verified **Jul-2026**; the `structur
|
|
|
106
106
|
|
|
107
107
|
> **Oz (Warp's cloud sibling).** `oz agent run` is a cloud agent orchestrator that **reuses Warp's surfaces**: same skills (`.agents/skills`, top-level dirs like Warp) and `AGENTS.md`. No dedicated structured-choice schema is documented for Oz itself, so a direct Oz run uses labeled markdown; if Oz delegates to another harness and exposes that harness's native question surface, follow that harness's own binding. Oz differs from Warp in three points: **detection** via `OZ_RUN_ID` (takes priority over Warp when both markers coexist); **MCP without a config file** — the JSON is passed via the `--mcp` flag of `oz agent run` (or the `OZ_MCP_CONFIG` env), it never writes `.warp/.mcp.json`; and **no plugin or hooks** (advisory enforcement, like Warp). Hence it shares the **Warp / Oz** column with those caveats.
|
|
108
108
|
|
|
109
|
-
> **compaction (signal & self-regulation).** The chassis' *Self-regulation (proactive compaction)* doctrine (`../modules/COMPACTION.md`, loaded under the `compaction` signal) needs
|
|
109
|
+
> **compaction (signal & self-regulation).** The chassis' *Self-regulation (proactive compaction)* doctrine (`../modules/COMPACTION.md`, loaded under the `compaction` signal) needs one per-host fact: the **context-pressure signal** (does the host surface one the agent can read?). Claude Code: the signal is the harness' own context warnings; `/compact` is user-invoked — the agent cannot run it itself (the native auto-compact is already cushioned by the PreCompact/PostCompact hooks: checkpoint-write + resume-summary). Hosts with compaction hooks/events (Codex Pre/PostCompact, OpenCode `session.compacted`) cushion resume the same way; hosts with neither signal nor mechanism run the universal fallback (CHECKPOINT + restart + resume). Self-regulation semantics: the chassis' subsection — single source.
|
|
110
110
|
|
|
111
111
|
> **host-memory (tiers & consumers).** Two tiers: *cheap* (structured, bounded — on Claude Code the auto-memory `MEMORY.md` + `CLAUDE.md`) and *deep* (transcript / `--resume` search, expensive). Consumers: **`/status`** reads only the *cheap* tier, **opportunistically and additively** (a `CONTEXTO DEL HOST` section when available; it **never asks** — a read-only dashboard — and silently omits the section on degrade); **`/resume`** **composes `/status`** and escalates a host-only finding **to a proposal only when the workline level does not explain the pending work** (the spec's fixed order governs the proposals, not the summary), optionally using the *deep* tier or asking as fallback. It is *enhancement*, never a `must`.
|
|
112
112
|
|
package/skills/w/hooks/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
| `PreToolUse` (`execute_sql`) | `hook sql-mutation-guard` | Blocks DML/DDL over MCP — reads only (DB scripts-only invariant). |
|
|
12
12
|
| `PreToolUse` (Bash) | `hook git-commit-advisor` | **Advisory (does not block)**: warns if a `git commit` message lacks the active session's `sessionNNN` tag (traceability). Does **not** inspect `push`/`--amend`/`--no-verify`. |
|
|
13
13
|
| `SessionEnd` | `auto-compact-on-close` | Writes `CHECKPOINT.md` on close — the resume key (*CHECKPOINT always* — chassis § Convergence / exit). |
|
|
14
|
-
| `PreCompact` | `checkpoint-write
|
|
14
|
+
| `PreCompact` | `checkpoint-write` | Writes `CHECKPOINT.md` before the host compacts. **Never blocks the compaction.** |
|
|
15
15
|
| `PostCompact` | `resume-summary` | Recovers **the conversation's own** loop state after a compact. |
|
|
16
16
|
|
|
17
17
|
> **Conversation identity (spec 011).** The three lifecycle hooks act on **one**
|
|
@@ -24,14 +24,18 @@
|
|
|
24
24
|
> `.workflow/sessions/.bindings.json` keyed by the SHA-256 of that id — the raw
|
|
25
25
|
> value is never persisted.
|
|
26
26
|
>
|
|
27
|
-
> **
|
|
28
|
-
>
|
|
29
|
-
>
|
|
30
|
-
>
|
|
31
|
-
>
|
|
32
|
-
> `
|
|
33
|
-
>
|
|
34
|
-
>
|
|
27
|
+
> **An unresolved session never holds a compaction back.** `PreCompact` always
|
|
28
|
+
> exits **0**. It used to exit 2 on an ambiguity so a person could name the
|
|
29
|
+
> session first, and that trapped the conversation: the remedy it printed does
|
|
30
|
+
> not always bind the conversation, so the next `/compact` blocked again. Now the
|
|
31
|
+
> host's compaction completes, Workline reports `continuity: "degraded"` with
|
|
32
|
+
> `primary_session: null`, and — whenever there is a candidate that could adopt
|
|
33
|
+
> it — parks a **refuge checkpoint** in `.workflow/sessions/.refuge/` naming the
|
|
34
|
+
> reason, the candidates and the way out. `PostCompact` reports it as `refuge`,
|
|
35
|
+
> and the first `checkpoint-write` that does resolve the session (typically
|
|
36
|
+
> `--code <NNN>`) folds it into that session's `CHECKPOINT.md` and removes it.
|
|
37
|
+
> The refuge names its conversation by the SHA-256 of the id, like the
|
|
38
|
+
> association registry. Per-host installation and transport belong to spec 010.
|
|
35
39
|
|
|
36
40
|
> **What they enforce (host-level, blocking):** invariant **#4** (DB scripts-only) via `sql-mutation-guard` (blocks DML/DDL over MCP), and the *expected-branch* clause of **#5** via `branch-check` (blocks edits on the wrong branch). The rest of git-safe (`push`/`--amend`/`--no-verify`/`--force`) is **doctrinal** — `git-commit-advisor` only **warns**, it does not block; a host may add its own deny hook if it wants hard enforcement.
|
|
37
41
|
>
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"hooks": [
|
|
63
63
|
{
|
|
64
64
|
"type": "command",
|
|
65
|
-
"command": "agent-workflow checkpoint-write
|
|
65
|
+
"command": "agent-workflow checkpoint-write",
|
|
66
66
|
"statusMessage": "Escribiendo CHECKPOINT.md antes de compactar...",
|
|
67
67
|
"timeout": 10
|
|
68
68
|
}
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
},
|
|
82
82
|
{
|
|
83
83
|
"type": "prompt",
|
|
84
|
-
"prompt": "Contexto compactado. El JSON anterior es output de `agent-workflow resume-summary`. Si `continuity` es `ok`, reanudá el loop de `primary_session` desde su CHECKPOINT.md y presentá un resumen. Si `continuity` es `degraded`, NO reanudes ninguna sesión: `active_sessions` es un listado, no una identidad — mostrá `candidates` con su `action` y pedí al usuario que elija (después reintentá con `--code <NNN>`). Si no hay sesiones, terminá."
|
|
84
|
+
"prompt": "Contexto compactado. El JSON anterior es output de `agent-workflow resume-summary`. Si `continuity` es `ok`, reanudá el loop de `primary_session` desde su CHECKPOINT.md y presentá un resumen. Si `continuity` es `degraded`, NO reanudes ninguna sesión: `active_sessions` es un listado, no una identidad — mostrá `candidates` con su `action` y pedí al usuario que elija (después reintentá con `--code <NNN>`). Si el JSON trae `refuge`, la compactación dejó un CHECKPOINT de refugio fuera de toda sesión: mostrá su `path` y avisá que se adopta al resolver la sesión (`aw checkpoint-write --code <NNN>`). Si no hay sesiones, terminá."
|
|
85
85
|
}
|
|
86
86
|
]
|
|
87
87
|
}
|
|
@@ -115,7 +115,7 @@ Resume **keys off the `CHECKPOINT`** of the run's session, not the existence of
|
|
|
115
115
|
|
|
116
116
|
> Each heir defines its **prior-work mark**: spec-refine the spec's frontmatter `status`; plan-refine `## Refinement decisions`; plan-exec the plan-doc's `- [x]` checkboxes; quick has no doc (CHECKPOINT only).
|
|
117
117
|
|
|
118
|
-
> **`Compactar`** (the `flow` control, across all 3 cases) → write `CHECKPOINT.md` in the session → trigger the harness compaction → resume by reading the checkpoint. **CHECKPOINT before compacting** is invariant. The proactive raise
|
|
118
|
+
> **`Compactar`** (the `flow` control, across all 3 cases) → write `CHECKPOINT.md` in the session → trigger the harness compaction → resume by reading the checkpoint. **CHECKPOINT before compacting** is invariant. The proactive raise and its host binding live in the `compaction` module.
|
|
119
119
|
|
|
120
120
|
## Convergence / exit
|
|
121
121
|
|