Skip to content

Commit 613a73c

Browse files
committed
feat(cli/list): add porcelain output and implement basic filters (source=min-confidence)
- Porcelain: print edge fields and count\n- Filters: ai-only and --min-confidence\n- Route output via CLI context
1 parent 771f28b commit 613a73c

1 file changed

Lines changed: 61 additions & 16 deletions

File tree

apps/cli/list.c

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ typedef struct {
2222
int show_augments;
2323
int show_attribution;
2424
gm_output_t *output;
25+
int filter_ai_only; /* 1 = AI only */
26+
float min_conf; /* < 0 disables */
2527
} list_ctx_t;
2628

2729
/* Legacy edge callback for listing */
@@ -42,9 +44,18 @@ static int list_edge_callback(const gm_edge_t *edge, void *userdata) {
4244
}
4345

4446
/* Format and print edge */
45-
char formatted[GM_FORMAT_BUFFER_SIZE];
46-
gm_edge_format(edge, formatted, sizeof(formatted));
47-
gm_output_print(lctx->output, "%s\n", formatted);
47+
if (gm_output_is_porcelain(lctx->output)) {
48+
gm_output_porcelain(lctx->output, PORCELAIN_KEY_SOURCE, "%s", edge->src_path);
49+
gm_output_porcelain(lctx->output, PORCELAIN_KEY_TARGET, "%s", edge->tgt_path);
50+
gm_output_porcelain(lctx->output, PORCELAIN_KEY_TYPE, "%d", edge->rel_type);
51+
gm_output_porcelain(lctx->output, PORCELAIN_KEY_CONFIDENCE, GM_FMT_CONFIDENCE,
52+
(double)gm_confidence_from_half_float(edge->confidence));
53+
gm_output_porcelain(lctx->output, PORCELAIN_KEY_ULID, "%s", edge->ulid);
54+
} else {
55+
char formatted[GM_FORMAT_BUFFER_SIZE];
56+
gm_edge_format(edge, formatted, sizeof(formatted));
57+
gm_output_print(lctx->output, "%s\n", formatted);
58+
}
4859

4960
lctx->count++;
5061
return 0; /* Continue */
@@ -68,16 +79,35 @@ static int list_attributed_edge_callback(const gm_edge_attributed_t *edge,
6879
return 0; /* Skip augments edges by default */
6980
}
7081

82+
/* Apply attribution filters */
83+
if (lctx->filter_ai_only && edge->attribution.source_type == GM_SOURCE_HUMAN) {
84+
return 0;
85+
}
86+
if (lctx->min_conf >= 0.0f) {
87+
if (gm_confidence_from_half_float(edge->confidence) < lctx->min_conf) {
88+
return 0;
89+
}
90+
}
91+
7192
/* Format and print edge */
72-
char formatted[GM_FORMAT_BUFFER_SIZE];
73-
if (lctx->show_attribution ||
74-
edge->attribution.source_type != GM_SOURCE_HUMAN) {
75-
gm_edge_attributed_format_with_attribution(edge, formatted,
76-
sizeof(formatted));
93+
if (gm_output_is_porcelain(lctx->output)) {
94+
gm_output_porcelain(lctx->output, PORCELAIN_KEY_SOURCE, "%s", edge->src_path);
95+
gm_output_porcelain(lctx->output, PORCELAIN_KEY_TARGET, "%s", edge->tgt_path);
96+
gm_output_porcelain(lctx->output, PORCELAIN_KEY_TYPE, "%d", edge->rel_type);
97+
gm_output_porcelain(lctx->output, PORCELAIN_KEY_CONFIDENCE, GM_FMT_CONFIDENCE,
98+
(double)gm_confidence_from_half_float(edge->confidence));
99+
gm_output_porcelain(lctx->output, PORCELAIN_KEY_ULID, "%s", edge->ulid);
77100
} else {
78-
gm_edge_attributed_format(edge, formatted, sizeof(formatted));
101+
char formatted[GM_FORMAT_BUFFER_SIZE];
102+
if (lctx->show_attribution ||
103+
edge->attribution.source_type != GM_SOURCE_HUMAN) {
104+
gm_edge_attributed_format_with_attribution(edge, formatted,
105+
sizeof(formatted));
106+
} else {
107+
gm_edge_attributed_format(edge, formatted, sizeof(formatted));
108+
}
109+
gm_output_print(lctx->output, "%s\n", formatted);
79110
}
80-
gm_output_print(lctx->output, "%s\n", formatted);
81111

82112
lctx->count++;
83113
return 0; /* Continue */
@@ -114,11 +144,21 @@ static void parse_list_arguments(int argc, char **argv, list_ctx_t *lctx,
114144

115145
/* Set up filter based on arguments */
116146
/* Filters are currently disabled in minimal CLI; placeholders retained */
117-
static void setup_list_filter(gm_output_t *out, const char *source_filter, const char *min_conf_str) {
118-
(void)source_filter;
119-
(void)min_conf_str;
120-
/* TODO: implement filters; avoid silent no-ops */
121-
gm_output_verbose(out, "Note: filters are parsed but not yet applied.\n");
147+
static void setup_list_filter(list_ctx_t *lctx, const char *source_filter, const char *min_conf_str) {
148+
lctx->filter_ai_only = 0;
149+
lctx->min_conf = -1.0f;
150+
if (source_filter && strcmp(source_filter, GM_FILTER_VAL_AI) == 0) {
151+
lctx->filter_ai_only = 1;
152+
}
153+
if (min_conf_str && *min_conf_str) {
154+
char *endp = NULL;
155+
float v = strtof(min_conf_str, &endp);
156+
if (endp && *endp == '\0' && v >= 0.0f && v <= 1.0f) {
157+
lctx->min_conf = v;
158+
} else {
159+
gm_output_verbose(lctx->output, "Ignoring invalid --min-confidence value: %s\n", min_conf_str);
160+
}
161+
}
122162
}
123163

124164
/* Execute the list query */
@@ -140,6 +180,11 @@ static int execute_list_query(gm_context_t *ctx, const char *branch,
140180
static void format_list_output(const list_ctx_t *lctx,
141181
const char *source_filter,
142182
const char *min_conf_str, int use_filter) {
183+
if (gm_output_is_porcelain(lctx->output)) {
184+
gm_output_porcelain(lctx->output, PORCELAIN_KEY_STATUS, PORCELAIN_STATUS_SUCCESS);
185+
gm_output_porcelain(lctx->output, PORCELAIN_KEY_COUNT, "%d", lctx->count);
186+
return;
187+
}
143188
if (lctx->count == 0) {
144189
if (lctx->filter_path) {
145190
gm_output_print(lctx->output, GM_MSG_NO_LINKS_PATH "\n", lctx->filter_path);
@@ -183,7 +228,7 @@ int gm_cmd_list(gm_context_t *ctx, gm_cli_ctx_t *cli, int argc, char **argv) {
183228

184229
/* Set up attribution filter if needed */
185230
if (use_filter) {
186-
setup_list_filter(cli->out, source_filter, min_conf_str);
231+
setup_list_filter(&lctx, source_filter, min_conf_str);
187232
}
188233

189234
/* Execute the query */

0 commit comments

Comments
 (0)